def _symbolize_app_frame(self, instruction_addr, obj, sdk_info=None): symcache = self.symcaches.get(obj.uuid) if symcache is None: if self._is_optional_dsym(obj, sdk_info=sdk_info): type = EventError.NATIVE_MISSING_OPTIONALLY_BUNDLED_DSYM else: type = EventError.NATIVE_MISSING_DSYM raise SymbolicationFailed(type=type, obj=obj) try: rv = symcache.lookup(rebase_addr(instruction_addr, obj)) except SymbolicError as e: raise SymbolicationFailed(type=EventError.NATIVE_BAD_DSYM, message=six.text_type(e), obj=obj) if not rv: # For some frameworks we are willing to ignore missing symbol # errors. if self._is_optional_dsym(obj, sdk_info=sdk_info): return [] raise SymbolicationFailed(type=EventError.NATIVE_MISSING_SYMBOL, obj=obj) return [ self._process_frame(s, obj, addr_off=obj.addr) for s in reversed(rv) ]
def preprocess_frame(self, processable_frame): instr_addr = self.find_best_instruction(processable_frame) obj = self.object_lookup.find_object(instr_addr) processable_frame.data = { 'instruction_addr': instr_addr, 'obj': obj, 'debug_id': obj.debug_id if obj is not None else None, 'symbolserver_match': None, # `[]` is used to indicate to the symbolizer that the symbolicator # deliberately discarded this frame, while `None` means the # symbolicator didn't run (because `self.use_symbolicator` is # false). # If the symbolicator did run and was not able to symbolize the # frame, this value will be a list with the raw frame as only item. 'symbolicator_match': [] if self.use_symbolicator else None, } if obj 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, obj), obj.debug_id, obj.arch, obj.size, ) )
def _symbolize_app_frame(self, instruction_addr, obj, sdk_info=None, trust=None): symcache = self.symcaches.get(obj.debug_id) if symcache is None: # In case we know what error happened on symcache conversion # we can report it to the user now. if obj.debug_id in self.symcaches_conversion_errors: raise SymbolicationFailed( message=self.symcaches_conversion_errors[obj.debug_id], type=EventError.NATIVE_BAD_DSYM, obj=obj ) if is_optional_package(obj.code_file, sdk_info=sdk_info): type = EventError.NATIVE_MISSING_OPTIONALLY_BUNDLED_DSYM else: type = EventError.NATIVE_MISSING_DSYM raise SymbolicationFailed(type=type, obj=obj) try: rv = symcache.lookup(rebase_addr(instruction_addr, obj)) except SymbolicError as e: raise SymbolicationFailed( type=EventError.NATIVE_BAD_DSYM, message=six.text_type(e), obj=obj ) if not rv: # For some frameworks we are willing to ignore missing symbol # errors. Also, ignore scanned stack frames when symbols are # available to complete breakpad's stack scanning heuristics. if trust == 'scan' or is_optional_package(obj.code_file, sdk_info=sdk_info): return [] raise SymbolicationFailed( type=EventError.NATIVE_MISSING_SYMBOL, obj=obj) return [self._process_frame(s, addr_off=obj.addr) for s in reversed(rv)]
def fetch_system_symbols(self, processing_task): to_lookup = [] pf_list = [] for pf in processing_task.iter_processable_frames(self): obj = pf.data['obj'] if pf.cache_value is not None or obj is None or \ self.sym.is_image_from_app_bundle(obj): continue # We can only look up objects in the symbol server that have a # uuid. If we encounter things with an age appended or # similar we need to skip. try: uuid.UUID(obj.debug_id) except (ValueError, TypeError): continue to_lookup.append( { 'object_uuid': obj.debug_id, 'object_name': obj.name or '<unknown>', 'addr': '0x%x' % rebase_addr(pf.data['instruction_addr'], obj) } ) pf_list.append(pf) if not to_lookup: return rv = lookup_system_symbols(to_lookup, self.sdk_info, self.arch) if rv is not None: for symrv, pf in zip(rv, pf_list): if symrv is None: continue pf.data['symbolserver_match'] = symrv
def _symbolize_app_frame(self, instruction_addr, obj, sdk_info=None, trust=None): symcache = self.symcaches.get(obj.id) if symcache is None: # In case we know what error happened on symcache conversion # we can report it to the user now. if obj.id in self.symcaches_conversion_errors: raise SymbolicationFailed( message=self.symcaches_conversion_errors[obj.id], type=EventError.NATIVE_BAD_DSYM, obj=obj ) if self._is_optional_dif(obj, sdk_info=sdk_info): type = EventError.NATIVE_MISSING_OPTIONALLY_BUNDLED_DSYM else: type = EventError.NATIVE_MISSING_DSYM raise SymbolicationFailed(type=type, obj=obj) try: rv = symcache.lookup(rebase_addr(instruction_addr, obj)) except SymbolicError as e: raise SymbolicationFailed( type=EventError.NATIVE_BAD_DSYM, message=six.text_type(e), obj=obj ) if not rv: # For some frameworks we are willing to ignore missing symbol # errors. Also, ignore scanned stack frames when symbols are # available to complete breakpad's stack scanning heuristics. if trust == 'scan' or self._is_optional_dif(obj, sdk_info=sdk_info): return [] raise SymbolicationFailed( type=EventError.NATIVE_MISSING_SYMBOL, obj=obj) return [self._process_frame(s, obj, addr_off=obj.addr) for s in reversed(rv)]
def fetch_system_symbols(self, processing_task): to_lookup = [] pf_list = [] for pf in processing_task.iter_processable_frames(self): obj = pf.data['obj'] if pf.cache_value is not None or obj is None or \ self.sym.is_image_from_app_bundle(obj): continue # We can only look up objects in the symbol server that have a # uuid. If we encounter things with an age appended or # similar we need to skip. try: uuid.UUID(obj.id) except (ValueError, TypeError): continue to_lookup.append( { 'object_uuid': obj.id, 'object_name': obj.name or '<unknown>', 'addr': '0x%x' % rebase_addr(pf.data['instruction_addr'], obj) } ) pf_list.append(pf) if not to_lookup: return rv = lookup_system_symbols(to_lookup, self.sdk_info, self.arch) if rv is not None: for symrv, pf in zip(rv, pf_list): if symrv is None: continue pf.data['symbolserver_match'] = symrv
def fetch_system_symbols(self, processing_task): to_lookup = [] pf_list = [] for pf in processing_task.iter_processable_frames(self): obj = pf.data['obj'] if pf.cache_value is not None or obj is None or \ self.sym.is_image_from_app_bundle(obj): continue to_lookup.append( { 'object_uuid': six.text_type(obj.uuid), 'object_name': obj.name or '<unknown>', 'addr': '0x%x' % rebase_addr(pf.data['instruction_addr'], obj) } ) pf_list.append(pf) if not to_lookup: return rv = lookup_system_symbols(to_lookup, self.sdk_info, self.arch) if rv is not None: for symrv, pf in zip(rv, pf_list): if symrv is None: continue pf.data['symbolserver_match'] = symrv
def preprocess_frame(self, processable_frame): instr_addr = self.find_best_instruction(processable_frame) obj = self.object_lookup.find_object(instr_addr) processable_frame.data = { 'instruction_addr': instr_addr, 'obj': obj, 'debug_id': obj.debug_id if obj is not None else None, 'symbolserver_match': None, # `[]` is used to indicate to the symbolizer that the symbolicator # deliberately discarded this frame, while `None` means the # symbolicator didn't run (because `self.use_symbolicator` is # false). # If the symbolicator did run and was not able to symbolize the # frame, this value will be a list with the raw frame as only item. 'symbolicator_match': [] if self.use_symbolicator else None, } if obj 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, obj), obj.debug_id, obj.arch, obj.size, ))
def _symbolize_app_frame(self, instruction_addr, obj, sdk_info=None): symcache = self.symcaches.get(obj.id) if symcache is None: # In case we know what error happened on symcache conversion # we can report it to the user now. if obj.id in self.symcaches_conversion_errors: raise SymbolicationFailed( message=self.symcaches_conversion_errors[obj.id], type=EventError.NATIVE_BAD_DSYM, obj=obj) if self._is_optional_dif(obj, sdk_info=sdk_info): type = EventError.NATIVE_MISSING_OPTIONALLY_BUNDLED_DSYM else: type = EventError.NATIVE_MISSING_DSYM raise SymbolicationFailed(type=type, obj=obj) try: rv = symcache.lookup(rebase_addr(instruction_addr, obj)) except SymbolicError as e: raise SymbolicationFailed(type=EventError.NATIVE_BAD_DSYM, message=six.text_type(e), obj=obj) if not rv: # For some frameworks we are willing to ignore missing symbol # errors. if self._is_optional_dif(obj, sdk_info=sdk_info): return [] raise SymbolicationFailed(type=EventError.NATIVE_MISSING_SYMBOL, obj=obj) return [ self._process_frame(s, obj, addr_off=obj.addr) for s in reversed(rv) ]
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_image_from_app_bundle(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 fetch_system_symbols(self, processing_task): to_lookup = [] pf_list = [] for pf in processing_task.iter_processable_frames(self): obj = pf.data['obj'] if pf.cache_value is not None or obj is None or \ self.sym.is_image_from_app_bundle(obj): continue to_lookup.append({ 'object_uuid': six.text_type(obj.uuid), 'object_name': obj.name or '<unknown>', 'addr': '0x%x' % rebase_addr(pf.data['instruction_addr'], obj) }) pf_list.append(pf) if not to_lookup: return rv = lookup_system_symbols(to_lookup, self.sdk_info, self.arch) if rv is not None: for symrv, pf in zip(rv, pf_list): if symrv is None: continue pf.data['symbolserver_match'] = symrv
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 _get_frame_key(self, frame): module = self.modules.find_object(frame['instruction_addr']) # If we cannot resolve a module for this frame, this means we're dealing # with an absolute address here. Since this address changes with every # crash and would poison our cache, we skip it for the key calculation. if not module: return None return (module.id, rebase_addr(frame['instruction_addr'], module))
def _get_frame_key(self, frame): module = self.modules.find_object(frame['instruction_addr']) # If we cannot resolve a module for this frame, this means we're dealing # with an absolute address here. Since this address changes with every # crash and would poison our cache, we skip it for the key calculation. if not module: return None return ( module.debug_id, rebase_addr(frame['instruction_addr'], module) )
def save_to_cache(self): """Stores the reprocessed stack trace to the cache. For frames with known code modules only relative offsets are stored, otherwise the absolute address as fallback.""" if self.resolved_frames is None: raise RuntimeError('save_to_cache called before resolving frames') if self.resolved_frames == NO_CFI_PLACEHOLDER: cache.set(self._cache_key, NO_CFI_PLACEHOLDER) return values = [] for module, frame in self.resolved_frames: module_id = module and module.debug_id addr = frame['instruction_addr'] if module: addr = '0x%x' % rebase_addr(addr, module) values.append((module_id, addr, frame['trust'])) cache.set(self._cache_key, values)
def save_to_cache(self): """Stores the reprocessed stack trace to the cache. For frames with known code modules only relative offsets are stored, otherwise the absolute address as fallback.""" if self.resolved_frames is None: raise RuntimeError('save_to_cache called before resolving frames') if self.resolved_frames == NO_CFI_PLACEHOLDER: cache.set(self._cache_key, NO_CFI_PLACEHOLDER) return values = [] for module, frame in self.resolved_frames: module_id = module and module.id addr = frame['instruction_addr'] if module: addr = '0x%x' % rebase_addr(addr, module) values.append((module_id, addr, frame['trust'])) cache.set(self._cache_key, values)
def fetch_ios_system_symbols(self, processing_task): to_lookup = [] pf_list = [] for pf in processing_task.iter_processable_frames(self): if pf.cache_value is not None: continue obj = pf.data['obj'] package = obj and obj.code_file # TODO(ja): This should check for iOS specifically if not package or not is_known_third_party(package): continue # We can only look up objects in the symbol server that have a # uuid. If we encounter things with an age appended or # similar we need to skip. try: uuid.UUID(obj.debug_id) except (ValueError, TypeError): continue to_lookup.append({ 'object_uuid': obj.debug_id, 'object_name': obj.code_file or '<unknown>', 'addr': '0x%x' % rebase_addr(pf.data['instruction_addr'], obj) }) pf_list.append(pf) if not to_lookup: return rv = lookup_system_symbols(to_lookup, self.sdk_info, self.arch) if rv is not None: for symrv, pf in zip(rv, pf_list): if symrv is None: continue pf.data['symbolserver_match'] = symrv
def fetch_ios_system_symbols(self, processing_task): to_lookup = [] pf_list = [] for pf in processing_task.iter_processable_frames(self): if pf.cache_value is not None: continue obj = pf.data['obj'] package = obj and obj.code_file # TODO(ja): This should check for iOS specifically if not package or not is_known_third_party(package): continue # We can only look up objects in the symbol server that have a # uuid. If we encounter things with an age appended or # similar we need to skip. try: uuid.UUID(obj.debug_id) except (ValueError, TypeError): continue to_lookup.append( { 'object_uuid': obj.debug_id, 'object_name': obj.code_file or '<unknown>', 'addr': '0x%x' % rebase_addr(pf.data['instruction_addr'], obj) } ) pf_list.append(pf) if not to_lookup: return rv = lookup_system_symbols(to_lookup, self.sdk_info, self.arch) if rv is not None: for symrv, pf in zip(rv, pf_list): if symrv is None: continue pf.data['symbolserver_match'] = symrv
def preprocess_frame(self, processable_frame): instr_addr = self.find_best_instruction(processable_frame) obj = self.object_lookup.find_object(instr_addr) processable_frame.data = { 'instruction_addr': instr_addr, 'obj': obj, 'debug_id': obj.id if obj is not None else None, 'symbolserver_match': None, } if obj 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, obj), obj.id, obj.arch, obj.size, ))
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 _symbolize_app_frame(self, instruction_addr, obj, sdk_info=None): symcache = self.symcaches.get(obj.uuid) if symcache is None: if self._is_optional_dsym(obj, sdk_info=sdk_info): type = EventError.NATIVE_MISSING_OPTIONALLY_BUNDLED_DSYM else: type = EventError.NATIVE_MISSING_DSYM raise SymbolicationFailed(type=type, obj=obj) try: rv = symcache.lookup(rebase_addr(instruction_addr, obj)) except SymbolicError as e: raise SymbolicationFailed( type=EventError.NATIVE_BAD_DSYM, message=six.text_type(e), obj=obj ) if not rv: # For some frameworks we are willing to ignore missing symbol # errors. if self._is_optional_dsym(obj, sdk_info=sdk_info): return [] raise SymbolicationFailed( type=EventError.NATIVE_MISSING_SYMBOL, obj=obj) return [self._process_frame(s, obj, addr_off=obj.addr) for s in reversed(rv)]
def preprocess_frame(self, processable_frame): instr_addr = self.find_best_instruction(processable_frame) obj = self.object_lookup.find_object(instr_addr) processable_frame.data = { 'instruction_addr': instr_addr, 'obj': obj, 'obj_uuid': obj.id if obj is not None else None, 'symbolserver_match': None, } if obj 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, obj), obj.id, obj.arch, obj.size, ) )