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
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
27 from collections
import OrderedDict
# pylint: disable=E0611
29 _SIMPLEJSON_PATH
= os
.path
.join(_BASE_PATH
, os
.pardir
, os
.pardir
,
31 sys
.path
.insert(0, _SIMPLEJSON_PATH
)
32 from simplejson
import OrderedDict
36 SOURCEFILE_SYMBOLS
= 1
39 _MAPS_FILENAME
= 'maps'
40 _FILES_FILENAME
= 'files.json'
43 class RuntimeSymbolsInProcess(object):
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
)
53 return static_symbols
.find_procedure_by_runtime_address(
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
)
64 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(
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
:
90 # pylint: disable=W0212
91 for vma
in symbols_in_process
._maps
.iter(ProcMaps
.executable_and_constants
):
92 file_entry
= files
.get(vma
.name
)
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')
105 with
open(os
.path
.join(prepared_data_dir
, readelf_entry
['file']),
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
)
127 result
[address
] = found
.name
129 result
[address
] = '0x%016x' % address
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
)
140 result
[address
] = found
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)
152 result
[address
] = 'no typeinfo'
154 found
= symbols_in_process
.find_typeinfo(address
)
156 if found
.startswith('typeinfo for '):
157 result
[address
] = found
[13:]
159 result
[address
] = found
161 result
[address
] = '0x%016x' % address
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
)
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
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
)
196 if not os
.path
.isdir(prepared_data_dir
):
197 log
.warn("Not a directory: %s" % prepared_data_dir
)
200 symbols_in_process
= RuntimeSymbolsInProcess
.load(prepared_data_dir
)
201 symbols_dict
= find_runtime_symbols(FUNCTION_SYMBOLS
,
204 for address
, symbol
in symbols_dict
:
206 print '%016x %s' % (address
, symbol
)
208 print '%016x' % address
213 if __name__
== '__main__':