| 1 | # Copyright (C) 2009-2018 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 | |
| 18 | import gdb |
| 19 | import os.path |
| 20 | |
| 21 | class TypeFlag: |
| 22 | """A class that allows us to store a flag name, its short name, |
| 23 | and its value. |
| 24 | |
| 25 | In the GDB sources, struct type has a component called instance_flags |
| 26 | in which the value is the addition of various flags. These flags are |
| 27 | defined by the enumerates type_instance_flag_value. This class helps us |
| 28 | recreate a list with all these flags that is easy to manipulate and sort. |
| 29 | Because all flag names start with TYPE_INSTANCE_FLAG_, a short_name |
| 30 | attribute is provided that strips this prefix. |
| 31 | |
| 32 | ATTRIBUTES |
| 33 | name: The enumeration name (eg: "TYPE_INSTANCE_FLAG_CONST"). |
| 34 | value: The associated value. |
| 35 | short_name: The enumeration name, with the suffix stripped. |
| 36 | """ |
| 37 | def __init__(self, name, value): |
| 38 | self.name = name |
| 39 | self.value = value |
| 40 | self.short_name = name.replace("TYPE_INSTANCE_FLAG_", '') |
| 41 | |
| 42 | def __lt__(self, other): |
| 43 | """Sort by value order.""" |
| 44 | return self.value < other.value |
| 45 | |
| 46 | |
| 47 | # A list of all existing TYPE_INSTANCE_FLAGS_* enumerations, |
| 48 | # stored as TypeFlags objects. Lazy-initialized. |
| 49 | TYPE_FLAGS = None |
| 50 | |
| 51 | class TypeFlagsPrinter: |
| 52 | """A class that prints a decoded form of an instance_flags value. |
| 53 | |
| 54 | This class uses a global named TYPE_FLAGS, which is a list of |
| 55 | all defined TypeFlag values. Using a global allows us to compute |
| 56 | this list only once. |
| 57 | |
| 58 | This class relies on a couple of enumeration types being defined. |
| 59 | If not, then printing of the instance_flag is going to be degraded, |
| 60 | but it's not a fatal error. |
| 61 | """ |
| 62 | def __init__(self, val): |
| 63 | self.val = val |
| 64 | def __str__(self): |
| 65 | global TYPE_FLAGS |
| 66 | if TYPE_FLAGS is None: |
| 67 | self.init_TYPE_FLAGS() |
| 68 | if not self.val: |
| 69 | return "0" |
| 70 | if TYPE_FLAGS: |
| 71 | flag_list = [flag.short_name for flag in TYPE_FLAGS |
| 72 | if self.val & flag.value] |
| 73 | else: |
| 74 | flag_list = ["???"] |
| 75 | return "0x%x [%s]" % (self.val, "|".join(flag_list)) |
| 76 | def init_TYPE_FLAGS(self): |
| 77 | """Initialize the TYPE_FLAGS global as a list of TypeFlag objects. |
| 78 | This operation requires the search of a couple of enumeration types. |
| 79 | If not found, a warning is printed on stdout, and TYPE_FLAGS is |
| 80 | set to the empty list. |
| 81 | |
| 82 | The resulting list is sorted by increasing value, to facilitate |
| 83 | printing of the list of flags used in an instance_flags value. |
| 84 | """ |
| 85 | global TYPE_FLAGS |
| 86 | TYPE_FLAGS = [] |
| 87 | try: |
| 88 | iflags = gdb.lookup_type("enum type_instance_flag_value") |
| 89 | except: |
| 90 | print("Warning: Cannot find enum type_instance_flag_value type.") |
| 91 | print(" `struct type' pretty-printer will be degraded") |
| 92 | return |
| 93 | TYPE_FLAGS = [TypeFlag(field.name, field.enumval) |
| 94 | for field in iflags.fields()] |
| 95 | TYPE_FLAGS.sort() |
| 96 | |
| 97 | class StructTypePrettyPrinter: |
| 98 | """Pretty-print an object of type struct type""" |
| 99 | def __init__(self, val): |
| 100 | self.val = val |
| 101 | def to_string(self): |
| 102 | fields = [] |
| 103 | fields.append("pointer_type = %s" % self.val['pointer_type']) |
| 104 | fields.append("reference_type = %s" % self.val['reference_type']) |
| 105 | fields.append("chain = %s" % self.val['reference_type']) |
| 106 | fields.append("instance_flags = %s" |
| 107 | % TypeFlagsPrinter(self.val['instance_flags'])) |
| 108 | fields.append("length = %d" % self.val['length']) |
| 109 | fields.append("main_type = %s" % self.val['main_type']) |
| 110 | return "\n{" + ",\n ".join(fields) + "}" |
| 111 | |
| 112 | class StructMainTypePrettyPrinter: |
| 113 | """Pretty-print an objet of type main_type""" |
| 114 | def __init__(self, val): |
| 115 | self.val = val |
| 116 | def flags_to_string(self): |
| 117 | """struct main_type contains a series of components that |
| 118 | are one-bit ints whose name start with "flag_". For instance: |
| 119 | flag_unsigned, flag_stub, etc. In essence, these components are |
| 120 | really boolean flags, and this method prints a short synthetic |
| 121 | version of the value of all these flags. For instance, if |
| 122 | flag_unsigned and flag_static are the only components set to 1, |
| 123 | this function will return "unsigned|static". |
| 124 | """ |
| 125 | fields = [field.name.replace("flag_", "") |
| 126 | for field in self.val.type.fields() |
| 127 | if field.name.startswith("flag_") |
| 128 | and self.val[field.name]] |
| 129 | return "|".join(fields) |
| 130 | def owner_to_string(self): |
| 131 | """Return an image of component "owner". |
| 132 | """ |
| 133 | if self.val['flag_objfile_owned'] != 0: |
| 134 | return "%s (objfile)" % self.val['owner']['objfile'] |
| 135 | else: |
| 136 | return "%s (gdbarch)" % self.val['owner']['gdbarch'] |
| 137 | def struct_field_location_img(self, field_val): |
| 138 | """Return an image of the loc component inside the given field |
| 139 | gdb.Value. |
| 140 | """ |
| 141 | loc_val = field_val['loc'] |
| 142 | loc_kind = str(field_val['loc_kind']) |
| 143 | if loc_kind == "FIELD_LOC_KIND_BITPOS": |
| 144 | return 'bitpos = %d' % loc_val['bitpos'] |
| 145 | elif loc_kind == "FIELD_LOC_KIND_ENUMVAL": |
| 146 | return 'enumval = %d' % loc_val['enumval'] |
| 147 | elif loc_kind == "FIELD_LOC_KIND_PHYSADDR": |
| 148 | return 'physaddr = 0x%x' % loc_val['physaddr'] |
| 149 | elif loc_kind == "FIELD_LOC_KIND_PHYSNAME": |
| 150 | return 'physname = %s' % loc_val['physname'] |
| 151 | elif loc_kind == "FIELD_LOC_KIND_DWARF_BLOCK": |
| 152 | return 'dwarf_block = %s' % loc_val['dwarf_block'] |
| 153 | else: |
| 154 | return 'loc = ??? (unsupported loc_kind value)' |
| 155 | def struct_field_img(self, fieldno): |
| 156 | """Return an image of the main_type field number FIELDNO. |
| 157 | """ |
| 158 | f = self.val['flds_bnds']['fields'][fieldno] |
| 159 | label = "flds_bnds.fields[%d]:" % fieldno |
| 160 | if f['artificial']: |
| 161 | label += " (artificial)" |
| 162 | fields = [] |
| 163 | fields.append("name = %s" % f['name']) |
| 164 | fields.append("type = %s" % f['type']) |
| 165 | fields.append("loc_kind = %s" % f['loc_kind']) |
| 166 | fields.append("bitsize = %d" % f['bitsize']) |
| 167 | fields.append(self.struct_field_location_img(f)) |
| 168 | return label + "\n" + " {" + ",\n ".join(fields) + "}" |
| 169 | def bounds_img(self): |
| 170 | """Return an image of the main_type bounds. |
| 171 | """ |
| 172 | b = self.val['flds_bnds']['bounds'].dereference() |
| 173 | low = str(b['low']) |
| 174 | if b['low_undefined'] != 0: |
| 175 | low += " (undefined)" |
| 176 | high = str(b['high']) |
| 177 | if b['high_undefined'] != 0: |
| 178 | high += " (undefined)" |
| 179 | return "flds_bnds.bounds = {%s, %s}" % (low, high) |
| 180 | def type_specific_img(self): |
| 181 | """Return a string image of the main_type type_specific union. |
| 182 | Only the relevant component of that union is printed (based on |
| 183 | the value of the type_specific_kind field. |
| 184 | """ |
| 185 | type_specific_kind = str(self.val['type_specific_field']) |
| 186 | type_specific = self.val['type_specific'] |
| 187 | if type_specific_kind == "TYPE_SPECIFIC_NONE": |
| 188 | img = 'type_specific_field = %s' % type_specific_kind |
| 189 | elif type_specific_kind == "TYPE_SPECIFIC_CPLUS_STUFF": |
| 190 | img = "cplus_stuff = %s" % type_specific['cplus_stuff'] |
| 191 | elif type_specific_kind == "TYPE_SPECIFIC_GNAT_STUFF": |
| 192 | img = ("gnat_stuff = {descriptive_type = %s}" |
| 193 | % type_specific['gnat_stuff']['descriptive_type']) |
| 194 | elif type_specific_kind == "TYPE_SPECIFIC_FLOATFORMAT": |
| 195 | img = "floatformat[0..1] = %s" % type_specific['floatformat'] |
| 196 | elif type_specific_kind == "TYPE_SPECIFIC_FUNC": |
| 197 | img = ("calling_convention = %d" |
| 198 | % type_specific['func_stuff']['calling_convention']) |
| 199 | # tail_call_list is not printed. |
| 200 | elif type_specific_kind == "TYPE_SPECIFIC_SELF_TYPE": |
| 201 | img = "self_type = %s" % type_specific['self_type'] |
| 202 | else: |
| 203 | img = ("type_specific = ??? (unknown type_secific_kind: %s)" |
| 204 | % type_specific_kind) |
| 205 | return img |
| 206 | |
| 207 | def to_string(self): |
| 208 | """Return a pretty-printed image of our main_type. |
| 209 | """ |
| 210 | fields = [] |
| 211 | fields.append("name = %s" % self.val['name']) |
| 212 | fields.append("code = %s" % self.val['code']) |
| 213 | fields.append("flags = [%s]" % self.flags_to_string()) |
| 214 | fields.append("owner = %s" % self.owner_to_string()) |
| 215 | fields.append("target_type = %s" % self.val['target_type']) |
| 216 | if self.val['nfields'] > 0: |
| 217 | for fieldno in range(self.val['nfields']): |
| 218 | fields.append(self.struct_field_img(fieldno)) |
| 219 | if self.val['code'] == gdb.TYPE_CODE_RANGE: |
| 220 | fields.append(self.bounds_img()) |
| 221 | fields.append(self.type_specific_img()) |
| 222 | |
| 223 | return "\n{" + ",\n ".join(fields) + "}" |
| 224 | |
| 225 | def type_lookup_function(val): |
| 226 | """A routine that returns the correct pretty printer for VAL |
| 227 | if appropriate. Returns None otherwise. |
| 228 | """ |
| 229 | if val.type.tag == "type": |
| 230 | return StructTypePrettyPrinter(val) |
| 231 | elif val.type.tag == "main_type": |
| 232 | return StructMainTypePrettyPrinter(val) |
| 233 | return None |
| 234 | |
| 235 | def register_pretty_printer(objfile): |
| 236 | """A routine to register a pretty-printer against the given OBJFILE. |
| 237 | """ |
| 238 | objfile.pretty_printers.append(type_lookup_function) |
| 239 | |
| 240 | if __name__ == "__main__": |
| 241 | if gdb.current_objfile() is not None: |
| 242 | # This is the case where this script is being "auto-loaded" |
| 243 | # for a given objfile. Register the pretty-printer for that |
| 244 | # objfile. |
| 245 | register_pretty_printer(gdb.current_objfile()) |
| 246 | else: |
| 247 | # We need to locate the objfile corresponding to the GDB |
| 248 | # executable, and register the pretty-printer for that objfile. |
| 249 | # FIXME: The condition used to match the objfile is too simplistic |
| 250 | # and will not work on Windows. |
| 251 | for objfile in gdb.objfiles(): |
| 252 | if os.path.basename(objfile.filename) == "gdb": |
| 253 | objfile.pretty_printers.append(type_lookup_function) |