|  | # 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) |