gdb_helper.py 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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. ''' A bunch of helper functions for querying gdb.'''
  9. import logging
  10. import os
  11. import re
  12. import tempfile
  13. GDB_LINE_RE = re.compile(r'Line ([0-9]*) of "([^"]*)".*')
  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. def ResolveAddressesWithinABinary(binary_name, load_address, address_list):
  22. ''' For each address, return a pair (file, line num) '''
  23. commands = tempfile.NamedTemporaryFile()
  24. commands.write('add-symbol-file "%s" %s\n' % (binary_name, load_address))
  25. for addr in address_list:
  26. commands.write('info line *%s\n' % addr)
  27. commands.write('quit\n')
  28. commands.flush()
  29. gdb_commandline = 'gdb -batch -x %s 2>/dev/null' % commands.name
  30. gdb_pipe = os.popen(gdb_commandline)
  31. result = gdb_pipe.readlines()
  32. address_count = 0
  33. ret = {}
  34. for line in result:
  35. if line.startswith('Line'):
  36. ret[address_list[address_count]] = _GdbOutputToFileLine(line)
  37. address_count += 1
  38. if line.startswith('No line'):
  39. ret[address_list[address_count]] = (None, None)
  40. address_count += 1
  41. gdb_pipe.close()
  42. commands.close()
  43. return ret
  44. class AddressTable(object):
  45. ''' Object to do batched line number lookup. '''
  46. def __init__(self):
  47. self._load_addresses = {}
  48. self._binaries = {}
  49. self._all_resolved = False
  50. def AddBinaryAt(self, binary, load_address):
  51. ''' Register a new shared library or executable. '''
  52. self._load_addresses[binary] = load_address
  53. def Add(self, binary, address):
  54. ''' Register a lookup request. '''
  55. if binary == '':
  56. logging.warn('adding address %s in empty binary?' % address)
  57. if binary in self._binaries:
  58. self._binaries[binary].append(address)
  59. else:
  60. self._binaries[binary] = [address]
  61. self._all_resolved = False
  62. def ResolveAll(self):
  63. ''' Carry out all lookup requests. '''
  64. self._translation = {}
  65. for binary in self._binaries.keys():
  66. if binary != '' and binary in self._load_addresses:
  67. load_address = self._load_addresses[binary]
  68. addr = ResolveAddressesWithinABinary(
  69. binary, load_address, self._binaries[binary])
  70. self._translation[binary] = addr
  71. self._all_resolved = True
  72. def GetFileLine(self, binary, addr):
  73. ''' Get the (filename, linenum) result of a previously-registered lookup
  74. request.
  75. '''
  76. if self._all_resolved:
  77. if binary in self._translation:
  78. if addr in self._translation[binary]:
  79. return self._translation[binary][addr]
  80. return (None, None)