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