#!/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())