1*6881a400Schristos# Copyright (C) 2009-2023 Free Software Foundation, Inc. 27f2ac410Schristos# 37f2ac410Schristos# This file is part of GDB. 47f2ac410Schristos# 57f2ac410Schristos# This program is free software; you can redistribute it and/or modify 67f2ac410Schristos# it under the terms of the GNU General Public License as published by 77f2ac410Schristos# the Free Software Foundation; either version 3 of the License, or 87f2ac410Schristos# (at your option) any later version. 97f2ac410Schristos# 107f2ac410Schristos# This program is distributed in the hope that it will be useful, 117f2ac410Schristos# but WITHOUT ANY WARRANTY; without even the implied warranty of 127f2ac410Schristos# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 137f2ac410Schristos# GNU General Public License for more details. 147f2ac410Schristos# 157f2ac410Schristos# You should have received a copy of the GNU General Public License 167f2ac410Schristos# along with this program. If not, see <http://www.gnu.org/licenses/>. 177f2ac410Schristos 187f2ac410Schristosimport gdb 197f2ac410Schristosimport os.path 207f2ac410Schristos 217f2ac410Schristos 227f2ac410Schristosclass TypeFlag: 237f2ac410Schristos """A class that allows us to store a flag name, its short name, 247f2ac410Schristos and its value. 257f2ac410Schristos 267f2ac410Schristos In the GDB sources, struct type has a component called instance_flags 277f2ac410Schristos in which the value is the addition of various flags. These flags are 287f2ac410Schristos defined by the enumerates type_instance_flag_value. This class helps us 297f2ac410Schristos recreate a list with all these flags that is easy to manipulate and sort. 307f2ac410Schristos Because all flag names start with TYPE_INSTANCE_FLAG_, a short_name 317f2ac410Schristos attribute is provided that strips this prefix. 327f2ac410Schristos 337f2ac410Schristos ATTRIBUTES 347f2ac410Schristos name: The enumeration name (eg: "TYPE_INSTANCE_FLAG_CONST"). 357f2ac410Schristos value: The associated value. 367f2ac410Schristos short_name: The enumeration name, with the suffix stripped. 377f2ac410Schristos """ 387f2ac410Schristos 397f2ac410Schristos def __init__(self, name, value): 407f2ac410Schristos self.name = name 417f2ac410Schristos self.value = value 42*6881a400Schristos self.short_name = name.replace("TYPE_INSTANCE_FLAG_", "") 437f2ac410Schristos 447f2ac410Schristos def __lt__(self, other): 457f2ac410Schristos """Sort by value order.""" 467f2ac410Schristos return self.value < other.value 477f2ac410Schristos 487f2ac410Schristos 497f2ac410Schristos# A list of all existing TYPE_INSTANCE_FLAGS_* enumerations, 507f2ac410Schristos# stored as TypeFlags objects. Lazy-initialized. 517f2ac410SchristosTYPE_FLAGS = None 527f2ac410Schristos 537f2ac410Schristos 547f2ac410Schristosclass TypeFlagsPrinter: 557f2ac410Schristos """A class that prints a decoded form of an instance_flags value. 567f2ac410Schristos 577f2ac410Schristos This class uses a global named TYPE_FLAGS, which is a list of 587f2ac410Schristos all defined TypeFlag values. Using a global allows us to compute 597f2ac410Schristos this list only once. 607f2ac410Schristos 617f2ac410Schristos This class relies on a couple of enumeration types being defined. 627f2ac410Schristos If not, then printing of the instance_flag is going to be degraded, 637f2ac410Schristos but it's not a fatal error. 647f2ac410Schristos """ 657f2ac410Schristos 667f2ac410Schristos def __init__(self, val): 677f2ac410Schristos self.val = val 687f2ac410Schristos 697f2ac410Schristos def __str__(self): 707f2ac410Schristos global TYPE_FLAGS 717f2ac410Schristos if TYPE_FLAGS is None: 727f2ac410Schristos self.init_TYPE_FLAGS() 737f2ac410Schristos if not self.val: 747f2ac410Schristos return "0" 757f2ac410Schristos if TYPE_FLAGS: 76*6881a400Schristos flag_list = [ 77*6881a400Schristos flag.short_name for flag in TYPE_FLAGS if self.val & flag.value 78*6881a400Schristos ] 797f2ac410Schristos else: 807f2ac410Schristos flag_list = ["???"] 817f2ac410Schristos return "0x%x [%s]" % (self.val, "|".join(flag_list)) 827f2ac410Schristos 837f2ac410Schristos def init_TYPE_FLAGS(self): 847f2ac410Schristos """Initialize the TYPE_FLAGS global as a list of TypeFlag objects. 857f2ac410Schristos This operation requires the search of a couple of enumeration types. 867f2ac410Schristos If not found, a warning is printed on stdout, and TYPE_FLAGS is 877f2ac410Schristos set to the empty list. 887f2ac410Schristos 897f2ac410Schristos The resulting list is sorted by increasing value, to facilitate 907f2ac410Schristos printing of the list of flags used in an instance_flags value. 917f2ac410Schristos """ 927f2ac410Schristos global TYPE_FLAGS 937f2ac410Schristos TYPE_FLAGS = [] 947f2ac410Schristos try: 957f2ac410Schristos iflags = gdb.lookup_type("enum type_instance_flag_value") 967f2ac410Schristos except: 977f2ac410Schristos print("Warning: Cannot find enum type_instance_flag_value type.") 987f2ac410Schristos print(" `struct type' pretty-printer will be degraded") 997f2ac410Schristos return 100*6881a400Schristos TYPE_FLAGS = [TypeFlag(field.name, field.enumval) for field in iflags.fields()] 1017f2ac410Schristos TYPE_FLAGS.sort() 1027f2ac410Schristos 1037f2ac410Schristos 1047f2ac410Schristosclass StructTypePrettyPrinter: 1057f2ac410Schristos """Pretty-print an object of type struct type""" 1067f2ac410Schristos 1077f2ac410Schristos def __init__(self, val): 1087f2ac410Schristos self.val = val 1097f2ac410Schristos 1107f2ac410Schristos def to_string(self): 1117f2ac410Schristos fields = [] 112*6881a400Schristos fields.append("pointer_type = %s" % self.val["pointer_type"]) 113*6881a400Schristos fields.append("reference_type = %s" % self.val["reference_type"]) 114*6881a400Schristos fields.append("chain = %s" % self.val["reference_type"]) 115*6881a400Schristos fields.append( 116*6881a400Schristos "instance_flags = %s" % TypeFlagsPrinter(self.val["m_instance_flags"]) 117*6881a400Schristos ) 118*6881a400Schristos fields.append("length = %d" % self.val["m_length"]) 119*6881a400Schristos fields.append("main_type = %s" % self.val["main_type"]) 1207f2ac410Schristos return "\n{" + ",\n ".join(fields) + "}" 1217f2ac410Schristos 1227f2ac410Schristos 1237f2ac410Schristosclass StructMainTypePrettyPrinter: 1247f2ac410Schristos """Pretty-print an objet of type main_type""" 1257f2ac410Schristos 1267f2ac410Schristos def __init__(self, val): 1277f2ac410Schristos self.val = val 1287f2ac410Schristos 1297f2ac410Schristos def flags_to_string(self): 1307f2ac410Schristos """struct main_type contains a series of components that 1317f2ac410Schristos are one-bit ints whose name start with "flag_". For instance: 1327f2ac410Schristos flag_unsigned, flag_stub, etc. In essence, these components are 1337f2ac410Schristos really boolean flags, and this method prints a short synthetic 1347f2ac410Schristos version of the value of all these flags. For instance, if 1357f2ac410Schristos flag_unsigned and flag_static are the only components set to 1, 1367f2ac410Schristos this function will return "unsigned|static". 1377f2ac410Schristos """ 138*6881a400Schristos fields = [ 139*6881a400Schristos field.name.replace("flag_", "") 1407f2ac410Schristos for field in self.val.type.fields() 141*6881a400Schristos if field.name.startswith("flag_") and self.val[field.name] 142*6881a400Schristos ] 1437f2ac410Schristos return "|".join(fields) 1447f2ac410Schristos 1457f2ac410Schristos def owner_to_string(self): 146*6881a400Schristos """Return an image of component "owner".""" 147*6881a400Schristos if self.val["m_flag_objfile_owned"] != 0: 148*6881a400Schristos return "%s (objfile)" % self.val["m_owner"]["objfile"] 1497f2ac410Schristos else: 150*6881a400Schristos return "%s (gdbarch)" % self.val["m_owner"]["gdbarch"] 1517f2ac410Schristos 1527f2ac410Schristos def struct_field_location_img(self, field_val): 1537f2ac410Schristos """Return an image of the loc component inside the given field 1547f2ac410Schristos gdb.Value. 1557f2ac410Schristos """ 156*6881a400Schristos loc_val = field_val["m_loc"] 157*6881a400Schristos loc_kind = str(field_val["m_loc_kind"]) 1587f2ac410Schristos if loc_kind == "FIELD_LOC_KIND_BITPOS": 159*6881a400Schristos return "bitpos = %d" % loc_val["bitpos"] 1607f2ac410Schristos elif loc_kind == "FIELD_LOC_KIND_ENUMVAL": 161*6881a400Schristos return "enumval = %d" % loc_val["enumval"] 1627f2ac410Schristos elif loc_kind == "FIELD_LOC_KIND_PHYSADDR": 163*6881a400Schristos return "physaddr = 0x%x" % loc_val["physaddr"] 1647f2ac410Schristos elif loc_kind == "FIELD_LOC_KIND_PHYSNAME": 165*6881a400Schristos return "physname = %s" % loc_val["physname"] 1667f2ac410Schristos elif loc_kind == "FIELD_LOC_KIND_DWARF_BLOCK": 167*6881a400Schristos return "dwarf_block = %s" % loc_val["dwarf_block"] 1687f2ac410Schristos else: 169*6881a400Schristos return "m_loc = ??? (unsupported m_loc_kind value)" 1707f2ac410Schristos 1717f2ac410Schristos def struct_field_img(self, fieldno): 172*6881a400Schristos """Return an image of the main_type field number FIELDNO.""" 173*6881a400Schristos f = self.val["flds_bnds"]["fields"][fieldno] 1747f2ac410Schristos label = "flds_bnds.fields[%d]:" % fieldno 175*6881a400Schristos if f["artificial"]: 1767f2ac410Schristos label += " (artificial)" 1777f2ac410Schristos fields = [] 178*6881a400Schristos fields.append("m_name = %s" % f["m_name"]) 179*6881a400Schristos fields.append("m_type = %s" % f["m_type"]) 180*6881a400Schristos fields.append("m_loc_kind = %s" % f["m_loc_kind"]) 181*6881a400Schristos fields.append("bitsize = %d" % f["bitsize"]) 1827f2ac410Schristos fields.append(self.struct_field_location_img(f)) 1837f2ac410Schristos return label + "\n" + " {" + ",\n ".join(fields) + "}" 1847f2ac410Schristos 1857d62b00eSchristos def bound_img(self, bound_name): 1867d62b00eSchristos """Return an image of the given main_type's bound.""" 187*6881a400Schristos bounds = self.val["flds_bnds"]["bounds"].dereference() 188*6881a400Schristos b = bounds[bound_name] 189*6881a400Schristos bnd_kind = str(b["m_kind"]) 190*6881a400Schristos if bnd_kind == "PROP_CONST": 191*6881a400Schristos return str(b["m_data"]["const_val"]) 192*6881a400Schristos elif bnd_kind == "PROP_UNDEFINED": 193*6881a400Schristos return "(undefined)" 1947d62b00eSchristos else: 1957d62b00eSchristos info = [bnd_kind] 196*6881a400Schristos if bound_name == "high" and bounds["flag_upper_bound_is_count"]: 197*6881a400Schristos info.append("upper_bound_is_count") 198*6881a400Schristos return "{} ({})".format(str(b["m_data"]["baton"]), ",".join(info)) 1997d62b00eSchristos 2007f2ac410Schristos def bounds_img(self): 201*6881a400Schristos """Return an image of the main_type bounds.""" 202*6881a400Schristos b = self.val["flds_bnds"]["bounds"].dereference() 203*6881a400Schristos low = self.bound_img("low") 204*6881a400Schristos high = self.bound_img("high") 2057d62b00eSchristos 2067d62b00eSchristos img = "flds_bnds.bounds = {%s, %s}" % (low, high) 207*6881a400Schristos if b["flag_bound_evaluated"]: 208*6881a400Schristos img += " [evaluated]" 2097d62b00eSchristos return img 2107f2ac410Schristos 2117f2ac410Schristos def type_specific_img(self): 2127f2ac410Schristos """Return a string image of the main_type type_specific union. 2137f2ac410Schristos Only the relevant component of that union is printed (based on 2147f2ac410Schristos the value of the type_specific_kind field. 2157f2ac410Schristos """ 216*6881a400Schristos type_specific_kind = str(self.val["type_specific_field"]) 217*6881a400Schristos type_specific = self.val["type_specific"] 2187f2ac410Schristos if type_specific_kind == "TYPE_SPECIFIC_NONE": 219*6881a400Schristos img = "type_specific_field = %s" % type_specific_kind 2207f2ac410Schristos elif type_specific_kind == "TYPE_SPECIFIC_CPLUS_STUFF": 221*6881a400Schristos img = "cplus_stuff = %s" % type_specific["cplus_stuff"] 2227f2ac410Schristos elif type_specific_kind == "TYPE_SPECIFIC_GNAT_STUFF": 223*6881a400Schristos img = ( 224*6881a400Schristos "gnat_stuff = {descriptive_type = %s}" 225*6881a400Schristos % type_specific["gnat_stuff"]["descriptive_type"] 226*6881a400Schristos ) 2277f2ac410Schristos elif type_specific_kind == "TYPE_SPECIFIC_FLOATFORMAT": 228*6881a400Schristos img = "floatformat[0..1] = %s" % type_specific["floatformat"] 2297f2ac410Schristos elif type_specific_kind == "TYPE_SPECIFIC_FUNC": 230*6881a400Schristos img = ( 231*6881a400Schristos "calling_convention = %d" 232*6881a400Schristos % type_specific["func_stuff"]["calling_convention"] 233*6881a400Schristos ) 2347f2ac410Schristos # tail_call_list is not printed. 2357f2ac410Schristos elif type_specific_kind == "TYPE_SPECIFIC_SELF_TYPE": 236*6881a400Schristos img = "self_type = %s" % type_specific["self_type"] 237*6881a400Schristos elif type_specific_kind == "TYPE_SPECIFIC_FIXED_POINT": 238*6881a400Schristos # The scaling factor is an opaque structure, so we cannot 239*6881a400Schristos # decode its value from Python (not without insider knowledge). 240*6881a400Schristos img = ( 241*6881a400Schristos "scaling_factor: <opaque> (call __gmpz_dump with " 242*6881a400Schristos " _mp_num and _mp_den fields if needed)" 243*6881a400Schristos ) 244*6881a400Schristos elif type_specific_kind == "TYPE_SPECIFIC_INT": 245*6881a400Schristos img = "int_stuff = { bit_size = %d, bit_offset = %d }" % ( 246*6881a400Schristos type_specific["int_stuff"]["bit_size"], 247*6881a400Schristos type_specific["int_stuff"]["bit_offset"], 248*6881a400Schristos ) 2497f2ac410Schristos else: 250*6881a400Schristos img = ( 251*6881a400Schristos "type_specific = ??? (unknown type_specific_kind: %s)" 252*6881a400Schristos % type_specific_kind 253*6881a400Schristos ) 2547f2ac410Schristos return img 2557f2ac410Schristos 2567f2ac410Schristos def to_string(self): 257*6881a400Schristos """Return a pretty-printed image of our main_type.""" 2587f2ac410Schristos fields = [] 259*6881a400Schristos fields.append("name = %s" % self.val["name"]) 260*6881a400Schristos fields.append("code = %s" % self.val["code"]) 2617f2ac410Schristos fields.append("flags = [%s]" % self.flags_to_string()) 2627f2ac410Schristos fields.append("owner = %s" % self.owner_to_string()) 263*6881a400Schristos fields.append("target_type = %s" % self.val["m_target_type"]) 264*6881a400Schristos if self.val["nfields"] > 0: 265*6881a400Schristos for fieldno in range(self.val["nfields"]): 2667f2ac410Schristos fields.append(self.struct_field_img(fieldno)) 267*6881a400Schristos if self.val["code"] == gdb.TYPE_CODE_RANGE: 2687f2ac410Schristos fields.append(self.bounds_img()) 2697f2ac410Schristos fields.append(self.type_specific_img()) 2707f2ac410Schristos 2717f2ac410Schristos return "\n{" + ",\n ".join(fields) + "}" 2727f2ac410Schristos 2737f2ac410Schristos 2747f2ac410Schristosclass CoreAddrPrettyPrinter: 2757f2ac410Schristos """Print CORE_ADDR values as hex.""" 2767f2ac410Schristos 2777f2ac410Schristos def __init__(self, val): 2787f2ac410Schristos self._val = val 2797f2ac410Schristos 2807f2ac410Schristos def to_string(self): 2817f2ac410Schristos return hex(int(self._val)) 2827f2ac410Schristos 2837f2ac410Schristos 284*6881a400Schristosclass IntrusiveListPrinter: 285*6881a400Schristos """Print a struct intrusive_list.""" 286*6881a400Schristos 287*6881a400Schristos def __init__(self, val): 288*6881a400Schristos self._val = val 289*6881a400Schristos 290*6881a400Schristos # Type of linked items. 291*6881a400Schristos self._item_type = self._val.type.template_argument(0) 292*6881a400Schristos self._node_ptr_type = gdb.lookup_type( 293*6881a400Schristos "intrusive_list_node<{}>".format(self._item_type.tag) 294*6881a400Schristos ).pointer() 295*6881a400Schristos 296*6881a400Schristos # Type of value -> node converter. 297*6881a400Schristos self._conv_type = self._val.type.template_argument(1) 298*6881a400Schristos 299*6881a400Schristos if self._uses_member_node(): 300*6881a400Schristos # The second template argument of intrusive_member_node is a member 301*6881a400Schristos # pointer value. Its value is the offset of the node member in the 302*6881a400Schristos # enclosing type. 303*6881a400Schristos member_node_ptr = self._conv_type.template_argument(1) 304*6881a400Schristos member_node_ptr = member_node_ptr.cast(gdb.lookup_type("int")) 305*6881a400Schristos self._member_node_offset = int(member_node_ptr) 306*6881a400Schristos 307*6881a400Schristos # This is only needed in _as_node_ptr if using a member node. Look it 308*6881a400Schristos # up here so we only do it once. 309*6881a400Schristos self._char_ptr_type = gdb.lookup_type("char").pointer() 310*6881a400Schristos 311*6881a400Schristos def display_hint(self): 312*6881a400Schristos return "array" 313*6881a400Schristos 314*6881a400Schristos def _uses_member_node(self): 315*6881a400Schristos """Return True if the list items use a node as a member, False if 316*6881a400Schristos they use a node as a base class. 317*6881a400Schristos """ 318*6881a400Schristos 319*6881a400Schristos if self._conv_type.name.startswith("intrusive_member_node<"): 320*6881a400Schristos return True 321*6881a400Schristos elif self._conv_type.name.startswith("intrusive_base_node<"): 322*6881a400Schristos return False 323*6881a400Schristos else: 324*6881a400Schristos raise RuntimeError( 325*6881a400Schristos "Unexpected intrusive_list value -> node converter type: {}".format( 326*6881a400Schristos self._conv_type.name 327*6881a400Schristos ) 328*6881a400Schristos ) 329*6881a400Schristos 330*6881a400Schristos def to_string(self): 331*6881a400Schristos s = "intrusive list of {}".format(self._item_type) 332*6881a400Schristos 333*6881a400Schristos if self._uses_member_node(): 334*6881a400Schristos node_member = self._conv_type.template_argument(1) 335*6881a400Schristos s += ", linked through {}".format(node_member) 336*6881a400Schristos 337*6881a400Schristos return s 338*6881a400Schristos 339*6881a400Schristos def _as_node_ptr(self, elem_ptr): 340*6881a400Schristos """Given ELEM_PTR, a pointer to a list element, return a pointer to the 341*6881a400Schristos corresponding intrusive_list_node. 342*6881a400Schristos """ 343*6881a400Schristos 344*6881a400Schristos assert elem_ptr.type.code == gdb.TYPE_CODE_PTR 345*6881a400Schristos 346*6881a400Schristos if self._uses_member_node(): 347*6881a400Schristos # Node as a member: add the member node offset from to the element's 348*6881a400Schristos # address to get the member node's address. 349*6881a400Schristos elem_char_ptr = elem_ptr.cast(self._char_ptr_type) 350*6881a400Schristos node_char_ptr = elem_char_ptr + self._member_node_offset 351*6881a400Schristos return node_char_ptr.cast(self._node_ptr_type) 352*6881a400Schristos else: 353*6881a400Schristos # Node as a base: just casting from node pointer to item pointer 354*6881a400Schristos # will adjust the pointer value. 355*6881a400Schristos return elem_ptr.cast(self._node_ptr_type) 356*6881a400Schristos 357*6881a400Schristos def _children_generator(self): 358*6881a400Schristos """Generator that yields one tuple per list item.""" 359*6881a400Schristos 360*6881a400Schristos elem_ptr = self._val["m_front"] 361*6881a400Schristos idx = 0 362*6881a400Schristos while elem_ptr != 0: 363*6881a400Schristos yield (str(idx), elem_ptr.dereference()) 364*6881a400Schristos node_ptr = self._as_node_ptr(elem_ptr) 365*6881a400Schristos elem_ptr = node_ptr["next"] 366*6881a400Schristos idx += 1 367*6881a400Schristos 368*6881a400Schristos def children(self): 369*6881a400Schristos return self._children_generator() 370*6881a400Schristos 371*6881a400Schristos 3727f2ac410Schristosdef type_lookup_function(val): 3737f2ac410Schristos """A routine that returns the correct pretty printer for VAL 3747f2ac410Schristos if appropriate. Returns None otherwise. 3757f2ac410Schristos """ 376*6881a400Schristos tag = val.type.tag 377*6881a400Schristos name = val.type.name 378*6881a400Schristos if tag == "type": 3797f2ac410Schristos return StructTypePrettyPrinter(val) 380*6881a400Schristos elif tag == "main_type": 3817f2ac410Schristos return StructMainTypePrettyPrinter(val) 382*6881a400Schristos elif name == "CORE_ADDR": 3837f2ac410Schristos return CoreAddrPrettyPrinter(val) 384*6881a400Schristos elif tag is not None and tag.startswith("intrusive_list<"): 385*6881a400Schristos return IntrusiveListPrinter(val) 3867f2ac410Schristos return None 3877f2ac410Schristos 3887f2ac410Schristos 3897f2ac410Schristosdef register_pretty_printer(objfile): 390*6881a400Schristos """A routine to register a pretty-printer against the given OBJFILE.""" 3917f2ac410Schristos objfile.pretty_printers.append(type_lookup_function) 3927f2ac410Schristos 3937f2ac410Schristos 3947f2ac410Schristosif __name__ == "__main__": 3957f2ac410Schristos if gdb.current_objfile() is not None: 3967f2ac410Schristos # This is the case where this script is being "auto-loaded" 3977f2ac410Schristos # for a given objfile. Register the pretty-printer for that 3987f2ac410Schristos # objfile. 3997f2ac410Schristos register_pretty_printer(gdb.current_objfile()) 4007f2ac410Schristos else: 4017f2ac410Schristos # We need to locate the objfile corresponding to the GDB 4027f2ac410Schristos # executable, and register the pretty-printer for that objfile. 4037f2ac410Schristos # FIXME: The condition used to match the objfile is too simplistic 4047f2ac410Schristos # and will not work on Windows. 4057f2ac410Schristos for objfile in gdb.objfiles(): 4067f2ac410Schristos if os.path.basename(objfile.filename) == "gdb": 4077f2ac410Schristos objfile.pretty_printers.append(type_lookup_function) 408