Chromium Code Reviews| 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..84a01006bfd578782b5f025142cd532aa68206e3 100644 |
| --- a/build/android/pylib/symbols/elf_symbolizer.py |
| +++ b/build/android/pylib/symbols/elf_symbolizer.py |
| @@ -13,7 +13,7 @@ import re |
| import subprocess |
| import sys |
| import threading |
| - |
| +from sets import Set |
| # addr2line builds a possibly infinite memory cache that can exhaust |
| # the computer's memory if allowed to grow for too long. This constant |
| @@ -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, |
| + disambiguate=False, disambiguation_source_path=''): |
| """Args: |
| elf_file_path: path of the elf file to be symbolized. |
| addr2line_path: path of the toolchain's addr2line binary. |
| @@ -91,6 +92,12 @@ 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. |
| + disambiguate: Whether to run a disambiguation process or not. |
| + Disambiguation means to resolve ambigious source_paths, |
|
Andrew Hayden (chromium.org)
2014/06/17 11:36:27
ambigious -> ambiguous (Spelling)
You may also wa
|
| + example turn addr2line output "unicode.cc" into a full and absolute |
|
Andrew Hayden (chromium.org)
2014/06/17 11:36:27
"for example" instead of "example"
|
| + path |
| + disambiguate_source_path: The path of the source code that the |
|
Andrew Hayden (chromium.org)
2014/06/17 11:36:27
I'd say: the path to the directory where source fi
|
| + disambiguation will lookup source files |
| """ |
| assert(os.path.isfile(addr2line_path)), 'Cannot find ' + addr2line_path |
| self.elf_file_path = elf_file_path |
| @@ -104,6 +111,13 @@ 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 = disambiguate |
| + self.commonprefix = '' |
| + self.lookup_table = {} |
| + if(self.disambiguate): |
| + self._CreateDisambiguationTable(disambiguation_source_path) |
| + |
| # 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 +175,38 @@ class ELFSymbolizer(object): |
| self._a2l_instances.append(a2l) |
| return a2l |
| + def _CreateDisambiguationTable(self, src_root_path): |
| + """ Creates a table of files used for disambiguation later |
| + Disambiguation: |
| + addr2line sometimes return an ambigous file-name rather than the |
| + full path of the file where the symbol is located. |
| + |
| + adopted from andrewhaydens implementation in earlier commits """ |
| + interesting_file_endings = { ".c", ".cc", ".h", ".cp", ".cpp", ".cxx", |
| + ".c++", ".asm", ".inc", ".s", ".hxx" } |
| + duplicates = Set() |
| + self.lookup_table = {} |
| + src_root_path = os.path.abspath(src_root_path) |
| + |
| + for root, _, filenames in os.walk(src_root_path): |
| + for f in filenames: |
| + _, ext = os.path.splitext(f) |
| + if not ext in interesting_file_endings: |
| + continue |
| + |
| + base = os.path.basename(f) # Just in case |
| + if self.lookup_table.get(base) is None: |
| + self.lookup_table[base] = "%s/%s" % (root, f) |
| + else: |
| + duplicates.add(base) |
| + |
| + # Duplicates can not be used for disambiguation, as we can not determine |
| + # the true source if we have more than one to choose from |
| + for d in duplicates: |
| + del self.lookup_table[d] |
| + |
| + # Get the common prefix for the source paths |
| + self.commonprefix = os.path.commonprefix(self.lookup_table.values()) |
| class Addr2Line(object): |
| """A python wrapper around an addr2line instance. |
| @@ -306,13 +352,29 @@ class ELFSymbolizer(object): |
| m = ELFSymbolizer.Addr2Line.SYM_ADDR_RE.match(line2) |
| if m: |
| if not m.group(1).startswith('?'): |
| - source_path = m.group(1) |
| + source_path = os.path.abspath(m.group(1)) |
| if not m.group(2).startswith('?'): |
| source_line = int(m.group(2)) |
| 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 |
| + disambiguated = False |
| + if self._symbolizer.disambiguate: |
| + # Strip the common prefix to determine whether the source is ambigous |
|
Andrew Hayden (chromium.org)
2014/06/17 11:36:27
"ambiguous"
|
| + # or not (we assume that there are no source files in the common |
| + # prefix of the paths) |
| + if not source_path is None: |
| + common_prefix = self._symbolizer.commonprefix |
| + if source_path.startswith(common_prefix): |
| + path = source_path[len(common_prefix):] |
| + # In case no '/' character is found in this "relative" path |
| + # it is most likely that addr2line did not get the whole path |
| + if not path.find('/') != -1: |
|
Andrew Hayden (chromium.org)
2014/06/17 11:36:27
Double negation is hard to reason about. How about
|
| + source_path = self._symbolizer.lookup_table.get(path) |
| + disambiguated = True |
| + |
| + sym_info = ELFSymbolInfo(name, source_path, source_line, disambiguated) |
| if prev_sym_info: |
| prev_sym_info.inlined_by = sym_info |
| if not innermost_sym_info: |
| @@ -393,7 +455,7 @@ 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, disambiguated=False): |
| """All the fields here can be None (if addr2line replies with '??').""" |
| self.name = name |
| self.source_path = source_path |
| @@ -401,6 +463,7 @@ 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 |
| def __str__(self): |
| return '%s [%s:%d]' % ( |