Home | History | Annotate | Download | only in valgrind
      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 
      7 import logging
      8 import os
      9 import re
     10 import tempfile
     11 
     12 GDB_LINE_RE = re.compile(r'Line ([0-9]*) of "([^"]*)".*')
     13 
     14 def _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 
     22 def 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 
     47 class 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