Extract protobuf database into a new 'leveldb_proto' component
[chromium-blink-merge.git] / tools / find_runtime_symbols / find_runtime_symbols.py
blob038874132dba7334d33f4d08c8e4f5ad2507979b
1 #!/usr/bin/env python
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
4 # found in the LICENSE file.
5 """Find symbols in a binary corresponding to given runtime virtual addresses.
7 Note that source file names are treated as symbols in this script while they
8 are actually not.
9 """
11 import json
12 import logging
13 import os
14 import sys
16 from static_symbols import StaticSymbolsInFile
19 _BASE_PATH = os.path.dirname(os.path.abspath(__file__))
20 _TOOLS_LINUX_PATH = os.path.join(_BASE_PATH, os.pardir, 'linux')
21 sys.path.insert(0, _TOOLS_LINUX_PATH)
24 from procfs import ProcMaps # pylint: disable=F0401
26 try:
27 from collections import OrderedDict # pylint: disable=E0611
28 except ImportError:
29 _SIMPLEJSON_PATH = os.path.join(_BASE_PATH, os.pardir, os.pardir,
30 'third_party')
31 sys.path.insert(0, _SIMPLEJSON_PATH)
32 from simplejson import OrderedDict
35 FUNCTION_SYMBOLS = 0
36 SOURCEFILE_SYMBOLS = 1
37 TYPEINFO_SYMBOLS = 2
39 _MAPS_FILENAME = 'maps'
40 _FILES_FILENAME = 'files.json'
43 class RuntimeSymbolsInProcess(object):
44 def __init__(self):
45 self._maps = None
46 self._static_symbols_in_filse = {}
48 def find_procedure(self, runtime_address):
49 for vma in self._maps.iter(ProcMaps.executable):
50 if vma.begin <= runtime_address < vma.end:
51 static_symbols = self._static_symbols_in_filse.get(vma.name)
52 if static_symbols:
53 return static_symbols.find_procedure_by_runtime_address(
54 runtime_address, vma)
55 else:
56 return None
57 return None
59 def find_sourcefile(self, runtime_address):
60 for vma in self._maps.iter(ProcMaps.executable):
61 if vma.begin <= runtime_address < vma.end:
62 static_symbols = self._static_symbols_in_filse.get(vma.name)
63 if static_symbols:
64 return static_symbols.find_sourcefile_by_runtime_address(
65 runtime_address, vma)
66 else:
67 return None
68 return None
70 def find_typeinfo(self, runtime_address):
71 for vma in self._maps.iter(ProcMaps.constants):
72 if vma.begin <= runtime_address < vma.end:
73 static_symbols = self._static_symbols_in_filse.get(vma.name)
74 if static_symbols:
75 return static_symbols.find_typeinfo_by_runtime_address(
76 runtime_address, vma)
77 else:
78 return None
79 return None
81 @staticmethod
82 def load(prepared_data_dir):
83 symbols_in_process = RuntimeSymbolsInProcess()
85 with open(os.path.join(prepared_data_dir, _MAPS_FILENAME), mode='r') as f:
86 symbols_in_process._maps = ProcMaps.load_file(f)
87 with open(os.path.join(prepared_data_dir, _FILES_FILENAME), mode='r') as f:
88 files = json.load(f)
90 # pylint: disable=W0212
91 for vma in symbols_in_process._maps.iter(ProcMaps.executable_and_constants):
92 file_entry = files.get(vma.name)
93 if not file_entry:
94 continue
96 static_symbols = StaticSymbolsInFile(vma.name)
98 nm_entry = file_entry.get('nm')
99 if nm_entry and nm_entry['format'] == 'bsd':
100 with open(os.path.join(prepared_data_dir, nm_entry['file']), 'r') as f:
101 static_symbols.load_nm_bsd(f, nm_entry['mangled'])
103 readelf_entry = file_entry.get('readelf-e')
104 if readelf_entry:
105 with open(os.path.join(prepared_data_dir, readelf_entry['file']),
106 'r') as f:
107 static_symbols.load_readelf_ew(f)
109 decodedline_file_entry = file_entry.get('readelf-debug-decodedline-file')
110 if decodedline_file_entry:
111 with open(os.path.join(prepared_data_dir,
112 decodedline_file_entry['file']), 'r') as f:
113 static_symbols.load_readelf_debug_decodedline_file(f)
115 symbols_in_process._static_symbols_in_filse[vma.name] = static_symbols
117 return symbols_in_process
120 def _find_runtime_function_symbols(symbols_in_process, addresses):
121 result = OrderedDict()
122 for address in addresses:
123 if isinstance(address, basestring):
124 address = int(address, 16)
125 found = symbols_in_process.find_procedure(address)
126 if found:
127 result[address] = found.name
128 else:
129 result[address] = '0x%016x' % address
130 return result
133 def _find_runtime_sourcefile_symbols(symbols_in_process, addresses):
134 result = OrderedDict()
135 for address in addresses:
136 if isinstance(address, basestring):
137 address = int(address, 16)
138 found = symbols_in_process.find_sourcefile(address)
139 if found:
140 result[address] = found
141 else:
142 result[address] = ''
143 return result
146 def _find_runtime_typeinfo_symbols(symbols_in_process, addresses):
147 result = OrderedDict()
148 for address in addresses:
149 if isinstance(address, basestring):
150 address = int(address, 16)
151 if address == 0:
152 result[address] = 'no typeinfo'
153 else:
154 found = symbols_in_process.find_typeinfo(address)
155 if found:
156 if found.startswith('typeinfo for '):
157 result[address] = found[13:]
158 else:
159 result[address] = found
160 else:
161 result[address] = '0x%016x' % address
162 return result
165 _INTERNAL_FINDERS = {
166 FUNCTION_SYMBOLS: _find_runtime_function_symbols,
167 SOURCEFILE_SYMBOLS: _find_runtime_sourcefile_symbols,
168 TYPEINFO_SYMBOLS: _find_runtime_typeinfo_symbols,
172 def find_runtime_symbols(symbol_type, symbols_in_process, addresses):
173 return _INTERNAL_FINDERS[symbol_type](symbols_in_process, addresses)
176 def main():
177 # FIX: Accept only .pre data
178 if len(sys.argv) < 2:
179 sys.stderr.write("""Usage:
180 %s /path/to/prepared_data_dir/ < addresses.txt
181 """ % sys.argv[0])
182 return 1
184 log = logging.getLogger('find_runtime_symbols')
185 log.setLevel(logging.WARN)
186 handler = logging.StreamHandler()
187 handler.setLevel(logging.WARN)
188 formatter = logging.Formatter('%(message)s')
189 handler.setFormatter(formatter)
190 log.addHandler(handler)
192 prepared_data_dir = sys.argv[1]
193 if not os.path.exists(prepared_data_dir):
194 log.warn("Nothing found: %s" % prepared_data_dir)
195 return 1
196 if not os.path.isdir(prepared_data_dir):
197 log.warn("Not a directory: %s" % prepared_data_dir)
198 return 1
200 symbols_in_process = RuntimeSymbolsInProcess.load(prepared_data_dir)
201 symbols_dict = find_runtime_symbols(FUNCTION_SYMBOLS,
202 symbols_in_process,
203 sys.stdin)
204 for address, symbol in symbols_dict.iteritems():
205 if symbol:
206 print '%016x %s' % (address, symbol)
207 else:
208 print '%016x' % address
210 return 0
213 if __name__ == '__main__':
214 sys.exit(main())