blob: 57c83f54e1b6324480856c1bb78b177a030f1a1f [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import logging
import os
import sys
from static_symbols import StaticSymbolsInFile
from proc_maps import ProcMaps
_MAPS_FILENAME = 'maps'
_FILES_FILENAME = 'files.json'
class _ListOutput(object):
def __init__(self, result):
self.result = result
def output(self, address, symbol): # pylint: disable=W0613
self.result.append(symbol)
class _DictOutput(object):
def __init__(self, result):
self.result = result
def output(self, address, symbol):
self.result[address] = symbol
class _FileOutput(object):
def __init__(self, result, with_address):
self.result = result
self.with_address = with_address
def output(self, address, symbol):
if self.with_address:
self.result.write('%016x %s\n' % (address, symbol))
else:
self.result.write('%s\n' % symbol)
class RuntimeSymbolsInProcess(object):
def __init__(self):
self._maps = None
self._static_symbols_in_filse = {}
def find_procedure(self, runtime_address):
for vma in self._maps.iter(ProcMaps.executable):
if vma.begin <= runtime_address < vma.end:
static_symbols = self._static_symbols_in_filse.get(vma.name)
if static_symbols:
return static_symbols.find_procedure_by_runtime_address(
runtime_address, vma)
else:
return None
return None
def find_typeinfo(self, runtime_address):
for vma in self._maps.iter(ProcMaps.constants):
if vma.begin <= runtime_address < vma.end:
static_symbols = self._static_symbols_in_filse.get(vma.name)
if static_symbols:
return static_symbols.find_typeinfo_by_runtime_address(
runtime_address, vma)
else:
return None
return None
@staticmethod
def load(prepared_data_dir):
symbols_in_process = RuntimeSymbolsInProcess()
with open(os.path.join(prepared_data_dir, _MAPS_FILENAME), mode='r') as f:
symbols_in_process._maps = ProcMaps.load(f)
with open(os.path.join(prepared_data_dir, _FILES_FILENAME), mode='r') as f:
files = json.load(f)
# pylint: disable=W0212
for vma in symbols_in_process._maps.iter(ProcMaps.executable_and_constants):
file_entry = files.get(vma.name)
if not file_entry:
continue
static_symbols = StaticSymbolsInFile(vma.name)
nm_entry = file_entry.get('nm')
if nm_entry and nm_entry['format'] == 'bsd':
with open(os.path.join(prepared_data_dir, nm_entry['file']), 'r') as f:
static_symbols.load_nm_bsd(f, nm_entry['mangled'])
readelf_entry = file_entry.get('readelf-e')
if readelf_entry:
with open(os.path.join(prepared_data_dir, readelf_entry['file']),
'r') as f:
static_symbols.load_readelf_ew(f)
symbols_in_process._static_symbols_in_filse[vma.name] = static_symbols
return symbols_in_process
def _find_runtime_symbols(symbols_in_process, addresses, outputter):
for address in addresses:
if isinstance(address, basestring):
address = int(address, 16)
found = symbols_in_process.find_procedure(address)
if found:
outputter.output(address, found.name)
else:
outputter.output(address, '0x%016x' % address)
def _find_runtime_typeinfo_symbols(symbols_in_process, addresses, outputter):
for address in addresses:
if isinstance(address, basestring):
address = int(address, 16)
if address == 0:
outputter.output(address, 'no typeinfo')
else:
found = symbols_in_process.find_typeinfo(address)
if found:
if found.startswith('typeinfo for '):
outputter.output(address, found[13:])
else:
outputter.output(address, found)
else:
outputter.output(address, '0x%016x' % address)
def find_runtime_typeinfo_symbols_list(symbols_in_process, addresses):
result = []
_find_runtime_typeinfo_symbols(
symbols_in_process, addresses, _ListOutput(result))
return result
def find_runtime_typeinfo_symbols_dict(symbols_in_process, addresses):
result = {}
_find_runtime_typeinfo_symbols(
symbols_in_process, addresses, _DictOutput(result))
return result
def find_runtime_typeinfo_symbols_file(symbols_in_process, addresses, f):
_find_runtime_typeinfo_symbols(
symbols_in_process, addresses, _FileOutput(f, False))
def find_runtime_symbols_list(symbols_in_process, addresses):
result = []
_find_runtime_symbols(symbols_in_process, addresses, _ListOutput(result))
return result
def find_runtime_symbols_dict(symbols_in_process, addresses):
result = {}
_find_runtime_symbols(symbols_in_process, addresses, _DictOutput(result))
return result
def find_runtime_symbols_file(symbols_in_process, addresses, f):
_find_runtime_symbols(
symbols_in_process, addresses, _FileOutput(f, False))
def main():
# FIX: Accept only .pre data
if len(sys.argv) < 2:
sys.stderr.write("""Usage:
%s /path/to/prepared_data_dir/ < addresses.txt
""" % sys.argv[0])
return 1
log = logging.getLogger('find_runtime_symbols')
log.setLevel(logging.WARN)
handler = logging.StreamHandler()
handler.setLevel(logging.WARN)
formatter = logging.Formatter('%(message)s')
handler.setFormatter(formatter)
log.addHandler(handler)
prepared_data_dir = sys.argv[1]
if not os.path.exists(prepared_data_dir):
log.warn("Nothing found: %s" % prepared_data_dir)
return 1
if not os.path.isdir(prepared_data_dir):
log.warn("Not a directory: %s" % prepared_data_dir)
return 1
symbols_in_process = RuntimeSymbolsInProcess.load(prepared_data_dir)
return find_runtime_symbols_file(symbols_in_process, sys.stdin, sys.stdout)
if __name__ == '__main__':
sys.exit(main())