def __init__(self, project, binary_images, referenced_images=None, cpu_name=None): self.symsynd_symbolizer = make_symbolizer( project, binary_images, referenced_images=referenced_images) # This is a duplication from symsynd. The reason is that symsynd # will only load images that it can find dsyms for but we also # have system symbols which there are no dsyms for. self._image_addresses = [] self.images = {} for img in binary_images: img_addr = parse_addr(img['image_addr']) self._image_addresses.append(img_addr) self.images[img_addr] = img self._image_addresses.sort() # This should always succeed but you never quite know. self.cpu_name = cpu_name if self.cpu_name is None: for img in six.itervalues(self.images): cpu_name = get_cpu_name(img['cpu_type'], img['cpu_subtype']) if self.cpu_name is None: self.cpu_name = cpu_name elif self.cpu_name != cpu_name: self.cpu_name = None break
def find_system_symbol(img, instruction_addr, system_info=None): """Finds a system symbol.""" return DSymSymbol.objects.lookup_symbol(instruction_addr=instruction_addr, image_addr=img['image_addr'], uuid=img['uuid'], cpu_name=get_cpu_name( img['cpu_type'], img['cpu_subtype']), object_path=img['name'], system_info=system_info)
def symbolize_system_frame(self, frame, img, sdk_info, symbolize_inlined=False): """Symbolizes a frame with system symbols only.""" # This is most likely a good enough cache match even though we are # ignoring the image here since we cache by instruction address. # # In some cases old clients might not send an sdk_info with it # in which case the caching won't work. if sdk_info is not None: cache_key = 'ssym:%s:%s:%s:%s:%s:%s:%s' % ( frame['instruction_addr'], get_cpu_name(img['cpu_type'], img['cpu_subtype']), sdk_info['sdk_name'], sdk_info['dsym_type'], sdk_info['version_major'], sdk_info['version_minor'], sdk_info['version_patchlevel'], ) symbol = cache.get(cache_key) else: cache_key = None symbol = None if symbol is None: symbol = find_system_symbol(img, frame['instruction_addr'], sdk_info, self.cpu_name) if symbol is None: # Simulator frames cannot be symbolicated if self._is_simulator_frame(frame, img): type = EventError.NATIVE_SIMULATOR_FRAME else: type = EventError.NATIVE_MISSING_SYSTEM_DSYM raise SymbolicationFailed(type=type, image=img) elif cache_key is not None: cache.set(cache_key, symbol, 3600) rv = self._process_frame( dict(frame, symbol_name=symbol, filename=None, line=0, column=0, uuid=img['uuid'], object_name=img['name']), img) # We actually do not support inline symbolication for system # frames, so we just only ever return a single frame here. Maybe # we can improve this in the future. if symbolize_inlined: return [rv] return rv
def find_system_symbol(img, instruction_addr, system_info=None): """Finds a system symbol.""" return DSymSymbol.objects.lookup_symbol( instruction_addr=instruction_addr, image_addr=img['image_addr'], uuid=img['uuid'], cpu_name=get_cpu_name(img['cpu_type'], img['cpu_subtype']), object_path=img['name'], system_info=system_info )
def symbolize_system_frame(self, frame, img, sdk_info, symbolize_inlined=False): """Symbolizes a frame with system symbols only.""" # This is most likely a good enough cache match even though we are # ignoring the image here since we cache by instruction address. # # In some cases old clients might not send an sdk_info with it # in which case the caching won't work. if sdk_info is not None: cache_key = 'ssym:%s:%s:%s:%s:%s:%s:%s' % ( frame['instruction_addr'], get_cpu_name(img['cpu_type'], img['cpu_subtype']), sdk_info['sdk_name'], sdk_info['dsym_type'], sdk_info['version_major'], sdk_info['version_minor'], sdk_info['version_patchlevel'], ) symbol = cache.get(cache_key) else: cache_key = None symbol = None if symbol is None: symbol = find_system_symbol( img, frame['instruction_addr'], sdk_info, self.cpu_name) if symbol is None: # Simulator frames cannot be symbolicated if self._is_simulator_frame(frame, img): type = EventError.NATIVE_SIMULATOR_FRAME else: type = EventError.NATIVE_MISSING_SYSTEM_DSYM raise SymbolicationFailed( type=type, image=img ) elif cache_key is not None: cache.set(cache_key, symbol, 3600) rv = self._process_frame(dict(frame, symbol_name=symbol, filename=None, line=0, column=0, object_name=img['name']), img) # We actually do not support inline symbolication for system # frames, so we just only ever return a single frame here. Maybe # we can improve this in the future. if symbolize_inlined: return [rv] return rv
def __init__(self, message=None, type=None, image=None): Exception.__init__(self) self.message = six.text_type(message) self.type = type if image is not None: self.image_uuid = image['uuid'].lower() self.image_path = image['name'] self.image_name = image['name'].rsplit('/', 1)[-1] self.image_arch = get_cpu_name(image['cpu_type'], image['cpu_subtype']) else: self.image_uuid = None self.image_name = None self.image_path = None self.image_arch = None
def cpu_name_from_data(data): """Returns the CPU name from the given data if it exists.""" device = DeviceContextType.primary_value_for_data(data) if device: arch = device.get('arch') if isinstance(arch, six.string_types): return arch # TODO: kill this here. we want to not support that going forward unique_cpu_name = None images = (data.get('debug_meta') or {}).get('images') or [] for img in images: cpu_name = get_cpu_name(img['cpu_type'], img['cpu_subtype']) if unique_cpu_name is None: unique_cpu_name = cpu_name elif unique_cpu_name != cpu_name: unique_cpu_name = None break return unique_cpu_name
def find_debug_images(dsym_paths, binary_images): images_to_load = set() with timedsection('iterimages0'): for image in binary_images: cpu_name = get_cpu_name(image['cpu_type'], image['cpu_subtype']) if cpu_name is not None: images_to_load.add(image['uuid'].lower()) images = {} # Step one: load images that are named by their UUID with timedsection('loadimages-fast'): for uuid in list(images_to_load): for dsym_path in dsym_paths: fn = os.path.join(dsym_path, uuid) if os.path.isfile(fn): images[uuid] = fn images_to_load.discard(uuid) break # Otherwise fall back to loading images from the dsym bundle. Because # this loading strategy is pretty slow we do't actually want to use it # unless we have a path that looks like a bundle. As a result we # find all the paths which are bundles and then only process those. if images_to_load: slow_paths = [] for dsym_path in dsym_paths: if os.path.isdir(os.path.join(dsym_path, 'Contents')): slow_paths.append(dsym_path) with timedsection('loadimages-slow'): for dsym_path in slow_paths: dwarf_base = os.path.join(dsym_path, 'Contents', 'Resources', 'DWARF') if os.path.isdir(dwarf_base): for fn in os.listdir(dwarf_base): # Looks like a UUID we loaded, skip it if fn in images: continue full_fn = os.path.join(dwarf_base, fn) uuids = get_macho_uuids(full_fn) for _, uuid in uuids: if uuid in images_to_load: images[uuid] = full_fn images_to_load.discard(uuid) rv = {} # Now resolve all the images. with timedsection('resolveimages'): for image in binary_images: cpu_name = get_cpu_name(image['cpu_type'], image['cpu_subtype']) if cpu_name is None: continue uid = image['uuid'].lower() if uid not in images: continue rv[image['image_addr']] = { 'uuid': uid, 'image_addr': image['image_addr'], 'dsym_path': images[uid], 'image_vmaddr': image['image_vmaddr'], 'cpu_name': cpu_name, } return rv
def test_cpu_names(): assert arch.get_cpu_name(12, 9) == 'armv7'