15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)''' A bunch of helper functions for querying gdb.'''
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import tempfile
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GDB_LINE_RE = re.compile(r'Line ([0-9]*) of "([^"]*)".*')
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _GdbOutputToFileLine(output_line):
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ''' Parse the gdb output line, return a pair (file, line num) '''
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  match =  GDB_LINE_RE.match(output_line)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if match:
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return match.groups()[1], match.groups()[0]
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ResolveAddressesWithinABinary(binary_name, load_address, address_list):
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ''' For each address, return a pair (file, line num) '''
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  commands = tempfile.NamedTemporaryFile()
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  commands.write('add-symbol-file "%s" %s\n' % (binary_name, load_address))
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for addr in address_list:
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    commands.write('info line *%s\n' % addr)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  commands.write('quit\n')
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  commands.flush()
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdb_commandline = 'gdb -batch -x %s 2>/dev/null' % commands.name
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdb_pipe = os.popen(gdb_commandline)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = gdb_pipe.readlines()
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  address_count = 0
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret = {}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in result:
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if line.startswith('Line'):
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret[address_list[address_count]] = _GdbOutputToFileLine(line)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      address_count += 1
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if line.startswith('No line'):
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret[address_list[address_count]] = (None, None)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      address_count += 1
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdb_pipe.close()
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  commands.close()
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class AddressTable(object):
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ''' Object to do batched line number lookup. '''
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._load_addresses = {}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._binaries = {}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._all_resolved = False
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AddBinaryAt(self, binary, load_address):
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ''' Register a new shared library or executable. '''
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._load_addresses[binary] = load_address
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Add(self, binary, address):
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ''' Register a lookup request. '''
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if binary == '':
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.warn('adding address %s in empty binary?' % address)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if binary in self._binaries:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._binaries[binary].append(address)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._binaries[binary] = [address]
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._all_resolved = False
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ResolveAll(self):
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ''' Carry out all lookup requests. '''
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._translation = {}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for binary in self._binaries.keys():
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if binary != '' and binary in self._load_addresses:
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        load_address = self._load_addresses[binary]
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        addr = ResolveAddressesWithinABinary(
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            binary, load_address, self._binaries[binary])
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._translation[binary] = addr
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._all_resolved = True
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetFileLine(self, binary, addr):
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ''' Get the (filename, linenum) result of a previously-registered lookup
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '''
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._all_resolved:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if binary in self._translation:
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if addr in self._translation[binary]:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return self._translation[binary][addr]
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (None, None)
88