1 |
35 |
ultra_embe |
# GDB 'explore' command.
|
2 |
|
|
# Copyright (C) 2012 Free Software Foundation, Inc.
|
3 |
|
|
|
4 |
|
|
# This program is free software; you can redistribute it and/or modify
|
5 |
|
|
# it under the terms of the GNU General Public License as published by
|
6 |
|
|
# the Free Software Foundation; either version 3 of the License, or
|
7 |
|
|
# (at your option) any later version.
|
8 |
|
|
#
|
9 |
|
|
# This program is distributed in the hope that it will be useful,
|
10 |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12 |
|
|
# GNU General Public License for more details.
|
13 |
|
|
#
|
14 |
|
|
# You should have received a copy of the GNU General Public License
|
15 |
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16 |
|
|
|
17 |
|
|
"""Implementation of the GDB 'explore' command using the GDB Python API."""
|
18 |
|
|
|
19 |
|
|
import gdb
|
20 |
|
|
|
21 |
|
|
class Explorer(object):
|
22 |
|
|
"""Internal class which invokes other explorers."""
|
23 |
|
|
|
24 |
|
|
# This map is filled by the Explorer.init_env() function
|
25 |
|
|
type_code_to_explorer_map = { }
|
26 |
|
|
|
27 |
|
|
_SCALAR_TYPE_LIST = (
|
28 |
|
|
gdb.TYPE_CODE_CHAR,
|
29 |
|
|
gdb.TYPE_CODE_INT,
|
30 |
|
|
gdb.TYPE_CODE_BOOL,
|
31 |
|
|
gdb.TYPE_CODE_FLT,
|
32 |
|
|
gdb.TYPE_CODE_VOID,
|
33 |
|
|
gdb.TYPE_CODE_ENUM,
|
34 |
|
|
)
|
35 |
|
|
|
36 |
|
|
@staticmethod
|
37 |
|
|
def guard_expr(expr):
|
38 |
|
|
length = len(expr)
|
39 |
|
|
guard = False
|
40 |
|
|
|
41 |
|
|
if expr[0] == '(' and expr[length-1] == ')':
|
42 |
|
|
pass
|
43 |
|
|
else:
|
44 |
|
|
i = 0
|
45 |
|
|
while i < length:
|
46 |
|
|
c = expr[i]
|
47 |
|
|
if (c == '_' or ('a' <= c and c <= 'z') or
|
48 |
|
|
('A' <= c and c <= 'Z') or ('0' <= c and c <= '9')):
|
49 |
|
|
pass
|
50 |
|
|
else:
|
51 |
|
|
guard = True
|
52 |
|
|
break
|
53 |
|
|
i += 1
|
54 |
|
|
|
55 |
|
|
if guard:
|
56 |
|
|
return "(" + expr + ")"
|
57 |
|
|
else:
|
58 |
|
|
return expr
|
59 |
|
|
|
60 |
|
|
@staticmethod
|
61 |
|
|
def explore_expr(expr, value, is_child):
|
62 |
|
|
"""Main function to explore an expression value.
|
63 |
|
|
|
64 |
|
|
Arguments:
|
65 |
|
|
expr: The expression string that is being explored.
|
66 |
|
|
value: The gdb.Value value of the expression.
|
67 |
|
|
is_child: Boolean value to indicate if the expression is a child.
|
68 |
|
|
An expression is a child if it is derived from the main
|
69 |
|
|
expression entered by the user. For example, if the user
|
70 |
|
|
entered an expression which evaluates to a struct, then
|
71 |
|
|
when exploring the fields of the struct, is_child is set
|
72 |
|
|
to True internally.
|
73 |
|
|
|
74 |
|
|
Returns:
|
75 |
|
|
No return value.
|
76 |
|
|
"""
|
77 |
|
|
type_code = value.type.code
|
78 |
|
|
if type_code in Explorer.type_code_to_explorer_map:
|
79 |
|
|
explorer_class = Explorer.type_code_to_explorer_map[type_code]
|
80 |
|
|
while explorer_class.explore_expr(expr, value, is_child):
|
81 |
|
|
pass
|
82 |
|
|
else:
|
83 |
|
|
print ("Explorer for type '%s' not yet available.\n" %
|
84 |
|
|
str(value.type))
|
85 |
|
|
|
86 |
|
|
@staticmethod
|
87 |
|
|
def explore_type(name, datatype, is_child):
|
88 |
|
|
"""Main function to explore a data type.
|
89 |
|
|
|
90 |
|
|
Arguments:
|
91 |
|
|
name: The string representing the path to the data type being
|
92 |
|
|
explored.
|
93 |
|
|
datatype: The gdb.Type value of the data type being explored.
|
94 |
|
|
is_child: Boolean value to indicate if the name is a child.
|
95 |
|
|
A name is a child if it is derived from the main name
|
96 |
|
|
entered by the user. For example, if the user entered
|
97 |
|
|
the name of struct type, then when exploring the fields
|
98 |
|
|
of the struct, is_child is set to True internally.
|
99 |
|
|
|
100 |
|
|
Returns:
|
101 |
|
|
No return value.
|
102 |
|
|
"""
|
103 |
|
|
type_code = datatype.code
|
104 |
|
|
if type_code in Explorer.type_code_to_explorer_map:
|
105 |
|
|
explorer_class = Explorer.type_code_to_explorer_map[type_code]
|
106 |
|
|
while explorer_class.explore_type(name, datatype, is_child):
|
107 |
|
|
pass
|
108 |
|
|
else:
|
109 |
|
|
print ("Explorer for type '%s' not yet available.\n" %
|
110 |
|
|
str(datatype))
|
111 |
|
|
|
112 |
|
|
@staticmethod
|
113 |
|
|
def init_env():
|
114 |
|
|
"""Initializes the Explorer environment.
|
115 |
|
|
This function should be invoked before starting any exploration. If
|
116 |
|
|
invoked before an exploration, it need not be invoked for subsequent
|
117 |
|
|
explorations.
|
118 |
|
|
"""
|
119 |
|
|
Explorer.type_code_to_explorer_map = {
|
120 |
|
|
gdb.TYPE_CODE_CHAR : ScalarExplorer,
|
121 |
|
|
gdb.TYPE_CODE_INT : ScalarExplorer,
|
122 |
|
|
gdb.TYPE_CODE_BOOL : ScalarExplorer,
|
123 |
|
|
gdb.TYPE_CODE_FLT : ScalarExplorer,
|
124 |
|
|
gdb.TYPE_CODE_VOID : ScalarExplorer,
|
125 |
|
|
gdb.TYPE_CODE_ENUM : ScalarExplorer,
|
126 |
|
|
gdb.TYPE_CODE_STRUCT : CompoundExplorer,
|
127 |
|
|
gdb.TYPE_CODE_UNION : CompoundExplorer,
|
128 |
|
|
gdb.TYPE_CODE_PTR : PointerExplorer,
|
129 |
|
|
gdb.TYPE_CODE_REF : ReferenceExplorer,
|
130 |
|
|
gdb.TYPE_CODE_TYPEDEF : TypedefExplorer,
|
131 |
|
|
gdb.TYPE_CODE_ARRAY : ArrayExplorer
|
132 |
|
|
}
|
133 |
|
|
|
134 |
|
|
@staticmethod
|
135 |
|
|
def is_scalar_type(type):
|
136 |
|
|
"""Checks whether a type is a scalar type.
|
137 |
|
|
A type is a scalar type of its type is
|
138 |
|
|
gdb.TYPE_CODE_CHAR or
|
139 |
|
|
gdb.TYPE_CODE_INT or
|
140 |
|
|
gdb.TYPE_CODE_BOOL or
|
141 |
|
|
gdb.TYPE_CODE_FLT or
|
142 |
|
|
gdb.TYPE_CODE_VOID or
|
143 |
|
|
gdb.TYPE_CODE_ENUM.
|
144 |
|
|
|
145 |
|
|
Arguments:
|
146 |
|
|
type: The type to be checked.
|
147 |
|
|
|
148 |
|
|
Returns:
|
149 |
|
|
'True' if 'type' is a scalar type. 'False' otherwise.
|
150 |
|
|
"""
|
151 |
|
|
return type.code in Explorer._SCALAR_TYPE_LIST
|
152 |
|
|
|
153 |
|
|
@staticmethod
|
154 |
|
|
def return_to_parent_value():
|
155 |
|
|
"""A utility function which prints that the current exploration session
|
156 |
|
|
is returning to the parent value. Useful when exploring values.
|
157 |
|
|
"""
|
158 |
|
|
print "\nReturning to parent value...\n"
|
159 |
|
|
|
160 |
|
|
@staticmethod
|
161 |
|
|
def return_to_parent_value_prompt():
|
162 |
|
|
"""A utility function which prompts the user to press the 'enter' key
|
163 |
|
|
so that the exploration session can shift back to the parent value.
|
164 |
|
|
Useful when exploring values.
|
165 |
|
|
"""
|
166 |
|
|
raw_input("\nPress enter to return to parent value: ")
|
167 |
|
|
|
168 |
|
|
@staticmethod
|
169 |
|
|
def return_to_enclosing_type():
|
170 |
|
|
"""A utility function which prints that the current exploration session
|
171 |
|
|
is returning to the enclosing type. Useful when exploring types.
|
172 |
|
|
"""
|
173 |
|
|
print "\nReturning to enclosing type...\n"
|
174 |
|
|
|
175 |
|
|
@staticmethod
|
176 |
|
|
def return_to_enclosing_type_prompt():
|
177 |
|
|
"""A utility function which prompts the user to press the 'enter' key
|
178 |
|
|
so that the exploration session can shift back to the enclosing type.
|
179 |
|
|
Useful when exploring types.
|
180 |
|
|
"""
|
181 |
|
|
raw_input("\nPress enter to return to enclosing type: ")
|
182 |
|
|
|
183 |
|
|
|
184 |
|
|
class ScalarExplorer(object):
|
185 |
|
|
"""Internal class used to explore scalar values."""
|
186 |
|
|
|
187 |
|
|
@staticmethod
|
188 |
|
|
def explore_expr(expr, value, is_child):
|
189 |
|
|
"""Function to explore scalar values.
|
190 |
|
|
See Explorer.explore_expr and Explorer.is_scalar_type for more
|
191 |
|
|
information.
|
192 |
|
|
"""
|
193 |
|
|
print ("'%s' is a scalar value of type '%s'." %
|
194 |
|
|
(expr, value.type))
|
195 |
|
|
print "%s = %s" % (expr, str(value))
|
196 |
|
|
|
197 |
|
|
if is_child:
|
198 |
|
|
Explorer.return_to_parent_value_prompt()
|
199 |
|
|
Explorer.return_to_parent_value()
|
200 |
|
|
|
201 |
|
|
return False
|
202 |
|
|
|
203 |
|
|
@staticmethod
|
204 |
|
|
def explore_type(name, datatype, is_child):
|
205 |
|
|
"""Function to explore scalar types.
|
206 |
|
|
See Explorer.explore_type and Explorer.is_scalar_type for more
|
207 |
|
|
information.
|
208 |
|
|
"""
|
209 |
|
|
if datatype.code == gdb.TYPE_CODE_ENUM:
|
210 |
|
|
if is_child:
|
211 |
|
|
print ("%s is of an enumerated type '%s'." %
|
212 |
|
|
(name, str(datatype)))
|
213 |
|
|
else:
|
214 |
|
|
print "'%s' is an enumerated type." % name
|
215 |
|
|
else:
|
216 |
|
|
if is_child:
|
217 |
|
|
print ("%s is of a scalar type '%s'." %
|
218 |
|
|
(name, str(datatype)))
|
219 |
|
|
else:
|
220 |
|
|
print "'%s' is a scalar type." % name
|
221 |
|
|
|
222 |
|
|
if is_child:
|
223 |
|
|
Explorer.return_to_enclosing_type_prompt()
|
224 |
|
|
Explorer.return_to_enclosing_type()
|
225 |
|
|
|
226 |
|
|
return False
|
227 |
|
|
|
228 |
|
|
|
229 |
|
|
class PointerExplorer(object):
|
230 |
|
|
"""Internal class used to explore pointer values."""
|
231 |
|
|
|
232 |
|
|
@staticmethod
|
233 |
|
|
def explore_expr(expr, value, is_child):
|
234 |
|
|
"""Function to explore pointer values.
|
235 |
|
|
See Explorer.explore_expr for more information.
|
236 |
|
|
"""
|
237 |
|
|
print ("'%s' is a pointer to a value of type '%s'" %
|
238 |
|
|
(expr, str(value.type.target())))
|
239 |
|
|
option = raw_input("Continue exploring it as a pointer to a single "
|
240 |
|
|
"value [y/n]: ")
|
241 |
|
|
if option == "y":
|
242 |
|
|
deref_value = None
|
243 |
|
|
try:
|
244 |
|
|
deref_value = value.dereference()
|
245 |
|
|
str(deref_value)
|
246 |
|
|
except gdb.MemoryError:
|
247 |
|
|
print ("'%s' a pointer pointing to an invalid memory "
|
248 |
|
|
"location." % expr)
|
249 |
|
|
if is_child:
|
250 |
|
|
Explorer.return_to_parent_value_prompt()
|
251 |
|
|
return False
|
252 |
|
|
Explorer.explore_expr("*%s" % Explorer.guard_expr(expr),
|
253 |
|
|
deref_value, is_child)
|
254 |
|
|
return False
|
255 |
|
|
|
256 |
|
|
option = raw_input("Continue exploring it as a pointer to an "
|
257 |
|
|
"array [y/n]: ")
|
258 |
|
|
if option == "y":
|
259 |
|
|
while True:
|
260 |
|
|
index = 0
|
261 |
|
|
try:
|
262 |
|
|
index = int(raw_input("Enter the index of the element you "
|
263 |
|
|
"want to explore in '%s': " % expr))
|
264 |
|
|
except ValueError:
|
265 |
|
|
break
|
266 |
|
|
element_expr = "%s[%d]" % (Explorer.guard_expr(expr), index)
|
267 |
|
|
element = value[index]
|
268 |
|
|
try:
|
269 |
|
|
str(element)
|
270 |
|
|
except gdb.MemoryError:
|
271 |
|
|
print "Cannot read value at index %d." % index
|
272 |
|
|
continue
|
273 |
|
|
Explorer.explore_expr(element_expr, element, True)
|
274 |
|
|
return False
|
275 |
|
|
|
276 |
|
|
if is_child:
|
277 |
|
|
Explorer.return_to_parent_value()
|
278 |
|
|
return False
|
279 |
|
|
|
280 |
|
|
@staticmethod
|
281 |
|
|
def explore_type(name, datatype, is_child):
|
282 |
|
|
"""Function to explore pointer types.
|
283 |
|
|
See Explorer.explore_type for more information.
|
284 |
|
|
"""
|
285 |
|
|
target_type = datatype.target()
|
286 |
|
|
print ("\n%s is a pointer to a value of type '%s'." %
|
287 |
|
|
(name, str(target_type)))
|
288 |
|
|
|
289 |
|
|
Explorer.explore_type("the pointee type of %s" % name,
|
290 |
|
|
target_type,
|
291 |
|
|
is_child)
|
292 |
|
|
return False
|
293 |
|
|
|
294 |
|
|
|
295 |
|
|
class ReferenceExplorer(object):
|
296 |
|
|
"""Internal class used to explore reference (TYPE_CODE_REF) values."""
|
297 |
|
|
|
298 |
|
|
@staticmethod
|
299 |
|
|
def explore_expr(expr, value, is_child):
|
300 |
|
|
"""Function to explore array values.
|
301 |
|
|
See Explorer.explore_expr for more information.
|
302 |
|
|
"""
|
303 |
|
|
referenced_value = value.referenced_value()
|
304 |
|
|
Explorer.explore_expr(expr, referenced_value, is_child)
|
305 |
|
|
return False
|
306 |
|
|
|
307 |
|
|
@staticmethod
|
308 |
|
|
def explore_type(name, datatype, is_child):
|
309 |
|
|
"""Function to explore pointer types.
|
310 |
|
|
See Explorer.explore_type for more information.
|
311 |
|
|
"""
|
312 |
|
|
target_type = datatype.target()
|
313 |
|
|
Explorer.explore_type(name, target_type, is_child)
|
314 |
|
|
return False
|
315 |
|
|
|
316 |
|
|
|
317 |
|
|
class ArrayExplorer(object):
|
318 |
|
|
"""Internal class used to explore arrays."""
|
319 |
|
|
|
320 |
|
|
@staticmethod
|
321 |
|
|
def explore_expr(expr, value, is_child):
|
322 |
|
|
"""Function to explore array values.
|
323 |
|
|
See Explorer.explore_expr for more information.
|
324 |
|
|
"""
|
325 |
|
|
target_type = value.type.target()
|
326 |
|
|
print ("'%s' is an array of '%s'." % (expr, str(target_type)))
|
327 |
|
|
index = 0
|
328 |
|
|
try:
|
329 |
|
|
index = int(raw_input("Enter the index of the element you want to "
|
330 |
|
|
"explore in '%s': " % expr))
|
331 |
|
|
except ValueError:
|
332 |
|
|
if is_child:
|
333 |
|
|
Explorer.return_to_parent_value()
|
334 |
|
|
return False
|
335 |
|
|
|
336 |
|
|
element = None
|
337 |
|
|
try:
|
338 |
|
|
element = value[index]
|
339 |
|
|
str(element)
|
340 |
|
|
except gdb.MemoryError:
|
341 |
|
|
print "Cannot read value at index %d." % index
|
342 |
|
|
raw_input("Press enter to continue... ")
|
343 |
|
|
return True
|
344 |
|
|
|
345 |
|
|
Explorer.explore_expr("%s[%d]" % (Explorer.guard_expr(expr), index),
|
346 |
|
|
element, True)
|
347 |
|
|
return True
|
348 |
|
|
|
349 |
|
|
@staticmethod
|
350 |
|
|
def explore_type(name, datatype, is_child):
|
351 |
|
|
"""Function to explore array types.
|
352 |
|
|
See Explorer.explore_type for more information.
|
353 |
|
|
"""
|
354 |
|
|
target_type = datatype.target()
|
355 |
|
|
print "%s is an array of '%s'." % (name, str(target_type))
|
356 |
|
|
|
357 |
|
|
Explorer.explore_type("the array element of %s" % name, target_type,
|
358 |
|
|
is_child)
|
359 |
|
|
return False
|
360 |
|
|
|
361 |
|
|
|
362 |
|
|
class CompoundExplorer(object):
|
363 |
|
|
"""Internal class used to explore struct, classes and unions."""
|
364 |
|
|
|
365 |
|
|
@staticmethod
|
366 |
|
|
def _print_fields(print_list):
|
367 |
|
|
"""Internal function which prints the fields of a struct/class/union.
|
368 |
|
|
"""
|
369 |
|
|
max_field_name_length = 0
|
370 |
|
|
for pair in print_list:
|
371 |
|
|
if max_field_name_length < len(pair[0]):
|
372 |
|
|
max_field_name_length = len(pair[0])
|
373 |
|
|
|
374 |
|
|
format_str = " {0:>%d} = {1}" % max_field_name_length
|
375 |
|
|
for pair in print_list:
|
376 |
|
|
print format_str.format(pair[0], pair[1])
|
377 |
|
|
|
378 |
|
|
@staticmethod
|
379 |
|
|
def _get_real_field_count(fields):
|
380 |
|
|
real_field_count = 0;
|
381 |
|
|
for field in fields:
|
382 |
|
|
if not field.artificial:
|
383 |
|
|
real_field_count = real_field_count + 1
|
384 |
|
|
|
385 |
|
|
return real_field_count
|
386 |
|
|
|
387 |
|
|
@staticmethod
|
388 |
|
|
def explore_expr(expr, value, is_child):
|
389 |
|
|
"""Function to explore structs/classes and union values.
|
390 |
|
|
See Explorer.explore_expr for more information.
|
391 |
|
|
"""
|
392 |
|
|
datatype = value.type
|
393 |
|
|
type_code = datatype.code
|
394 |
|
|
fields = datatype.fields()
|
395 |
|
|
|
396 |
|
|
if type_code == gdb.TYPE_CODE_STRUCT:
|
397 |
|
|
type_desc = "struct/class"
|
398 |
|
|
else:
|
399 |
|
|
type_desc = "union"
|
400 |
|
|
|
401 |
|
|
if CompoundExplorer._get_real_field_count(fields) == 0:
|
402 |
|
|
print ("The value of '%s' is a %s of type '%s' with no fields." %
|
403 |
|
|
(expr, type_desc, str(value.type)))
|
404 |
|
|
if is_child:
|
405 |
|
|
Explorer.return_to_parent_value_prompt()
|
406 |
|
|
return False
|
407 |
|
|
|
408 |
|
|
print ("The value of '%s' is a %s of type '%s' with the following "
|
409 |
|
|
"fields:\n" % (expr, type_desc, str(value.type)))
|
410 |
|
|
|
411 |
|
|
has_explorable_fields = False
|
412 |
|
|
choice_to_compound_field_map = { }
|
413 |
|
|
current_choice = 0
|
414 |
|
|
print_list = [ ]
|
415 |
|
|
for field in fields:
|
416 |
|
|
if field.artificial:
|
417 |
|
|
continue
|
418 |
|
|
field_full_name = Explorer.guard_expr(expr) + "." + field.name
|
419 |
|
|
if field.is_base_class:
|
420 |
|
|
field_value = value.cast(field.type)
|
421 |
|
|
else:
|
422 |
|
|
field_value = value[field.name]
|
423 |
|
|
literal_value = ""
|
424 |
|
|
if type_code == gdb.TYPE_CODE_UNION:
|
425 |
|
|
literal_value = ("<Enter %d to explore this field of type "
|
426 |
|
|
"'%s'>" % (current_choice, str(field.type)))
|
427 |
|
|
has_explorable_fields = True
|
428 |
|
|
else:
|
429 |
|
|
if Explorer.is_scalar_type(field.type):
|
430 |
|
|
literal_value = ("%s .. (Value of type '%s')" %
|
431 |
|
|
(str(field_value), str(field.type)))
|
432 |
|
|
else:
|
433 |
|
|
if field.is_base_class:
|
434 |
|
|
field_desc = "base class"
|
435 |
|
|
else:
|
436 |
|
|
field_desc = "field"
|
437 |
|
|
literal_value = ("<Enter %d to explore this %s of type "
|
438 |
|
|
"'%s'>" %
|
439 |
|
|
(current_choice, field_desc,
|
440 |
|
|
str(field.type)))
|
441 |
|
|
has_explorable_fields = True
|
442 |
|
|
|
443 |
|
|
choice_to_compound_field_map[str(current_choice)] = (
|
444 |
|
|
field_full_name, field_value)
|
445 |
|
|
current_choice = current_choice + 1
|
446 |
|
|
|
447 |
|
|
print_list.append((field.name, literal_value))
|
448 |
|
|
|
449 |
|
|
CompoundExplorer._print_fields(print_list)
|
450 |
|
|
print ""
|
451 |
|
|
|
452 |
|
|
if has_explorable_fields:
|
453 |
|
|
choice = raw_input("Enter the field number of choice: ")
|
454 |
|
|
if choice in choice_to_compound_field_map:
|
455 |
|
|
Explorer.explore_expr(choice_to_compound_field_map[choice][0],
|
456 |
|
|
choice_to_compound_field_map[choice][1],
|
457 |
|
|
True)
|
458 |
|
|
return True
|
459 |
|
|
else:
|
460 |
|
|
if is_child:
|
461 |
|
|
Explorer.returning_to_parent_value_message()
|
462 |
|
|
else:
|
463 |
|
|
if is_child:
|
464 |
|
|
Explorer.return_to_parent_value_prompt()
|
465 |
|
|
|
466 |
|
|
return False
|
467 |
|
|
|
468 |
|
|
@staticmethod
|
469 |
|
|
def explore_type(name, datatype, is_child):
|
470 |
|
|
"""Function to explore struct/class and union types.
|
471 |
|
|
See Explorer.explore_type for more information.
|
472 |
|
|
"""
|
473 |
|
|
type_code = datatype.code
|
474 |
|
|
type_desc = ""
|
475 |
|
|
if type_code == gdb.TYPE_CODE_STRUCT:
|
476 |
|
|
type_desc = "struct/class"
|
477 |
|
|
else:
|
478 |
|
|
type_desc = "union"
|
479 |
|
|
|
480 |
|
|
fields = datatype.fields()
|
481 |
|
|
if CompoundExplorer._get_real_field_count(fields) == 0:
|
482 |
|
|
if is_child:
|
483 |
|
|
print ("%s is a %s of type '%s' with no fields." %
|
484 |
|
|
(name, type_desc, str(datatype)))
|
485 |
|
|
Explorer.return_to_enclosing_type_prompt()
|
486 |
|
|
else:
|
487 |
|
|
print "'%s' is a %s with no fields." % (name, type_desc)
|
488 |
|
|
return False
|
489 |
|
|
|
490 |
|
|
if is_child:
|
491 |
|
|
print ("%s is a %s of type '%s' "
|
492 |
|
|
"with the following fields:\n" %
|
493 |
|
|
(name, type_desc, str(datatype)))
|
494 |
|
|
else:
|
495 |
|
|
print ("'%s' is a %s with the following "
|
496 |
|
|
"fields:\n" %
|
497 |
|
|
(name, type_desc))
|
498 |
|
|
|
499 |
|
|
has_explorable_fields = False
|
500 |
|
|
current_choice = 0
|
501 |
|
|
choice_to_compound_field_map = { }
|
502 |
|
|
print_list = [ ]
|
503 |
|
|
for field in fields:
|
504 |
|
|
if field.artificial:
|
505 |
|
|
continue
|
506 |
|
|
if field.is_base_class:
|
507 |
|
|
field_desc = "base class"
|
508 |
|
|
else:
|
509 |
|
|
field_desc = "field"
|
510 |
|
|
rhs = ("<Enter %d to explore this %s of type '%s'>" %
|
511 |
|
|
(current_choice, field_desc, str(field.type)))
|
512 |
|
|
print_list.append((field.name, rhs))
|
513 |
|
|
choice_to_compound_field_map[str(current_choice)] = (
|
514 |
|
|
field.name, field.type, field_desc)
|
515 |
|
|
current_choice = current_choice + 1
|
516 |
|
|
|
517 |
|
|
CompoundExplorer._print_fields(print_list)
|
518 |
|
|
print ""
|
519 |
|
|
|
520 |
|
|
if len(choice_to_compound_field_map) > 0:
|
521 |
|
|
choice = raw_input("Enter the field number of choice: ")
|
522 |
|
|
if choice in choice_to_compound_field_map:
|
523 |
|
|
if is_child:
|
524 |
|
|
new_name = ("%s '%s' of %s" %
|
525 |
|
|
(choice_to_compound_field_map[choice][2],
|
526 |
|
|
choice_to_compound_field_map[choice][0],
|
527 |
|
|
name))
|
528 |
|
|
else:
|
529 |
|
|
new_name = ("%s '%s' of '%s'" %
|
530 |
|
|
(choice_to_compound_field_map[choice][2],
|
531 |
|
|
choice_to_compound_field_map[choice][0],
|
532 |
|
|
name))
|
533 |
|
|
Explorer.explore_type(new_name,
|
534 |
|
|
choice_to_compound_field_map[choice][1], True)
|
535 |
|
|
return True
|
536 |
|
|
else:
|
537 |
|
|
if is_child:
|
538 |
|
|
Explorer.return_to_enclosing_type()
|
539 |
|
|
else:
|
540 |
|
|
if is_child:
|
541 |
|
|
Explorer.return_to_enclosing_type_prompt()
|
542 |
|
|
|
543 |
|
|
return False
|
544 |
|
|
|
545 |
|
|
|
546 |
|
|
class TypedefExplorer(object):
|
547 |
|
|
"""Internal class used to explore values whose type is a typedef."""
|
548 |
|
|
|
549 |
|
|
@staticmethod
|
550 |
|
|
def explore_expr(expr, value, is_child):
|
551 |
|
|
"""Function to explore typedef values.
|
552 |
|
|
See Explorer.explore_expr for more information.
|
553 |
|
|
"""
|
554 |
|
|
actual_type = value.type.strip_typedefs()
|
555 |
|
|
print ("The value of '%s' is of type '%s' "
|
556 |
|
|
"which is a typedef of type '%s'" %
|
557 |
|
|
(expr, str(value.type), str(actual_type)))
|
558 |
|
|
|
559 |
|
|
Explorer.explore_expr(expr, value.cast(actual_type), is_child)
|
560 |
|
|
return False
|
561 |
|
|
|
562 |
|
|
@staticmethod
|
563 |
|
|
def explore_type(name, datatype, is_child):
|
564 |
|
|
"""Function to explore typedef types.
|
565 |
|
|
See Explorer.explore_type for more information.
|
566 |
|
|
"""
|
567 |
|
|
actual_type = datatype.strip_typedefs()
|
568 |
|
|
if is_child:
|
569 |
|
|
print ("The type of %s is a typedef of type '%s'." %
|
570 |
|
|
(name, str(actual_type)))
|
571 |
|
|
else:
|
572 |
|
|
print ("The type '%s' is a typedef of type '%s'." %
|
573 |
|
|
(name, str(actual_type)))
|
574 |
|
|
|
575 |
|
|
Explorer.explore_type(name, actual_type, is_child)
|
576 |
|
|
return False
|
577 |
|
|
|
578 |
|
|
|
579 |
|
|
class ExploreUtils(object):
|
580 |
|
|
"""Internal class which provides utilities for the main command classes."""
|
581 |
|
|
|
582 |
|
|
@staticmethod
|
583 |
|
|
def check_args(name, arg_str):
|
584 |
|
|
"""Utility to check if adequate number of arguments are passed to an
|
585 |
|
|
explore command.
|
586 |
|
|
|
587 |
|
|
Arguments:
|
588 |
|
|
name: The name of the explore command.
|
589 |
|
|
arg_str: The argument string passed to the explore command.
|
590 |
|
|
|
591 |
|
|
Returns:
|
592 |
|
|
True if adequate arguments are passed, false otherwise.
|
593 |
|
|
|
594 |
|
|
Raises:
|
595 |
|
|
gdb.GdbError if adequate arguments are not passed.
|
596 |
|
|
"""
|
597 |
|
|
if len(arg_str) < 1:
|
598 |
|
|
raise gdb.GdbError("ERROR: '%s' requires an argument."
|
599 |
|
|
% name)
|
600 |
|
|
return False
|
601 |
|
|
else:
|
602 |
|
|
return True
|
603 |
|
|
|
604 |
|
|
@staticmethod
|
605 |
|
|
def get_type_from_str(type_str):
|
606 |
|
|
"""A utility function to deduce the gdb.Type value from a string
|
607 |
|
|
representing the type.
|
608 |
|
|
|
609 |
|
|
Arguments:
|
610 |
|
|
type_str: The type string from which the gdb.Type value should be
|
611 |
|
|
deduced.
|
612 |
|
|
|
613 |
|
|
Returns:
|
614 |
|
|
The deduced gdb.Type value if possible, None otherwise.
|
615 |
|
|
"""
|
616 |
|
|
try:
|
617 |
|
|
# Assume the current language to be C/C++ and make a try.
|
618 |
|
|
return gdb.parse_and_eval("(%s *)0" % type_str).type.target()
|
619 |
|
|
except RuntimeError:
|
620 |
|
|
# If assumption of current language to be C/C++ was wrong, then
|
621 |
|
|
# lookup the type using the API.
|
622 |
|
|
try:
|
623 |
|
|
return gdb.lookup_type(type_str)
|
624 |
|
|
except RuntimeError:
|
625 |
|
|
return None
|
626 |
|
|
|
627 |
|
|
@staticmethod
|
628 |
|
|
def get_value_from_str(value_str):
|
629 |
|
|
"""A utility function to deduce the gdb.Value value from a string
|
630 |
|
|
representing the value.
|
631 |
|
|
|
632 |
|
|
Arguments:
|
633 |
|
|
value_str: The value string from which the gdb.Value value should
|
634 |
|
|
be deduced.
|
635 |
|
|
|
636 |
|
|
Returns:
|
637 |
|
|
The deduced gdb.Value value if possible, None otherwise.
|
638 |
|
|
"""
|
639 |
|
|
try:
|
640 |
|
|
return gdb.parse_and_eval(value_str)
|
641 |
|
|
except RuntimeError:
|
642 |
|
|
return None
|
643 |
|
|
|
644 |
|
|
|
645 |
|
|
class ExploreCommand(gdb.Command):
|
646 |
|
|
"""Explore a value or a type valid in the current context.
|
647 |
|
|
|
648 |
|
|
Usage:
|
649 |
|
|
|
650 |
|
|
explore ARG
|
651 |
|
|
|
652 |
|
|
- ARG is either a valid expression or a type name.
|
653 |
|
|
- At any stage of exploration, hit the return key (instead of a
|
654 |
|
|
choice, if any) to return to the enclosing type or value.
|
655 |
|
|
"""
|
656 |
|
|
|
657 |
|
|
def __init__(self):
|
658 |
|
|
super(ExploreCommand, self).__init__(name = "explore",
|
659 |
|
|
command_class = gdb.COMMAND_DATA,
|
660 |
|
|
prefix = True)
|
661 |
|
|
|
662 |
|
|
def invoke(self, arg_str, from_tty):
|
663 |
|
|
if ExploreUtils.check_args("explore", arg_str) == False:
|
664 |
|
|
return
|
665 |
|
|
|
666 |
|
|
# Check if it is a value
|
667 |
|
|
value = ExploreUtils.get_value_from_str(arg_str)
|
668 |
|
|
if value is not None:
|
669 |
|
|
Explorer.explore_expr(arg_str, value, False)
|
670 |
|
|
return
|
671 |
|
|
|
672 |
|
|
# If it is not a value, check if it is a type
|
673 |
|
|
datatype = ExploreUtils.get_type_from_str(arg_str)
|
674 |
|
|
if datatype is not None:
|
675 |
|
|
Explorer.explore_type(arg_str, datatype, False)
|
676 |
|
|
return
|
677 |
|
|
|
678 |
|
|
# If it is neither a value nor a type, raise an error.
|
679 |
|
|
raise gdb.GdbError(
|
680 |
|
|
("'%s' neither evaluates to a value nor is a type "
|
681 |
|
|
"in the current context." %
|
682 |
|
|
arg_str))
|
683 |
|
|
|
684 |
|
|
|
685 |
|
|
class ExploreValueCommand(gdb.Command):
|
686 |
|
|
"""Explore value of an expression valid in the current context.
|
687 |
|
|
|
688 |
|
|
Usage:
|
689 |
|
|
|
690 |
|
|
explore value ARG
|
691 |
|
|
|
692 |
|
|
- ARG is a valid expression.
|
693 |
|
|
- At any stage of exploration, hit the return key (instead of a
|
694 |
|
|
choice, if any) to return to the enclosing value.
|
695 |
|
|
"""
|
696 |
|
|
|
697 |
|
|
def __init__(self):
|
698 |
|
|
super(ExploreValueCommand, self).__init__(
|
699 |
|
|
name = "explore value", command_class = gdb.COMMAND_DATA)
|
700 |
|
|
|
701 |
|
|
def invoke(self, arg_str, from_tty):
|
702 |
|
|
if ExploreUtils.check_args("explore value", arg_str) == False:
|
703 |
|
|
return
|
704 |
|
|
|
705 |
|
|
value = ExploreUtils.get_value_from_str(arg_str)
|
706 |
|
|
if value is None:
|
707 |
|
|
raise gdb.GdbError(
|
708 |
|
|
(" '%s' does not evaluate to a value in the current "
|
709 |
|
|
"context." %
|
710 |
|
|
arg_str))
|
711 |
|
|
return
|
712 |
|
|
|
713 |
|
|
Explorer.explore_expr(arg_str, value, False)
|
714 |
|
|
|
715 |
|
|
|
716 |
|
|
class ExploreTypeCommand(gdb.Command):
|
717 |
|
|
"""Explore a type or the type of an expression valid in the current
|
718 |
|
|
context.
|
719 |
|
|
|
720 |
|
|
Usage:
|
721 |
|
|
|
722 |
|
|
explore type ARG
|
723 |
|
|
|
724 |
|
|
- ARG is a valid expression or a type name.
|
725 |
|
|
- At any stage of exploration, hit the return key (instead of a
|
726 |
|
|
choice, if any) to return to the enclosing type.
|
727 |
|
|
"""
|
728 |
|
|
|
729 |
|
|
def __init__(self):
|
730 |
|
|
super(ExploreTypeCommand, self).__init__(
|
731 |
|
|
name = "explore type", command_class = gdb.COMMAND_DATA)
|
732 |
|
|
|
733 |
|
|
def invoke(self, arg_str, from_tty):
|
734 |
|
|
if ExploreUtils.check_args("explore type", arg_str) == False:
|
735 |
|
|
return
|
736 |
|
|
|
737 |
|
|
datatype = ExploreUtils.get_type_from_str(arg_str)
|
738 |
|
|
if datatype is not None:
|
739 |
|
|
Explorer.explore_type(arg_str, datatype, False)
|
740 |
|
|
return
|
741 |
|
|
|
742 |
|
|
value = ExploreUtils.get_value_from_str(arg_str)
|
743 |
|
|
if value is not None:
|
744 |
|
|
print "'%s' is of type '%s'." % (arg_str, str(value.type))
|
745 |
|
|
Explorer.explore_type(str(value.type), value.type, False)
|
746 |
|
|
|
747 |
|
|
raise gdb.GdbError(("'%s' is not a type or value in the current "
|
748 |
|
|
"context." % arg_str))
|
749 |
|
|
|
750 |
|
|
|
751 |
|
|
Explorer.init_env()
|
752 |
|
|
|
753 |
|
|
ExploreCommand()
|
754 |
|
|
ExploreValueCommand()
|
755 |
|
|
ExploreTypeCommand()
|