utils.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #
  2. # gdb helper commands and functions for Linux kernel debugging
  3. #
  4. # common utilities
  5. #
  6. # Copyright (c) Siemens AG, 2011-2013
  7. #
  8. # Authors:
  9. # Jan Kiszka <jan.kiszka@siemens.com>
  10. #
  11. # This work is licensed under the terms of the GNU GPL version 2.
  12. #
  13. import contextlib
  14. import dataclasses
  15. import re
  16. import typing
  17. import gdb
  18. class CachedType:
  19. def __init__(self, name):
  20. self._type = None
  21. self._name = name
  22. def _new_objfile_handler(self, event):
  23. self._type = None
  24. gdb.events.new_objfile.disconnect(self._new_objfile_handler)
  25. def get_type(self):
  26. if self._type is None:
  27. self._type = gdb.lookup_type(self._name)
  28. if self._type is None:
  29. raise gdb.GdbError(
  30. "cannot resolve type '{0}'".format(self._name))
  31. if hasattr(gdb, 'events') and hasattr(gdb.events, 'new_objfile'):
  32. gdb.events.new_objfile.connect(self._new_objfile_handler)
  33. return self._type
  34. long_type = CachedType("long")
  35. ulong_type = CachedType("unsigned long")
  36. uint_type = CachedType("unsigned int")
  37. atomic_long_type = CachedType("atomic_long_t")
  38. size_t_type = CachedType("size_t")
  39. struct_page_type = CachedType("struct page")
  40. def get_uint_type():
  41. global uint_type
  42. return uint_type.get_type()
  43. def get_page_type():
  44. global struct_page_type
  45. return struct_page_type.get_type()
  46. def get_long_type():
  47. global long_type
  48. return long_type.get_type()
  49. def get_ulong_type():
  50. global ulong_type
  51. return ulong_type.get_type()
  52. def get_size_t_type():
  53. global size_t_type
  54. return size_t_type.get_type()
  55. def offset_of(typeobj, field):
  56. element = gdb.Value(0).cast(typeobj)
  57. return int(str(element[field].address).split()[0], 16)
  58. def container_of(ptr, typeobj, member):
  59. return (ptr.cast(get_long_type()) -
  60. offset_of(typeobj, member)).cast(typeobj)
  61. class ContainerOf(gdb.Function):
  62. """Return pointer to containing data structure.
  63. $container_of(PTR, "TYPE", "ELEMENT"): Given PTR, return a pointer to the
  64. data structure of the type TYPE in which PTR is the address of ELEMENT.
  65. Note that TYPE and ELEMENT have to be quoted as strings."""
  66. def __init__(self):
  67. super(ContainerOf, self).__init__("container_of")
  68. def invoke(self, ptr, typename, elementname):
  69. return container_of(ptr, gdb.lookup_type(typename.string()).pointer(),
  70. elementname.string())
  71. ContainerOf()
  72. BIG_ENDIAN = 0
  73. LITTLE_ENDIAN = 1
  74. target_endianness = None
  75. def get_target_endianness():
  76. global target_endianness
  77. if target_endianness is None:
  78. endian = gdb.execute("show endian", to_string=True)
  79. if "little endian" in endian:
  80. target_endianness = LITTLE_ENDIAN
  81. elif "big endian" in endian:
  82. target_endianness = BIG_ENDIAN
  83. else:
  84. raise gdb.GdbError("unknown endianness '{0}'".format(str(endian)))
  85. return target_endianness
  86. def read_memoryview(inf, start, length):
  87. m = inf.read_memory(start, length)
  88. if type(m) is memoryview:
  89. return m
  90. return memoryview(m)
  91. def read_u16(buffer, offset):
  92. buffer_val = buffer[offset:offset + 2]
  93. value = [0, 0]
  94. if type(buffer_val[0]) is str:
  95. value[0] = ord(buffer_val[0])
  96. value[1] = ord(buffer_val[1])
  97. else:
  98. value[0] = buffer_val[0]
  99. value[1] = buffer_val[1]
  100. if get_target_endianness() == LITTLE_ENDIAN:
  101. return value[0] + (value[1] << 8)
  102. else:
  103. return value[1] + (value[0] << 8)
  104. def read_u32(buffer, offset):
  105. if get_target_endianness() == LITTLE_ENDIAN:
  106. return read_u16(buffer, offset) + (read_u16(buffer, offset + 2) << 16)
  107. else:
  108. return read_u16(buffer, offset + 2) + (read_u16(buffer, offset) << 16)
  109. def read_u64(buffer, offset):
  110. if get_target_endianness() == LITTLE_ENDIAN:
  111. return read_u32(buffer, offset) + (read_u32(buffer, offset + 4) << 32)
  112. else:
  113. return read_u32(buffer, offset + 4) + (read_u32(buffer, offset) << 32)
  114. def read_ulong(buffer, offset):
  115. if get_long_type().sizeof == 8:
  116. return read_u64(buffer, offset)
  117. else:
  118. return read_u32(buffer, offset)
  119. atomic_long_counter_offset = atomic_long_type.get_type()['counter'].bitpos
  120. atomic_long_counter_sizeof = atomic_long_type.get_type()['counter'].type.sizeof
  121. def read_atomic_long(buffer, offset):
  122. global atomic_long_counter_offset
  123. global atomic_long_counter_sizeof
  124. if atomic_long_counter_sizeof == 8:
  125. return read_u64(buffer, offset + atomic_long_counter_offset)
  126. else:
  127. return read_u32(buffer, offset + atomic_long_counter_offset)
  128. target_arch = None
  129. def is_target_arch(arch):
  130. if hasattr(gdb.Frame, 'architecture'):
  131. return arch in gdb.newest_frame().architecture().name()
  132. else:
  133. global target_arch
  134. if target_arch is None:
  135. target_arch = gdb.execute("show architecture", to_string=True)
  136. return arch in target_arch
  137. GDBSERVER_QEMU = 0
  138. GDBSERVER_KGDB = 1
  139. gdbserver_type = None
  140. def get_gdbserver_type():
  141. def exit_handler(event):
  142. global gdbserver_type
  143. gdbserver_type = None
  144. gdb.events.exited.disconnect(exit_handler)
  145. def probe_qemu():
  146. try:
  147. return gdb.execute("monitor info version", to_string=True) != ""
  148. except gdb.error:
  149. return False
  150. def probe_kgdb():
  151. try:
  152. thread_info = gdb.execute("info thread 1", to_string=True)
  153. return "shadowCPU" in thread_info
  154. except gdb.error:
  155. return False
  156. global gdbserver_type
  157. if gdbserver_type is None:
  158. if probe_qemu():
  159. gdbserver_type = GDBSERVER_QEMU
  160. elif probe_kgdb():
  161. gdbserver_type = GDBSERVER_KGDB
  162. if gdbserver_type is not None and hasattr(gdb, 'events'):
  163. gdb.events.exited.connect(exit_handler)
  164. return gdbserver_type
  165. def gdb_eval_or_none(expresssion):
  166. try:
  167. return gdb.parse_and_eval(expresssion)
  168. except gdb.error:
  169. return None
  170. @contextlib.contextmanager
  171. def qemu_phy_mem_mode():
  172. connection = gdb.selected_inferior().connection
  173. orig = connection.send_packet("qqemu.PhyMemMode")
  174. if orig not in b"01":
  175. raise gdb.error("Unexpected qemu.PhyMemMode")
  176. orig = orig.decode()
  177. if connection.send_packet("Qqemu.PhyMemMode:1") != b"OK":
  178. raise gdb.error("Failed to set qemu.PhyMemMode")
  179. try:
  180. yield
  181. finally:
  182. if connection.send_packet("Qqemu.PhyMemMode:" + orig) != b"OK":
  183. raise gdb.error("Failed to restore qemu.PhyMemMode")
  184. @dataclasses.dataclass
  185. class VmCore:
  186. kerneloffset: typing.Optional[int]
  187. def parse_vmcore(s):
  188. match = re.search(r"KERNELOFFSET=([0-9a-f]+)", s)
  189. if match is None:
  190. kerneloffset = None
  191. else:
  192. kerneloffset = int(match.group(1), 16)
  193. return VmCore(kerneloffset=kerneloffset)
  194. def get_vmlinux():
  195. vmlinux = 'vmlinux'
  196. for obj in gdb.objfiles():
  197. if (obj.filename.endswith('vmlinux') or
  198. obj.filename.endswith('vmlinux.debug')):
  199. vmlinux = obj.filename
  200. return vmlinux
  201. @contextlib.contextmanager
  202. def pagination_off():
  203. show_pagination = gdb.execute("show pagination", to_string=True)
  204. pagination = show_pagination.endswith("on.\n")
  205. gdb.execute("set pagination off")
  206. try:
  207. yield
  208. finally:
  209. gdb.execute("set pagination %s" % ("on" if pagination else "off"))