Chromium Code Reviews| Index: tracing/bin/symbolize_trace |
| diff --git a/tracing/bin/symbolize_trace b/tracing/bin/symbolize_trace |
| index ecfbb673bf0c46bbbcb4dce0f414a68388f237fe..27ea0f03117f74f28f9e10cd0ed27fe0726b20d8 100755 |
| --- a/tracing/bin/symbolize_trace |
| +++ b/tracing/bin/symbolize_trace |
| @@ -52,10 +52,77 @@ def FindInSystemPath(binary_name): |
| return None |
| +class Symbolizer(object): |
| + # Encapsulates platform-specific symbolization logic. |
| + def __init__(self): |
| + self.is_mac = sys.platform == 'darwin' |
| + if self.is_mac: |
| + self.binary = 'atos' |
| + else: |
| + self.binary = 'addr2line' |
| + self.symbolizer_path = FindInSystemPath(self.binary) |
| + |
| + def _SymbolizeLinuxAndAndroid(self, sym_file): |
|
DmitrySkiba
2017/02/06 19:28:33
Argument should be 'symfile' (without underscore).
erikchen
2017/02/11 02:45:23
Done.
|
| + def _SymbolizerCallback(sym_info, frames): |
| + # Unwind inline chain to the top. |
| + while sym_info.inlined_by: |
| + sym_info = sym_info.inlined_by |
| + |
| + symbolized_name = sym_info.name if sym_info.name else unsymbolized_name |
| + for frame in frames: |
| + frame.name = symbolized_name |
| + |
| + symbolizer = elf_symbolizer.ELFSymbolizer(symfile.symbolizable_path, |
| + self.symbolizer_path, |
| + _SymbolizerCallback, |
| + inlines=True) |
| + |
| + for address, frames in symfile.frames_by_address.iteritems(): |
| + # SymbolizeAsync() asserts that the type of address is int. We operate |
| + # on longs (since they are raw pointers possibly from 64-bit processes). |
| + # It's OK to cast here because we're passing relative PC, which should |
| + # always fit into int. |
| + symbolizer.SymbolizeAsync(int(address), frames) |
| + |
| + symbolizer.Join() |
| + |
| + def _SymbolizeMac(self, symfile): |
| + chars_max = int(subprocess.check_output("getconf ARG_MAX", shell=True)) |
| + |
| + # 16 for the address, 2 for "0x", 1 for the space |
| + chars_per_address = 19 |
| + chars_for_other_arguments = 2000 |
|
DmitrySkiba
2017/02/06 19:28:34
Since symfile doesn't change in this function, we
erikchen
2017/02/11 02:45:23
Done.
|
| + |
| + # The maximum number of inputs that can be processed at once is limited by |
| + # ARG_MAX. This currently evalutes to ~13000 on macOS. |
| + max_inputs = (chars_max - chars_for_other_arguments) / chars_per_address |
| + |
| + all_keys = symfile.frames_by_address.keys() |
| + while len(all_keys): |
| + input_count = min(len(all_keys), max_inputs) |
| + keys_to_process = all_keys[0:input_count] |
| + |
| + cmd = [self.symbolizer_path, '-arch', 'x86_64', '-l', |
| + '0x0', '-o' , symfile.symbolizable_path] |
| + cmd.extend([hex(int(x)) for x in keys_to_process]) |
| + output_array = subprocess.check_output(cmd).split('\n') |
| + for i in range(len(keys_to_process)): |
| + for frame in symfile.frames_by_address.values()[i]: |
|
DmitrySkiba
2017/02/06 19:28:34
|i| should include offset (number of keys already
erikchen
2017/02/11 02:45:23
Good catch, thanks. Done.
|
| + frame.name = output_array[i] |
|
DmitrySkiba
2017/02/06 19:28:34
Hmm, according to the docs, atos output can includ
erikchen
2017/02/11 02:45:23
what parsing logic are you referring to? Something
|
| + all_keys = all_keys[input_count:] |
| + |
| + def Symbolize(self, symfile): |
| + if self.is_mac: |
| + self._SymbolizeMac(symfile) |
| + else: |
| + self._SymbolizeLinuxAndAndroid(symfile) |
| + |
| + |
| def IsSymbolizableFile(file_path): |
| result = subprocess.check_output(['file', '-0', file_path]) |
| type_string = result[result.find('\0') + 1:] |
| - return bool(re.match(r'\: (ELF|Mach-O) (32|64)-bit\b', type_string)) |
| + return bool(re.match(r'.*(ELF|Mach-O) (32|64)-bit\b.*', |
| + type_string, re.DOTALL)) |
| class ProcessMemoryMaps(object): |
| @@ -271,7 +338,7 @@ def ResolveSymbolizableFiles(processes): |
| return symfile_by_path.values() |
| -def SymbolizeFiles(symfiles, addr2line_path): |
| +def SymbolizeFiles(symfiles, symbolizer): |
| """Symbolizes each file in the given list of SymbolizableFiles |
| and updates stack frames with symbolization results.""" |
| print 'Symbolizing...' |
| @@ -301,32 +368,11 @@ def SymbolizeFiles(symfiles, addr2line_path): |
| frame.name = unsymbolized_name |
| continue |
| - def _SymbolizerCallback(sym_info, frames): |
| - # Unwind inline chain to the top. |
| - while sym_info.inlined_by: |
| - sym_info = sym_info.inlined_by |
| - |
| - symbolized_name = sym_info.name if sym_info.name else unsymbolized_name |
| - for frame in frames: |
| - frame.name = symbolized_name |
| - |
| - symbolizer = elf_symbolizer.ELFSymbolizer(symfile.symbolizable_path, |
| - addr2line_path, |
| - _SymbolizerCallback, |
| - inlines=True) |
| - |
| _SubPrintf('Symbolizing {} PCs from {}...', |
| len(symfile.frames_by_address), |
| symfile.path) |
| - for address, frames in symfile.frames_by_address.iteritems(): |
| - # SymbolizeAsync() asserts that the type of address is int. We operate |
| - # on longs (since they are raw pointers possibly from 64-bit processes). |
| - # It's OK to cast here because we're passing relative PC, which should |
| - # always fit into int. |
| - symbolizer.SymbolizeAsync(int(address), frames) |
| - |
| - symbolizer.Join() |
| + symbolizer.Symbolize(symfile) |
| symbolized = True |
| return symbolized |
| @@ -372,9 +418,9 @@ def main(): |
| else: |
| return open(trace_file_path, mode + 't') |
| - addr2line_path = FindInSystemPath('addr2line') |
| - if addr2line_path is None: |
| - sys.exit("Can't symbolize - no addr2line in PATH.") |
| + symbolizer = Symbolizer() |
| + if symbolizer.symbolizer_path is None: |
| + sys.exit("Can't symbolize - no %s in PATH." % symbolizer.binary) |
| print 'Reading trace file...' |
| with _OpenTraceFile('r') as trace_file: |
| @@ -392,7 +438,7 @@ def main(): |
| 'symbolize it.') |
| RemapAndroidFiles(symfiles, os.path.abspath(options.output_directory)) |
| - if SymbolizeFiles(symfiles, addr2line_path): |
| + if SymbolizeFiles(symfiles, symbolizer): |
| if options.backup: |
| backup_file_path = trace_file_path + BACKUP_FILE_TAG |
| print 'Backing up trace file to {}...'.format(backup_file_path) |