123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- # Copyright 2022 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- import logging
- import os
- import re
- import subprocess
- _CHROME_SRC = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
- _LLVM_OBJDUMP_PATH = os.path.join(_CHROME_SRC, 'third_party', 'llvm-build',
- 'Release+Asserts', 'bin', 'llvm-objdump')
- # 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 = re.compile(r"(^[a-f0-9]*) <(.*)>:$")
- _OFFSET = re.compile(r"(.*)\+0x([a-f0-9]*)")
- # A disassembly line looks like:
- # 177b2: b510 push {r4, lr}
- _ASM = re.compile(r"(^[ a-f0-9]*):[ a-f0-0]*.*$")
- def _StripPC(addr, cpu_arch):
- """Strips the Thumb bit from a program counter address when appropriate.
- Args:
- addr: the program counter address
- cpu_arch: Target CPU architecture.
- Returns:
- The stripped program counter address.
- """
- if cpu_arch == "arm":
- return addr & ~1
- return addr
- class ObjdumpInformation(object):
- def __init__(self, address, library, symbol, offset):
- self.address = address
- self.library = library
- self.symbol = symbol
- self.offset = offset
- class LLVMObjdumper(object):
- def __init__(self):
- """Creates an instance of LLVMObjdumper that interacts with llvm-objdump.
- """
- self._llvm_objdump_parameters = [
- '--disassemble',
- '--demangle',
- '--section=.text',
- ]
- def __enter__(self):
- return self
- def __exit__(self, exc_type, exc_val, exc_tb):
- pass
- @staticmethod
- def GetSymbolDataFromObjdumpOutput(objdump_out, address, cpu_arch):
- stripped_target_address = _StripPC(address, cpu_arch)
- for line in objdump_out.split(os.linesep):
- components = _FUNC.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.match(current_symbol)
- if components:
- current_symbol = components.group(1)
- offset = components.group(2)
- if offset:
- current_symbol_addr -= int(offset, 16)
- # Is it a disassembly line like: "177b2: b510 push {r4, lr}"?
- components = _ASM.match(line)
- if components:
- addr = components.group(1)
- i_addr = int(addr, 16)
- if i_addr == stripped_target_address:
- return (current_symbol, stripped_target_address - current_symbol_addr)
- return (None, None)
- def GetSymbolInformation(self, lib, address, cpu_arch):
- """Returns the corresponding function names and line numbers.
- Args:
- lib: library to search for info.
- address: address to look for info.
- cpu_arch: architecture where the dump was taken
- Returns:
- An ObjdumpInformation object
- """
- if not os.path.isfile(_LLVM_OBJDUMP_PATH):
- logging.error('Cannot find llvm-objdump. path=%s', _LLVM_OBJDUMP_PATH)
- return None
- stripped_address = _StripPC(address, cpu_arch)
- full_arguments = [_LLVM_OBJDUMP_PATH] + self._llvm_objdump_parameters
- full_arguments.append('--start-address=' + str(stripped_address))
- full_arguments.append('--stop-address=' + str(stripped_address + 8))
- full_arguments.append(lib)
- objdump_process = subprocess.Popen(full_arguments,
- stdout=subprocess.PIPE,
- stdin=subprocess.PIPE,
- universal_newlines=True)
- stdout, stderr = objdump_process.communicate()
- objdump_process_return_code = objdump_process.poll()
- if objdump_process_return_code != 0:
- logging.error(
- 'Invocation of llvm-objdump failed!' +
- ' tool-command-line=\'{}\', return-code={}, std-error=\'{}\''.format(
- ' '.join(full_arguments), objdump_process_return_code, stderr))
- return None
- symbol, offset = LLVMObjdumper.GetSymbolDataFromObjdumpOutput(
- stdout, address, cpu_arch)
- return ObjdumpInformation(address=address,
- library=lib,
- symbol=symbol,
- offset=offset)
|