class NativeStacktraceProcessor(StacktraceProcessor): def __init__(self, *args, **kwargs): StacktraceProcessor.__init__(self, *args, **kwargs) debug_meta = self.data.get('debug_meta') self.sym = None if debug_meta: self.available = True self.debug_meta = debug_meta self.sdk_info = get_sdk_from_event(self.data) else: self.available = False def close(self): StacktraceProcessor.close(self) if self.sym is not None: self.sym.close() self.sym = None def preprocess_related_data(self): if not self.available: return False is_debug_build = self.debug_meta.get('is_debug_build') referenced_images = find_stacktrace_referenced_images( self.debug_meta['images'], [ x.stacktrace for x in self.stacktrace_infos]) self.sym = Symbolizer(self.project, self.debug_meta['images'], referenced_images=referenced_images, is_debug_build=is_debug_build) # The symbolizer gets a reference to the debug meta's images so # when it resolves the missing vmaddrs it changes them in the data # dict. return self.sym.resolve_missing_vmaddrs() def process_frame(self, frame): # XXX: warn on missing availability? # Only process frames here that are of supported platforms and # have the mandatory requirements for if not self.available or \ self.get_effective_platform(frame) != 'cocoa' or \ 'image_addr' not in frame or \ 'instruction_addr' not in frame or \ 'symbol_addr' not in frame: return None errors = [] # Construct a raw frame that is used by the symbolizer # backend. sym_frame = { 'object_name': frame.get('package'), 'object_addr': frame['image_addr'], 'instruction_addr': frame['instruction_addr'], 'symbol_name': frame.get('function'), 'symbol_addr': frame['symbol_addr'], } new_frame = dict(frame) raw_frame = dict(frame) try: sfrm = self.sym.symbolize_frame(sym_frame, self.sdk_info) except SymbolicationFailed as e: if e.is_user_fixable or e.is_sdk_failure: errors.append({ 'type': EventError.NATIVE_INTERNAL_FAILURE, 'image_uuid': e.image_uuid, 'image_path': e.image_path, 'image_arch': e.image_arch, 'message': e.message, }) else: logger.debug('Failed to symbolicate with native backend', exc_info=True) else: symbol = sfrm.get('symbol_name') or \ new_frame.get('function') or '<unknown>' function = demangle_symbol(symbol, simplified=True) new_frame['function'] = function # If we demangled something, store the original in the # symbol portion of the frame if function != symbol: new_frame['symbol'] = symbol new_frame['abs_path'] = sfrm.get('filename') or None if new_frame['abs_path']: new_frame['filename'] = posixpath.basename( new_frame['abs_path']) if sfrm.get('line') is not None: new_frame['lineno'] = sfrm['line'] else: new_frame['instruction_offset'] = \ parse_addr(sfrm['instruction_addr']) - \ parse_addr(sfrm['symbol_addr']) if sfrm.get('column') is not None: new_frame['colno'] = sfrm['column'] new_frame['package'] = sfrm['object_name'] \ or new_frame.get('package') new_frame['symbol_addr'] = '0x%x' % \ parse_addr(sfrm['symbol_addr']) new_frame['instruction_addr'] = '0x%x' % parse_addr( sfrm['instruction_addr']) in_app = self.sym.is_in_app(sym_frame) new_frame['in_app'] = raw_frame['in_app'] = in_app return [new_frame], [raw_frame], errors
class NativeStacktraceProcessor(StacktraceProcessor): def __init__(self, *args, **kwargs): StacktraceProcessor.__init__(self, *args, **kwargs) debug_meta = self.data.get('debug_meta') self.sym = None if debug_meta: self.available = True self.debug_meta = debug_meta self.sdk_info = get_sdk_from_event(self.data) else: self.available = False def close(self): StacktraceProcessor.close(self) if self.sym is not None: self.sym.close() self.sym = None def preprocess_related_data(self): if not self.available: return False is_debug_build = self.debug_meta.get('is_debug_build') referenced_images = find_stacktrace_referenced_images( self.debug_meta['images'], [x.stacktrace for x in self.stacktrace_infos]) self.sym = Symbolizer(self.project, self.debug_meta['images'], referenced_images=referenced_images, is_debug_build=is_debug_build) # The symbolizer gets a reference to the debug meta's images so # when it resolves the missing vmaddrs it changes them in the data # dict. return self.sym.resolve_missing_vmaddrs() def find_best_instruction(self, frame, stacktrace_info, idx): """Given a frame, stacktrace info and frame index this returns the interpolated instruction address we then use for symbolication later. """ meta = None # We only need to provide meta information for frame zero if idx == 0: # The signal is useful information for symsynd in some situations # to disambiugate the first frame. If we can get this information # from the mechanism we want to pass it onwards. signal = None exc = self.data.get('sentry.interfaces.Exception') if exc is not None: mechanism = exc['values'][0].get('mechanism') if mechanism and 'posix_signal' in mechanism and \ 'signal' in mechanism['posix_signal']: signal = mechanism['posix_signal']['signal'] meta = { 'frame_number': 0, 'registers': stacktrace_info.stacktrace.get('registers'), 'signal': signal, } return self.sym.find_best_instruction(frame, meta=meta) def process_frame(self, frame, stacktrace_info, idx): # XXX: warn on missing availability? # Only process frames here that are of supported platforms and # have the mandatory requirements for if not self.available or \ self.get_effective_platform(frame) != 'cocoa' or \ 'instruction_addr' not in frame: return None errors = [] # Construct a raw frame that is used by the symbolizer # backend. We only assemble the bare minimum we need here. sym_input_frame = { 'object_name': frame.get('package'), 'instruction_addr': self.find_best_instruction(frame, stacktrace_info, idx), 'symbol_name': frame.get('function'), 'symbol_addr': frame.get('symbol_addr'), } in_app = self.sym.is_in_app(sym_input_frame) new_frames = [] raw_frame = dict(frame) raw_frame['in_app'] = in_app try: symbolicated_frames = self.sym.symbolize_frame( sym_input_frame, self.sdk_info, symbolize_inlined=True) if not symbolicated_frames: return None, [raw_frame], [] except SymbolicationFailed as e: errors = [] if e.is_user_fixable or e.is_sdk_failure: errors.append({ 'type': e.type, 'image_uuid': e.image_uuid, 'image_path': e.image_path, 'image_arch': e.image_arch, 'message': e.message, }) else: logger.debug('Failed to symbolicate with native backend', exc_info=True) return None, [raw_frame], errors for sfrm in symbolicated_frames: symbol = sfrm.get('symbol_name') or \ frame.get('function') or '<unknown>' function = demangle_symbol(symbol, simplified=True) new_frame = dict(frame) new_frame['function'] = function # If we demangled something, store the original in the # symbol portion of the frame if function != symbol: new_frame['symbol'] = symbol new_frame['abs_path'] = sfrm.get('filename') or None if new_frame['abs_path']: new_frame['filename'] = posixpath.basename( new_frame['abs_path']) if sfrm.get('line') is not None: new_frame['lineno'] = sfrm['line'] if sfrm.get('column') is not None: new_frame['colno'] = sfrm['column'] new_frame['package'] = sfrm['object_name'] \ or new_frame.get('package') new_frame['in_app'] = in_app new_frames.append(new_frame) return new_frames, [raw_frame], []
class NativeStacktraceProcessor(StacktraceProcessor): def __init__(self, *args, **kwargs): StacktraceProcessor.__init__(self, *args, **kwargs) debug_meta = self.data.get('debug_meta') self.cpu_name = cpu_name_from_data(self.data) self.sym = None self.dsyms_referenced = set() if debug_meta: self.available = True self.debug_meta = debug_meta self.sdk_info = get_sdk_from_event(self.data) self.image_lookup = ImageLookup(self.debug_meta['images']) else: self.available = False def close(self): StacktraceProcessor.close(self) if self.dsyms_referenced: metrics.incr('dsyms.processed', amount=len(self.dsyms_referenced), instance=self.project.id) if self.sym is not None: self.sym.close() self.sym = None def find_best_instruction(self, processable_frame): """Given a frame, stacktrace info and frame index this returns the interpolated instruction address we then use for symbolication later. """ if self.cpu_name is None: return parse_addr(processable_frame['instruction_addr']) meta = None # We only need to provide meta information for frame zero if processable_frame.idx == 0: # The signal is useful information for symsynd in some situations # to disambiugate the first frame. If we can get this information # from the mechanism we want to pass it onwards. signal = None exc = self.data.get('sentry.interfaces.Exception') if exc is not None: mechanism = exc['values'][0].get('mechanism') if mechanism and 'posix_signal' in mechanism and \ 'signal' in mechanism['posix_signal']: signal = mechanism['posix_signal']['signal'] meta = { 'frame_number': 0, 'registers': processable_frame.stacktrace_info.stacktrace.get('registers'), 'signal': signal, } return find_best_instruction(processable_frame['instruction_addr'], self.cpu_name, meta=meta) def handles_frame(self, frame, stacktrace_info): platform = frame.get('platform') or self.data.get('platform') return (platform == 'cocoa' and self.available and 'instruction_addr' in frame) def preprocess_frame(self, processable_frame): instr_addr = self.find_best_instruction(processable_frame) img = self.image_lookup.find_image(instr_addr) processable_frame.data = { 'instruction_addr': instr_addr, 'image': img, 'image_uuid': img['uuid'] if img is not None else None, 'symbolserver_match': None, } if img is not None: processable_frame.set_cache_key_from_values(( FRAME_CACHE_VERSION, # Because the images can move around, we want to rebase # the address for the cache key to be within the image # the same way as we do it in the symbolizer. rebase_addr(instr_addr, img), img['uuid'].lower(), img['cpu_type'], img['cpu_subtype'], img['image_size'], )) def preprocess_step(self, processing_task): if not self.available: return False referenced_images = set( pf.data['image_uuid'] for pf in processing_task.iter_processable_frames(self) if pf.cache_value is None and pf.data['image_uuid'] is not None) def on_referenced(dsym_file): app_info = version_build_from_data(self.data) if app_info is not None: dsym_app = DSymApp.objects.create_or_update_app( sync_id=None, app_id=app_info.id, project=self.project, data={'name': app_info.name}, platform=DSymPlatform.APPLE, ) try: with transaction.atomic(): version_dsym_file, created = VersionDSymFile.objects.get_or_create( dsym_file=dsym_file, dsym_app=dsym_app, version=app_info.version, build=app_info.build, ) except IntegrityError: # XXX: this can currently happen because we only # support one app per dsym file. Since this can # happen in some cases anyways we ignore it. pass self.sym = Symbolizer(self.project, self.image_lookup, cpu_name=self.cpu_name, referenced_images=referenced_images, on_dsym_file_referenced=on_referenced) # The symbolizer gets a reference to the debug meta's images so # when it resolves the missing vmaddrs it changes them in the data # dict. data = self.sym.resolve_missing_vmaddrs() if options.get('symbolserver.enabled'): self.fetch_system_symbols(processing_task) return data def fetch_system_symbols(self, processing_task): to_lookup = [] pf_list = [] for pf in processing_task.iter_processable_frames(self): img = pf.data['image'] if pf.cache_value is not None or img is None or \ self.sym.is_frame_from_app_bundle(pf.frame, img): continue to_lookup.append({ 'object_uuid': img['uuid'], 'object_name': img['name'], 'addr': '0x%x' % rebase_addr(pf.data['instruction_addr'], img) }) pf_list.append(pf) if not to_lookup: return rv = lookup_system_symbols(to_lookup, self.sdk_info, self.sym.cpu_name) if rv is not None: for symrv, pf in zip(rv, pf_list): if symrv is None: continue pf.data['symbolserver_match'] = symrv def process_frame(self, processable_frame, processing_task): frame = processable_frame.frame errors = [] new_frames = [] raw_frame = dict(frame) if processable_frame.cache_value is None: # Construct a raw frame that is used by the symbolizer # backend. We only assemble the bare minimum we need here. sym_input_frame = { 'object_name': frame.get('package'), 'instruction_addr': processable_frame.data['instruction_addr'], 'symbol_name': frame.get('function'), } in_app = self.sym.is_in_app(sym_input_frame) raw_frame['in_app'] = in_app img_uuid = processable_frame.data['image_uuid'] if img_uuid is not None: self.dsyms_referenced.add(img_uuid) try: symbolicated_frames = self.sym.symbolize_frame( sym_input_frame, self.sdk_info, symbolserver_match=processable_frame. data['symbolserver_match'], symbolize_inlined=True) if not symbolicated_frames: return None, [raw_frame], [] except SymbolicationFailed as e: reprocessing_active = False if self.project: reprocessing_active = bool( self.project.get_option('sentry:reprocessing_active', False)) # User fixable but fatal errors are reported as processing # issues but only if the feature is activated. if reprocessing_active and e.is_user_fixable and e.is_fatal: report_processing_issue(self.data, scope='native', object='dsym:%s' % e.image_uuid, type=e.type, data={ 'image_path': e.image_path, 'image_uuid': e.image_uuid, 'image_arch': e.image_arch, 'message': e.message, }) # This in many ways currently does not really do anything. # The reason is that once a processing issue is reported # the event will only be stored as a raw event and no # group will be generated. As a result it also means that # we will not have any user facing event or error showing # up at all. We want to keep this here though in case we # do not want to report some processing issues (eg: # optional dsyms) errors = [] if e.is_user_fixable or e.is_sdk_failure: errors.append({ 'type': e.type, 'image_uuid': e.image_uuid, 'image_path': e.image_path, 'image_arch': e.image_arch, 'message': e.message, }) else: logger.debug('Failed to symbolicate with native backend', exc_info=True) return [raw_frame], [raw_frame], errors processable_frame.set_cache_value([in_app, symbolicated_frames]) else: in_app, symbolicated_frames = processable_frame.cache_value raw_frame['in_app'] = in_app for sfrm in symbolicated_frames: symbol = sfrm.get('symbol_name') or \ frame.get('function') or NATIVE_UNKNOWN_STRING function = demangle_symbol(symbol, simplified=True) new_frame = dict(frame) new_frame['function'] = function # If we demangled something, store the original in the # symbol portion of the frame if function != symbol: new_frame['symbol'] = symbol new_frame['abs_path'] = sfrm.get('filename') or None if new_frame['abs_path']: new_frame['filename'] = posixpath.basename( new_frame['abs_path']) if sfrm.get('line') is not None: new_frame['lineno'] = sfrm['line'] if sfrm.get('column') is not None: new_frame['colno'] = sfrm['column'] new_frame['package'] = sfrm['object_name'] \ or new_frame.get('package') new_frame['in_app'] = in_app new_frames.append(new_frame) return new_frames, [raw_frame], []
class NativeStacktraceProcessor(StacktraceProcessor): def __init__(self, *args, **kwargs): StacktraceProcessor.__init__(self, *args, **kwargs) debug_meta = self.data.get('debug_meta') self.cpu_name = cpu_name_from_data(self.data) self.sym = None if debug_meta: self.available = True self.debug_meta = debug_meta self.sdk_info = get_sdk_from_event(self.data) self.image_lookup = ImageLookup(self.debug_meta['images']) else: self.available = False def close(self): StacktraceProcessor.close(self) if self.sym is not None: self.sym.close() self.sym = None def find_best_instruction(self, processable_frame): """Given a frame, stacktrace info and frame index this returns the interpolated instruction address we then use for symbolication later. """ if self.cpu_name is None: return parse_addr(processable_frame['instruction_addr']) meta = None # We only need to provide meta information for frame zero if processable_frame.idx == 0: # The signal is useful information for symsynd in some situations # to disambiugate the first frame. If we can get this information # from the mechanism we want to pass it onwards. signal = None exc = self.data.get('sentry.interfaces.Exception') if exc is not None: mechanism = exc['values'][0].get('mechanism') if mechanism and 'posix_signal' in mechanism and \ 'signal' in mechanism['posix_signal']: signal = mechanism['posix_signal']['signal'] meta = { 'frame_number': 0, 'registers': processable_frame.stacktrace_info.stacktrace.get('registers'), 'signal': signal, } return find_best_instruction( processable_frame['instruction_addr'], self.cpu_name, meta=meta) def handles_frame(self, frame, stacktrace_info): platform = frame.get('platform') or self.data.get('platform') return ( platform == 'cocoa' and self.available and 'instruction_addr' in frame ) def preprocess_frame(self, processable_frame): instr_addr = self.find_best_instruction(processable_frame) img = self.image_lookup.find_image(instr_addr) processable_frame.data = { 'instruction_addr': instr_addr, 'image': img, 'image_uuid': img['uuid'] if img is not None else None, 'symbolserver_match': None, } if img is not None: processable_frame.set_cache_key_from_values(( FRAME_CACHE_VERSION, # Because the images can move around, we want to rebase # the address for the cache key to be within the image # the same way as we do it in the symbolizer. rebase_addr(instr_addr, img), img['uuid'].lower(), img['cpu_type'], img['cpu_subtype'], img['image_size'], )) def preprocess_step(self, processing_task): if not self.available: return False referenced_images = set( pf.data['image_uuid'] for pf in processing_task.iter_processable_frames(self) if pf.cache_value is None and pf.data['image_uuid'] is not None) def on_referenced(dsym_file): app_info = version_build_from_data(self.data) if app_info is not None: dsym_app = DSymApp.objects.create_or_update_app( sync_id=None, app_id=app_info.id, project=self.project, data={'name': app_info.name}, platform=DSymPlatform.APPLE, ) version_dsym_file, created = VersionDSymFile.objects.get_or_create( dsym_file=dsym_file, dsym_app=dsym_app, version=app_info.version, build=app_info.build, ) self.sym = Symbolizer(self.project, self.image_lookup, cpu_name=self.cpu_name, referenced_images=referenced_images, on_dsym_file_referenced=on_referenced) # The symbolizer gets a reference to the debug meta's images so # when it resolves the missing vmaddrs it changes them in the data # dict. data = self.sym.resolve_missing_vmaddrs() if options.get('symbolserver.enabled'): self.fetch_system_symbols(processing_task) return data def fetch_system_symbols(self, processing_task): to_lookup = [] pf_list = [] for pf in processing_task.iter_processable_frames(self): img = pf.data['image'] if pf.cache_value is not None or img is None or \ self.sym.is_frame_from_app_bundle(pf.frame, img): continue to_lookup.append({ 'object_uuid': img['uuid'], 'object_name': img['name'], 'addr': '0x%x' % rebase_addr(pf.data['instruction_addr'], img) }) pf_list.append(pf) if not to_lookup: return rv = lookup_system_symbols(to_lookup, self.sdk_info, self.sym.cpu_name) if rv is not None: for symrv, pf in zip(rv, pf_list): if symrv is None: continue pf.data['symbolserver_match'] = symrv def process_frame(self, processable_frame, processing_task): frame = processable_frame.frame errors = [] new_frames = [] raw_frame = dict(frame) if processable_frame.cache_value is None: # Construct a raw frame that is used by the symbolizer # backend. We only assemble the bare minimum we need here. sym_input_frame = { 'object_name': frame.get('package'), 'instruction_addr': processable_frame.data['instruction_addr'], 'symbol_name': frame.get('function'), } in_app = self.sym.is_in_app(sym_input_frame) raw_frame['in_app'] = in_app try: symbolicated_frames = self.sym.symbolize_frame( sym_input_frame, self.sdk_info, symbolserver_match=processable_frame.data['symbolserver_match'], symbolize_inlined=True) if not symbolicated_frames: return None, [raw_frame], [] except SymbolicationFailed as e: reprocessing_active = False if self.project: reprocessing_active = bool( self.project.get_option('sentry:reprocessing_active', False) ) # User fixable but fatal errors are reported as processing # issues but only if the feature is activated. if reprocessing_active and e.is_user_fixable and e.is_fatal: report_processing_issue(self.data, scope='native', object='dsym:%s' % e.image_uuid, type=e.type, data={ 'image_path': e.image_path, 'image_uuid': e.image_uuid, 'image_arch': e.image_arch, 'message': e.message, } ) # This in many ways currently does not really do anything. # The reason is that once a processing issue is reported # the event will only be stored as a raw event and no # group will be generated. As a result it also means that # we will not have any user facing event or error showing # up at all. We want to keep this here though in case we # do not want to report some processing issues (eg: # optional dsyms) errors = [] if e.is_user_fixable or e.is_sdk_failure: errors.append({ 'type': e.type, 'image_uuid': e.image_uuid, 'image_path': e.image_path, 'image_arch': e.image_arch, 'message': e.message, }) else: logger.debug('Failed to symbolicate with native backend', exc_info=True) return [raw_frame], [raw_frame], errors processable_frame.set_cache_value([in_app, symbolicated_frames]) else: in_app, symbolicated_frames = processable_frame.cache_value raw_frame['in_app'] = in_app for sfrm in symbolicated_frames: symbol = sfrm.get('symbol_name') or \ frame.get('function') or NATIVE_UNKNOWN_STRING function = demangle_symbol(symbol, simplified=True) new_frame = dict(frame) new_frame['function'] = function # If we demangled something, store the original in the # symbol portion of the frame if function != symbol: new_frame['symbol'] = symbol new_frame['abs_path'] = sfrm.get('filename') or None if new_frame['abs_path']: new_frame['filename'] = posixpath.basename( new_frame['abs_path']) if sfrm.get('line') is not None: new_frame['lineno'] = sfrm['line'] if sfrm.get('column') is not None: new_frame['colno'] = sfrm['column'] new_frame['package'] = sfrm['object_name'] \ or new_frame.get('package') new_frame['in_app'] = in_app new_frames.append(new_frame) return new_frames, [raw_frame], []
class NativeStacktraceProcessor(StacktraceProcessor): def __init__(self, *args, **kwargs): StacktraceProcessor.__init__(self, *args, **kwargs) debug_meta = self.data.get('debug_meta') self.cpu_name = cpu_name_from_data(self.data) self.sym = None if debug_meta: self.available = True self.debug_meta = debug_meta self.sdk_info = get_sdk_from_event(self.data) self.image_lookup = ImageLookup(self.debug_meta['images']) else: self.available = False def close(self): StacktraceProcessor.close(self) if self.sym is not None: self.sym.close() self.sym = None def find_best_instruction(self, processable_frame): """Given a frame, stacktrace info and frame index this returns the interpolated instruction address we then use for symbolication later. """ if self.cpu_name is None: return parse_addr(processable_frame['instruction_addr']) meta = None # We only need to provide meta information for frame zero if processable_frame.idx == 0: # The signal is useful information for symsynd in some situations # to disambiugate the first frame. If we can get this information # from the mechanism we want to pass it onwards. signal = None exc = self.data.get('sentry.interfaces.Exception') if exc is not None: mechanism = exc['values'][0].get('mechanism') if mechanism and 'posix_signal' in mechanism and \ 'signal' in mechanism['posix_signal']: signal = mechanism['posix_signal']['signal'] meta = { 'frame_number': 0, 'registers': processable_frame.stacktrace_info.stacktrace.get('registers'), 'signal': signal, } return find_best_instruction(processable_frame['instruction_addr'], self.cpu_name, meta=meta) def handles_frame(self, frame, stacktrace_info): platform = frame.get('platform') or self.data.get('platform') return (platform == 'cocoa' and self.available and 'instruction_addr' in frame) def preprocess_frame(self, processable_frame): instr_addr = self.find_best_instruction(processable_frame) img = self.image_lookup.find_image(instr_addr) processable_frame.data = { 'instruction_addr': instr_addr, 'image_uuid': img['uuid'] if img is not None else None, } if img is not None: processable_frame.set_cache_key_from_values(( FRAME_CACHE_VERSION, # Because the images can move around, we want to rebase # the address for the cache key to be within the image # the same way as we do it in the symbolizer. (parse_addr(img['image_vmaddr']) + instr_addr - parse_addr(img['image_addr'])), img['uuid'].lower(), img['cpu_type'], img['cpu_subtype'], img['image_size'], )) def preprocess_step(self, processing_task): if not self.available: return False referenced_images = set( pf.data['image_uuid'] for pf in processing_task.iter_processable_frames(self) if pf.cache_value is None and pf.data['image_uuid'] is not None) self.sym = Symbolizer(self.project, self.image_lookup, cpu_name=self.cpu_name, referenced_images=referenced_images) # The symbolizer gets a reference to the debug meta's images so # when it resolves the missing vmaddrs it changes them in the data # dict. return self.sym.resolve_missing_vmaddrs() def process_frame(self, processable_frame, processing_task): frame = processable_frame.frame errors = [] new_frames = [] raw_frame = dict(frame) if processable_frame.cache_value is None: # Construct a raw frame that is used by the symbolizer # backend. We only assemble the bare minimum we need here. sym_input_frame = { 'object_name': frame.get('package'), 'instruction_addr': processable_frame.data['instruction_addr'], 'symbol_name': frame.get('function'), } in_app = self.sym.is_in_app(sym_input_frame) raw_frame['in_app'] = in_app try: symbolicated_frames = self.sym.symbolize_frame( sym_input_frame, self.sdk_info, symbolize_inlined=True) if not symbolicated_frames: return None, [raw_frame], [] except SymbolicationFailed as e: errors = [] if e.is_user_fixable or e.is_sdk_failure: errors.append({ 'type': e.type, 'image_uuid': e.image_uuid, 'image_path': e.image_path, 'image_arch': e.image_arch, 'message': e.message, }) else: logger.debug('Failed to symbolicate with native backend', exc_info=True) return None, [raw_frame], errors processable_frame.set_cache_value([in_app, symbolicated_frames]) else: in_app, symbolicated_frames = processable_frame.cache_value raw_frame['in_app'] = in_app for sfrm in symbolicated_frames: symbol = sfrm.get('symbol_name') or \ frame.get('function') or NATIVE_UNKNOWN_STRING function = demangle_symbol(symbol, simplified=True) new_frame = dict(frame) new_frame['function'] = function # If we demangled something, store the original in the # symbol portion of the frame if function != symbol: new_frame['symbol'] = symbol new_frame['abs_path'] = sfrm.get('filename') or None if new_frame['abs_path']: new_frame['filename'] = posixpath.basename( new_frame['abs_path']) if sfrm.get('line') is not None: new_frame['lineno'] = sfrm['line'] if sfrm.get('column') is not None: new_frame['colno'] = sfrm['column'] new_frame['package'] = sfrm['object_name'] \ or new_frame.get('package') new_frame['in_app'] = in_app new_frames.append(new_frame) return new_frames, [raw_frame], []