1 # Copyright (C) 2009-2023 Free Software Foundation, Inc.
3 # This file is part of GDB.
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.
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.
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/>.
23 """A class that allows us to store a flag name, its short name,
26 In the GDB sources, struct type has a component called instance_flags
27 in which the value is the addition of various flags. These flags are
28 defined by the enumerates type_instance_flag_value. This class helps us
29 recreate a list with all these flags that is easy to manipulate and sort.
30 Because all flag names start with TYPE_INSTANCE_FLAG_, a short_name
31 attribute is provided that strips this prefix.
34 name: The enumeration name (eg: "TYPE_INSTANCE_FLAG_CONST").
35 value: The associated value.
36 short_name: The enumeration name, with the suffix stripped.
39 def __init__(self
, name
, value
):
42 self
.short_name
= name
.replace("TYPE_INSTANCE_FLAG_", "")
44 def __lt__(self
, other
):
45 """Sort by value order."""
46 return self
.value
< other
.value
49 # A list of all existing TYPE_INSTANCE_FLAGS_* enumerations,
50 # stored as TypeFlags objects. Lazy-initialized.
54 class TypeFlagsPrinter
:
55 """A class that prints a decoded form of an instance_flags value.
57 This class uses a global named TYPE_FLAGS, which is a list of
58 all defined TypeFlag values. Using a global allows us to compute
61 This class relies on a couple of enumeration types being defined.
62 If not, then printing of the instance_flag is going to be degraded,
63 but it's not a fatal error.
66 def __init__(self
, val
):
71 if TYPE_FLAGS
is None:
72 self
.init_TYPE_FLAGS()
77 flag
.short_name
for flag
in TYPE_FLAGS
if self
.val
& flag
.value
81 return "0x%x [%s]" % (self
.val
, "|".join(flag_list
))
83 def init_TYPE_FLAGS(self
):
84 """Initialize the TYPE_FLAGS global as a list of TypeFlag objects.
85 This operation requires the search of a couple of enumeration types.
86 If not found, a warning is printed on stdout, and TYPE_FLAGS is
87 set to the empty list.
89 The resulting list is sorted by increasing value, to facilitate
90 printing of the list of flags used in an instance_flags value.
95 iflags
= gdb
.lookup_type("enum type_instance_flag_value")
97 print("Warning: Cannot find enum type_instance_flag_value type.")
98 print(" `struct type' pretty-printer will be degraded")
100 TYPE_FLAGS
= [TypeFlag(field
.name
, field
.enumval
) for field
in iflags
.fields()]
104 class StructTypePrettyPrinter
:
105 """Pretty-print an object of type struct type"""
107 def __init__(self
, val
):
112 fields
.append("pointer_type = %s" % self
.val
["pointer_type"])
113 fields
.append("reference_type = %s" % self
.val
["reference_type"])
114 fields
.append("chain = %s" % self
.val
["reference_type"])
116 "instance_flags = %s" % TypeFlagsPrinter(self
.val
["m_instance_flags"])
118 fields
.append("length = %d" % self
.val
["m_length"])
119 fields
.append("main_type = %s" % self
.val
["main_type"])
120 return "\n{" + ",\n ".join(fields
) + "}"
123 class StructMainTypePrettyPrinter
:
124 """Pretty-print an objet of type main_type"""
126 def __init__(self
, val
):
129 def flags_to_string(self
):
130 """struct main_type contains a series of components that
131 are one-bit ints whose name start with "flag_". For instance:
132 flag_unsigned, flag_stub, etc. In essence, these components are
133 really boolean flags, and this method prints a short synthetic
134 version of the value of all these flags. For instance, if
135 flag_unsigned and flag_static are the only components set to 1,
136 this function will return "unsigned|static".
139 field
.name
.replace("flag_", "")
140 for field
in self
.val
.type.fields()
141 if field
.name
.startswith("flag_") and self
.val
[field
.name
]
143 return "|".join(fields
)
145 def owner_to_string(self
):
146 """Return an image of component "owner"."""
147 if self
.val
["m_flag_objfile_owned"] != 0:
148 return "%s (objfile)" % self
.val
["m_owner"]["objfile"]
150 return "%s (gdbarch)" % self
.val
["m_owner"]["gdbarch"]
152 def struct_field_location_img(self
, field_val
):
153 """Return an image of the loc component inside the given field
156 loc_val
= field_val
["m_loc"]
157 loc_kind
= str(field_val
["m_loc_kind"])
158 if loc_kind
== "FIELD_LOC_KIND_BITPOS":
159 return "bitpos = %d" % loc_val
["bitpos"]
160 elif loc_kind
== "FIELD_LOC_KIND_ENUMVAL":
161 return "enumval = %d" % loc_val
["enumval"]
162 elif loc_kind
== "FIELD_LOC_KIND_PHYSADDR":
163 return "physaddr = 0x%x" % loc_val
["physaddr"]
164 elif loc_kind
== "FIELD_LOC_KIND_PHYSNAME":
165 return "physname = %s" % loc_val
["physname"]
166 elif loc_kind
== "FIELD_LOC_KIND_DWARF_BLOCK":
167 return "dwarf_block = %s" % loc_val
["dwarf_block"]
169 return "m_loc = ??? (unsupported m_loc_kind value)"
171 def struct_field_img(self
, fieldno
):
172 """Return an image of the main_type field number FIELDNO."""
173 f
= self
.val
["flds_bnds"]["fields"][fieldno
]
174 label
= "flds_bnds.fields[%d]:" % fieldno
175 if f
["m_artificial"]:
176 label
+= " (artificial)"
178 fields
.append("m_name = %s" % f
["m_name"])
179 fields
.append("m_type = %s" % f
["m_type"])
180 fields
.append("m_loc_kind = %s" % f
["m_loc_kind"])
181 fields
.append("bitsize = %d" % f
["m_bitsize"])
182 fields
.append(self
.struct_field_location_img(f
))
183 return label
+ "\n" + " {" + ",\n ".join(fields
) + "}"
185 def bound_img(self
, bound_name
):
186 """Return an image of the given main_type's bound."""
187 bounds
= self
.val
["flds_bnds"]["bounds"].dereference()
188 b
= bounds
[bound_name
]
189 bnd_kind
= str(b
["m_kind"])
190 if bnd_kind
== "PROP_CONST":
191 return str(b
["m_data"]["const_val"])
192 elif bnd_kind
== "PROP_UNDEFINED":
196 if bound_name
== "high" and bounds
["flag_upper_bound_is_count"]:
197 info
.append("upper_bound_is_count")
198 return "{} ({})".format(str(b
["m_data"]["baton"]), ",".join(info
))
200 def bounds_img(self
):
201 """Return an image of the main_type bounds."""
202 b
= self
.val
["flds_bnds"]["bounds"].dereference()
203 low
= self
.bound_img("low")
204 high
= self
.bound_img("high")
206 img
= "flds_bnds.bounds = {%s, %s}" % (low
, high
)
207 if b
["flag_bound_evaluated"]:
208 img
+= " [evaluated]"
211 def type_specific_img(self
):
212 """Return a string image of the main_type type_specific union.
213 Only the relevant component of that union is printed (based on
214 the value of the type_specific_kind field.
216 type_specific_kind
= str(self
.val
["type_specific_field"])
217 type_specific
= self
.val
["type_specific"]
218 if type_specific_kind
== "TYPE_SPECIFIC_NONE":
219 img
= "type_specific_field = %s" % type_specific_kind
220 elif type_specific_kind
== "TYPE_SPECIFIC_CPLUS_STUFF":
221 img
= "cplus_stuff = %s" % type_specific
["cplus_stuff"]
222 elif type_specific_kind
== "TYPE_SPECIFIC_GNAT_STUFF":
224 "gnat_stuff = {descriptive_type = %s}"
225 % type_specific
["gnat_stuff"]["descriptive_type"]
227 elif type_specific_kind
== "TYPE_SPECIFIC_FLOATFORMAT":
228 img
= "floatformat[0..1] = %s" % type_specific
["floatformat"]
229 elif type_specific_kind
== "TYPE_SPECIFIC_FUNC":
231 "calling_convention = %d"
232 % type_specific
["func_stuff"]["calling_convention"]
234 # tail_call_list is not printed.
235 elif type_specific_kind
== "TYPE_SPECIFIC_SELF_TYPE":
236 img
= "self_type = %s" % type_specific
["self_type"]
237 elif type_specific_kind
== "TYPE_SPECIFIC_FIXED_POINT":
238 # The scaling factor is an opaque structure, so we cannot
239 # decode its value from Python (not without insider knowledge).
241 "scaling_factor: <opaque> (call __gmpz_dump with "
242 " _mp_num and _mp_den fields if needed)"
244 elif type_specific_kind
== "TYPE_SPECIFIC_INT":
245 img
= "int_stuff = { bit_size = %d, bit_offset = %d }" % (
246 type_specific
["int_stuff"]["bit_size"],
247 type_specific
["int_stuff"]["bit_offset"],
251 "type_specific = ??? (unknown type_specific_kind: %s)"
257 """Return a pretty-printed image of our main_type."""
259 fields
.append("name = %s" % self
.val
["name"])
260 fields
.append("code = %s" % self
.val
["code"])
261 fields
.append("flags = [%s]" % self
.flags_to_string())
262 fields
.append("owner = %s" % self
.owner_to_string())
263 fields
.append("target_type = %s" % self
.val
["m_target_type"])
264 if self
.val
["m_nfields"] > 0:
265 for fieldno
in range(self
.val
["m_nfields"]):
266 fields
.append(self
.struct_field_img(fieldno
))
267 if self
.val
["code"] == gdb
.TYPE_CODE_RANGE
:
268 fields
.append(self
.bounds_img())
269 fields
.append(self
.type_specific_img())
271 return "\n{" + ",\n ".join(fields
) + "}"
274 class CoreAddrPrettyPrinter
:
275 """Print CORE_ADDR values as hex."""
277 def __init__(self
, val
):
281 return hex(int(self
._val
))
284 class IntrusiveListPrinter
:
285 """Print a struct intrusive_list."""
287 def __init__(self
, val
):
290 # Type of linked items.
291 self
._item
_type
= self
._val
.type.template_argument(0)
292 self
._node
_ptr
_type
= gdb
.lookup_type(
293 "intrusive_list_node<{}>".format(self
._item
_type
.tag
)
296 # Type of value -> node converter.
297 self
._conv
_type
= self
._val
.type.template_argument(1)
299 if self
._uses
_member
_node
():
300 # The second template argument of intrusive_member_node is a member
301 # pointer value. Its value is the offset of the node member in the
303 member_node_ptr
= self
._conv
_type
.template_argument(1)
304 member_node_ptr
= member_node_ptr
.cast(gdb
.lookup_type("int"))
305 self
._member
_node
_offset
= int(member_node_ptr
)
307 # This is only needed in _as_node_ptr if using a member node. Look it
308 # up here so we only do it once.
309 self
._char
_ptr
_type
= gdb
.lookup_type("char").pointer()
311 def display_hint(self
):
314 def _uses_member_node(self
):
315 """Return True if the list items use a node as a member, False if
316 they use a node as a base class.
319 if self
._conv
_type
.name
.startswith("intrusive_member_node<"):
321 elif self
._conv
_type
.name
.startswith("intrusive_base_node<"):
325 "Unexpected intrusive_list value -> node converter type: {}".format(
331 s
= "intrusive list of {}".format(self
._item
_type
)
333 if self
._uses
_member
_node
():
334 node_member
= self
._conv
_type
.template_argument(1)
335 s
+= ", linked through {}".format(node_member
)
339 def _as_node_ptr(self
, elem_ptr
):
340 """Given ELEM_PTR, a pointer to a list element, return a pointer to the
341 corresponding intrusive_list_node.
344 assert elem_ptr
.type.code
== gdb
.TYPE_CODE_PTR
346 if self
._uses
_member
_node
():
347 # Node as a member: add the member node offset from to the element's
348 # address to get the member node's address.
349 elem_char_ptr
= elem_ptr
.cast(self
._char
_ptr
_type
)
350 node_char_ptr
= elem_char_ptr
+ self
._member
_node
_offset
351 return node_char_ptr
.cast(self
._node
_ptr
_type
)
353 # Node as a base: just casting from node pointer to item pointer
354 # will adjust the pointer value.
355 return elem_ptr
.cast(self
._node
_ptr
_type
)
357 def _children_generator(self
):
358 """Generator that yields one tuple per list item."""
360 elem_ptr
= self
._val
["m_front"]
363 yield (str(idx
), elem_ptr
.dereference())
364 node_ptr
= self
._as
_node
_ptr
(elem_ptr
)
365 elem_ptr
= node_ptr
["next"]
369 return self
._children
_generator
()
373 """Pretty-printer for htab_t hash tables."""
375 def __init__(self
, val
):
378 def display_hint(self
):
382 n
= int(self
._val
["n_elements"]) - int(self
._val
["n_deleted"])
383 return "htab_t with {} elements".format(n
)
386 size
= int(self
._val
["size"])
387 entries
= self
._val
["entries"]
390 for entries_i
in range(size
):
391 entry
= entries
[entries_i
]
392 # 0 (NULL pointer) means there's nothing, 1 (HTAB_DELETED_ENTRY)
393 # means there was something, but is now deleted.
394 if int(entry
) in (0, 1):
397 yield (str(child_i
), entry
)
401 def type_lookup_function(val
):
402 """A routine that returns the correct pretty printer for VAL
403 if appropriate. Returns None otherwise.
408 return StructTypePrettyPrinter(val
)
409 elif tag
== "main_type":
410 return StructMainTypePrettyPrinter(val
)
411 elif name
== "CORE_ADDR":
412 return CoreAddrPrettyPrinter(val
)
413 elif tag
is not None and tag
.startswith("intrusive_list<"):
414 return IntrusiveListPrinter(val
)
415 elif name
== "htab_t":
416 return HtabPrinter(val
)
420 def register_pretty_printer(objfile
):
421 """A routine to register a pretty-printer against the given OBJFILE."""
422 objfile
.pretty_printers
.append(type_lookup_function
)
425 if __name__
== "__main__":
426 if gdb
.current_objfile() is not None:
427 # This is the case where this script is being "auto-loaded"
428 # for a given objfile. Register the pretty-printer for that
430 register_pretty_printer(gdb
.current_objfile())
432 # We need to locate the objfile corresponding to the GDB
433 # executable, and register the pretty-printer for that objfile.
434 # FIXME: The condition used to match the objfile is too simplistic
435 # and will not work on Windows.
436 for objfile
in gdb
.objfiles():
437 if os
.path
.basename(objfile
.filename
) == "gdb":
438 objfile
.pretty_printers
.append(type_lookup_function
)