2 # Copyright 2012 The Chromium Authors
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
11 from __future__ import print_function
18 from static_symbols import StaticSymbolsInFile
21 _BASE_PATH = os.path.dirname(os.path.abspath(__file__))
22 _TOOLS_LINUX_PATH = os.path.join(_BASE_PATH, os.pardir, 'linux')
23 sys.path.insert(0, _TOOLS_LINUX_PATH)
26 from procfs import ProcMaps # pylint: disable=F0401
29 from collections import OrderedDict # pylint: disable=E0611
31 _SIMPLEJSON_PATH = os.path.join(_BASE_PATH, os.pardir, os.pardir,
33 sys.path.insert(0, _SIMPLEJSON_PATH)
34 from simplejson import OrderedDict
38 SOURCEFILE_SYMBOLS = 1
41 _MAPS_FILENAME = 'maps'
42 _FILES_FILENAME = 'files.json'
45 class RuntimeSymbolsInProcess:
48 self._static_symbols_in_filse = {}
50 def find_procedure(self, runtime_address):
51 for vma in self.maps.iter(ProcMaps.executable):
52 if vma.begin <= runtime_address < vma.end:
53 static_symbols = self._static_symbols_in_filse.get(vma.name)
55 return static_symbols.find_procedure_by_runtime_address(
60 def find_sourcefile(self, runtime_address):
61 for vma in self.maps.iter(ProcMaps.executable):
62 if vma.begin <= runtime_address < vma.end:
63 static_symbols = self._static_symbols_in_filse.get(vma.name)
65 return static_symbols.find_sourcefile_by_runtime_address(
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)
75 return static_symbols.find_typeinfo_by_runtime_address(
81 def load(prepared_data_dir):
82 symbols_in_process = RuntimeSymbolsInProcess()
84 with open(os.path.join(prepared_data_dir, _MAPS_FILENAME), mode='r') as f:
85 symbols_in_process.maps = ProcMaps.load_file(f)
86 with open(os.path.join(prepared_data_dir, _FILES_FILENAME), mode='r') as f:
89 # pylint: disable=W0212
90 for vma in symbols_in_process.maps.iter(ProcMaps.executable_and_constants):
91 file_entry = files.get(vma.name)
95 static_symbols = StaticSymbolsInFile(vma.name)
97 nm_entry = file_entry.get('nm')
98 if nm_entry and nm_entry['format'] == 'bsd':
99 with open(os.path.join(prepared_data_dir, nm_entry['file']), 'r') as f:
100 static_symbols.load_nm_bsd(f, nm_entry['mangled'])
102 readelf_entry = file_entry.get('readelf-e')
104 with open(os.path.join(prepared_data_dir, readelf_entry['file']),
106 static_symbols.load_readelf_ew(f)
108 decodedline_file_entry = file_entry.get('readelf-debug-decodedline-file')
109 if decodedline_file_entry:
110 with open(os.path.join(prepared_data_dir,
111 decodedline_file_entry['file']), 'r') as f:
112 static_symbols.load_readelf_debug_decodedline_file(f)
114 symbols_in_process._static_symbols_in_filse[vma.name] = static_symbols
116 return symbols_in_process
119 def _find_runtime_function_symbols(symbols_in_process, addresses):
120 result = OrderedDict()
121 for address in addresses:
122 if isinstance(address, basestring):
123 address = int(address, 16)
124 found = symbols_in_process.find_procedure(address)
126 result[address] = found.name
128 result[address] = '0x%016x' % address
132 def _find_runtime_sourcefile_symbols(symbols_in_process, addresses):
133 result = OrderedDict()
134 for address in addresses:
135 if isinstance(address, basestring):
136 address = int(address, 16)
137 found = symbols_in_process.find_sourcefile(address)
139 result[address] = found
145 def _find_runtime_typeinfo_symbols(symbols_in_process, addresses):
146 result = OrderedDict()
147 for address in addresses:
148 if isinstance(address, basestring):
149 address = int(address, 16)
151 result[address] = 'no typeinfo'
153 found = symbols_in_process.find_typeinfo(address)
155 if found.startswith('typeinfo for '):
156 result[address] = found[13:]
158 result[address] = found
160 result[address] = '0x%016x' % address
164 _INTERNAL_FINDERS = {
165 FUNCTION_SYMBOLS: _find_runtime_function_symbols,
166 SOURCEFILE_SYMBOLS: _find_runtime_sourcefile_symbols,
167 TYPEINFO_SYMBOLS: _find_runtime_typeinfo_symbols,
171 def find_runtime_symbols(symbol_type, symbols_in_process, addresses):
172 return _INTERNAL_FINDERS[symbol_type](symbols_in_process, addresses)
176 # FIX: Accept only .pre data
177 if len(sys.argv) < 2:
178 sys.stderr.write("""Usage:
179 %s /path/to/prepared_data_dir/ < addresses.txt
183 log = logging.getLogger('find_runtime_symbols')
184 log.setLevel(logging.WARN)
185 handler = logging.StreamHandler()
186 handler.setLevel(logging.WARN)
187 formatter = logging.Formatter('%(message)s')
188 handler.setFormatter(formatter)
189 log.addHandler(handler)
191 prepared_data_dir = sys.argv[1]
192 if not os.path.exists(prepared_data_dir):
193 log.warn("Nothing found: %s" % prepared_data_dir)
195 if not os.path.isdir(prepared_data_dir):
196 log.warn("Not a directory: %s" % prepared_data_dir)
199 symbols_in_process = RuntimeSymbolsInProcess.load(prepared_data_dir)
200 symbols_dict = find_runtime_symbols(FUNCTION_SYMBOLS,
203 for address, symbol in symbols_dict.iteritems():
205 print('%016x %s' % (address, symbol))
207 print('%016x' % address)
212 if __name__ == '__main__':