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