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
16 from static_symbols
import StaticSymbolsInFile
17 from proc_maps
import ProcMaps
20 from collections
import OrderedDict
# pylint: disable=E0611
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
29 SOURCEFILE_SYMBOLS
= 1
32 _MAPS_FILENAME
= 'maps'
33 _FILES_FILENAME
= 'files.json'
36 class RuntimeSymbolsInProcess(object):
39 self
._static
_symbols
_in
_filse
= {}
41 def find_procedure(self
, runtime_address
):
42 for vma
in self
._maps
.iter(ProcMaps
.executable
):
43 if vma
.begin
<= runtime_address
< vma
.end
:
44 static_symbols
= self
._static
_symbols
_in
_filse
.get(vma
.name
)
46 return static_symbols
.find_procedure_by_runtime_address(
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
)
57 return static_symbols
.find_sourcefile_by_runtime_address(
63 def find_typeinfo(self
, runtime_address
):
64 for vma
in self
._maps
.iter(ProcMaps
.constants
):
65 if vma
.begin
<= runtime_address
< vma
.end
:
66 static_symbols
= self
._static
_symbols
_in
_filse
.get(vma
.name
)
68 return static_symbols
.find_typeinfo_by_runtime_address(
75 def load(prepared_data_dir
):
76 symbols_in_process
= RuntimeSymbolsInProcess()
78 with
open(os
.path
.join(prepared_data_dir
, _MAPS_FILENAME
), mode
='r') as f
:
79 symbols_in_process
._maps
= ProcMaps
.load(f
)
80 with
open(os
.path
.join(prepared_data_dir
, _FILES_FILENAME
), mode
='r') as f
:
83 # pylint: disable=W0212
84 for vma
in symbols_in_process
._maps
.iter(ProcMaps
.executable_and_constants
):
85 file_entry
= files
.get(vma
.name
)
89 static_symbols
= StaticSymbolsInFile(vma
.name
)
91 nm_entry
= file_entry
.get('nm')
92 if nm_entry
and nm_entry
['format'] == 'bsd':
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'])
96 readelf_entry
= file_entry
.get('readelf-e')
98 with
open(os
.path
.join(prepared_data_dir
, readelf_entry
['file']),
100 static_symbols
.load_readelf_ew(f
)
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
)
108 symbols_in_process
._static
_symbols
_in
_filse
[vma
.name
] = static_symbols
110 return symbols_in_process
113 def _find_runtime_function_symbols(symbols_in_process
, addresses
):
114 result
= OrderedDict()
115 for address
in addresses
:
116 if isinstance(address
, basestring
):
117 address
= int(address
, 16)
118 found
= symbols_in_process
.find_procedure(address
)
120 result
[address
] = found
.name
122 result
[address
] = '0x%016x' % address
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
)
133 result
[address
] = found
139 def _find_runtime_typeinfo_symbols(symbols_in_process
, addresses
):
140 result
= OrderedDict()
141 for address
in addresses
:
142 if isinstance(address
, basestring
):
143 address
= int(address
, 16)
145 result
[address
] = 'no typeinfo'
147 found
= symbols_in_process
.find_typeinfo(address
)
149 if found
.startswith('typeinfo for '):
150 result
[address
] = found
[13:]
152 result
[address
] = found
154 result
[address
] = '0x%016x' % address
158 _INTERNAL_FINDERS
= {
159 FUNCTION_SYMBOLS
: _find_runtime_function_symbols
,
160 SOURCEFILE_SYMBOLS
: _find_runtime_sourcefile_symbols
,
161 TYPEINFO_SYMBOLS
: _find_runtime_typeinfo_symbols
,
165 def find_runtime_symbols(symbol_type
, symbols_in_process
, addresses
):
166 return _INTERNAL_FINDERS
[symbol_type
](symbols_in_process
, addresses
)
170 # FIX: Accept only .pre data
171 if len(sys
.argv
) < 2:
172 sys
.stderr
.write("""Usage:
173 %s /path/to/prepared_data_dir/ < addresses.txt
177 log
= logging
.getLogger('find_runtime_symbols')
178 log
.setLevel(logging
.WARN
)
179 handler
= logging
.StreamHandler()
180 handler
.setLevel(logging
.WARN
)
181 formatter
= logging
.Formatter('%(message)s')
182 handler
.setFormatter(formatter
)
183 log
.addHandler(handler
)
185 prepared_data_dir
= sys
.argv
[1]
186 if not os
.path
.exists(prepared_data_dir
):
187 log
.warn("Nothing found: %s" % prepared_data_dir
)
189 if not os
.path
.isdir(prepared_data_dir
):
190 log
.warn("Not a directory: %s" % prepared_data_dir
)
193 symbols_in_process
= RuntimeSymbolsInProcess
.load(prepared_data_dir
)
194 symbols_dict
= find_runtime_symbols(FUNCTION_SYMBOLS
,
197 for address
, symbol
in symbols_dict
:
199 print '%016x %s' % (address
, symbol
)
201 print '%016x' % address
206 if __name__
== '__main__':