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