| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 """Find symbols in a binary corresponding to given runtime virtual addresses. |
| 5 | 6 |
| 7 Note that source file names are treated as symbols in this script while they |
| 8 are actually not. |
| 9 """ |
| 10 |
| 11 import collections |
| 6 import json | 12 import json |
| 7 import logging | 13 import logging |
| 8 import os | 14 import os |
| 9 import sys | 15 import sys |
| 10 | 16 |
| 11 from static_symbols import StaticSymbolsInFile | 17 from static_symbols import StaticSymbolsInFile |
| 12 from proc_maps import ProcMaps | 18 from proc_maps import ProcMaps |
| 13 | 19 |
| 14 | 20 |
| 21 FUNCTION_SYMBOLS = 0 |
| 22 SOURCEFILE_SYMBOLS = 1 |
| 23 TYPEINFO_SYMBOLS = 2 |
| 24 |
| 15 _MAPS_FILENAME = 'maps' | 25 _MAPS_FILENAME = 'maps' |
| 16 _FILES_FILENAME = 'files.json' | 26 _FILES_FILENAME = 'files.json' |
| 17 | 27 |
| 18 | 28 |
| 19 class _ListOutput(object): | |
| 20 def __init__(self, result): | |
| 21 self.result = result | |
| 22 | |
| 23 def output(self, address, symbol): # pylint: disable=W0613 | |
| 24 self.result.append(symbol) | |
| 25 | |
| 26 | |
| 27 class _DictOutput(object): | |
| 28 def __init__(self, result): | |
| 29 self.result = result | |
| 30 | |
| 31 def output(self, address, symbol): | |
| 32 self.result[address] = symbol | |
| 33 | |
| 34 | |
| 35 class _FileOutput(object): | |
| 36 def __init__(self, result, with_address): | |
| 37 self.result = result | |
| 38 self.with_address = with_address | |
| 39 | |
| 40 def output(self, address, symbol): | |
| 41 if self.with_address: | |
| 42 self.result.write('%016x %s\n' % (address, symbol)) | |
| 43 else: | |
| 44 self.result.write('%s\n' % symbol) | |
| 45 | |
| 46 | |
| 47 class RuntimeSymbolsInProcess(object): | 29 class RuntimeSymbolsInProcess(object): |
| 48 def __init__(self): | 30 def __init__(self): |
| 49 self._maps = None | 31 self._maps = None |
| 50 self._static_symbols_in_filse = {} | 32 self._static_symbols_in_filse = {} |
| 51 | 33 |
| 52 def find_procedure(self, runtime_address): | 34 def find_procedure(self, runtime_address): |
| 53 for vma in self._maps.iter(ProcMaps.executable): | 35 for vma in self._maps.iter(ProcMaps.executable): |
| 54 if vma.begin <= runtime_address < vma.end: | 36 if vma.begin <= runtime_address < vma.end: |
| 55 static_symbols = self._static_symbols_in_filse.get(vma.name) | 37 static_symbols = self._static_symbols_in_filse.get(vma.name) |
| 56 if static_symbols: | 38 if static_symbols: |
| 57 return static_symbols.find_procedure_by_runtime_address( | 39 return static_symbols.find_procedure_by_runtime_address( |
| 58 runtime_address, vma) | 40 runtime_address, vma) |
| 59 else: | 41 else: |
| 60 return None | 42 return None |
| 61 return None | 43 return None |
| 62 | 44 |
| 45 def find_sourcefile(self, runtime_address): |
| 46 for vma in self._maps.iter(ProcMaps.executable): |
| 47 if vma.begin <= runtime_address < vma.end: |
| 48 static_symbols = self._static_symbols_in_filse.get(vma.name) |
| 49 if static_symbols: |
| 50 return static_symbols.find_sourcefile_by_runtime_address( |
| 51 runtime_address, vma) |
| 52 else: |
| 53 return None |
| 54 return None |
| 55 |
| 63 def find_typeinfo(self, runtime_address): | 56 def find_typeinfo(self, runtime_address): |
| 64 for vma in self._maps.iter(ProcMaps.constants): | 57 for vma in self._maps.iter(ProcMaps.constants): |
| 65 if vma.begin <= runtime_address < vma.end: | 58 if vma.begin <= runtime_address < vma.end: |
| 66 static_symbols = self._static_symbols_in_filse.get(vma.name) | 59 static_symbols = self._static_symbols_in_filse.get(vma.name) |
| 67 if static_symbols: | 60 if static_symbols: |
| 68 return static_symbols.find_typeinfo_by_runtime_address( | 61 return static_symbols.find_typeinfo_by_runtime_address( |
| 69 runtime_address, vma) | 62 runtime_address, vma) |
| 70 else: | 63 else: |
| 71 return None | 64 return None |
| 72 return None | 65 return None |
| (...skipping 19 matching lines...) Expand all Loading... |
| 92 if nm_entry and nm_entry['format'] == 'bsd': | 85 if nm_entry and nm_entry['format'] == 'bsd': |
| 93 with open(os.path.join(prepared_data_dir, nm_entry['file']), 'r') as f: | 86 with open(os.path.join(prepared_data_dir, nm_entry['file']), 'r') as f: |
| 94 static_symbols.load_nm_bsd(f, nm_entry['mangled']) | 87 static_symbols.load_nm_bsd(f, nm_entry['mangled']) |
| 95 | 88 |
| 96 readelf_entry = file_entry.get('readelf-e') | 89 readelf_entry = file_entry.get('readelf-e') |
| 97 if readelf_entry: | 90 if readelf_entry: |
| 98 with open(os.path.join(prepared_data_dir, readelf_entry['file']), | 91 with open(os.path.join(prepared_data_dir, readelf_entry['file']), |
| 99 'r') as f: | 92 'r') as f: |
| 100 static_symbols.load_readelf_ew(f) | 93 static_symbols.load_readelf_ew(f) |
| 101 | 94 |
| 95 decodedline_file_entry = file_entry.get('readelf-debug-decodedline-file') |
| 96 if decodedline_file_entry: |
| 97 with open(os.path.join(prepared_data_dir, |
| 98 decodedline_file_entry['file']), 'r') as f: |
| 99 static_symbols.load_readelf_debug_decodedline_file(f) |
| 100 |
| 102 symbols_in_process._static_symbols_in_filse[vma.name] = static_symbols | 101 symbols_in_process._static_symbols_in_filse[vma.name] = static_symbols |
| 103 | 102 |
| 104 return symbols_in_process | 103 return symbols_in_process |
| 105 | 104 |
| 106 | 105 |
| 107 def _find_runtime_symbols(symbols_in_process, addresses, outputter): | 106 def _find_runtime_function_symbols(symbols_in_process, addresses): |
| 107 result = collections.OrderedDict() |
| 108 for address in addresses: | 108 for address in addresses: |
| 109 if isinstance(address, basestring): | 109 if isinstance(address, basestring): |
| 110 address = int(address, 16) | 110 address = int(address, 16) |
| 111 found = symbols_in_process.find_procedure(address) | 111 found = symbols_in_process.find_procedure(address) |
| 112 if found: | 112 if found: |
| 113 outputter.output(address, found.name) | 113 result[address] = found.name |
| 114 else: | 114 else: |
| 115 outputter.output(address, '0x%016x' % address) | 115 result[address] = '0x%016x' % address |
| 116 return result |
| 116 | 117 |
| 117 | 118 |
| 118 def _find_runtime_typeinfo_symbols(symbols_in_process, addresses, outputter): | 119 def _find_runtime_sourcefile_symbols(symbols_in_process, addresses): |
| 120 result = collections.OrderedDict() |
| 121 for address in addresses: |
| 122 if isinstance(address, basestring): |
| 123 address = int(address, 16) |
| 124 found = symbols_in_process.find_sourcefile(address) |
| 125 if found: |
| 126 result[address] = found |
| 127 else: |
| 128 result[address] = '' |
| 129 return result |
| 130 |
| 131 |
| 132 def _find_runtime_typeinfo_symbols(symbols_in_process, addresses): |
| 133 result = collections.OrderedDict() |
| 119 for address in addresses: | 134 for address in addresses: |
| 120 if isinstance(address, basestring): | 135 if isinstance(address, basestring): |
| 121 address = int(address, 16) | 136 address = int(address, 16) |
| 122 if address == 0: | 137 if address == 0: |
| 123 outputter.output(address, 'no typeinfo') | 138 result[address] = 'no typeinfo' |
| 124 else: | 139 else: |
| 125 found = symbols_in_process.find_typeinfo(address) | 140 found = symbols_in_process.find_typeinfo(address) |
| 126 if found: | 141 if found: |
| 127 if found.startswith('typeinfo for '): | 142 if found.startswith('typeinfo for '): |
| 128 outputter.output(address, found[13:]) | 143 result[address] = found[13:] |
| 129 else: | 144 else: |
| 130 outputter.output(address, found) | 145 result[address] = found |
| 131 else: | 146 else: |
| 132 outputter.output(address, '0x%016x' % address) | 147 result[address] = '0x%016x' % address |
| 133 | |
| 134 | |
| 135 def find_runtime_typeinfo_symbols_list(symbols_in_process, addresses): | |
| 136 result = [] | |
| 137 _find_runtime_typeinfo_symbols( | |
| 138 symbols_in_process, addresses, _ListOutput(result)) | |
| 139 return result | 148 return result |
| 140 | 149 |
| 141 | 150 |
| 142 def find_runtime_typeinfo_symbols_dict(symbols_in_process, addresses): | 151 _INTERNAL_FINDERS = { |
| 143 result = {} | 152 FUNCTION_SYMBOLS: _find_runtime_function_symbols, |
| 144 _find_runtime_typeinfo_symbols( | 153 SOURCEFILE_SYMBOLS: _find_runtime_sourcefile_symbols, |
| 145 symbols_in_process, addresses, _DictOutput(result)) | 154 TYPEINFO_SYMBOLS: _find_runtime_typeinfo_symbols, |
| 146 return result | 155 } |
| 147 | 156 |
| 148 | 157 |
| 149 def find_runtime_typeinfo_symbols_file(symbols_in_process, addresses, f): | 158 def find_runtime_symbols(symbol_type, symbols_in_process, addresses): |
| 150 _find_runtime_typeinfo_symbols( | 159 return _INTERNAL_FINDERS[symbol_type](symbols_in_process, addresses) |
| 151 symbols_in_process, addresses, _FileOutput(f, False)) | |
| 152 | |
| 153 | |
| 154 def find_runtime_symbols_list(symbols_in_process, addresses): | |
| 155 result = [] | |
| 156 _find_runtime_symbols(symbols_in_process, addresses, _ListOutput(result)) | |
| 157 return result | |
| 158 | |
| 159 | |
| 160 def find_runtime_symbols_dict(symbols_in_process, addresses): | |
| 161 result = {} | |
| 162 _find_runtime_symbols(symbols_in_process, addresses, _DictOutput(result)) | |
| 163 return result | |
| 164 | |
| 165 | |
| 166 def find_runtime_symbols_file(symbols_in_process, addresses, f): | |
| 167 _find_runtime_symbols( | |
| 168 symbols_in_process, addresses, _FileOutput(f, False)) | |
| 169 | 160 |
| 170 | 161 |
| 171 def main(): | 162 def main(): |
| 172 # FIX: Accept only .pre data | 163 # FIX: Accept only .pre data |
| 173 if len(sys.argv) < 2: | 164 if len(sys.argv) < 2: |
| 174 sys.stderr.write("""Usage: | 165 sys.stderr.write("""Usage: |
| 175 %s /path/to/prepared_data_dir/ < addresses.txt | 166 %s /path/to/prepared_data_dir/ < addresses.txt |
| 176 """ % sys.argv[0]) | 167 """ % sys.argv[0]) |
| 177 return 1 | 168 return 1 |
| 178 | 169 |
| 179 log = logging.getLogger('find_runtime_symbols') | 170 log = logging.getLogger('find_runtime_symbols') |
| 180 log.setLevel(logging.WARN) | 171 log.setLevel(logging.WARN) |
| 181 handler = logging.StreamHandler() | 172 handler = logging.StreamHandler() |
| 182 handler.setLevel(logging.WARN) | 173 handler.setLevel(logging.WARN) |
| 183 formatter = logging.Formatter('%(message)s') | 174 formatter = logging.Formatter('%(message)s') |
| 184 handler.setFormatter(formatter) | 175 handler.setFormatter(formatter) |
| 185 log.addHandler(handler) | 176 log.addHandler(handler) |
| 186 | 177 |
| 187 prepared_data_dir = sys.argv[1] | 178 prepared_data_dir = sys.argv[1] |
| 188 if not os.path.exists(prepared_data_dir): | 179 if not os.path.exists(prepared_data_dir): |
| 189 log.warn("Nothing found: %s" % prepared_data_dir) | 180 log.warn("Nothing found: %s" % prepared_data_dir) |
| 190 return 1 | 181 return 1 |
| 191 if not os.path.isdir(prepared_data_dir): | 182 if not os.path.isdir(prepared_data_dir): |
| 192 log.warn("Not a directory: %s" % prepared_data_dir) | 183 log.warn("Not a directory: %s" % prepared_data_dir) |
| 193 return 1 | 184 return 1 |
| 194 | 185 |
| 195 symbols_in_process = RuntimeSymbolsInProcess.load(prepared_data_dir) | 186 symbols_in_process = RuntimeSymbolsInProcess.load(prepared_data_dir) |
| 196 return find_runtime_symbols_file(symbols_in_process, sys.stdin, sys.stdout) | 187 symbols_dict = find_runtime_symbols(FUNCTION_SYMBOLS, |
| 188 symbols_in_process, |
| 189 sys.stdin) |
| 190 for address, symbol in symbols_dict: |
| 191 if symbol: |
| 192 print '%016x %s' % (address, symbol) |
| 193 else: |
| 194 print '%016x' % address |
| 195 |
| 196 return 0 |
| 197 | 197 |
| 198 | 198 |
| 199 if __name__ == '__main__': | 199 if __name__ == '__main__': |
| 200 sys.exit(main()) | 200 sys.exit(main()) |
| OLD | NEW |