Exemplo n.º 1
0
    def testIncompleteSyminfo(self):
        """Stimulate the symbol-not-resolved logic."""
        symbolizer = elf_symbolizer.ELFSymbolizer(
            elf_file_path='/path/doesnt/matter/mock_lib1.so',
            addr2line_path=_MOCK_A2L_PATH,
            callback=self._callback,
            max_concurrent_jobs=1)

        # Test symbols with valid name but incomplete path.
        addr = _INCOMPLETE_MOCK_ADDR
        exp_name = 'mock_sym_for_addr_%d' % addr
        exp_source_path = None
        exp_source_line = None
        cb_arg = (addr, exp_name, exp_source_path, exp_source_line, False)
        symbolizer.SymbolizeAsync(addr, cb_arg)

        # Test symbols with no name or sym info.
        addr = _UNKNOWN_MOCK_ADDR
        exp_name = None
        exp_source_path = None
        exp_source_line = None
        cb_arg = (addr, exp_name, exp_source_path, exp_source_line, False)
        symbolizer.SymbolizeAsync(addr, cb_arg)

        symbolizer.Join()
Exemplo n.º 2
0
def CallAddr2LineForSet(lib, unique_addrs):
    """Look up line and symbol information for a set of addresses.

  Args:
    lib: library (or executable) pathname containing symbols
    unique_addrs: set of string hexidecimal addresses look up.

  Returns:
    A dictionary of the form {addr: [(symbol, file:line)]} where
    each address has a list of associated symbols and locations
    or an empty list if no symbol information was found.

    If the function has been inlined then the list may contain
    more than one element with the symbols for the most deeply
    nested inlined location appearing first.
  """
    if not lib:
        return None

    symbols = SYMBOLS_DIR + lib
    if not os.path.splitext(symbols)[1] in ['', '.so', '.apk']:
        return None

    if not os.path.isfile(symbols):
        return None

    addrs = sorted(unique_addrs)
    result = {}

    def _Callback(sym, addr):
        records = []
        while sym:  # Traverse all the inlines following the |inlined_by| chain.
            if sym.source_path and sym.source_line:
                location = '%s:%d' % (sym.source_path, sym.source_line)
            else:
                location = None
            records += [(sym.name, location)]
            sym = sym.inlined_by
        result[addr] = records

    (label, platform, target) = FindToolchain()
    symbolizer = elf_symbolizer.ELFSymbolizer(
        elf_file_path=symbols,
        addr2line_path=ToolPath("addr2line"),
        callback=_Callback,
        inlines=True)

    for addr in addrs:
        symbolizer.SymbolizeAsync(int(addr, 16), addr)
    symbolizer.Join()
    return result
Exemplo n.º 3
0
  def _CreateSymbolizerFor(self, host_path):
    """Create the ELFSymbolizer instance associated with a given lib path."""
    addr2line_path = self._addr2line_path
    if not addr2line_path:
      if not self._android_abi:
        raise Exception(
            'Android CPU ABI must be set before calling FindSymbolInfo!')

      cpu_arch = _AndroidAbiToCpuArch(self._android_abi)
      self._addr2line_path = host_paths.ToolPath('addr2line', cpu_arch)

    return elf_symbolizer.ELFSymbolizer(
        elf_file_path=host_path, addr2line_path=self._addr2line_path,
        callback=ElfSymbolResolver._Callback, inlines=True)
Exemplo n.º 4
0
    def testInlines(self):
        """Stimulate the inline processing logic."""
        symbolizer = elf_symbolizer.ELFSymbolizer(
            elf_file_path='/path/doesnt/matter/mock_lib1.so',
            addr2line_path=_MOCK_A2L_PATH,
            callback=self._callback,
            inlines=True,
            max_concurrent_jobs=4)

        for addr in xrange(1000):
            exp_inline = False
            exp_unknown = False

            # First 100 addresses with inlines.
            if addr < 100:
                addr += _INLINE_MOCK_ADDR
                exp_inline = True

            # Followed by 100 without inlines.
            elif addr < 200:
                pass

            # Followed by 100 interleaved inlines and not inlines.
            elif addr < 300:
                if addr & 1:
                    addr += _INLINE_MOCK_ADDR
                    exp_inline = True

            # Followed by 100 interleaved inlines and unknonwn.
            elif addr < 400:
                if addr & 1:
                    addr += _INLINE_MOCK_ADDR
                    exp_inline = True
                else:
                    addr += _UNKNOWN_MOCK_ADDR
                    exp_unknown = True

            exp_name = 'mock_sym_for_addr_%d' % addr if not exp_unknown else None
            exp_source_path = 'mock_src/mock_lib1.so.c' if not exp_unknown else None
            exp_source_line = addr if not exp_unknown else None
            cb_arg = (addr, exp_name, exp_source_path, exp_source_line,
                      exp_inline)
            symbolizer.SymbolizeAsync(addr, cb_arg)

        symbolizer.Join()
Exemplo n.º 5
0
    def _RunTest(self, max_concurrent_jobs, num_symbols):
        symbolizer = elf_symbolizer.ELFSymbolizer(
            elf_file_path='/path/doesnt/matter/mock_lib1.so',
            addr2line_path=_MOCK_A2L_PATH,
            callback=self._callback,
            max_concurrent_jobs=max_concurrent_jobs,
            addr2line_timeout=0.5)

        for addr in xrange(num_symbols):
            exp_name = 'mock_sym_for_addr_%d' % addr
            exp_source_path = 'mock_src/mock_lib1.so.c'
            exp_source_line = addr
            cb_arg = (addr, exp_name, exp_source_path, exp_source_line, False)
            symbolizer.SymbolizeAsync(addr, cb_arg)

        symbolizer.Join()

        # Check that all the expected callbacks have been received.
        for addr in xrange(num_symbols):
            self.assertIn(addr, self._resolved_addresses)
            self._resolved_addresses.remove(addr)

        # Check for unexpected callbacks.
        self.assertEqual(len(self._resolved_addresses), 0)
Exemplo n.º 6
0
    def ExtractSymbols(self, native_heaps, sym_paths):
        """Performs symbolization. Returns a |symbol.Symbols| from |NativeHeap|s.

    This method performs the symbolization but does NOT decorate (i.e. add
    symbol/source info) to the stack frames of |native_heaps|. The heaps
    can be decorated as needed using the native_heap.SymbolizeUsingSymbolDB()
    method. Rationale: the most common use case in this application is:
    symbolize-and-store-symbols and load-symbols-and-decorate-heaps (in two
    different stages at two different times).

    Args:
      native_heaps: a collection of native_heap.NativeHeap instances.
      sym_paths: either a list of or a string of comma-separated symbol paths.
    """
        assert (all(
            isinstance(x, native_heap.NativeHeap) for x in native_heaps))
        symbols = symbol.Symbols()

        # Find addr2line in toolchain_path.
        if isinstance(sym_paths, basestring):
            sym_paths = sym_paths.split(',')
        matches = glob.glob(
            os.path.join(self.settings['toolchain_path'], '*addr2line'))
        if not matches:
            raise exceptions.MemoryInspectorException('Cannot find addr2line')
        addr2line_path = matches[0]

        # First group all the stack frames together by lib path.
        frames_by_lib = {}
        for nheap in native_heaps:
            for stack_frame in nheap.stack_frames.itervalues():
                frames = frames_by_lib.setdefault(
                    stack_frame.exec_file_rel_path, set())
                frames.add(stack_frame)

        # The symbolization process is asynchronous (but yet single-threaded). This
        # callback is invoked every time the symbol info for a stack frame is ready.
        def SymbolizeAsyncCallback(sym_info, stack_frame):
            if not sym_info.name:
                return
            sym = symbol.Symbol(name=sym_info.name,
                                source_file_path=sym_info.source_path,
                                line_number=sym_info.source_line)
            symbols.Add(stack_frame.exec_file_rel_path, stack_frame.offset,
                        sym)
            # TODO(primiano): support inline sym info (i.e. |sym_info.inlined_by|).

        # Perform the actual symbolization (ordered by lib).
        for exec_file_rel_path, frames in frames_by_lib.iteritems():
            # Look up the full path of the symbol in the sym paths.
            exec_file_name = posixpath.basename(exec_file_rel_path)
            if exec_file_rel_path.startswith('/'):
                exec_file_rel_path = exec_file_rel_path[1:]
            exec_file_abs_path = ''
            for sym_path in sym_paths:
                # First try to locate the symbol file following the full relative path
                # e.g. /host/syms/ + /system/lib/foo.so => /host/syms/system/lib/foo.so.
                exec_file_abs_path = os.path.join(sym_path, exec_file_rel_path)
                if os.path.exists(exec_file_abs_path):
                    break

                # If no luck, try looking just for the file name in the sym path,
                # e.g. /host/syms/ + (/system/lib/)foo.so => /host/syms/foo.so
                exec_file_abs_path = os.path.join(sym_path, exec_file_name)
                if os.path.exists(exec_file_abs_path):
                    break

            if not os.path.exists(exec_file_abs_path):
                continue

            symbolizer = elf_symbolizer.ELFSymbolizer(
                elf_file_path=exec_file_abs_path,
                addr2line_path=addr2line_path,
                callback=SymbolizeAsyncCallback,
                inlines=False)

            # Kick off the symbolizer and then wait that all callbacks are issued.
            for stack_frame in sorted(frames, key=lambda x: x.offset):
                symbolizer.SymbolizeAsync(stack_frame.offset, stack_frame)
            symbolizer.Join()

        return symbols