class Driver(object): def __init__(self, symbolizer_path=None): # symbolizer_path is no longer used. self._lock = RLock() self._proc = None self._closed = False self.symbolizer = Symbolizer() def __enter__(self): return self def __exit__(self, exc_type, exc_value, tb): self.close() def close(self): if not self._closed: self.symbolizer.close() self._closed = True 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, }
class Driver(object): def __init__(self, symbolizer_path=None): # symbolizer_path is no longer used. self._lock = RLock() self._proc = None self._closed = False self.symbolizer = Symbolizer() def __enter__(self): return self def __exit__(self, exc_type, exc_value, tb): self.close() def close(self): if not self._closed: self.symbolizer.close() self._closed = True 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, }
class Symbolizer(object): """The main symbolication driver. This abstracts around a low level LLVM based symbolizer that works with DWARF files. It's recommended to explicitly close the driver to ensure memory cleans up timely. """ def __init__(self): self._lock = RLock() self._proc = None self._closed = False self._symbolizer = LowLevelSymbolizer() def __enter__(self): return self def __exit__(self, exc_type, exc_value, tb): self.close() def close(self): if not self._closed: self._symbolizer.close() self._closed = True def symbolize(self, dsym_path, image_vmaddr, image_addr, instruction_addr, cpu_name, symbolize_inlined=False): """Symbolizes a single frame based on the information provided. If the symbolication fails a `SymbolicationError` is raised. `dsym_path` is the path to the dsym file on the file system. `image_vmaddr` is the slide of the image. For most situations this can just be set to `0`. If it's zero or unset we will attempt to find the slide from the dsym file. `image_addr` is the canonical image address as loaded. `instruction_addr` is the address where the error happened. `cpu_name` is the CPU name. It follows general apple conventions and is used to special case certain behavior and look up the right symbols. Common names are `armv7` and `arm64`. Additionally if `symbolize_inlined` is set to `True` then a list of frames is returned instead which might contain inlined frames. In that case the return value might be an empty list instead. """ if self._closed: raise RuntimeError('Symbolizer is closed') dsym_path = normalize_dsym_path(dsym_path) image_vmaddr = parse_addr(image_vmaddr) if not image_vmaddr: di = self._symbolizer.get_debug_info(dsym_path) if di is not None: variant = di.get_variant(cpu_name) if variant is not None: image_vmaddr = variant.vmaddr image_addr = parse_addr(image_addr) instruction_addr = parse_addr(instruction_addr) if not is_valid_cpu_name(cpu_name): raise SymbolicationError('"%s" is not a valid cpu name' % cpu_name) addr = image_vmaddr + instruction_addr - image_addr with self._lock: with timedsection('symbolize'): if symbolize_inlined: return self._symbolizer.symbolize_inlined( dsym_path, addr, cpu_name) return self._symbolizer.symbolize(dsym_path, addr, cpu_name)