2012-04-02 Siva Chandra Reddy <sivachandra@google.com>
New command 'explore' which helps explore values and types in scope. * NEWS: Add an entry about the new 'explore' command. * data-directory/Makefile.in: Add gdb/command/explore.py * python/lib/gdb/command/explore.py: Implemention of the 'explore' command using the GDB Python API. * doc/gdb.texinfo (Examining Data): Document the 'explore' command. * testsuite/gdb.python/Makefile.in: Add py-explore to EXECUTABLES. * testsuite/gdb.python/py-explore.c: C program used for testing the new 'explore' command on C constructs. * testsuite/gdb.python/py-explore.cc: C++ program used for testing the new 'explore' command on C++ constructs. * testsuite/gdb-python/py-explore.exp: Tests for the new 'explore' command on C constructs. * testsuite/gdb-python/py-explore-cc.exp: Tests for the new 'explore' command on C++ constructs.
This commit is contained in:
parent
1cd470df20
commit
06fc020f10
12 changed files with 1688 additions and 2 deletions
755
gdb/python/lib/gdb/command/explore.py
Normal file
755
gdb/python/lib/gdb/command/explore.py
Normal file
|
@ -0,0 +1,755 @@
|
|||
# GDB 'explore' command.
|
||||
# Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Implementation of the GDB 'explore' command using the GDB Python API."""
|
||||
|
||||
import gdb
|
||||
|
||||
class Explorer(object):
|
||||
"""Internal class which invokes other explorers."""
|
||||
|
||||
# This map is filled by the Explorer.init_env() function
|
||||
type_code_to_explorer_map = { }
|
||||
|
||||
_SCALAR_TYPE_LIST = (
|
||||
gdb.TYPE_CODE_CHAR,
|
||||
gdb.TYPE_CODE_INT,
|
||||
gdb.TYPE_CODE_BOOL,
|
||||
gdb.TYPE_CODE_FLT,
|
||||
gdb.TYPE_CODE_VOID,
|
||||
gdb.TYPE_CODE_ENUM,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def guard_expr(expr):
|
||||
length = len(expr)
|
||||
guard = False
|
||||
|
||||
if expr[0] == '(' and expr[length-1] == ')':
|
||||
pass
|
||||
else:
|
||||
i = 0
|
||||
while i < length:
|
||||
c = expr[i]
|
||||
if (c == '_' or ('a' <= c and c <= 'z') or
|
||||
('A' <= c and c <= 'Z') or ('0' <= c and c <= '9')):
|
||||
pass
|
||||
else:
|
||||
guard = True
|
||||
break
|
||||
i += 1
|
||||
|
||||
if guard:
|
||||
return "(" + expr + ")"
|
||||
else:
|
||||
return expr
|
||||
|
||||
@staticmethod
|
||||
def explore_expr(expr, value, is_child):
|
||||
"""Main function to explore an expression value.
|
||||
|
||||
Arguments:
|
||||
expr: The expression string that is being explored.
|
||||
value: The gdb.Value value of the expression.
|
||||
is_child: Boolean value to indicate if the expression is a child.
|
||||
An expression is a child if it is derived from the main
|
||||
expression entered by the user. For example, if the user
|
||||
entered an expression which evaluates to a struct, then
|
||||
when exploring the fields of the struct, is_child is set
|
||||
to True internally.
|
||||
|
||||
Returns:
|
||||
No return value.
|
||||
"""
|
||||
type_code = value.type.code
|
||||
if type_code in Explorer.type_code_to_explorer_map:
|
||||
explorer_class = Explorer.type_code_to_explorer_map[type_code]
|
||||
while explorer_class.explore_expr(expr, value, is_child):
|
||||
pass
|
||||
else:
|
||||
print ("Explorer for type '%s' not yet available.\n" %
|
||||
str(value.type))
|
||||
|
||||
@staticmethod
|
||||
def explore_type(name, datatype, is_child):
|
||||
"""Main function to explore a data type.
|
||||
|
||||
Arguments:
|
||||
name: The string representing the path to the data type being
|
||||
explored.
|
||||
datatype: The gdb.Type value of the data type being explored.
|
||||
is_child: Boolean value to indicate if the name is a child.
|
||||
A name is a child if it is derived from the main name
|
||||
entered by the user. For example, if the user entered
|
||||
the name of struct type, then when exploring the fields
|
||||
of the struct, is_child is set to True internally.
|
||||
|
||||
Returns:
|
||||
No return value.
|
||||
"""
|
||||
type_code = datatype.code
|
||||
if type_code in Explorer.type_code_to_explorer_map:
|
||||
explorer_class = Explorer.type_code_to_explorer_map[type_code]
|
||||
while explorer_class.explore_type(name, datatype, is_child):
|
||||
pass
|
||||
else:
|
||||
print ("Explorer for type '%s' not yet available.\n" %
|
||||
str(datatype))
|
||||
|
||||
@staticmethod
|
||||
def init_env():
|
||||
"""Initializes the Explorer environment.
|
||||
This function should be invoked before starting any exploration. If
|
||||
invoked before an exploration, it need not be invoked for subsequent
|
||||
explorations.
|
||||
"""
|
||||
Explorer.type_code_to_explorer_map = {
|
||||
gdb.TYPE_CODE_CHAR : ScalarExplorer,
|
||||
gdb.TYPE_CODE_INT : ScalarExplorer,
|
||||
gdb.TYPE_CODE_BOOL : ScalarExplorer,
|
||||
gdb.TYPE_CODE_FLT : ScalarExplorer,
|
||||
gdb.TYPE_CODE_VOID : ScalarExplorer,
|
||||
gdb.TYPE_CODE_ENUM : ScalarExplorer,
|
||||
gdb.TYPE_CODE_STRUCT : CompoundExplorer,
|
||||
gdb.TYPE_CODE_UNION : CompoundExplorer,
|
||||
gdb.TYPE_CODE_PTR : PointerExplorer,
|
||||
gdb.TYPE_CODE_REF : ReferenceExplorer,
|
||||
gdb.TYPE_CODE_TYPEDEF : TypedefExplorer,
|
||||
gdb.TYPE_CODE_ARRAY : ArrayExplorer
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def is_scalar_type(type):
|
||||
"""Checks whether a type is a scalar type.
|
||||
A type is a scalar type of its type is
|
||||
gdb.TYPE_CODE_CHAR or
|
||||
gdb.TYPE_CODE_INT or
|
||||
gdb.TYPE_CODE_BOOL or
|
||||
gdb.TYPE_CODE_FLT or
|
||||
gdb.TYPE_CODE_VOID or
|
||||
gdb.TYPE_CODE_ENUM.
|
||||
|
||||
Arguments:
|
||||
type: The type to be checked.
|
||||
|
||||
Returns:
|
||||
'True' if 'type' is a scalar type. 'False' otherwise.
|
||||
"""
|
||||
return type.code in Explorer._SCALAR_TYPE_LIST
|
||||
|
||||
@staticmethod
|
||||
def return_to_parent_value():
|
||||
"""A utility function which prints that the current exploration session
|
||||
is returning to the parent value. Useful when exploring values.
|
||||
"""
|
||||
print "\nReturning to parent value...\n"
|
||||
|
||||
@staticmethod
|
||||
def return_to_parent_value_prompt():
|
||||
"""A utility function which prompts the user to press the 'enter' key
|
||||
so that the exploration session can shift back to the parent value.
|
||||
Useful when exploring values.
|
||||
"""
|
||||
raw_input("\nPress enter to return to parent value: ")
|
||||
|
||||
@staticmethod
|
||||
def return_to_enclosing_type():
|
||||
"""A utility function which prints that the current exploration session
|
||||
is returning to the enclosing type. Useful when exploring types.
|
||||
"""
|
||||
print "\nReturning to enclosing type...\n"
|
||||
|
||||
@staticmethod
|
||||
def return_to_enclosing_type_prompt():
|
||||
"""A utility function which prompts the user to press the 'enter' key
|
||||
so that the exploration session can shift back to the enclosing type.
|
||||
Useful when exploring types.
|
||||
"""
|
||||
raw_input("\nPress enter to return to enclosing type: ")
|
||||
|
||||
|
||||
class ScalarExplorer(object):
|
||||
"""Internal class used to explore scalar values."""
|
||||
|
||||
@staticmethod
|
||||
def explore_expr(expr, value, is_child):
|
||||
"""Function to explore scalar values.
|
||||
See Explorer.explore_expr and Explorer.is_scalar_type for more
|
||||
information.
|
||||
"""
|
||||
print ("'%s' is a scalar value of type '%s'." %
|
||||
(expr, value.type))
|
||||
print "%s = %s" % (expr, str(value))
|
||||
|
||||
if is_child:
|
||||
Explorer.return_to_parent_value_prompt()
|
||||
Explorer.return_to_parent_value()
|
||||
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def explore_type(name, datatype, is_child):
|
||||
"""Function to explore scalar types.
|
||||
See Explorer.explore_type and Explorer.is_scalar_type for more
|
||||
information.
|
||||
"""
|
||||
if datatype.code == gdb.TYPE_CODE_ENUM:
|
||||
if is_child:
|
||||
print ("%s is of an enumerated type '%s'." %
|
||||
(name, str(datatype)))
|
||||
else:
|
||||
print "'%s' is an enumerated type." % name
|
||||
else:
|
||||
if is_child:
|
||||
print ("%s is of a scalar type '%s'." %
|
||||
(name, str(datatype)))
|
||||
else:
|
||||
print "'%s' is a scalar type." % name
|
||||
|
||||
if is_child:
|
||||
Explorer.return_to_enclosing_type_prompt()
|
||||
Explorer.return_to_enclosing_type()
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class PointerExplorer(object):
|
||||
"""Internal class used to explore pointer values."""
|
||||
|
||||
@staticmethod
|
||||
def explore_expr(expr, value, is_child):
|
||||
"""Function to explore pointer values.
|
||||
See Explorer.explore_expr for more information.
|
||||
"""
|
||||
print ("'%s' is a pointer to a value of type '%s'" %
|
||||
(expr, str(value.type.target())))
|
||||
option = raw_input("Continue exploring it as a pointer to a single "
|
||||
"value [y/n]: ")
|
||||
if option == "y":
|
||||
deref_value = None
|
||||
try:
|
||||
deref_value = value.dereference()
|
||||
str(deref_value)
|
||||
except gdb.MemoryError:
|
||||
print ("'%s' a pointer pointing to an invalid memory "
|
||||
"location." % expr)
|
||||
if is_child:
|
||||
Explorer.return_to_parent_value_prompt()
|
||||
return False
|
||||
Explorer.explore_expr("*%s" % Explorer.guard_expr(expr),
|
||||
deref_value, is_child)
|
||||
return False
|
||||
|
||||
option = raw_input("Continue exploring it as a pointer to an "
|
||||
"array [y/n]: ")
|
||||
if option == "y":
|
||||
while True:
|
||||
index = 0
|
||||
try:
|
||||
index = int(raw_input("Enter the index of the element you "
|
||||
"want to explore in '%s': " % expr))
|
||||
except ValueError:
|
||||
break
|
||||
element_expr = "%s[%d]" % (Explorer.guard_expr(expr), index)
|
||||
element = value[index]
|
||||
try:
|
||||
str(element)
|
||||
except gdb.MemoryError:
|
||||
print "Cannot read value at index %d." % index
|
||||
continue
|
||||
Explorer.explore_expr(element_expr, element, True)
|
||||
return False
|
||||
|
||||
if is_child:
|
||||
Explorer.return_to_parent_value()
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def explore_type(name, datatype, is_child):
|
||||
"""Function to explore pointer types.
|
||||
See Explorer.explore_type for more information.
|
||||
"""
|
||||
target_type = datatype.target()
|
||||
print ("\n%s is a pointer to a value of type '%s'." %
|
||||
(name, str(target_type)))
|
||||
|
||||
Explorer.explore_type("the pointee type of %s" % name,
|
||||
target_type,
|
||||
is_child)
|
||||
return False
|
||||
|
||||
|
||||
class ReferenceExplorer(object):
|
||||
"""Internal class used to explore reference (TYPE_CODE_REF) values."""
|
||||
|
||||
@staticmethod
|
||||
def explore_expr(expr, value, is_child):
|
||||
"""Function to explore array values.
|
||||
See Explorer.explore_expr for more information.
|
||||
"""
|
||||
referenced_value = value.referenced_value()
|
||||
Explorer.explore_expr(expr, referenced_value, is_child)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def explore_type(name, datatype, is_child):
|
||||
"""Function to explore pointer types.
|
||||
See Explorer.explore_type for more information.
|
||||
"""
|
||||
target_type = datatype.target()
|
||||
Explorer.explore_type(name, target_type, is_child)
|
||||
return False
|
||||
|
||||
|
||||
class ArrayExplorer(object):
|
||||
"""Internal class used to explore arrays."""
|
||||
|
||||
@staticmethod
|
||||
def explore_expr(expr, value, is_child):
|
||||
"""Function to explore array values.
|
||||
See Explorer.explore_expr for more information.
|
||||
"""
|
||||
target_type = value.type.target()
|
||||
print ("'%s' is an array of '%s'." % (expr, str(target_type)))
|
||||
index = 0
|
||||
try:
|
||||
index = int(raw_input("Enter the index of the element you want to "
|
||||
"explore in '%s': " % expr))
|
||||
except ValueError:
|
||||
if is_child:
|
||||
Explorer.return_to_parent_value()
|
||||
return False
|
||||
|
||||
element = None
|
||||
try:
|
||||
element = value[index]
|
||||
str(element)
|
||||
except gdb.MemoryError:
|
||||
print "Cannot read value at index %d." % index
|
||||
raw_input("Press enter to continue... ")
|
||||
return True
|
||||
|
||||
Explorer.explore_expr("%s[%d]" % (Explorer.guard_expr(expr), index),
|
||||
element, True)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def explore_type(name, datatype, is_child):
|
||||
"""Function to explore array types.
|
||||
See Explorer.explore_type for more information.
|
||||
"""
|
||||
target_type = datatype.target()
|
||||
print "%s is an array of '%s'." % (name, str(target_type))
|
||||
|
||||
Explorer.explore_type("the array element of %s" % name, target_type,
|
||||
is_child)
|
||||
return False
|
||||
|
||||
|
||||
class CompoundExplorer(object):
|
||||
"""Internal class used to explore struct, classes and unions."""
|
||||
|
||||
@staticmethod
|
||||
def _print_fields(print_list):
|
||||
"""Internal function which prints the fields of a struct/class/union.
|
||||
"""
|
||||
max_field_name_length = 0
|
||||
for pair in print_list:
|
||||
if max_field_name_length < len(pair[0]):
|
||||
max_field_name_length = len(pair[0])
|
||||
|
||||
format_str = " {0:>%d} = {1}" % max_field_name_length
|
||||
for pair in print_list:
|
||||
print format_str.format(pair[0], pair[1])
|
||||
|
||||
@staticmethod
|
||||
def _get_real_field_count(fields):
|
||||
real_field_count = 0;
|
||||
for field in fields:
|
||||
if not field.artificial:
|
||||
real_field_count = real_field_count + 1
|
||||
|
||||
return real_field_count
|
||||
|
||||
@staticmethod
|
||||
def explore_expr(expr, value, is_child):
|
||||
"""Function to explore structs/classes and union values.
|
||||
See Explorer.explore_expr for more information.
|
||||
"""
|
||||
datatype = value.type
|
||||
type_code = datatype.code
|
||||
fields = datatype.fields()
|
||||
|
||||
if type_code == gdb.TYPE_CODE_STRUCT:
|
||||
type_desc = "struct/class"
|
||||
else:
|
||||
type_desc = "union"
|
||||
|
||||
if CompoundExplorer._get_real_field_count(fields) == 0:
|
||||
print ("The value of '%s' is a %s of type '%s' with no fields." %
|
||||
(expr, type_desc, str(value.type)))
|
||||
if is_child:
|
||||
Explorer.return_to_parent_value_prompt()
|
||||
return False
|
||||
|
||||
print ("The value of '%s' is a %s of type '%s' with the following "
|
||||
"fields:\n" % (expr, type_desc, str(value.type)))
|
||||
|
||||
has_explorable_fields = False
|
||||
choice_to_compound_field_map = { }
|
||||
current_choice = 0
|
||||
print_list = [ ]
|
||||
for field in fields:
|
||||
if field.artificial:
|
||||
continue
|
||||
field_full_name = Explorer.guard_expr(expr) + "." + field.name
|
||||
if field.is_base_class:
|
||||
field_value = value.cast(field.type)
|
||||
else:
|
||||
field_value = value[field.name]
|
||||
literal_value = ""
|
||||
if type_code == gdb.TYPE_CODE_UNION:
|
||||
literal_value = ("<Enter %d to explore this field of type "
|
||||
"'%s'>" % (current_choice, str(field.type)))
|
||||
has_explorable_fields = True
|
||||
else:
|
||||
if Explorer.is_scalar_type(field.type):
|
||||
literal_value = ("%s .. (Value of type '%s')" %
|
||||
(str(field_value), str(field.type)))
|
||||
else:
|
||||
if field.is_base_class:
|
||||
field_desc = "base class"
|
||||
else:
|
||||
field_desc = "field"
|
||||
literal_value = ("<Enter %d to explore this %s of type "
|
||||
"'%s'>" %
|
||||
(current_choice, field_desc,
|
||||
str(field.type)))
|
||||
has_explorable_fields = True
|
||||
|
||||
choice_to_compound_field_map[str(current_choice)] = (
|
||||
field_full_name, field_value)
|
||||
current_choice = current_choice + 1
|
||||
|
||||
print_list.append((field.name, literal_value))
|
||||
|
||||
CompoundExplorer._print_fields(print_list)
|
||||
print ""
|
||||
|
||||
if has_explorable_fields:
|
||||
choice = raw_input("Enter the field number of choice: ")
|
||||
if choice in choice_to_compound_field_map:
|
||||
Explorer.explore_expr(choice_to_compound_field_map[choice][0],
|
||||
choice_to_compound_field_map[choice][1],
|
||||
True)
|
||||
return True
|
||||
else:
|
||||
if is_child:
|
||||
Explorer.returning_to_parent_value_message()
|
||||
else:
|
||||
if is_child:
|
||||
Explorer.return_to_parent_value_prompt()
|
||||
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def explore_type(name, datatype, is_child):
|
||||
"""Function to explore struct/class and union types.
|
||||
See Explorer.explore_type for more information.
|
||||
"""
|
||||
type_code = datatype.code
|
||||
type_desc = ""
|
||||
if type_code == gdb.TYPE_CODE_STRUCT:
|
||||
type_desc = "struct/class"
|
||||
else:
|
||||
type_desc = "union"
|
||||
|
||||
fields = datatype.fields()
|
||||
if CompoundExplorer._get_real_field_count(fields) == 0:
|
||||
if is_child:
|
||||
print ("%s is a %s of type '%s' with no fields." %
|
||||
(name, type_desc, str(datatype)))
|
||||
Explorer.return_to_enclosing_type_prompt()
|
||||
else:
|
||||
print "'%s' is a %s with no fields." % (name, type_desc)
|
||||
return False
|
||||
|
||||
if is_child:
|
||||
print ("%s is a %s of type '%s' "
|
||||
"with the following fields:\n" %
|
||||
(name, type_desc, str(datatype)))
|
||||
else:
|
||||
print ("'%s' is a %s with the following "
|
||||
"fields:\n" %
|
||||
(name, type_desc))
|
||||
|
||||
has_explorable_fields = False
|
||||
current_choice = 0
|
||||
choice_to_compound_field_map = { }
|
||||
print_list = [ ]
|
||||
for field in fields:
|
||||
if field.artificial:
|
||||
continue
|
||||
if field.is_base_class:
|
||||
field_desc = "base class"
|
||||
else:
|
||||
field_desc = "field"
|
||||
rhs = ("<Enter %d to explore this %s of type '%s'>" %
|
||||
(current_choice, field_desc, str(field.type)))
|
||||
print_list.append((field.name, rhs))
|
||||
choice_to_compound_field_map[str(current_choice)] = (
|
||||
field.name, field.type, field_desc)
|
||||
current_choice = current_choice + 1
|
||||
|
||||
CompoundExplorer._print_fields(print_list)
|
||||
print ""
|
||||
|
||||
if len(choice_to_compound_field_map) > 0:
|
||||
choice = raw_input("Enter the field number of choice: ")
|
||||
if choice in choice_to_compound_field_map:
|
||||
if is_child:
|
||||
new_name = ("%s '%s' of %s" %
|
||||
(choice_to_compound_field_map[choice][2],
|
||||
choice_to_compound_field_map[choice][0],
|
||||
name))
|
||||
else:
|
||||
new_name = ("%s '%s' of '%s'" %
|
||||
(choice_to_compound_field_map[choice][2],
|
||||
choice_to_compound_field_map[choice][0],
|
||||
name))
|
||||
Explorer.explore_type(new_name,
|
||||
choice_to_compound_field_map[choice][1], True)
|
||||
return True
|
||||
else:
|
||||
if is_child:
|
||||
Explorer.return_to_enclosing_type()
|
||||
else:
|
||||
if is_child:
|
||||
Explorer.return_to_enclosing_type_prompt()
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class TypedefExplorer(object):
|
||||
"""Internal class used to explore values whose type is a typedef."""
|
||||
|
||||
@staticmethod
|
||||
def explore_expr(expr, value, is_child):
|
||||
"""Function to explore typedef values.
|
||||
See Explorer.explore_expr for more information.
|
||||
"""
|
||||
actual_type = value.type.strip_typedefs()
|
||||
print ("The value of '%s' is of type '%s' "
|
||||
"which is a typedef of type '%s'" %
|
||||
(expr, str(value.type), str(actual_type)))
|
||||
|
||||
Explorer.explore_expr(expr, value.cast(actual_type), is_child)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def explore_type(name, datatype, is_child):
|
||||
"""Function to explore typedef types.
|
||||
See Explorer.explore_type for more information.
|
||||
"""
|
||||
actual_type = datatype.strip_typedefs()
|
||||
if is_child:
|
||||
print ("The type of %s is a typedef of type '%s'." %
|
||||
(name, str(actual_type)))
|
||||
else:
|
||||
print ("The type '%s' is a typedef of type '%s'." %
|
||||
(name, str(actual_type)))
|
||||
|
||||
Explorer.explore_type(name, actual_type, is_child)
|
||||
return False
|
||||
|
||||
|
||||
class ExploreUtils(object):
|
||||
"""Internal class which provides utilities for the main command classes."""
|
||||
|
||||
@staticmethod
|
||||
def check_args(name, arg_str):
|
||||
"""Utility to check if adequate number of arguments are passed to an
|
||||
explore command.
|
||||
|
||||
Arguments:
|
||||
name: The name of the explore command.
|
||||
arg_str: The argument string passed to the explore command.
|
||||
|
||||
Returns:
|
||||
True if adequate arguments are passed, false otherwise.
|
||||
|
||||
Raises:
|
||||
gdb.GdbError if adequate arguments are not passed.
|
||||
"""
|
||||
if len(arg_str) < 1:
|
||||
raise gdb.GdbError("ERROR: '%s' requires an argument."
|
||||
% name)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def get_type_from_str(type_str):
|
||||
"""A utility function to deduce the gdb.Type value from a string
|
||||
representing the type.
|
||||
|
||||
Arguments:
|
||||
type_str: The type string from which the gdb.Type value should be
|
||||
deduced.
|
||||
|
||||
Returns:
|
||||
The deduced gdb.Type value if possible, None otherwise.
|
||||
"""
|
||||
try:
|
||||
# Assume the current language to be C/C++ and make a try.
|
||||
return gdb.parse_and_eval("(%s *)0" % type_str).type.target()
|
||||
except RuntimeError:
|
||||
# If assumption of current language to be C/C++ was wrong, then
|
||||
# lookup the type using the API.
|
||||
try:
|
||||
return gdb.lookup_type(type_str)
|
||||
except RuntimeError:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_value_from_str(value_str):
|
||||
"""A utility function to deduce the gdb.Value value from a string
|
||||
representing the value.
|
||||
|
||||
Arguments:
|
||||
value_str: The value string from which the gdb.Value value should
|
||||
be deduced.
|
||||
|
||||
Returns:
|
||||
The deduced gdb.Value value if possible, None otherwise.
|
||||
"""
|
||||
try:
|
||||
return gdb.parse_and_eval(value_str)
|
||||
except RuntimeError:
|
||||
return None
|
||||
|
||||
|
||||
class ExploreCommand(gdb.Command):
|
||||
"""Explore a value or a type valid in the current context.
|
||||
|
||||
Usage:
|
||||
|
||||
explore ARG
|
||||
|
||||
- ARG is either a valid expression or a type name.
|
||||
- At any stage of exploration, hit the return key (instead of a
|
||||
choice, if any) to return to the enclosing type or value.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(ExploreCommand, self).__init__(name = "explore",
|
||||
command_class = gdb.COMMAND_DATA,
|
||||
prefix = True)
|
||||
|
||||
def invoke(self, arg_str, from_tty):
|
||||
if ExploreUtils.check_args("explore", arg_str) == False:
|
||||
return
|
||||
|
||||
# Check if it is a value
|
||||
value = ExploreUtils.get_value_from_str(arg_str)
|
||||
if value is not None:
|
||||
Explorer.explore_expr(arg_str, value, False)
|
||||
return
|
||||
|
||||
# If it is not a value, check if it is a type
|
||||
datatype = ExploreUtils.get_type_from_str(arg_str)
|
||||
if datatype is not None:
|
||||
Explorer.explore_type(arg_str, datatype, False)
|
||||
return
|
||||
|
||||
# If it is neither a value nor a type, raise an error.
|
||||
raise gdb.GdbError(
|
||||
("'%s' neither evaluates to a value nor is a type "
|
||||
"in the current context." %
|
||||
arg_str))
|
||||
|
||||
|
||||
class ExploreValueCommand(gdb.Command):
|
||||
"""Explore value of an expression valid in the current context.
|
||||
|
||||
Usage:
|
||||
|
||||
explore value ARG
|
||||
|
||||
- ARG is a valid expression.
|
||||
- At any stage of exploration, hit the return key (instead of a
|
||||
choice, if any) to return to the enclosing value.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(ExploreValueCommand, self).__init__(
|
||||
name = "explore value", command_class = gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg_str, from_tty):
|
||||
if ExploreUtils.check_args("explore value", arg_str) == False:
|
||||
return
|
||||
|
||||
value = ExploreUtils.get_value_from_str(arg_str)
|
||||
if value is None:
|
||||
raise gdb.GdbError(
|
||||
(" '%s' does not evaluate to a value in the current "
|
||||
"context." %
|
||||
arg_str))
|
||||
return
|
||||
|
||||
Explorer.explore_expr(arg_str, value, False)
|
||||
|
||||
|
||||
class ExploreTypeCommand(gdb.Command):
|
||||
"""Explore a type or the type of an expression valid in the current
|
||||
context.
|
||||
|
||||
Usage:
|
||||
|
||||
explore type ARG
|
||||
|
||||
- ARG is a valid expression or a type name.
|
||||
- At any stage of exploration, hit the return key (instead of a
|
||||
choice, if any) to return to the enclosing type.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(ExploreTypeCommand, self).__init__(
|
||||
name = "explore type", command_class = gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg_str, from_tty):
|
||||
if ExploreUtils.check_args("explore type", arg_str) == False:
|
||||
return
|
||||
|
||||
datatype = ExploreUtils.get_type_from_str(arg_str)
|
||||
if datatype is not None:
|
||||
Explorer.explore_type(arg_str, datatype, False)
|
||||
return
|
||||
|
||||
value = ExploreUtils.get_value_from_str(arg_str)
|
||||
if value is not None:
|
||||
print "'%s' is of type '%s'." % (arg_str, str(value.type))
|
||||
Explorer.explore_type(str(value.type), value.type, False)
|
||||
|
||||
raise gdb.GdbError(("'%s' is not a type or value in the current "
|
||||
"context." % arg_str))
|
||||
|
||||
|
||||
Explorer.init_env()
|
||||
|
||||
ExploreCommand()
|
||||
ExploreValueCommand()
|
||||
ExploreTypeCommand()
|
Loading…
Add table
Add a link
Reference in a new issue