Ejemplo n.º 1
0
 def test_ToolPath(self):
     for cpu_arch, binprefix in _EXPECTED_NDK_TOOL_SUBDIR_MAP.iteritems():
         expected_binprefix = os.path.join(constants.ANDROID_NDK_ROOT,
                                           binprefix)
         expected_path = expected_binprefix + 'foo'
         self.assertEqual(host_paths.ToolPath('foo', cpu_arch),
                          expected_path)
Ejemplo n.º 2
0
def DemangleSymbol(mangled_symbol):
    """Return the demangled form of mangled_symbol."""
    cmd = [host_paths.ToolPath("c++filt", _arch)]
    process = subprocess.Popen(cmd,
                               stdin=subprocess.PIPE,
                               stdout=subprocess.PIPE)
    demangled_symbol, _ = process.communicate(mangled_symbol + '\n')
    return demangled_symbol
Ejemplo n.º 3
0
def _CallAddr2LineForSet(lib, unique_addrs, cpu_arch):
  """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.
    cpu_arch: Target CPU architecture.

  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

  symbolizer = elf_symbolizer.ELFSymbolizer(
      elf_file_path=symbols,
      addr2line_path=host_paths.ToolPath("addr2line", cpu_arch),
      callback=_Callback,
      inlines=True)

  for addr in addrs:
    symbolizer.SymbolizeAsync(int(addr, 16), addr)
  symbolizer.Join()
  return result
Ejemplo n.º 4
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)
Ejemplo n.º 5
0
def SymbolInfosFromBinary(binary_filename):
  """Runs objdump to get all the symbols from a binary.

  Args:
    binary_filename: path to the binary.

  Returns:
    A list of SymbolInfo from the binary.
  """
  command = (host_paths.ToolPath('objdump', _arch), '-t', '-w', binary_filename)
  p = subprocess.Popen(command, shell=False, stdout=subprocess.PIPE)
  try:
    result = _SymbolInfosFromStream(p.stdout)
    return result
  finally:
    p.stdout.close()
    p.wait()
Ejemplo n.º 6
0
def _CallObjdumpForSet(lib, unique_addrs, cpu_arch):
  """Use objdump to find out the names of the containing functions.

  Args:
    lib: library (or executable) pathname containing symbols
    unique_addrs: set of string hexidecimal addresses to find the functions for.
    cpu_arch: Target CPU architecture.

  Returns:
    A dictionary of the form {addr: (string symbol, offset)}.
  """
  if not lib:
    return None

  symbols = SYMBOLS_DIR + lib
  if not os.path.exists(symbols):
    return None

  symbols = SYMBOLS_DIR + lib
  if not os.path.exists(symbols):
    return None

  result = {}

  # Function lines look like:
  #   000177b0 <android::IBinder::~IBinder()+0x2c>:
  # We pull out the address and function first. Then we check for an optional
  # offset. This is tricky due to functions that look like "operator+(..)+0x2c"
  func_regexp = re.compile("(^[a-f0-9]*) \<(.*)\>:$")
  offset_regexp = re.compile("(.*)\+0x([a-f0-9]*)")

  # A disassembly line looks like:
  #   177b2:  b510        push  {r4, lr}
  asm_regexp = re.compile("(^[ a-f0-9]*):[ a-f0-0]*.*$")

  for target_addr in unique_addrs:
    start_addr_dec = str(_StripPC(int(target_addr, 16), cpu_arch))
    stop_addr_dec = str(_StripPC(int(target_addr, 16), cpu_arch) + 8)
    cmd = [host_paths.ToolPath("objdump", cpu_arch),
           "--section=.text",
           "--demangle",
           "--disassemble",
           "--start-address=" + start_addr_dec,
           "--stop-address=" + stop_addr_dec,
           symbols]

    current_symbol = None    # The current function symbol in the disassembly.
    current_symbol_addr = 0  # The address of the current function.

    stream = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout
    for line in stream:
      # Is it a function line like:
      #   000177b0 <android::IBinder::~IBinder()>:
      components = func_regexp.match(line)
      if components:
        # This is a new function, so record the current function and its
        # address.
        current_symbol_addr = int(components.group(1), 16)
        current_symbol = components.group(2)

        # Does it have an optional offset like: "foo(..)+0x2c"?
        components = offset_regexp.match(current_symbol)
        if components:
          current_symbol = components.group(1)
          offset = components.group(2)
          if offset:
            current_symbol_addr -= int(offset, 16)

      # Is it an disassembly line like:
      #   177b2:  b510        push  {r4, lr}
      components = asm_regexp.match(line)
      if components:
        addr = components.group(1)
        i_addr = int(addr, 16)
        i_target = _StripPC(int(target_addr, 16), cpu_arch)
        if i_addr == i_target:
          result[target_addr] = (current_symbol, i_target - current_symbol_addr)
    stream.close()

  return result
Ejemplo n.º 7
0
 def setUp(self):
     self._old_demangle = None
     if not os.path.exists(host_paths.ToolPath('c++filt', 'arm')):
         print 'Using fake demangling due to missing c++filt binary'
         self._old_demangle = symbol_extractor.DemangleSymbol
         symbol_extractor.DemangleSymbol = _FakeDemangle