Commit | Line | Data |
---|---|---|
3666a048 | 1 | # Copyright (C) 2009-2021 Free Software Foundation, Inc. |
737a160e JB |
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 | ||
e76f78a0 | 21 | |
737a160e JB |
22 | class TypeFlag: |
23 | """A class that allows us to store a flag name, its short name, | |
24 | and its value. | |
25 | ||
26 | In the GDB sources, struct type has a component called instance_flags | |
2fe842e5 | 27 | in which the value is the addition of various flags. These flags are |
a9ff5f12 UW |
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. | |
737a160e JB |
32 | |
33 | ATTRIBUTES | |
a9ff5f12 | 34 | name: The enumeration name (eg: "TYPE_INSTANCE_FLAG_CONST"). |
737a160e JB |
35 | value: The associated value. |
36 | short_name: The enumeration name, with the suffix stripped. | |
37 | """ | |
e76f78a0 | 38 | |
737a160e JB |
39 | def __init__(self, name, value): |
40 | self.name = name | |
41 | self.value = value | |
a9ff5f12 | 42 | self.short_name = name.replace("TYPE_INSTANCE_FLAG_", '') |
68ad5fb9 SM |
43 | |
44 | def __lt__(self, other): | |
737a160e | 45 | """Sort by value order.""" |
68ad5fb9 | 46 | return self.value < other.value |
e76f78a0 | 47 | |
737a160e | 48 | |
a9ff5f12 UW |
49 | # A list of all existing TYPE_INSTANCE_FLAGS_* enumerations, |
50 | # stored as TypeFlags objects. Lazy-initialized. | |
737a160e JB |
51 | TYPE_FLAGS = None |
52 | ||
e76f78a0 | 53 | |
737a160e JB |
54 | class TypeFlagsPrinter: |
55 | """A class that prints a decoded form of an instance_flags value. | |
56 | ||
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 | |
59 | this list only once. | |
60 | ||
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. | |
64 | """ | |
e76f78a0 | 65 | |
737a160e JB |
66 | def __init__(self, val): |
67 | self.val = val | |
e76f78a0 | 68 | |
737a160e JB |
69 | def __str__(self): |
70 | global TYPE_FLAGS | |
71 | if TYPE_FLAGS is None: | |
72 | self.init_TYPE_FLAGS() | |
73 | if not self.val: | |
74 | return "0" | |
75 | if TYPE_FLAGS: | |
76 | flag_list = [flag.short_name for flag in TYPE_FLAGS | |
77 | if self.val & flag.value] | |
78 | else: | |
79 | flag_list = ["???"] | |
80 | return "0x%x [%s]" % (self.val, "|".join(flag_list)) | |
e76f78a0 | 81 | |
737a160e JB |
82 | def init_TYPE_FLAGS(self): |
83 | """Initialize the TYPE_FLAGS global as a list of TypeFlag objects. | |
84 | This operation requires the search of a couple of enumeration types. | |
85 | If not found, a warning is printed on stdout, and TYPE_FLAGS is | |
86 | set to the empty list. | |
87 | ||
88 | The resulting list is sorted by increasing value, to facilitate | |
89 | printing of the list of flags used in an instance_flags value. | |
90 | """ | |
91 | global TYPE_FLAGS | |
92 | TYPE_FLAGS = [] | |
737a160e JB |
93 | try: |
94 | iflags = gdb.lookup_type("enum type_instance_flag_value") | |
95 | except: | |
ac46107c JK |
96 | print("Warning: Cannot find enum type_instance_flag_value type.") |
97 | print(" `struct type' pretty-printer will be degraded") | |
737a160e | 98 | return |
14e75d8e | 99 | TYPE_FLAGS = [TypeFlag(field.name, field.enumval) |
a9ff5f12 | 100 | for field in iflags.fields()] |
737a160e JB |
101 | TYPE_FLAGS.sort() |
102 | ||
e76f78a0 | 103 | |
737a160e JB |
104 | class StructTypePrettyPrinter: |
105 | """Pretty-print an object of type struct type""" | |
e76f78a0 | 106 | |
737a160e JB |
107 | def __init__(self, val): |
108 | self.val = val | |
e76f78a0 | 109 | |
737a160e JB |
110 | def to_string(self): |
111 | fields = [] | |
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']) | |
115 | fields.append("instance_flags = %s" | |
4d0bcfcf | 116 | % TypeFlagsPrinter(self.val['m_instance_flags'])) |
737a160e JB |
117 | fields.append("length = %d" % self.val['length']) |
118 | fields.append("main_type = %s" % self.val['main_type']) | |
119 | return "\n{" + ",\n ".join(fields) + "}" | |
120 | ||
e76f78a0 | 121 | |
737a160e JB |
122 | class StructMainTypePrettyPrinter: |
123 | """Pretty-print an objet of type main_type""" | |
e76f78a0 | 124 | |
737a160e JB |
125 | def __init__(self, val): |
126 | self.val = val | |
e76f78a0 | 127 | |
737a160e JB |
128 | def flags_to_string(self): |
129 | """struct main_type contains a series of components that | |
130 | are one-bit ints whose name start with "flag_". For instance: | |
131 | flag_unsigned, flag_stub, etc. In essence, these components are | |
132 | really boolean flags, and this method prints a short synthetic | |
133 | version of the value of all these flags. For instance, if | |
134 | flag_unsigned and flag_static are the only components set to 1, | |
135 | this function will return "unsigned|static". | |
136 | """ | |
137 | fields = [field.name.replace("flag_", "") | |
138 | for field in self.val.type.fields() | |
e76f78a0 | 139 | if field.name.startswith("flag_") and self.val[field.name]] |
737a160e | 140 | return "|".join(fields) |
e76f78a0 | 141 | |
737a160e JB |
142 | def owner_to_string(self): |
143 | """Return an image of component "owner". | |
144 | """ | |
145 | if self.val['flag_objfile_owned'] != 0: | |
146 | return "%s (objfile)" % self.val['owner']['objfile'] | |
147 | else: | |
148 | return "%s (gdbarch)" % self.val['owner']['gdbarch'] | |
e76f78a0 | 149 | |
737a160e JB |
150 | def struct_field_location_img(self, field_val): |
151 | """Return an image of the loc component inside the given field | |
152 | gdb.Value. | |
153 | """ | |
154 | loc_val = field_val['loc'] | |
155 | loc_kind = str(field_val['loc_kind']) | |
156 | if loc_kind == "FIELD_LOC_KIND_BITPOS": | |
157 | return 'bitpos = %d' % loc_val['bitpos'] | |
14e75d8e JK |
158 | elif loc_kind == "FIELD_LOC_KIND_ENUMVAL": |
159 | return 'enumval = %d' % loc_val['enumval'] | |
737a160e JB |
160 | elif loc_kind == "FIELD_LOC_KIND_PHYSADDR": |
161 | return 'physaddr = 0x%x' % loc_val['physaddr'] | |
162 | elif loc_kind == "FIELD_LOC_KIND_PHYSNAME": | |
163 | return 'physname = %s' % loc_val['physname'] | |
8e3b41a9 JK |
164 | elif loc_kind == "FIELD_LOC_KIND_DWARF_BLOCK": |
165 | return 'dwarf_block = %s' % loc_val['dwarf_block'] | |
737a160e JB |
166 | else: |
167 | return 'loc = ??? (unsupported loc_kind value)' | |
e76f78a0 | 168 | |
737a160e JB |
169 | def struct_field_img(self, fieldno): |
170 | """Return an image of the main_type field number FIELDNO. | |
171 | """ | |
172 | f = self.val['flds_bnds']['fields'][fieldno] | |
f4859d94 | 173 | label = "flds_bnds.fields[%d]:" % fieldno |
737a160e JB |
174 | if f['artificial']: |
175 | label += " (artificial)" | |
176 | fields = [] | |
177 | fields.append("name = %s" % f['name']) | |
e51765f9 | 178 | fields.append("type = %s" % f['m_type']) |
737a160e JB |
179 | fields.append("loc_kind = %s" % f['loc_kind']) |
180 | fields.append("bitsize = %d" % f['bitsize']) | |
181 | fields.append(self.struct_field_location_img(f)) | |
182 | return label + "\n" + " {" + ",\n ".join(fields) + "}" | |
e76f78a0 | 183 | |
7f5331a8 JB |
184 | def bound_img(self, bound_name): |
185 | """Return an image of the given main_type's bound.""" | |
b66b4e65 HD |
186 | bounds = self.val['flds_bnds']['bounds'].dereference() |
187 | b = bounds[bound_name] | |
188 | bnd_kind = str(b['m_kind']) | |
7f5331a8 | 189 | if bnd_kind == 'PROP_CONST': |
b66b4e65 | 190 | return str(b['m_data']['const_val']) |
7f5331a8 JB |
191 | elif bnd_kind == 'PROP_UNDEFINED': |
192 | return '(undefined)' | |
193 | else: | |
194 | info = [bnd_kind] | |
b66b4e65 | 195 | if bound_name == 'high' and bounds['flag_upper_bound_is_count']: |
7f5331a8 | 196 | info.append('upper_bound_is_count') |
b66b4e65 | 197 | return '{} ({})'.format(str(b['m_data']['baton']), ','.join(info)) |
7f5331a8 | 198 | |
737a160e JB |
199 | def bounds_img(self): |
200 | """Return an image of the main_type bounds. | |
201 | """ | |
202 | b = self.val['flds_bnds']['bounds'].dereference() | |
7f5331a8 JB |
203 | low = self.bound_img('low') |
204 | high = self.bound_img('high') | |
205 | ||
206 | img = "flds_bnds.bounds = {%s, %s}" % (low, high) | |
207 | if b['flag_bound_evaluated']: | |
208 | img += ' [evaluated]' | |
209 | return img | |
e76f78a0 | 210 | |
c389c3dc JB |
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. | |
215 | """ | |
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": | |
223 | img = ("gnat_stuff = {descriptive_type = %s}" | |
224 | % type_specific['gnat_stuff']['descriptive_type']) | |
225 | elif type_specific_kind == "TYPE_SPECIFIC_FLOATFORMAT": | |
226 | img = "floatformat[0..1] = %s" % type_specific['floatformat'] | |
b6cdc2c1 | 227 | elif type_specific_kind == "TYPE_SPECIFIC_FUNC": |
c389c3dc | 228 | img = ("calling_convention = %d" |
b6cdc2c1 JK |
229 | % type_specific['func_stuff']['calling_convention']) |
230 | # tail_call_list is not printed. | |
09e2d7c7 DE |
231 | elif type_specific_kind == "TYPE_SPECIFIC_SELF_TYPE": |
232 | img = "self_type = %s" % type_specific['self_type'] | |
09584414 JB |
233 | elif type_specific_kind == "TYPE_SPECIFIC_FIXED_POINT": |
234 | # The scaling factor is an opaque structure, so we cannot | |
235 | # decode its value from Python (not without insider knowledge). | |
236 | img = ('scaling_factor: <opaque> (call __gmpz_dump with ' | |
237 | ' _mp_num and _mp_den fields if needed)') | |
c389c3dc JB |
238 | else: |
239 | img = ("type_specific = ??? (unknown type_secific_kind: %s)" | |
240 | % type_specific_kind) | |
241 | return img | |
242 | ||
737a160e JB |
243 | def to_string(self): |
244 | """Return a pretty-printed image of our main_type. | |
245 | """ | |
246 | fields = [] | |
247 | fields.append("name = %s" % self.val['name']) | |
737a160e JB |
248 | fields.append("code = %s" % self.val['code']) |
249 | fields.append("flags = [%s]" % self.flags_to_string()) | |
250 | fields.append("owner = %s" % self.owner_to_string()) | |
251 | fields.append("target_type = %s" % self.val['target_type']) | |
737a160e JB |
252 | if self.val['nfields'] > 0: |
253 | for fieldno in range(self.val['nfields']): | |
737a160e | 254 | fields.append(self.struct_field_img(fieldno)) |
64aa9731 | 255 | if self.val['code'] == gdb.TYPE_CODE_RANGE: |
737a160e | 256 | fields.append(self.bounds_img()) |
c389c3dc JB |
257 | fields.append(self.type_specific_img()) |
258 | ||
737a160e JB |
259 | return "\n{" + ",\n ".join(fields) + "}" |
260 | ||
9a14af7b SM |
261 | |
262 | class CoreAddrPrettyPrinter: | |
263 | """Print CORE_ADDR values as hex.""" | |
264 | ||
265 | def __init__(self, val): | |
266 | self._val = val | |
267 | ||
268 | def to_string(self): | |
269 | return hex(int(self._val)) | |
270 | ||
271 | ||
737a160e JB |
272 | def type_lookup_function(val): |
273 | """A routine that returns the correct pretty printer for VAL | |
274 | if appropriate. Returns None otherwise. | |
275 | """ | |
276 | if val.type.tag == "type": | |
277 | return StructTypePrettyPrinter(val) | |
278 | elif val.type.tag == "main_type": | |
279 | return StructMainTypePrettyPrinter(val) | |
9a14af7b SM |
280 | elif val.type.name == 'CORE_ADDR': |
281 | return CoreAddrPrettyPrinter(val) | |
737a160e JB |
282 | return None |
283 | ||
e76f78a0 | 284 | |
737a160e JB |
285 | def register_pretty_printer(objfile): |
286 | """A routine to register a pretty-printer against the given OBJFILE. | |
287 | """ | |
288 | objfile.pretty_printers.append(type_lookup_function) | |
289 | ||
e76f78a0 | 290 | |
737a160e JB |
291 | if __name__ == "__main__": |
292 | if gdb.current_objfile() is not None: | |
293 | # This is the case where this script is being "auto-loaded" | |
294 | # for a given objfile. Register the pretty-printer for that | |
295 | # objfile. | |
296 | register_pretty_printer(gdb.current_objfile()) | |
297 | else: | |
298 | # We need to locate the objfile corresponding to the GDB | |
299 | # executable, and register the pretty-printer for that objfile. | |
300 | # FIXME: The condition used to match the objfile is too simplistic | |
301 | # and will not work on Windows. | |
302 | for objfile in gdb.objfiles(): | |
303 | if os.path.basename(objfile.filename) == "gdb": | |
304 | objfile.pretty_printers.append(type_lookup_function) |