def _get_slide_value(self, image_addr): if self.debug_images: for debug_image in self.debug_images: if parse_addr( debug_image['image_addr']) == parse_addr(image_addr): return parse_addr(debug_image['image_vmaddr']) return 0
def _convert_frame_to_apple_string(self, frame, number=0): if frame.get('instruction_addr') is None: return None slide_value = self._get_slide_value(frame.get('image_addr')) instruction_addr = slide_value + parse_addr(frame.get('instruction_addr')) image_addr = slide_value + parse_addr(frame.get('image_addr')) offset = '' if frame.get('image_addr') is not None and \ (not self.symbolicated or ( frame.get('function') or NATIVE_UNKNOWN_STRING) == NATIVE_UNKNOWN_STRING): offset = ' + %s' % ( instruction_addr - slide_value - parse_addr( frame.get('symbol_addr')) ) symbol = hex(image_addr) if self.symbolicated: file = '' if frame.get('filename') and frame.get('lineno'): file = ' (%s:%s)' % ( frame.get('filename') or NATIVE_UNKNOWN_STRING, frame['lineno'] ) symbol = '%s%s' % ( frame.get('function') or NATIVE_UNKNOWN_STRING, file ) return '%s%s%s%s%s' % ( str(number).ljust(4, ' '), (frame.get('package') or NATIVE_UNKNOWN_STRING).rsplit('/', 1)[-1].ljust(32, ' '), hex(instruction_addr).ljust(20, ' '), symbol, offset )
def _convert_frame_to_apple_string(self, frame, next=None, number=0): if frame.get('instruction_addr') is None: return None slide_value = self._get_slide_value(frame.get('image_addr')) instruction_addr = slide_value + parse_addr( frame.get('instruction_addr')) image_addr = slide_value + parse_addr(frame.get('image_addr')) offset = '' if frame.get('image_addr') is not None and \ (not self.symbolicated or ( frame.get('function') or NATIVE_UNKNOWN_STRING) == NATIVE_UNKNOWN_STRING): offset = ' + %s' % (instruction_addr - slide_value - parse_addr(frame.get('symbol_addr'))) symbol = hex(image_addr) if self.symbolicated: file = '' if frame.get('filename') and frame.get('lineno'): file = ' (%s:%s)' % (posixpath.basename( frame.get('filename') or NATIVE_UNKNOWN_STRING), frame['lineno']) symbol = '%s%s' % (frame.get('function') or NATIVE_UNKNOWN_STRING, file) if next and parse_addr(frame['instruction_addr']) == \ parse_addr(next['instruction_addr']): symbol = '[inlined] ' + symbol return '%s%s%s%s%s' % (str(number).ljust( 4, ' '), (frame.get('package') or NATIVE_UNKNOWN_STRING).rsplit( '/', 1)[-1].ljust(32, ' '), hex(instruction_addr).ljust( 20, ' '), symbol, offset)
def _convert_frame_to_apple_string(self, frame, number=0): if frame.get('instruction_addr') is None: return None slide_value = self._get_slide_value(frame['image_addr']) instruction_addr = slide_value + parse_addr(frame['instruction_addr']) image_addr = slide_value + parse_addr(frame['image_addr']) offset = '' if frame['image_addr'] is not None and not self.symbolicated: offset = ' + {}'.format( instruction_addr - slide_value - parse_addr(frame['symbol_addr']) ) symbol = hex(image_addr) if self.symbolicated: file = '' if frame.get('filename') and frame.get('lineno'): file = " ({}:{})".format( frame['filename'], frame['lineno'] ) symbol = "{}{}".format( frame['function'], file ) return "{}{}{}{}{}".format( str(number).ljust(4, " "), frame['package'].rsplit('/', 1)[-1].ljust(32, " "), hex(instruction_addr).ljust(20, " "), symbol, offset )
def _convert_debug_meta_to_binary_image_row(self, debug_image): slide_value = parse_addr(debug_image['image_vmaddr']) image_addr = parse_addr(debug_image['image_addr']) + slide_value return '%s - %s %s %s <%s> %s' % ( hex(image_addr), hex(image_addr + debug_image['image_size'] - 1), debug_image['name'].rsplit('/', 1)[-1], self.context['device']['arch'], debug_image['uuid'].replace( '-', '').lower(), debug_image['name'])
def _convert_debug_meta_to_binary_image_row(self, debug_image): slide_value = parse_addr(debug_image['image_vmaddr']) image_addr = parse_addr(debug_image['image_addr']) + slide_value return '%s - %s %s %s <%s> %s' % ( hex(image_addr), hex(image_addr + debug_image['image_size'] - 1), debug_image['name'].rsplit('/', 1)[-1], self.context['device']['arch'], debug_image['uuid'].replace('-', '').lower(), debug_image['name'] )
def get_binary_images_apple_string(self): # We dont need binary images on symbolicated crashreport if self.symbolicated or self.debug_images is None: return '' binary_images = map(lambda i: self._convert_debug_meta_to_binary_image_row(debug_image=i), sorted(self.debug_images, key=lambda i: parse_addr(i['image_addr']) )) return 'Binary Images:\n' + '\n'.join(binary_images)
def _convert_frame_to_apple_string(self, frame, number=0): if frame.get('instruction_addr') is None: return None slide_value = self._get_slide_value(frame['image_addr']) instruction_addr = slide_value + parse_addr(frame['instruction_addr']) image_addr = slide_value + parse_addr(frame['image_addr']) offset = '' if frame['image_addr'] is not None and not self.symbolicated: offset = ' + {}'.format(instruction_addr - slide_value - parse_addr(frame['symbol_addr'])) symbol = hex(image_addr) if self.symbolicated: file = '' if frame.get('filename') and frame.get('lineno'): file = " ({}:{})".format(frame['filename'], frame['lineno']) symbol = "{}{}".format(frame['function'], file) return "{}{}{}{}{}".format( str(number).ljust(4, " "), frame['package'].rsplit('/', 1)[-1].ljust(32, " "), hex(instruction_addr).ljust(20, " "), symbol, offset)
def resolve_frame_symbols(data): debug_meta = data.get('debug_meta') if not debug_meta: return 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, 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), ) }) longest_addr = 0 processed_frames = [] with sym: for stacktrace in stacktraces: 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 # XXX: log here if symbol could not be found? frame['function'] = sfrm.get('symbol_name') or \ frame.get('function') or '<unknown>' frame['abs_path'] = sfrm.get('filename') or None if frame['abs_path']: frame['filename'] = posixpath.basename(frame['abs_path']) if sfrm.get('line') is not None: frame['lineno'] = sfrm['line'] else: frame['instruction_offset'] = \ parse_addr(sfrm['instruction_addr']) - \ parse_addr(sfrm['symbol_addr']) if sfrm.get('column') is not None: frame['colno'] = sfrm['column'] frame['package'] = sfrm['object_name'] or frame.get('package') frame['symbol_addr'] = '0x%x' % parse_addr(sfrm['symbol_addr']) frame['instruction_addr'] = '0x%x' % parse_addr( sfrm['instruction_addr']) frame['in_app'] = is_in_app(frame) longest_addr = max(longest_addr, len(frame['symbol_addr']), len(frame['instruction_addr'])) processed_frames.append(frame) except Exception: logger.exception('Failed to symbolicate') errors.append({ 'type': EventError.NATIVE_INTERNAL_FAILURE, 'error': 'The symbolicator encountered an internal failure', }) # Pad out addresses to be of the same length for frame in processed_frames: for key in 'symbol_addr', 'instruction_addr': frame[key] = '0x' + frame[key][2:].rjust(longest_addr - 2, '0') if errors: data.setdefault('errors', []).extend(errors) return data
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 lookup_symbol(self, instruction_addr, image_addr, uuid, cpu_name=None, object_path=None, sdk_info=None, image_vmaddr=None): """Finds a system symbol.""" # If we use the "none" dsym type we never return a symbol here. if sdk_info is not None and sdk_info['dsym_type'] == 'none': return instruction_addr = parse_addr(instruction_addr) image_addr = parse_addr(image_addr) addr_abs = None if image_vmaddr is not None: image_vmaddr = parse_addr(image_vmaddr) addr_abs = image_vmaddr + instruction_addr - image_addr addr_rel = instruction_addr - image_addr uuid = six.text_type(uuid).lower() cur = connection.cursor() try: # First try: exact match on uuid (addr_rel) cur.execute( ''' select s.symbol from sentry_dsymsymbol s, sentry_dsymobject o where o.uuid = %s and s.object_id = o.id and s.address <= o.vmaddr + %s and s.address >= o.vmaddr order by address desc limit 1; ''', [uuid, addr_rel]) rv = cur.fetchone() if rv: return rv[0] # Second try: exact match on uuid (addr_abs) if addr_abs is not None: cur.execute( ''' select s.symbol from sentry_dsymsymbol s, sentry_dsymobject o where o.uuid = %s and s.object_id = o.id and s.address <= %s and s.address >= %s order by address desc limit 1; ''', [uuid, addr_abs, image_vmaddr]) rv = cur.fetchone() if rv: return rv[0] # Third try: exact match on path and arch (addr_rel) if sdk_info is None or \ cpu_name is None or \ object_path is None: return cur.execute( ''' select s.symbol from sentry_dsymsymbol s, sentry_dsymobject o, sentry_dsymsdk k, sentry_dsymbundle b where b.sdk_id = k.id and b.object_id = o.id and s.object_id = o.id and k.sdk_name = %s and k.dsym_type = %s and k.version_major = %s and k.version_minor = %s and k.version_patchlevel = %s and o.cpu_name = %s and o.object_path = %s and s.address <= o.vmaddr + %s and s.address >= o.vmaddr order by address desc limit 1; ''', [ sdk_info['sdk_name'], sdk_info['dsym_type'], sdk_info['version_major'], sdk_info['version_minor'], sdk_info['version_patchlevel'], cpu_name, object_path, addr_rel ]) rv = cur.fetchone() if rv: return rv[0] # Fourth try: exact match on path and arch (addr_abs) if addr_abs is not None: cur.execute( ''' select s.symbol from sentry_dsymsymbol s, sentry_dsymobject o, sentry_dsymsdk k, sentry_dsymbundle b where b.sdk_id = k.id and b.object_id = o.id and s.object_id = o.id and k.sdk_name = %s and k.dsym_type = %s and k.version_major = %s and k.version_minor = %s and k.version_patchlevel = %s and o.cpu_name = %s and o.object_path = %s and s.address <= %s and s.address >= %s order by address desc limit 1; ''', [ sdk_info['sdk_name'], sdk_info['dsym_type'], sdk_info['version_major'], sdk_info['version_minor'], sdk_info['version_patchlevel'], cpu_name, object_path, addr_abs, image_vmaddr ]) rv = cur.fetchone() if rv: return rv[0] finally: cur.close()
def _addr(x): return '0x%x' % parse_addr(x)
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 _get_slide_value(self, image_addr): if self.debug_images: for debug_image in self.debug_images: if parse_addr(debug_image['image_addr']) == parse_addr(image_addr): return parse_addr(debug_image['image_vmaddr']) return 0
def lookup_symbol(self, instruction_addr, image_addr, uuid, cpu_name=None, object_path=None, sdk_info=None, image_vmaddr=None): """Finds a system symbol.""" # If we use the "none" dsym type we never return a symbol here. if sdk_info is not None and sdk_info['dsym_type'] == 'none': return instruction_addr = parse_addr(instruction_addr) image_addr = parse_addr(image_addr) addr_abs = None if image_vmaddr is not None: image_vmaddr = parse_addr(image_vmaddr) addr_abs = image_vmaddr + instruction_addr - image_addr addr_rel = instruction_addr - image_addr uuid = str(uuid).lower() cur = connection.cursor() try: # First try: exact match on uuid (addr_rel) cur.execute(''' select s.symbol from sentry_dsymsymbol s, sentry_dsymobject o where o.uuid = %s and s.object_id = o.id and s.address <= o.vmaddr + %s and s.address >= o.vmaddr order by address desc limit 1; ''', [uuid, addr_rel]) rv = cur.fetchone() if rv: return rv[0] # Second try: exact match on uuid (addr_abs) if addr_abs is not None: cur.execute(''' select s.symbol from sentry_dsymsymbol s, sentry_dsymobject o where o.uuid = %s and s.object_id = o.id and s.address <= %s and s.address >= %s order by address desc limit 1; ''', [uuid, addr_abs, image_vmaddr]) rv = cur.fetchone() if rv: return rv[0] # Third try: exact match on path and arch (addr_rel) if sdk_info is None or \ cpu_name is None or \ object_path is None: return cur.execute(''' select s.symbol from sentry_dsymsymbol s, sentry_dsymobject o, sentry_dsymsdk k, sentry_dsymbundle b where b.sdk_id = k.id and b.object_id = o.id and s.object_id = o.id and k.sdk_name = %s and k.dsym_type = %s and k.version_major = %s and k.version_minor = %s and k.version_patchlevel = %s and o.cpu_name = %s and o.object_path = %s and s.address <= o.vmaddr + %s and s.address >= o.vmaddr order by address desc limit 1; ''', [sdk_info['sdk_name'], sdk_info['dsym_type'], sdk_info['version_major'], sdk_info['version_minor'], sdk_info['version_patchlevel'], cpu_name, object_path, addr_rel]) rv = cur.fetchone() if rv: return rv[0] # Fourth try: exact match on path and arch (addr_abs) if addr_abs is not None: cur.execute(''' select s.symbol from sentry_dsymsymbol s, sentry_dsymobject o, sentry_dsymsdk k, sentry_dsymbundle b where b.sdk_id = k.id and b.object_id = o.id and s.object_id = o.id and k.sdk_name = %s and k.dsym_type = %s and k.version_major = %s and k.version_minor = %s and k.version_patchlevel = %s and o.cpu_name = %s and o.object_path = %s and s.address <= %s and s.address >= %s order by address desc limit 1; ''', [sdk_info['sdk_name'], sdk_info['dsym_type'], sdk_info['version_major'], sdk_info['version_minor'], sdk_info['version_patchlevel'], cpu_name, object_path, addr_abs, image_vmaddr]) rv = cur.fetchone() if rv: return rv[0] finally: cur.close()
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