find_runtime_symbols.py revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import json
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from static_symbols import StaticSymbolsInFile
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from proc_maps import ProcMaps
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_MAPS_FILENAME = 'maps'
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_FILES_FILENAME = 'files.json'
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class _ListOutput(object):
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, result):
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.result = result
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def output(self, address, symbol):  # pylint: disable=W0613
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.result.append(symbol)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class _DictOutput(object):
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, result):
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.result = result
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def output(self, address, symbol):
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.result[address] = symbol
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class _FileOutput(object):
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, result, with_address):
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.result = result
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.with_address = with_address
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def output(self, address, symbol):
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.with_address:
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.result.write('%016x %s\n' % (address, symbol))
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.result.write('%s\n' % symbol)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RuntimeSymbolsInProcess(object):
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._maps = None
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._static_symbols_in_filse = {}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def find_procedure(self, runtime_address):
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for vma in self._maps.iter(ProcMaps.executable):
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if vma.begin <= runtime_address < vma.end:
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_symbols = self._static_symbols_in_filse.get(vma.name)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if static_symbols:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return static_symbols.find_procedure_by_runtime_address(
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              runtime_address, vma)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return None
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def find_typeinfo(self, runtime_address):
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for vma in self._maps.iter(ProcMaps.constants):
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if vma.begin <= runtime_address < vma.end:
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_symbols = self._static_symbols_in_filse.get(vma.name)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if static_symbols:
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return static_symbols.find_typeinfo_by_runtime_address(
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              runtime_address, vma)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return None
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def load(prepared_data_dir):
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    symbols_in_process = RuntimeSymbolsInProcess()
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with open(os.path.join(prepared_data_dir, _MAPS_FILENAME), mode='r') as f:
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      symbols_in_process._maps = ProcMaps.load(f)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with open(os.path.join(prepared_data_dir, _FILES_FILENAME), mode='r') as f:
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      files = json.load(f)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # pylint: disable=W0212
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for vma in symbols_in_process._maps.iter(ProcMaps.executable_and_constants):
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_entry = files.get(vma.name)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not file_entry:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_symbols = StaticSymbolsInFile(vma.name)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      nm_entry = file_entry.get('nm')
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if nm_entry and nm_entry['format'] == 'bsd':
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        with open(os.path.join(prepared_data_dir, nm_entry['file']), 'r') as f:
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_symbols.load_nm_bsd(f, nm_entry['mangled'])
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      readelf_entry = file_entry.get('readelf-e')
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if readelf_entry:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        with open(os.path.join(prepared_data_dir, readelf_entry['file']),
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'r') as f:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_symbols.load_readelf_ew(f)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      symbols_in_process._static_symbols_in_filse[vma.name] = static_symbols
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return symbols_in_process
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _find_runtime_symbols(symbols_in_process, addresses, outputter):
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for address in addresses:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(address, basestring):
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      address = int(address, 16)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    found = symbols_in_process.find_procedure(address)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if found:
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outputter.output(address, found.name)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outputter.output(address, '0x%016x' % address)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _find_runtime_typeinfo_symbols(symbols_in_process, addresses, outputter):
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for address in addresses:
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(address, basestring):
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      address = int(address, 16)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if address == 0:
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      outputter.output(address, 'no typeinfo')
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      found = symbols_in_process.find_typeinfo(address)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if found:
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if found.startswith('typeinfo for '):
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          outputter.output(address, found[13:])
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          outputter.output(address, found)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        outputter.output(address, '0x%016x' % address)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def find_runtime_typeinfo_symbols_list(symbols_in_process, addresses):
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = []
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  _find_runtime_typeinfo_symbols(
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      symbols_in_process, addresses, _ListOutput(result))
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def find_runtime_typeinfo_symbols_dict(symbols_in_process, addresses):
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = {}
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  _find_runtime_typeinfo_symbols(
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      symbols_in_process, addresses, _DictOutput(result))
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def find_runtime_typeinfo_symbols_file(symbols_in_process, addresses, f):
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _find_runtime_typeinfo_symbols(
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      symbols_in_process, addresses, _FileOutput(f, False))
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def find_runtime_symbols_list(symbols_in_process, addresses):
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = []
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  _find_runtime_symbols(symbols_in_process, addresses, _ListOutput(result))
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def find_runtime_symbols_dict(symbols_in_process, addresses):
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = {}
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  _find_runtime_symbols(symbols_in_process, addresses, _DictOutput(result))
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def find_runtime_symbols_file(symbols_in_process, addresses, f):
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _find_runtime_symbols(
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      symbols_in_process, addresses, _FileOutput(f, False))
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main():
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # FIX: Accept only .pre data
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(sys.argv) < 2:
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stderr.write("""Usage:
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)%s /path/to/prepared_data_dir/ < addresses.txt
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" % sys.argv[0])
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  log = logging.getLogger('find_runtime_symbols')
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  log.setLevel(logging.WARN)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handler = logging.StreamHandler()
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handler.setLevel(logging.WARN)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  formatter = logging.Formatter('%(message)s')
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handler.setFormatter(formatter)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  log.addHandler(handler)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prepared_data_dir = sys.argv[1]
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not os.path.exists(prepared_data_dir):
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    log.warn("Nothing found: %s" % prepared_data_dir)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not os.path.isdir(prepared_data_dir):
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    log.warn("Not a directory: %s" % prepared_data_dir)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  symbols_in_process = RuntimeSymbolsInProcess.load(prepared_data_dir)
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return find_runtime_symbols_file(symbols_in_process, sys.stdin, sys.stdout)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(main())
201