blob: d127f7600806c39f8f89bce403276cb88f4b64df [file] [log] [blame]
# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
''' A bunch of helper functions for querying gdb.'''
import logging
import os
import re
import tempfile
GDB_LINE_RE = re.compile(r'Line ([0-9]*) of "([^"]*)".*')
def _GdbOutputToFileLine(output_line):
''' Parse the gdb output line, return a pair (file, line num) '''
match = GDB_LINE_RE.match(output_line)
if match:
return match.groups()[1], match.groups()[0]
else:
return None
def ResolveAddressesWithinABinary(binary_name, load_address, address_list):
''' For each address, return a pair (file, line num) '''
commands = tempfile.NamedTemporaryFile()
commands.write('add-symbol-file "%s" %s\n' % (binary_name, load_address))
for addr in address_list:
commands.write('info line *%s\n' % addr)
commands.write('quit\n')
commands.flush()
gdb_commandline = 'gdb -batch -x %s 2>/dev/null' % commands.name
gdb_pipe = os.popen(gdb_commandline)
result = gdb_pipe.readlines()
address_count = 0
ret = {}
for line in result:
if line.startswith('Line'):
ret[address_list[address_count]] = _GdbOutputToFileLine(line)
address_count += 1
if line.startswith('No line'):
ret[address_list[address_count]] = (None, None)
address_count += 1
gdb_pipe.close()
commands.close()
return ret
class AddressTable(object):
''' Object to do batched line number lookup. '''
def __init__(self):
self._load_addresses = {}
self._binaries = {}
self._all_resolved = False
def AddBinaryAt(self, binary, load_address):
''' Register a new shared library or executable. '''
self._load_addresses[binary] = load_address
def Add(self, binary, address):
''' Register a lookup request. '''
if binary == '':
logging.warn('adding address %s in empty binary?' % address)
if binary in self._binaries:
self._binaries[binary].append(address)
else:
self._binaries[binary] = [address]
self._all_resolved = False
def ResolveAll(self):
''' Carry out all lookup requests. '''
self._translation = {}
for binary in self._binaries.keys():
if binary != '' and binary in self._load_addresses:
load_address = self._load_addresses[binary]
addr = ResolveAddressesWithinABinary(
binary, load_address, self._binaries[binary])
self._translation[binary] = addr
self._all_resolved = True
def GetFileLine(self, binary, addr):
''' Get the (filename, linenum) result of a previously-registered lookup
request.
'''
if self._all_resolved:
if binary in self._translation:
if addr in self._translation[binary]:
return self._translation[binary][addr]
return (None, None)