find_runtime_symbols.py revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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.
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)"""Find symbols in a binary corresponding to given runtime virtual addresses.
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Note that source file names are treated as symbols in this script while they
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)are actually not.
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)"""
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import json
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from static_symbols import StaticSymbolsInFile
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from proc_maps import ProcMaps
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)try:
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  from collections import OrderedDict  # pylint: disable=E0611
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)except ImportError:
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  BASE_PATH = os.path.dirname(os.path.abspath(__file__))
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SIMPLEJSON_PATH = os.path.join(BASE_PATH, os.pardir, os.pardir, 'third_party')
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  sys.path.insert(0, SIMPLEJSON_PATH)
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  from simplejson import OrderedDict
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)FUNCTION_SYMBOLS = 0
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)SOURCEFILE_SYMBOLS = 1
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TYPEINFO_SYMBOLS = 2
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)_MAPS_FILENAME = 'maps'
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)_FILES_FILENAME = 'files.json'
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RuntimeSymbolsInProcess(object):
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._maps = None
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._static_symbols_in_filse = {}
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def find_procedure(self, runtime_address):
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for vma in self._maps.iter(ProcMaps.executable):
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if vma.begin <= runtime_address < vma.end:
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_symbols = self._static_symbols_in_filse.get(vma.name)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if static_symbols:
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return static_symbols.find_procedure_by_runtime_address(
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              runtime_address, vma)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return None
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def find_sourcefile(self, runtime_address):
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for vma in self._maps.iter(ProcMaps.executable):
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if vma.begin <= runtime_address < vma.end:
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        static_symbols = self._static_symbols_in_filse.get(vma.name)
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if static_symbols:
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          return static_symbols.find_sourcefile_by_runtime_address(
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              runtime_address, vma)
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        else:
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          return None
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return None
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (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)
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      decodedline_file_entry = file_entry.get('readelf-debug-decodedline-file')
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if decodedline_file_entry:
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        with open(os.path.join(prepared_data_dir,
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               decodedline_file_entry['file']), 'r') as f:
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          static_symbols.load_readelf_debug_decodedline_file(f)
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      symbols_in_process._static_symbols_in_filse[vma.name] = static_symbols
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return symbols_in_process
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _find_runtime_function_symbols(symbols_in_process, addresses):
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  result = OrderedDict()
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for address in addresses:
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(address, basestring):
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      address = int(address, 16)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    found = symbols_in_process.find_procedure(address)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if found:
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result[address] = found.name
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result[address] = '0x%016x' % address
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return result
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _find_runtime_sourcefile_symbols(symbols_in_process, addresses):
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  result = OrderedDict()
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for address in addresses:
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if isinstance(address, basestring):
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      address = int(address, 16)
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    found = symbols_in_process.find_sourcefile(address)
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if found:
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result[address] = found
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    else:
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result[address] = ''
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return result
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _find_runtime_typeinfo_symbols(symbols_in_process, addresses):
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  result = OrderedDict()
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for address in addresses:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(address, basestring):
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      address = int(address, 16)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if address == 0:
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result[address] = 'no typeinfo'
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      found = symbols_in_process.find_typeinfo(address)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if found:
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if found.startswith('typeinfo for '):
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          result[address] = found[13:]
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          result[address] = found
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        result[address] = '0x%016x' % address
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)_INTERNAL_FINDERS = {
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    FUNCTION_SYMBOLS: _find_runtime_function_symbols,
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SOURCEFILE_SYMBOLS: _find_runtime_sourcefile_symbols,
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    TYPEINFO_SYMBOLS: _find_runtime_typeinfo_symbols,
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def find_runtime_symbols(symbol_type, symbols_in_process, addresses):
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return _INTERNAL_FINDERS[symbol_type](symbols_in_process, addresses)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main():
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # FIX: Accept only .pre data
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(sys.argv) < 2:
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stderr.write("""Usage:
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)%s /path/to/prepared_data_dir/ < addresses.txt
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" % sys.argv[0])
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  log = logging.getLogger('find_runtime_symbols')
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  log.setLevel(logging.WARN)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handler = logging.StreamHandler()
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handler.setLevel(logging.WARN)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  formatter = logging.Formatter('%(message)s')
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handler.setFormatter(formatter)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  log.addHandler(handler)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prepared_data_dir = sys.argv[1]
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not os.path.exists(prepared_data_dir):
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    log.warn("Nothing found: %s" % prepared_data_dir)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not os.path.isdir(prepared_data_dir):
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    log.warn("Not a directory: %s" % prepared_data_dir)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  symbols_in_process = RuntimeSymbolsInProcess.load(prepared_data_dir)
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  symbols_dict = find_runtime_symbols(FUNCTION_SYMBOLS,
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      symbols_in_process,
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      sys.stdin)
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for address, symbol in symbols_dict:
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if symbol:
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      print '%016x %s' % (address, symbol)
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    else:
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      print '%016x' % address
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return 0
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(main())
208