Index: build/android/pylib/symbols/elf_symbolizer.py |
diff --git a/build/android/pylib/symbols/elf_symbolizer.py b/build/android/pylib/symbols/elf_symbolizer.py |
index b294654f20b1ee3c7f0cdb5c142789f3bc1b5933..08c02d5a8ac056d8f2cf5d79f6da5e8177f8d09c 100644 |
--- a/build/android/pylib/symbols/elf_symbolizer.py |
+++ b/build/android/pylib/symbols/elf_symbolizer.py |
@@ -75,7 +75,8 @@ class ELFSymbolizer(object): |
""" |
def __init__(self, elf_file_path, addr2line_path, callback, inlines=False, |
- max_concurrent_jobs=None, addr2line_timeout=30, max_queue_size=50): |
+ max_concurrent_jobs=None, addr2line_timeout=30, max_queue_size=50, |
+ source_root_path=None, strip_base_path=None): |
"""Args: |
elf_file_path: path of the elf file to be symbolized. |
addr2line_path: path of the toolchain's addr2line binary. |
@@ -91,6 +92,18 @@ class ELFSymbolizer(object): |
max_queue_size: Max number of outstanding requests per addr2line instance. |
addr2line_timeout: Max time (in seconds) to wait for a addr2line response. |
After the timeout, the instance will be considered hung and respawned. |
+ source_root_path: In some toolchains only the name of the source file is |
+ is output, without any path information; disambiguation searches |
+ through the source directory specified by |source_root_path| argument |
+ for files whose name matches, adding the full path information to the |
+ output. For example, if the toolchain outputs "unicode.cc" and there |
+ is a file called "unicode.cc" located under |source_root_path|/foo, |
+ the tool will replace "unicode.cc" with |
+ "|source_root_path|/foo/unicode.cc". If there are multiple files with |
+ the same name, disambiguation will fail because the tool cannot |
+ determine which of the files was the source of the symbol. |
+ strip_base_path: Rebases the symbols source paths onto |source_root_path| |
+ (i.e replace |strip_base_path| with |source_root_path). |
""" |
assert(os.path.isfile(addr2line_path)), 'Cannot find ' + addr2line_path |
self.elf_file_path = elf_file_path |
@@ -104,6 +117,14 @@ class ELFSymbolizer(object): |
self.requests_counter = 0 # For generating monotonic request IDs. |
self._a2l_instances = [] # Up to |max_concurrent_jobs| _Addr2Line inst. |
+ # If necessary, create disambiguation lookup table |
+ self.disambiguate = source_root_path is not None |
+ self.disambiguation_table = {} |
+ self.strip_base_path = strip_base_path |
+ if(self.disambiguate): |
+ self.source_root_path = os.path.abspath(source_root_path) |
+ self._CreateDisambiguationTable() |
+ |
# Create one addr2line instance. More instances will be created on demand |
# (up to |max_concurrent_jobs|) depending on the rate of the requests. |
self._CreateNewA2LInstance() |
@@ -161,6 +182,15 @@ class ELFSymbolizer(object): |
self._a2l_instances.append(a2l) |
return a2l |
+ def _CreateDisambiguationTable(self): |
+ """ Non-unique file names will result in None entries""" |
+ self.disambiguation_table = {} |
+ |
+ for root, _, filenames in os.walk(self.source_root_path): |
+ for f in filenames: |
+ self.disambiguation_table[f] = os.path.join(root, f) if (f not in |
+ self.disambiguation_table) else None |
+ |
class Addr2Line(object): |
"""A python wrapper around an addr2line instance. |
@@ -312,7 +342,28 @@ class ELFSymbolizer(object): |
else: |
logging.warning('Got invalid symbol path from addr2line: %s' % line2) |
- sym_info = ELFSymbolInfo(name, source_path, source_line) |
+ # In case disambiguation is on, and needed |
+ was_ambiguous = False |
+ disambiguated = False |
+ if self._symbolizer.disambiguate: |
+ if source_path and not posixpath.isabs(source_path): |
+ path = self._symbolizer.disambiguation_table.get(source_path) |
+ was_ambiguous = True |
+ disambiguated = path is not None |
+ source_path = path if disambiguated else source_path |
+ |
+ # Use absolute paths (so that paths are consistent, as disambiguation |
+ # uses absolute paths) |
+ if source_path and not was_ambiguous: |
+ source_path = os.path.abspath(source_path) |
+ |
+ if source_path and self._symbolizer.strip_base_path: |
+ # Strip the base path |
+ source_path = re.sub('^' + self._symbolizer.strip_base_path, |
+ self._symbolizer.source_root_path or '', source_path) |
+ |
+ sym_info = ELFSymbolInfo(name, source_path, source_line, was_ambiguous, |
+ disambiguated) |
if prev_sym_info: |
prev_sym_info.inlined_by = sym_info |
if not innermost_sym_info: |
@@ -393,7 +444,8 @@ class ELFSymbolizer(object): |
class ELFSymbolInfo(object): |
"""The result of the symbolization passed as first arg. of each callback.""" |
- def __init__(self, name, source_path, source_line): |
+ def __init__(self, name, source_path, source_line, was_ambiguous=False, |
+ disambiguated=False): |
"""All the fields here can be None (if addr2line replies with '??').""" |
self.name = name |
self.source_path = source_path |
@@ -401,6 +453,8 @@ class ELFSymbolInfo(object): |
# In the case of |inlines|=True, the |inlined_by| points to the outer |
# function inlining the current one (and so on, to form a chain). |
self.inlined_by = None |
+ self.disambiguated = disambiguated |
+ self.was_ambiguous = was_ambiguous |
def __str__(self): |
return '%s [%s:%d]' % ( |