gdb-gdb.py.in 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. # Copyright (C) 2009-2022 Free Software Foundation, Inc.
  2. #
  3. # This file is part of GDB.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 3 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. import gdb
  18. import os.path
  19. class TypeFlag:
  20. """A class that allows us to store a flag name, its short name,
  21. and its value.
  22. In the GDB sources, struct type has a component called instance_flags
  23. in which the value is the addition of various flags. These flags are
  24. defined by the enumerates type_instance_flag_value. This class helps us
  25. recreate a list with all these flags that is easy to manipulate and sort.
  26. Because all flag names start with TYPE_INSTANCE_FLAG_, a short_name
  27. attribute is provided that strips this prefix.
  28. ATTRIBUTES
  29. name: The enumeration name (eg: "TYPE_INSTANCE_FLAG_CONST").
  30. value: The associated value.
  31. short_name: The enumeration name, with the suffix stripped.
  32. """
  33. def __init__(self, name, value):
  34. self.name = name
  35. self.value = value
  36. self.short_name = name.replace("TYPE_INSTANCE_FLAG_", "")
  37. def __lt__(self, other):
  38. """Sort by value order."""
  39. return self.value < other.value
  40. # A list of all existing TYPE_INSTANCE_FLAGS_* enumerations,
  41. # stored as TypeFlags objects. Lazy-initialized.
  42. TYPE_FLAGS = None
  43. class TypeFlagsPrinter:
  44. """A class that prints a decoded form of an instance_flags value.
  45. This class uses a global named TYPE_FLAGS, which is a list of
  46. all defined TypeFlag values. Using a global allows us to compute
  47. this list only once.
  48. This class relies on a couple of enumeration types being defined.
  49. If not, then printing of the instance_flag is going to be degraded,
  50. but it's not a fatal error.
  51. """
  52. def __init__(self, val):
  53. self.val = val
  54. def __str__(self):
  55. global TYPE_FLAGS
  56. if TYPE_FLAGS is None:
  57. self.init_TYPE_FLAGS()
  58. if not self.val:
  59. return "0"
  60. if TYPE_FLAGS:
  61. flag_list = [
  62. flag.short_name for flag in TYPE_FLAGS if self.val & flag.value
  63. ]
  64. else:
  65. flag_list = ["???"]
  66. return "0x%x [%s]" % (self.val, "|".join(flag_list))
  67. def init_TYPE_FLAGS(self):
  68. """Initialize the TYPE_FLAGS global as a list of TypeFlag objects.
  69. This operation requires the search of a couple of enumeration types.
  70. If not found, a warning is printed on stdout, and TYPE_FLAGS is
  71. set to the empty list.
  72. The resulting list is sorted by increasing value, to facilitate
  73. printing of the list of flags used in an instance_flags value.
  74. """
  75. global TYPE_FLAGS
  76. TYPE_FLAGS = []
  77. try:
  78. iflags = gdb.lookup_type("enum type_instance_flag_value")
  79. except:
  80. print("Warning: Cannot find enum type_instance_flag_value type.")
  81. print(" `struct type' pretty-printer will be degraded")
  82. return
  83. TYPE_FLAGS = [TypeFlag(field.name, field.enumval) for field in iflags.fields()]
  84. TYPE_FLAGS.sort()
  85. class StructTypePrettyPrinter:
  86. """Pretty-print an object of type struct type"""
  87. def __init__(self, val):
  88. self.val = val
  89. def to_string(self):
  90. fields = []
  91. fields.append("pointer_type = %s" % self.val["pointer_type"])
  92. fields.append("reference_type = %s" % self.val["reference_type"])
  93. fields.append("chain = %s" % self.val["reference_type"])
  94. fields.append(
  95. "instance_flags = %s" % TypeFlagsPrinter(self.val["m_instance_flags"])
  96. )
  97. fields.append("length = %d" % self.val["length"])
  98. fields.append("main_type = %s" % self.val["main_type"])
  99. return "\n{" + ",\n ".join(fields) + "}"
  100. class StructMainTypePrettyPrinter:
  101. """Pretty-print an objet of type main_type"""
  102. def __init__(self, val):
  103. self.val = val
  104. def flags_to_string(self):
  105. """struct main_type contains a series of components that
  106. are one-bit ints whose name start with "flag_". For instance:
  107. flag_unsigned, flag_stub, etc. In essence, these components are
  108. really boolean flags, and this method prints a short synthetic
  109. version of the value of all these flags. For instance, if
  110. flag_unsigned and flag_static are the only components set to 1,
  111. this function will return "unsigned|static".
  112. """
  113. fields = [
  114. field.name.replace("flag_", "")
  115. for field in self.val.type.fields()
  116. if field.name.startswith("flag_") and self.val[field.name]
  117. ]
  118. return "|".join(fields)
  119. def owner_to_string(self):
  120. """Return an image of component "owner"."""
  121. if self.val["m_flag_objfile_owned"] != 0:
  122. return "%s (objfile)" % self.val["m_owner"]["objfile"]
  123. else:
  124. return "%s (gdbarch)" % self.val["m_owner"]["gdbarch"]
  125. def struct_field_location_img(self, field_val):
  126. """Return an image of the loc component inside the given field
  127. gdb.Value.
  128. """
  129. loc_val = field_val["m_loc"]
  130. loc_kind = str(field_val["m_loc_kind"])
  131. if loc_kind == "FIELD_LOC_KIND_BITPOS":
  132. return "bitpos = %d" % loc_val["bitpos"]
  133. elif loc_kind == "FIELD_LOC_KIND_ENUMVAL":
  134. return "enumval = %d" % loc_val["enumval"]
  135. elif loc_kind == "FIELD_LOC_KIND_PHYSADDR":
  136. return "physaddr = 0x%x" % loc_val["physaddr"]
  137. elif loc_kind == "FIELD_LOC_KIND_PHYSNAME":
  138. return "physname = %s" % loc_val["physname"]
  139. elif loc_kind == "FIELD_LOC_KIND_DWARF_BLOCK":
  140. return "dwarf_block = %s" % loc_val["dwarf_block"]
  141. else:
  142. return "m_loc = ??? (unsupported m_loc_kind value)"
  143. def struct_field_img(self, fieldno):
  144. """Return an image of the main_type field number FIELDNO."""
  145. f = self.val["flds_bnds"]["fields"][fieldno]
  146. label = "flds_bnds.fields[%d]:" % fieldno
  147. if f["artificial"]:
  148. label += " (artificial)"
  149. fields = []
  150. fields.append("m_name = %s" % f["m_name"])
  151. fields.append("m_type = %s" % f["m_type"])
  152. fields.append("m_loc_kind = %s" % f["m_loc_kind"])
  153. fields.append("bitsize = %d" % f["bitsize"])
  154. fields.append(self.struct_field_location_img(f))
  155. return label + "\n" + " {" + ",\n ".join(fields) + "}"
  156. def bound_img(self, bound_name):
  157. """Return an image of the given main_type's bound."""
  158. bounds = self.val["flds_bnds"]["bounds"].dereference()
  159. b = bounds[bound_name]
  160. bnd_kind = str(b["m_kind"])
  161. if bnd_kind == "PROP_CONST":
  162. return str(b["m_data"]["const_val"])
  163. elif bnd_kind == "PROP_UNDEFINED":
  164. return "(undefined)"
  165. else:
  166. info = [bnd_kind]
  167. if bound_name == "high" and bounds["flag_upper_bound_is_count"]:
  168. info.append("upper_bound_is_count")
  169. return "{} ({})".format(str(b["m_data"]["baton"]), ",".join(info))
  170. def bounds_img(self):
  171. """Return an image of the main_type bounds."""
  172. b = self.val["flds_bnds"]["bounds"].dereference()
  173. low = self.bound_img("low")
  174. high = self.bound_img("high")
  175. img = "flds_bnds.bounds = {%s, %s}" % (low, high)
  176. if b["flag_bound_evaluated"]:
  177. img += " [evaluated]"
  178. return img
  179. def type_specific_img(self):
  180. """Return a string image of the main_type type_specific union.
  181. Only the relevant component of that union is printed (based on
  182. the value of the type_specific_kind field.
  183. """
  184. type_specific_kind = str(self.val["type_specific_field"])
  185. type_specific = self.val["type_specific"]
  186. if type_specific_kind == "TYPE_SPECIFIC_NONE":
  187. img = "type_specific_field = %s" % type_specific_kind
  188. elif type_specific_kind == "TYPE_SPECIFIC_CPLUS_STUFF":
  189. img = "cplus_stuff = %s" % type_specific["cplus_stuff"]
  190. elif type_specific_kind == "TYPE_SPECIFIC_GNAT_STUFF":
  191. img = (
  192. "gnat_stuff = {descriptive_type = %s}"
  193. % type_specific["gnat_stuff"]["descriptive_type"]
  194. )
  195. elif type_specific_kind == "TYPE_SPECIFIC_FLOATFORMAT":
  196. img = "floatformat[0..1] = %s" % type_specific["floatformat"]
  197. elif type_specific_kind == "TYPE_SPECIFIC_FUNC":
  198. img = (
  199. "calling_convention = %d"
  200. % type_specific["func_stuff"]["calling_convention"]
  201. )
  202. # tail_call_list is not printed.
  203. elif type_specific_kind == "TYPE_SPECIFIC_SELF_TYPE":
  204. img = "self_type = %s" % type_specific["self_type"]
  205. elif type_specific_kind == "TYPE_SPECIFIC_FIXED_POINT":
  206. # The scaling factor is an opaque structure, so we cannot
  207. # decode its value from Python (not without insider knowledge).
  208. img = (
  209. "scaling_factor: <opaque> (call __gmpz_dump with "
  210. " _mp_num and _mp_den fields if needed)"
  211. )
  212. elif type_specific_kind == "TYPE_SPECIFIC_INT":
  213. img = "int_stuff = { bit_size = %d, bit_offset = %d }" % (
  214. type_specific["int_stuff"]["bit_size"],
  215. type_specific["int_stuff"]["bit_offset"],
  216. )
  217. else:
  218. img = (
  219. "type_specific = ??? (unknown type_specific_kind: %s)"
  220. % type_specific_kind
  221. )
  222. return img
  223. def to_string(self):
  224. """Return a pretty-printed image of our main_type."""
  225. fields = []
  226. fields.append("name = %s" % self.val["name"])
  227. fields.append("code = %s" % self.val["code"])
  228. fields.append("flags = [%s]" % self.flags_to_string())
  229. fields.append("owner = %s" % self.owner_to_string())
  230. fields.append("target_type = %s" % self.val["target_type"])
  231. if self.val["nfields"] > 0:
  232. for fieldno in range(self.val["nfields"]):
  233. fields.append(self.struct_field_img(fieldno))
  234. if self.val["code"] == gdb.TYPE_CODE_RANGE:
  235. fields.append(self.bounds_img())
  236. fields.append(self.type_specific_img())
  237. return "\n{" + ",\n ".join(fields) + "}"
  238. class CoreAddrPrettyPrinter:
  239. """Print CORE_ADDR values as hex."""
  240. def __init__(self, val):
  241. self._val = val
  242. def to_string(self):
  243. return hex(int(self._val))
  244. class IntrusiveListPrinter:
  245. """Print a struct intrusive_list."""
  246. def __init__(self, val):
  247. self._val = val
  248. # Type of linked items.
  249. self._item_type = self._val.type.template_argument(0)
  250. self._node_ptr_type = gdb.lookup_type(
  251. "intrusive_list_node<{}>".format(self._item_type.tag)
  252. ).pointer()
  253. # Type of value -> node converter.
  254. self._conv_type = self._val.type.template_argument(1)
  255. if self._uses_member_node():
  256. # The second template argument of intrusive_member_node is a member
  257. # pointer value. Its value is the offset of the node member in the
  258. # enclosing type.
  259. member_node_ptr = self._conv_type.template_argument(1)
  260. member_node_ptr = member_node_ptr.cast(gdb.lookup_type("int"))
  261. self._member_node_offset = int(member_node_ptr)
  262. # This is only needed in _as_node_ptr if using a member node. Look it
  263. # up here so we only do it once.
  264. self._char_ptr_type = gdb.lookup_type("char").pointer()
  265. def display_hint(self):
  266. return "array"
  267. def _uses_member_node(self):
  268. """Return True if the list items use a node as a member, False if
  269. they use a node as a base class.
  270. """
  271. if self._conv_type.name.startswith("intrusive_member_node<"):
  272. return True
  273. elif self._conv_type.name.startswith("intrusive_base_node<"):
  274. return False
  275. else:
  276. raise RuntimeError(
  277. "Unexpected intrusive_list value -> node converter type: {}".format(
  278. self._conv_type.name
  279. )
  280. )
  281. def to_string(self):
  282. s = "intrusive list of {}".format(self._item_type)
  283. if self._uses_member_node():
  284. node_member = self._conv_type.template_argument(1)
  285. s += ", linked through {}".format(node_member)
  286. return s
  287. def _as_node_ptr(self, elem_ptr):
  288. """Given ELEM_PTR, a pointer to a list element, return a pointer to the
  289. corresponding intrusive_list_node.
  290. """
  291. assert elem_ptr.type.code == gdb.TYPE_CODE_PTR
  292. if self._uses_member_node():
  293. # Node as a member: add the member node offset from to the element's
  294. # address to get the member node's address.
  295. elem_char_ptr = elem_ptr.cast(self._char_ptr_type)
  296. node_char_ptr = elem_char_ptr + self._member_node_offset
  297. return node_char_ptr.cast(self._node_ptr_type)
  298. else:
  299. # Node as a base: just casting from node pointer to item pointer
  300. # will adjust the pointer value.
  301. return elem_ptr.cast(self._node_ptr_type)
  302. def _children_generator(self):
  303. """Generator that yields one tuple per list item."""
  304. elem_ptr = self._val["m_front"]
  305. idx = 0
  306. while elem_ptr != 0:
  307. yield (str(idx), elem_ptr.dereference())
  308. node_ptr = self._as_node_ptr(elem_ptr)
  309. elem_ptr = node_ptr["next"]
  310. idx += 1
  311. def children(self):
  312. return self._children_generator()
  313. def type_lookup_function(val):
  314. """A routine that returns the correct pretty printer for VAL
  315. if appropriate. Returns None otherwise.
  316. """
  317. tag = val.type.tag
  318. name = val.type.name
  319. if tag == "type":
  320. return StructTypePrettyPrinter(val)
  321. elif tag == "main_type":
  322. return StructMainTypePrettyPrinter(val)
  323. elif name == "CORE_ADDR":
  324. return CoreAddrPrettyPrinter(val)
  325. elif tag is not None and tag.startswith("intrusive_list<"):
  326. return IntrusiveListPrinter(val)
  327. return None
  328. def register_pretty_printer(objfile):
  329. """A routine to register a pretty-printer against the given OBJFILE."""
  330. objfile.pretty_printers.append(type_lookup_function)
  331. if __name__ == "__main__":
  332. if gdb.current_objfile() is not None:
  333. # This is the case where this script is being "auto-loaded"
  334. # for a given objfile. Register the pretty-printer for that
  335. # objfile.
  336. register_pretty_printer(gdb.current_objfile())
  337. else:
  338. # We need to locate the objfile corresponding to the GDB
  339. # executable, and register the pretty-printer for that objfile.
  340. # FIXME: The condition used to match the objfile is too simplistic
  341. # and will not work on Windows.
  342. for objfile in gdb.objfiles():
  343. if os.path.basename(objfile.filename) == "gdb":
  344. objfile.pretty_printers.append(type_lookup_function)