| 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]' % (
|
|
|