| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2016 The Chromium Authors. All rights reserved. | 2 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """ | 6 """ |
| 7 This script processes trace files and symbolizes stack frames generated by | 7 This script processes trace files and symbolizes stack frames generated by |
| 8 Chrome's native heap profiler. This script assumes that the Chrome binary | 8 Chrome's native heap profiler. This script assumes that the Chrome binary |
| 9 referenced in the trace contains symbols, and is the same binary used to emit | 9 referenced in the trace contains symbols, and is the same binary used to emit |
| 10 the trace. | 10 the trace. |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 import gzip | 217 import gzip |
| 218 import itertools | 218 import itertools |
| 219 import json | 219 import json |
| 220 import os | 220 import os |
| 221 import re | 221 import re |
| 222 import shutil | 222 import shutil |
| 223 import subprocess | 223 import subprocess |
| 224 import sys | 224 import sys |
| 225 import tarfile | 225 import tarfile |
| 226 import zipfile | 226 import zipfile |
| 227 import tempfile |
| 227 | 228 |
| 228 _SYMBOLS_PATH = os.path.abspath(os.path.join( | 229 _SYMBOLS_PATH = os.path.abspath(os.path.join( |
| 229 os.path.dirname(os.path.realpath(__file__)), | 230 os.path.dirname(os.path.realpath(__file__)), |
| 230 '..', | 231 '..', |
| 231 'third_party', | 232 'third_party', |
| 232 'symbols')) | 233 'symbols')) |
| 233 sys.path.append(_SYMBOLS_PATH) | 234 sys.path.append(_SYMBOLS_PATH) |
| 234 # pylint: disable=import-error | 235 # pylint: disable=import-error |
| 235 import symbols.elf_symbolizer as elf_symbolizer | 236 import symbols.elf_symbolizer as elf_symbolizer |
| 236 | 237 |
| (...skipping 815 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1052 # SymbolizeAsync() asserts that the type of address is int. We operate | 1053 # SymbolizeAsync() asserts that the type of address is int. We operate |
| 1053 # on longs (since they are raw pointers possibly from 64-bit processes). | 1054 # on longs (since they are raw pointers possibly from 64-bit processes). |
| 1054 # It's OK to cast here because we're passing relative PC, which should | 1055 # It's OK to cast here because we're passing relative PC, which should |
| 1055 # always fit into int. | 1056 # always fit into int. |
| 1056 symbolizer.SymbolizeAsync(int(address), frames) | 1057 symbolizer.SymbolizeAsync(int(address), frames) |
| 1057 | 1058 |
| 1058 symbolizer.Join() | 1059 symbolizer.Join() |
| 1059 | 1060 |
| 1060 | 1061 |
| 1061 def _SymbolizeMac(self, symfile): | 1062 def _SymbolizeMac(self, symfile): |
| 1062 chars_max = int(subprocess.check_output("getconf ARG_MAX", shell=True)) | |
| 1063 | |
| 1064 # 16 for the address, 2 for "0x", 1 for the space | |
| 1065 chars_per_address = 19 | |
| 1066 | |
| 1067 load_address = (symbolize_trace_macho_reader. | 1063 load_address = (symbolize_trace_macho_reader. |
| 1068 ReadMachOTextLoadAddress(symfile.symbolizable_path)) | 1064 ReadMachOTextLoadAddress(symfile.symbolizable_path)) |
| 1069 assert load_address is not None | 1065 assert load_address is not None |
| 1070 | 1066 |
| 1071 cmd_base = [self.symbolizer_path, '-arch', 'x86_64', '-l', | 1067 address_os_file, address_file_path = tempfile.mkstemp() |
| 1072 '0x%x' % load_address, '-o', | 1068 try: |
| 1073 symfile.symbolizable_path] | 1069 with os.fdopen(address_os_file, 'w') as address_file: |
| 1074 chars_for_other_arguments = len(' '.join(cmd_base)) + 1 | 1070 for address in symfile.frames_by_address.iterkeys(): |
| 1071 address_file.write('{:x} '.format(address + load_address)) |
| 1075 | 1072 |
| 1076 # The maximum number of inputs that can be processed at once is limited by | 1073 cmd = [self.symbolizer_path, '-arch', 'x86_64', '-l', |
| 1077 # ARG_MAX. This currently evaluates to ~13000 on macOS. | 1074 '0x%x' % load_address, '-o', symfile.symbolizable_path, |
| 1078 max_inputs = (chars_max - chars_for_other_arguments) / chars_per_address | 1075 '-f', address_file_path] |
| 1076 output_array = subprocess.check_output(cmd).split('\n') |
| 1079 | 1077 |
| 1080 all_keys = symfile.frames_by_address.keys() | 1078 for i, frames in enumerate(symfile.frames_by_address.itervalues()): |
| 1081 processed_keys_count = 0 | 1079 symbolized_name = self._matcher.Match(output_array[i]) |
| 1082 while len(all_keys): | 1080 for frame in frames: |
| 1083 input_count = min(len(all_keys), max_inputs) | 1081 frame.name = symbolized_name |
| 1084 keys_to_process = all_keys[0:input_count] | 1082 finally: |
| 1085 cmd = list(cmd_base) | 1083 os.remove(address_file_path) |
| 1086 cmd.extend([hex(int(x) + load_address) | |
| 1087 for x in keys_to_process]) | |
| 1088 output_array = subprocess.check_output(cmd).split('\n') | |
| 1089 for i in range(len(keys_to_process)): | |
| 1090 for frame in (symfile.frames_by_address.values() | |
| 1091 [i + processed_keys_count]): | |
| 1092 frame.name = self._matcher.Match(output_array[i]) | |
| 1093 processed_keys_count += len(keys_to_process) | |
| 1094 all_keys = all_keys[input_count:] | |
| 1095 | 1084 |
| 1096 def _SymbolizeWin(self, symfile): | 1085 def _SymbolizeWin(self, symfile): |
| 1097 """Invoke symbolizer binary on windows and write all input in one go. | 1086 """Invoke symbolizer binary on windows and write all input in one go. |
| 1098 | 1087 |
| 1099 Unlike linux, on windows, symbolization talks through a shared system | 1088 Unlike linux, on windows, symbolization talks through a shared system |
| 1100 service that handles communication with the NT symbol servers. This | 1089 service that handles communication with the NT symbol servers. This |
| 1101 creates an explicit serialization (and therefor lock contention) of | 1090 creates an explicit serialization (and therefor lock contention) of |
| 1102 any process using the symbol API for files do not have a local PDB. | 1091 any process using the symbol API for files do not have a local PDB. |
| 1103 | 1092 |
| 1104 Thus, even though the windows symbolizer binary can be make command line | 1093 Thus, even though the windows symbolizer binary can be make command line |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1409 | 1398 |
| 1410 print 'Updating the trace file...' | 1399 print 'Updating the trace file...' |
| 1411 with OpenTraceFile(trace_file_path, 'w') as trace_file: | 1400 with OpenTraceFile(trace_file_path, 'w') as trace_file: |
| 1412 json.dump(trace.node, trace_file) | 1401 json.dump(trace.node, trace_file) |
| 1413 else: | 1402 else: |
| 1414 print 'No modifications were made - not updating the trace file.' | 1403 print 'No modifications were made - not updating the trace file.' |
| 1415 | 1404 |
| 1416 | 1405 |
| 1417 if __name__ == '__main__': | 1406 if __name__ == '__main__': |
| 1418 main() | 1407 main() |
| OLD | NEW |