def symbolize_frame(self, frame, system_info=None, report_error=None): error = None img = self.images.get(frame['object_addr']) # Step one: try to symbolize with cached dsym files. try: new_frame = self.symsynd_symbolizer.symbolize_frame( frame, silent=False) if new_frame is not None: return self._process_frame(new_frame, img) except SymbolicationError as e: error = e # If that does not work, look up system symbols. if img is not None: symbol = find_system_symbol(img, frame['instruction_addr'], system_info) if symbol is not None: symbol = demangle_symbol(symbol) or symbol rv = dict(frame, symbol_name=symbol, filename=None, line=0, column=0, uuid=img['uuid'], object_name=img['name']) return self._process_frame(rv, img) if report_error is not None and error is not None: report_error(error) return self._process_frame(frame, img)
def symbolize_frame(self, frame, system_info=None, report_error=None): error = None img = self.images.get(frame['object_addr']) # Step one: try to symbolize with cached dsym files. try: new_frame = self.symsynd_symbolizer.symbolize_frame(frame, silent=False) if new_frame is not None: return self._process_frame(new_frame, img) except SymbolicationError as e: error = e # If that does not work, look up system symbols. if img is not None: symbol = find_system_symbol(img, frame['instruction_addr'], system_info) if symbol is not None: symbol = demangle_symbol(symbol) or symbol rv = dict(frame, symbol_name=symbol, filename=None, line=0, column=0, uuid=img['uuid'], object_name=img['name']) return self._process_frame(rv, img) if report_error is not None and error is not None: report_error(error) return self._process_frame(frame, img)
def _process_symbol(sym): too_long = trim_symbols and len(sym) > MAX_SYM if demangle or too_long: new_sym = demangle_symbol(sym) if new_sym is not None and (len(new_sym) < sym or too_long): sym = new_sym if trim_symbols: sym = sym[:MAX_SYM] return sym
def symbolize_system_frame(self, frame, sdk_info): img = self.images.get(frame['object_addr']) if img is None: return symbol = find_system_symbol(img, frame['instruction_addr'], sdk_info) if symbol is None: return symbol = demangle_symbol(symbol) or symbol rv = dict(frame, symbol_name=symbol, filename=None, line=0, column=0, uuid=img['uuid'], object_name=img['name']) return self._process_frame(rv, img)
def symbolize_frame(self, frame, system_info=None): # Step one: try to symbolize with cached dsym files. new_frame = self.symsynd_symbolizer.symbolize_frame(frame) if new_frame is not None: return trim_frame(new_frame) # If that does not work, look up system symbols. img = self.images.get(frame['object_addr']) if img is not None: symbol = find_system_symbol(img, frame['instruction_addr'], system_info) if symbol is not None: symbol = demangle_symbol(symbol) or symbol rv = dict(frame, symbol_name=symbol, filename=None, line=0, column=0, uuid=img['uuid']) return trim_frame(rv)
def symbolize(self, dsym_path, image_vmaddr, image_addr, instruction_addr, cpu_name, uuid=None, silent=True, demangle=True): if self._closed: raise RuntimeError('Symbolizer is closed') if not is_valid_cpu_name(cpu_name): raise ValueError('"%s" is not a valid cpu name' % cpu_name) dsym_path = normalize_dsym_path(dsym_path) image_vmaddr = parse_addr(image_vmaddr) if not image_vmaddr: image_vmaddr = get_macho_vmaddr(dsym_path, cpu_name) or 0 image_addr = parse_addr(image_addr) instruction_addr = parse_addr(instruction_addr) addr = image_vmaddr + instruction_addr - image_addr try: with self._lock: with timedsection('symbolize'): sym = self.symbolizer.symbolize(dsym_path, addr, cpu_name) if sym[0] is None: raise SymbolicationError('Symbolizer could not find symbol') except SymbolicationError: if not silent: raise sym = (None, None, 0, 0) symbol_name = sym[0] if demangle: symbol_name = demangle_symbol(symbol_name) return { 'symbol_name': symbol_name, 'filename': sym[1], 'line': sym[2], 'column': sym[3], 'uuid': uuid, }
def symbolize(self, dsym_path, image_vmaddr, image_addr, instruction_addr, cpu_name, uuid=None, silent=True): if self._closed: raise RuntimeError('Symbolizer is closed') if not is_valid_cpu_name(cpu_name): raise ValueError('"%s" is not a valid cpu name' % cpu_name) dsym_path = normalize_dsym_path(dsym_path) image_vmaddr = parse_addr(image_vmaddr) if not image_vmaddr: image_vmaddr = get_macho_vmaddr(dsym_path, cpu_name) or 0 image_addr = parse_addr(image_addr) instruction_addr = parse_addr(instruction_addr) addr = image_vmaddr + instruction_addr - image_addr try: with self._lock: with timedsection('symbolize'): sym = self.symbolizer.symbolize(dsym_path, addr, cpu_name) if sym[0] is None: raise SymbolicationError('Symbolizer could not find symbol') except SymbolicationError: if not silent: raise sym = (None, None, 0, 0) return { 'symbol_name': demangle_symbol(sym[0]), 'filename': sym[1], 'line': sym[2], 'column': sym[3], 'uuid': uuid, }
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
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], []
def resolve_frame_symbols(data): debug_meta = data['debug_meta'] debug_images = debug_meta['images'] sdk_info = get_sdk_from_event(data) stacktraces = find_all_stacktraces(data) if not stacktraces: return project = Project.objects.get_from_cache( id=data['project'], ) errors = [] referenced_images = find_stacktrace_referenced_images( debug_images, [x[0] for x in stacktraces]) sym = Symbolizer(project, debug_images, referenced_images=referenced_images) frame = None idx = -1 def report_error(e): errors.append({ 'type': EventError.NATIVE_INTERNAL_FAILURE, 'frame': frame, 'error': 'frame #%d: %s: %s' % ( idx, e.__class__.__name__, six.text_type(e), ) }) with sym: for stacktrace, container in stacktraces: store_raw = False new_frames = list(stacktrace['frames']) for idx, frame in enumerate(stacktrace['frames']): if 'image_addr' not in frame or \ 'instruction_addr' not in frame or \ 'symbol_addr' not in frame: continue try: sfrm = sym.symbolize_frame({ 'object_name': frame.get('package'), 'object_addr': frame['image_addr'], 'instruction_addr': frame['instruction_addr'], 'symbol_addr': frame['symbol_addr'], }, sdk_info, report_error=report_error) if not sfrm: continue new_frame = dict(frame) # XXX: log here if symbol could not be found? 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']) new_frame['in_app'] = is_in_app(new_frame) if new_frame != frame: new_frames[idx] = new_frame store_raw = True except Exception: logger.exception('Failed to symbolicate') errors.append({ 'type': EventError.NATIVE_INTERNAL_FAILURE, 'error': 'The symbolicator encountered an internal failure', }) # Remember the raw stacktrace. if store_raw and container is not None: container['raw_stacktrace'] = { 'frames': stacktrace['frames'], } # Put the new frames in stacktrace['frames'] = new_frames if errors: data.setdefault('errors', []).extend(errors) return data
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], []
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], []
def resolve_frame_symbols(data): debug_meta = data['debug_meta'] debug_images = debug_meta['images'] sdk_info = get_sdk_from_event(data) stacktraces = find_all_stacktraces(data) if not stacktraces: return project = Project.objects.get_from_cache( id=data['project'], ) errors = [] referenced_images = find_stacktrace_referenced_images( debug_images, [x[0] for x in stacktraces]) sym = Symbolizer(project, debug_images, referenced_images=referenced_images) frame = None idx = -1 def report_error(exc_type, exc_value, tb): if exc_value.is_user_fixable or exc_value.is_sdk_failure: errors.append({ 'type': EventError.NATIVE_INTERNAL_FAILURE, 'frame': frame, 'error': u'frame #%d: %s' % (idx, exc_value) }) if not exc_value.is_user_fixable: logger.debug('Failed to symbolicate', exc_info=(exc_type, exc_value, tb)) with sym: for stacktrace, container in stacktraces: store_raw = False new_frames = list(stacktrace['frames']) for idx, frame in enumerate(stacktrace['frames']): if 'image_addr' not in frame or \ 'instruction_addr' not in frame or \ 'symbol_addr' not in frame: continue try: # Construct a raw frame that is used by the symbolizer # backend. raw_frame = { 'object_name': frame.get('package'), 'object_addr': frame['image_addr'], 'instruction_addr': frame['instruction_addr'], 'symbol_addr': frame['symbol_addr'], } new_frame = dict(frame) try: sfrm = sym.symbolize_frame(raw_frame, sdk_info) except SymbolicationFailed: report_error(*sys.exc_info()) 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']) new_frame['in_app'] = sym.is_in_app(raw_frame) if new_frame != frame: new_frames[idx] = new_frame store_raw = True except Exception: logger.exception('Failed to symbolicate') errors.append({ 'type': EventError.NATIVE_INTERNAL_FAILURE, 'error': 'The symbolicator encountered an internal failure', }) # Remember the raw stacktrace. if store_raw and container is not None: container['raw_stacktrace'] = { 'frames': stacktrace['frames'], } # Put the new frames in stacktrace['frames'] = new_frames if errors: data.setdefault('errors', []).extend(errors) return data
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], []