1# Copyright (c) 2011 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5''' A bunch of helper functions for querying gdb.''' 6 7import logging 8import os 9import re 10import tempfile 11 12GDB_LINE_RE = re.compile(r'Line ([0-9]*) of "([^"]*)".*') 13 14def _GdbOutputToFileLine(output_line): 15 ''' Parse the gdb output line, return a pair (file, line num) ''' 16 match = GDB_LINE_RE.match(output_line) 17 if match: 18 return match.groups()[1], match.groups()[0] 19 else: 20 return None 21 22def ResolveAddressesWithinABinary(binary_name, load_address, address_list): 23 ''' For each address, return a pair (file, line num) ''' 24 commands = tempfile.NamedTemporaryFile() 25 commands.write('add-symbol-file "%s" %s\n' % (binary_name, load_address)) 26 for addr in address_list: 27 commands.write('info line *%s\n' % addr) 28 commands.write('quit\n') 29 commands.flush() 30 gdb_commandline = 'gdb -batch -x %s 2>/dev/null' % commands.name 31 gdb_pipe = os.popen(gdb_commandline) 32 result = gdb_pipe.readlines() 33 34 address_count = 0 35 ret = {} 36 for line in result: 37 if line.startswith('Line'): 38 ret[address_list[address_count]] = _GdbOutputToFileLine(line) 39 address_count += 1 40 if line.startswith('No line'): 41 ret[address_list[address_count]] = (None, None) 42 address_count += 1 43 gdb_pipe.close() 44 commands.close() 45 return ret 46 47class AddressTable(object): 48 ''' Object to do batched line number lookup. ''' 49 def __init__(self): 50 self._load_addresses = {} 51 self._binaries = {} 52 self._all_resolved = False 53 54 def AddBinaryAt(self, binary, load_address): 55 ''' Register a new shared library or executable. ''' 56 self._load_addresses[binary] = load_address 57 58 def Add(self, binary, address): 59 ''' Register a lookup request. ''' 60 if binary == '': 61 logging.warn('adding address %s in empty binary?' % address) 62 if binary in self._binaries: 63 self._binaries[binary].append(address) 64 else: 65 self._binaries[binary] = [address] 66 self._all_resolved = False 67 68 def ResolveAll(self): 69 ''' Carry out all lookup requests. ''' 70 self._translation = {} 71 for binary in self._binaries.keys(): 72 if binary != '' and binary in self._load_addresses: 73 load_address = self._load_addresses[binary] 74 addr = ResolveAddressesWithinABinary( 75 binary, load_address, self._binaries[binary]) 76 self._translation[binary] = addr 77 self._all_resolved = True 78 79 def GetFileLine(self, binary, addr): 80 ''' Get the (filename, linenum) result of a previously-registered lookup 81 request. 82 ''' 83 if self._all_resolved: 84 if binary in self._translation: 85 if addr in self._translation[binary]: 86 return self._translation[binary][addr] 87 return (None, None) 88