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:
Siva Chandra Reddy 2012-04-11 05:50:44 +00:00
parent 1cd470df20
commit 06fc020f10
12 changed files with 1688 additions and 2 deletions

View File

@ -1,3 +1,12 @@
2012-04-11 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.
2011-04-10 Maciej W. Rozycki <macro@codesourcery.com>
* mips-tdep.c (mips_skip_pic_trampoline_code): Correct sign

View File

@ -93,6 +93,11 @@
** "info vtbl" can be used to show the virtual method tables for
C++ and Java objects.
** "explore" and its sub commands "explore value" and "explore type"
can be used to reccursively explore values and types of
expressions. These commands are available only if GDB is
configured with '--with-python'.
* New targets
Renesas RL78 rl78-*-elf

View File

@ -58,7 +58,8 @@ PYTHON_FILES = \
gdb/prompt.py \
gdb/command/__init__.py \
gdb/command/pretty_printers.py \
gdb/command/prompt.py
gdb/command/prompt.py \
gdb/command/explore.py
FLAGS_TO_PASS = \
"prefix=$(prefix)" \

View File

@ -1,3 +1,7 @@
2012-04-11 Siva Chandra Reddy <sivachandra@google.com>
* gdb.texinfo (Examining Data): Document the 'explore' command.
2012-03-28 Joel Brobecker <brobecker@adacore.com>
* gdb.texinfo (GDB/MI Variable Objects): Document what happens

View File

@ -7198,6 +7198,153 @@ fields of a struct or a class are declared, use the @code{ptype @var{exp}}
command rather than @code{print}. @xref{Symbols, ,Examining the Symbol
Table}.
@cindex exploring hierarchical data structures
@kindex explore
Another way of examining values of expressions and type information is
through the Python extension command @code{explore} (available only if
the @value{GDBN} build is configured with @code{--with-python}). It
offers an interactive way to start at the highest level (or, the most
abstract level) of the data type of an expression (or, the data type
itself) and explore all the way down to leaf scalar values/fields
embedded in the higher level data types.
@table @code
@item explore @var{arg}
@var{arg} is either an expression (in the source language), or a type
visible in the current context of the program being debugged.
@end table
The working of the @code{explore} command can be illustrated with an
example. If a data type @code{struct ComplexStruct} is defined in your
C program as
@smallexample
struct SimpleStruct
@{
int i;
double d;
@};
struct ComplexStruct
@{
struct SimpleStruct *ss_p;
int arr[10];
@};
@end smallexample
@noindent
followed by variable declarations as
@smallexample
struct SimpleStruct ss = @{ 10, 1.11 @};
struct ComplexStruct cs = @{ &ss, @{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 @} @};
@end smallexample
@noindent
then, the value of the variable @code{cs} can be explored using the
@code{explore} command as follows.
@smallexample
(gdb) explore cs
The value of `cs' is a struct/class of type `struct ComplexStruct' with
the following fields:
ss_p = <Enter 0 to explore this field of type `struct SimpleStruct *'>
arr = <Enter 1 to explore this field of type `int [10]'>
Enter the field number of choice:
@end smallexample
@noindent
Since the fields of @code{cs} are not scalar values, you are being
prompted to chose the field you want to explore. Let's say you choose
the field @code{ss_p} by entering @code{0}. Then, since this field is a
pointer, you will be asked if it is pointing to a single value. From
the declaration of @code{cs} above, it is indeed pointing to a single
value, hence you enter @code{y}. If you enter @code{n}, then you will
be asked if it were pointing to an array of values, in which case this
field will be explored as if it were an array.
@smallexample
`cs.ss_p' is a pointer to a value of type `struct SimpleStruct'
Continue exploring it as a pointer to a single value [y/n]: y
The value of `*(cs.ss_p)' is a struct/class of type `struct
SimpleStruct' with the following fields:
i = 10 .. (Value of type `int')
d = 1.1100000000000001 .. (Value of type `double')
Press enter to return to parent value:
@end smallexample
@noindent
If the field @code{arr} of @code{cs} was chosen for exploration by
entering @code{1} earlier, then since it is as array, you will be
prompted to enter the index of the element in the array that you want
to explore.
@smallexample
`cs.arr' is an array of `int'.
Enter the index of the element you want to explore in `cs.arr': 5
`(cs.arr)[5]' is a scalar value of type `int'.
(cs.arr)[5] = 4
Press enter to return to parent value:
@end smallexample
In general, at any stage of exploration, you can go deeper towards the
leaf values by responding to the prompts appropriately, or hit the
return key to return to the enclosing data structure (the @i{higher}
level data structure).
Similar to exploring values, you can use the @code{explore} command to
explore types. Instead of specifying a value (which is typically a
variable name or an expression valid in the current context of the
program being debugged), you specify a type name. If you consider the
same example as above, your can explore the type
@code{struct ComplexStruct} by passing the argument
@code{struct ComplexStruct} to the @code{explore} command.
@smallexample
(gdb) explore struct ComplexStruct
@end smallexample
@noindent
By responding to the prompts appropriately in the subsequent interactive
session, you can explore the type @code{struct ComplexStruct} in a
manner similar to how the value @code{cs} was explored in the above
example.
The @code{explore} command also has two sub-commands,
@code{explore value} and @code{explore type}. The former sub-command is
a way to explicitly specify that value exploration of the argument is
being invoked, while the latter is a way to explicitly specify that type
exploration of the argument is being invoked.
@table @code
@item explore value @var{expr}
@cindex explore value
This sub-command of @code{explore} explores the value of the
expression @var{expr} (if @var{expr} is an expression valid in the
current context of the program being debugged). The behavior of this
command is identical to that of the behavior of the @code{explore}
command being passed the argument @var{expr}.
@item explore type @var{arg}
@cindex explore type
This sub-command of @code{explore} explores the type of @var{arg} (if
@var{arg} is a type visible in the current context of program being
debugged), or the type of the value/expression @var{arg} (if @var{arg}
is an expression valid in the current context of the program being
debugged). If @var{arg} is a type, then the behavior of this command is
identical to that of the @code{explore} command being passed the
argument @var{arg}. If @var{arg} is an expression, then the behavior of
this command will be identical to that of the @code{explore} command
being passed the type of @var{arg} as the argument.
@end table
@menu
* Expressions:: Expressions
* Ambiguous Expressions:: Ambiguous Expressions

View 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()

View File

@ -1,3 +1,16 @@
2012-04-02 Siva Chandra Reddy <sivachandra@google.com>
* gdb.python/Makefile.in: Add py-explore and py-explore-cc to
EXECUTABLES.
* gdb.python/py-explore.c: C program used for testing the new
'explore' command on C constructs.
* gdb.python/py-explore.cc: C++ program used for testing the new
'explore' command on C++ constructs.
* gdb-python/py-explore.exp: Tests for the new 'explore'
command on C constructs.
* gdb-python/py-explore-cc.exp: Tests for the new 'explore'
command on C++ constructs.
2012-04-07 Mark Kettenis <kettenis@gnu.org>
* gdb.base/funcargs.exp (complex_args): Fix typo.

View File

@ -5,7 +5,8 @@ EXECUTABLES = py-type py-value py-prettyprint py-template py-block \
py-symbol py-mi py-breakpoint py-inferior py-infthread \
py-shared python lib-types py-events py-evthreads py-frame \
py-mi py-pp-maint py-progspace py-section-script py-objfile \
py-finish-breakpoint py-finish-breakpoint2 py-value-cc
py-finish-breakpoint py-finish-breakpoint2 py-value-cc py-explore \
py-explore-cc
MISCELLANEOUS = py-shared-sl.sl py-events-shlib.so py-events-shlib-nodebug.so

View File

@ -0,0 +1,146 @@
# 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/>.
# This file is part of the GDB testsuite. It tests the mechanism
# exposing values to Python.
if { [skip_cplus_tests] } { continue }
set testfile "py-explore"
set srcfile ${testfile}.cc
set binfile ${objdir}/${subdir}/${testfile}
if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
return -1
}
# Skip all tests if Python scripting is not enabled.
if { [skip_python_tests] } { continue }
set int_ptr_ref_desc "The value of 'int_ptr_ref' is of type 'int_ptr' which is a typedef of type 'int \\*'.*\'int_ptr_ref' is a pointer to a value of type 'int'.*"
set b_desc "The value of 'b' is a struct/class of type 'B' with the following fields:.*\
A = <Enter 0 to explore this base class of type 'A'>.*\
i = 10 \\.\\. \\(Value of type 'int'\\).*\
c = 97 'a' \\.\\. \\(Value of type 'char'\\).*"
set B_desc "'B' is a struct/class with the following fields:.*\
A = <Enter 0 to explore this base class of type 'A'>.*\
i = <Enter 1 to explore this field of type 'int'>.*\
c = <Enter 2 to explore this field of type 'char'>.*"
if ![runto_main] {
return -1
}
gdb_breakpoint [gdb_get_line_number "Break here."]
gdb_continue_to_breakpoint "Break here" ".*Break here.*"
gdb_test "explore A" "'A' is a struct/class with no fields\."
gdb_test "explore a" "The value of 'a' is a struct/class of type 'const A' with no fields\."
gdb_test "explore int_ref" "'int_ref' is a scalar value of type 'int'.*int_ref = 10"
gdb_test_multiple "explore int_ptr_ref" "" {
-re "$int_ptr_ref_desc.*Continue exploring it as a pointer to a single value \\\[y/n\\\]:.*" {
pass "explore int_ptr_ref"
gdb_test_multiple "y" "explore_int_ptr_ref_as_single_value_pointer" {
-re "'\[*\]int_ptr_ref' is a scalar value of type 'int'.*\[*\]int_ptr_ref = 10.*$gdb_prompt" {
pass "explore_int_ptr_ref_as_single_value_pointer"
}
}
}
}
gdb_test_multiple "explore b" "" {
-re "$b_desc.*Enter the field number of choice:.*" {
pass "explore b"
gdb_test_multiple "0" "explore_base_class_A" {
-re "The value of 'b\.A' is a struct/class of type 'A' with no fields\." {
pass "explore_base_class_A"
gdb_test_multiple "\0" "return_to_b_from_A" {
-re ".*$b_desc.*Enter the field number of choice:.*" {
pass "return_to_b_from_A"
gdb_test_multiple "1" "explore_field_i_of_b" {
-re "'b\.i' is a scalar value of type 'int'.*b\.i = 10.*" {
pass "explore_field_i_of_b"
gdb_test_multiple "\0" "return_to_b_from_i" {
-re "$b_desc.*Enter the field number of choice:.*" {
pass "return_to_b_from_i"
}
}
}
}
gdb_test_multiple "2" "explore_field_c_of_b" {
-re "'b\.c' is a scalar value of type 'char'.*b\.c = .*'a'.*" {
pass "explore_field_c_of_b"
gdb_test_multiple "\0" "return_to_b_from_c" {
-re "$b_desc.*Enter the field number of choice:.*" {
pass "return_to_b_from_i"
}
}
}
}
gdb_test_multiple "\0" "return_to_gdb_prompt" {
-re "$gdb_prompt" {
pass "return_to_gdb_prompt_from_b"
}
}
}
}
}
}
}
}
gdb_test_multiple "explore B" "" {
-re "$B_desc.*Enter the field number of choice:.*" {
pass "explore B"
gdb_test_multiple "0" "explore_base_class_A" {
-re "base class 'A' of 'B' is a struct/class of type 'A' with no fields\." {
pass "explore_base_class_A"
gdb_test_multiple "\0" "return_to_B" {
-re "$B_desc.*Enter the field number of choice:.*" {
pass "return_to_B"
gdb_test_multiple "1" "explore_field_i_of_B" {
-re "field 'i' of 'B' is of a scalar type 'int'.*" {
pass "explore_field_i_of_B"
gdb_test_multiple "\0" "return_to_B_from_i" {
-re "$B_desc.*Enter the field number of choice:.*" {
pass "return_to_B_from_i"
}
}
}
}
gdb_test_multiple "2" "explore_field_c_of_B" {
-re "field 'c' of 'B' is of a scalar type 'char'.*" {
pass "explore_field_c_of_B"
gdb_test_multiple "\0" "return_to_B_from_c" {
-re "$B_desc.*Enter the field number of choice:.*" {
pass "return_to_B_from_c"
}
}
}
}
gdb_test_multiple "\0" "return_to_gdb_prompt" {
-re "$gdb_prompt" {
pass "return_to_gdb_prompt_from_B"
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,82 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 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/>.
*/
#define ARRAY_SIZE 10
struct SimpleStruct
{
int a;
double d;
};
union SimpleUnion
{
int i;
char c;
float f;
double d;
};
typedef struct SimpleStruct SS;
struct ComplexStruct
{
struct SimpleStruct s;
union SimpleUnion u;
SS sa[ARRAY_SIZE];
};
union ComplexUnion
{
SS s;
struct SimpleStruct sa[ARRAY_SIZE];
};
int
main (void)
{
struct SimpleStruct ss;
struct SimpleStruct* ss_ptr = &ss;
SS ss_t;
union SimpleUnion su;
struct ComplexStruct cs;
struct ComplexStruct* cs_ptr = &cs;
union ComplexUnion cu;
int i;
double darray[5] = {0.1, 0.2, 0.3, 0.4, 0.5};
double *darray_ref = darray;
ss.a = 10;
ss.d = 100.01;
ss_t = ss;
su.d = 100.1;
cs.s = ss;
cs.u = su;
for (i = 0; i < ARRAY_SIZE; i++)
{
cs.sa[i].a = i;
cs.sa[i].d = 10.10 + i;
cu.sa[i].a = i;
cu.sa[i].d = 100.10 + i;
}
return 0; /* Break here. */
}

View File

@ -0,0 +1,54 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 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/>.
*/
class A {
public:
virtual ~A() { }
};
class B : public A {
public:
virtual ~B() { }
int i;
char c;
};
typedef int *int_ptr;
int
func (const A &a)
{
int val = 10;
int &int_ref = val;
int_ptr ptr = &val;
int_ptr &int_ptr_ref = ptr;
B b;
b.i = 10;
b.c = 'a';
return 0; /* Break here. */
}
int
main ()
{
A obj;
return func (obj);
}

View File

@ -0,0 +1,469 @@
# Copyright 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/>.
set testfile "py-explore"
set srcfile ${testfile}.c
set binfile ${objdir}/${subdir}/${testfile}
if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
return -1
}
# Skip all tests if Python scripting is not enabled.
if { [skip_python_tests] } { continue }
set SS "struct SimpleStruct"
set SU "union SimpleUnion"
set CS "struct ComplexStruct"
set CU "union ComplexUnion"
set enter_field_number_prompt {Enter the field number of choice: }
set return_to_parent_prompt {Press enter to return to parent value: }
set array_index_prompt {Enter the index of the element you want to explore in .*: }
proc compound_description { value_name type_desc type_name } {
return "The value of '$value_name' is a $type_desc of type '$type_name' with the following fields:\[\r\n\]+"
}
proc typedef_description { value_name typedef_name type_name } {
return "The value of '$value_name' is of type '$typedef_name' which is a typedef of type '$type_name'\.\[\r\n\]+"
}
proc scalar_description { value_name type } {
return "'$value_name' is a scalar value of type '$type'\.\[\r\n\]+"
}
proc array_description { value_name type } {
return "'$value_name' is an array of '$type'\.\[\r\n\]+"
}
proc pointer_description { value_name type_name } {
set type_description "'$value_name' is a pointer to a value of type '$type_name'\.\[\r\n\]+"
set prompt "Continue exploring it as a pointer to a single value \[\[\]y/n\[\]\]: "
return "$type_description$prompt"
}
proc field_values { args } {
set result ""
foreach field $args {
set result "$result\[ \]*$field \[\.\]\[\.\] \[\(\]Value of type .*\[\)\]\[\r\n\]+"
}
return $result
}
proc field_choices { args } {
set result ""
set field_num 0
foreach field $args {
set result "$result$field\[ \]+=\[ \]+<Enter $field_num to explore this field of type .*"
incr field_num
}
return $result
}
proc scalar_value { value_name value } {
return "$value_name = $value\[r\n\]+"
}
set SS_fields [field_values {a = 10} {d = 100[.].*}]
if ![runto_main] {
return -1
}
gdb_breakpoint [gdb_get_line_number "Break here."]
gdb_continue_to_breakpoint "Break here" ".*Break here.*"
#########################
# Value exploration tests
#########################
gdb_test "explore i" "[scalar_description {i} {int}].*i = .*"
gdb_test "explore ss" "[compound_description {ss} {struct/class} $SS].*$SS_fields"
gdb_test "explore *ss_ptr" "[compound_description {\*ss_ptr} {struct/class} $SS].*$SS_fields"
gdb_test "explore ss_t" "[typedef_description {ss_t} {SS} $SS].*[compound_description {ss_t} {struct/class} $SS].*$SS_fields"
gdb_test_multiple "explore ss_ptr" "" {
-re "[pointer_description {ss_ptr} $SS].*" {
pass "explore ss_ptr"
gdb_test_multiple "y" "explore_as_single_value_pointer" {
-re "$SS_fields" {
pass "explore ss_ptr as single value pointer"
}
}
}
}
gdb_test_multiple "explore darray_ref" "" {
-re "[pointer_description {darray_ref} {double}].*" {
pass "explore darray_ref"
gdb_test_multiple "n" "no_to_explore_as_pointer" {
-re "Continue exploring it as a pointer to an array \[\[\]y/n\[\]\]: " {
pass "no_to_explore_as_pointer"
gdb_test_multiple "y" "explore_as_array" {
-re ".*Enter the index of the element you want to explore in 'darray_ref':.*" {
pass "explore_as_array"
gdb_test_multiple "2" "explore_as_array_index_2" {
-re ".*'darray_ref\\\[2\\\]' is a scalar value of type 'double'\..*darray_ref\\\[2\\\] = 0.*" {
pass "explore_as_array_index_2"
gdb_test_multiple "\0" "end explore_as_array_index_2" {
-re ".*Returning to parent value.*Enter the index of the element you want to explore in 'darray_ref':.*" {
pass "end explore_as_array_index_2"
gdb_test_multiple "\0" "end explore_as_array" {
-re "\[\n\r\]+" {
pass "end explore_as_array"
}
}
}
}
}
}
}
}
}
}
}
}
gdb_test_multiple "explore su" "" {
-re "[compound_description {su} {union} {union SimpleUnion}].*[field_choices {i} {c} {f} {d}].*$enter_field_number_prompt" {
pass "explore su"
gdb_test_multiple "3" "explore su.d" {
-re "[scalar_description {su.d} {double}].*[scalar_value {su.d} {100[.].*}].*$return_to_parent_prompt" {
pass "explore su.d"
gdb_test_multiple " " "end su.d exploration" {
-re ".*[compound_description {su} {union} {union SimpleUnion}].*[field_choices {i} {c} {f} {d}].*$enter_field_number_prompt" {
pass "end su.d exploration"
gdb_test_multiple "\0" "end su exploration" {
-re "$gdb_prompt" {
pass "end su exploration"
}
}
}
}
}
}
}
}
gdb_test_multiple "explore cs" "" {
-re "[compound_description {cs} {struct/class} {struct ComplexStruct}].*[field_choices {s} {u} {sa}].*$enter_field_number_prompt" {
pass "explore cs"
gdb_test_multiple "0" "explore cs.s" {
-re "[compound_description {cs.s} {struct/class} {struct SimpleStruct}].*[field_values {a = 10} {d = 100[.].*}].*$return_to_parent_prompt" {
pass "explore cs.s"
gdb_test_multiple " " "end cs.s exploration" {
-re ".*$enter_field_number_prompt" {
pass "end cs.s exploration"
gdb_test_multiple "\0" "end cs exploration" {
-re "$gdb_prompt" {
pass "end cs exploration"
}
}
}
}
}
}
}
}
gdb_test_multiple "explore cu" "" {
-re "[compound_description {cu} {union} {union ComplexUnion}].*[field_choices {s} {sa}].*$enter_field_number_prompt" {
pass "explore cu"
gdb_test_multiple "1" "explore cu.sa" {
-re ".*[array_description {cu.sa} $SS].*$array_index_prompt" {
pass "explore cu.sa"
gdb_test_multiple "0" "explore cu.sa\[0\]" {
-re "[compound_description {\(cu.sa\)\[0\]} {struct/class} {struct SimpleStruct}].*[field_values {a = 0} {d = 100[.].*}].*$return_to_parent_prompt" {
pass "explore cu.sa\[0\]"
gdb_test_multiple "\0" "end cu.sa\[0\] exploration" {
-re "[array_description {cu.sa} $SS]$array_index_prompt" {
pass "end cu.sa\[0\] exploration"
}
}
}
}
gdb_test_multiple "\0" "end cu.sa exploration" {
-re ".*$enter_field_number_prompt" {
pass "end cu.sa exploration"
gdb_test_multiple "\0" "end cu exploration" {
-re "$gdb_prompt" {
pass "end cu exploration"
}
}
}
}
}
}
}
}
########################
# Type exploration tests
########################
proc scalar_type_decsription {type} {
return "'$type' is a scalar type\."
}
proc child_scalar_type_description {path type} {
return "$path is of a scalar type '$type'\."
}
proc compound_type_description { type_name type_desc } {
return "'$type_name' is a $type_desc with the following fields:"
}
proc child_compound_type_description { path type_name type_desc } {
return "$path is a $type_desc of type '$type_name' with the following fields:"
}
proc child_array_type_description { path target_type_name } {
return "$path is an array of '$target_type_name'\."
}
proc typedef_type_description { type_name target_name } {
return "The type '$type_name' is a typedef of type '$target_name'\."
}
set SS_fields_types [field_choices {a} {d}]
set SU_fields_types [field_choices {i} {c} {f} {d}]
set CS_fields_types [field_choices {s} {u} {sa}]
set CU_fields_types [field_choices {s} {sa}]
set CS_field_0 "field 's' of 'struct ComplexStruct'"
set CS_field_1 "field 'u' of 'struct ComplexStruct'"
set CS_field_2 "field 'sa' of 'struct ComplexStruct'"
set CS_field_2_array_element "an array element of $CS_field_2"
set CU_field_0 "field 's' of 'union ComplexUnion'"
set CU_field_1 "field 'sa' of 'union ComplexUnion'"
set CU_field_1_array_element "an array element of $CU_field_1"
gdb_test "explore int" ".*[scalar_type_decsription {int}].*"
gdb_test_multiple "explore struct SimpleStruct" "" {
-re ".*[compound_type_description $SS {struct/class}].*$SS_fields_types.*" {
pass "explore struct SimpleStruct"
gdb_test_multiple "0" "explore type struct SimpleStruct feild 0" {
-re ".*[child_scalar_type_description {field 'a' of 'struct SimpleStruct'} {int}].*" {
pass "explore type struct SimpleStruct feild 0"
gdb_test_multiple "\0" "return to struct SimpleStruct from field 0" {
-re ".*[compound_type_description $SS {struct/class}].*$SS_fields_types.*" {
pass "return to struct SimpleStruct from field 0"
}
}
}
}
gdb_test_multiple "1" "explore type struct SimpleStruct feild 1" {
-re ".*[child_scalar_type_description {field 'd' of 'struct SimpleStruct'} {double}].*" {
pass "explore type struct SimpleStruct feild 1"
gdb_test_multiple "\0" "return to struct SimpleStruct from field 1" {
-re ".*[compound_type_description $SS {struct/class}].*$SS_fields_types.*" {
pass "return to struct SimpleStruct from field 1"
}
}
}
}
gdb_test_multiple "\0" "return to GDB prompt from struct SimpleStruct" {
-re "$gdb_prompt" {
pass "return to GDB prompt from struct SimpleStruct"
}
}
}
}
gdb_test_multiple "explore union SimpleUnion" "" {
-re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" {
pass "explore union SimpleUnion"
gdb_test_multiple "0" "explore type union SimpleUnion feild 0" {
-re ".*[child_scalar_type_description {field 'i' of 'union SimpleUnion'} {int}].*" {
pass "explore type union SimpleUnion feild 0"
gdb_test_multiple "\0" "return to union SimpleUnion from field 0" {
-re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" {
pass "return to union SimpleUnion from field 0"
}
}
}
}
gdb_test_multiple "1" "explore type union SimpleUnion feild 1" {
-re ".*[child_scalar_type_description {field 'c' of 'union SimpleUnion'} {char}].*" {
pass "explore type union SimpleUnion feild 1"
gdb_test_multiple "\0" "return to union SimpleUnion from field 1" {
-re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" {
pass "return to union SimpleUnion from field 1"
}
}
}
}
gdb_test_multiple "2" "explore type union SimpleUnion feild 2" {
-re ".*[child_scalar_type_description {field 'f' of 'union SimpleUnion'} {float}].*" {
pass "explore type union SimpleUnion feild 2"
gdb_test_multiple "\0" "return to union SimpleUnion from field 2" {
-re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" {
pass "return to union SimpleUnion from field 2"
}
}
}
}
gdb_test_multiple "3" "explore type union SimpleUnion feild 3" {
-re ".*[child_scalar_type_description {field 'd' of 'union SimpleUnion'} {double}].*" {
pass "explore type union SimpleUnion feild 3"
gdb_test_multiple "\0" "return to union SimpleUnion from field 3" {
-re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" {
pass "return to union SimpleUnion from field 3"
}
}
}
}
gdb_test_multiple "\0" "return to GDB prompt from union SimpleUnion" {
-re "$gdb_prompt" {
pass "return to GDB prompt from union SimpleUnion"
}
}
}
}
gdb_test_multiple "explore SS" "" {
-re ".*[typedef_type_description {SS} $SS].*[compound_type_description {SS} {struct/class}].*$SS_fields_types.*" {
pass "explore SS"
gdb_test_multiple "0" "explore type SS feild 0" {
-re ".*[child_scalar_type_description {field 'a' of 'SS'} {int}].*" {
pass "explore type SS feild 0"
gdb_test_multiple "\0" "return to SS from field 0" {
-re ".*[compound_type_description {SS} {struct/class}].*$SS_fields_types.*" {
pass "return to SS from field 0"
}
}
}
}
gdb_test_multiple "1" "explore type SS feild 1" {
-re ".*[child_scalar_type_description {field 'd' of 'SS'} {double}].*" {
pass "explore type SS feild 1"
gdb_test_multiple "\0" "return to struct SimpleStruct from field 1" {
-re ".*[compound_type_description {SS} {struct/class}].*$SS_fields_types.*" {
pass "return to SS field 1"
}
}
}
}
gdb_test_multiple "\0" "return to GDB prompt from SS" {
-re "$gdb_prompt" {
pass "return to GDB prompt from SS"
}
}
}
}
gdb_test_multiple "explore type struct ComplexStruct" "" {
-re ".*[compound_type_description $CS {struct/class}].*$CS_fields_types.*" {
pass "explore type struct ComplexStruct"
gdb_test_multiple "0" "explore type struct ComplexStruct field 0" {
-re ".*[child_compound_type_description $CS_field_0 $SS {struct/class}].*$SS_fields_types.*" {
pass "explore type struct ComplexStruct field 0"
gdb_test_multiple "\0" "return to ComplexStruct from field 0" {
-re ".*[compound_type_description $CS {struct/class}].*$CS_fields_types.*" {
pass "return to ComplexStruct from field 0"
}
}
}
}
gdb_test_multiple "1" "explore type struct ComplexStruct field 1" {
-re ".*[child_compound_type_description $CS_field_1 $SU {union}].*$SU_fields_types.*" {
pass "explore type struct ComplexStruct field 1"
gdb_test_multiple "\0" "return to ComplexStruct from field 1" {
-re ".*[compound_type_description $CS {struct/class}].*$CS_fields_types.*" {
pass "return to ComplexStruct from field 1"
}
}
}
}
gdb_test_multiple "2" "explore type struct ComplexStruct field 2" {
-re ".*[child_array_type_description $CS_field_2 {SS}].*" {
pass "explore type struct ComplexStruct field 2"
gdb_test_multiple "\0" "return to ComplexStruct from field 2" {
-re ".*[compound_type_description $CS {struct/class}].*$CS_fields_types.*" {
pass "return to ComplexStruct from field 2"
}
}
}
}
gdb_test_multiple "\0" "return to GDB prompt from ComplexStruct type exploration" {
-re "$gdb_prompt" {
pass "return to GDB prompt from ComplexStruct type exploration"
}
}
}
}
gdb_test_multiple "explore type union ComplexUnion" "" {
-re ".*[compound_type_description $CU {union}].*$CU_fields_types.*" {
pass "explore type union ComplexUnion"
gdb_test_multiple "0" "explore type union ComplexStruct field 0" {
-re ".*[child_compound_type_description $CU_field_0 $SS {struct/class}].*$SS_fields_types.*" {
pass "explore type union ComplexUnion field 0"
gdb_test_multiple "\0" "return to ComplexUnion from field 0" {
-re ".*[compound_type_description $CU {union}].*$CU_fields_types.*" {
pass "return to ComplexUnion from field 0"
}
}
}
}
gdb_test_multiple "1" "explore type union ComplexUnion field 1" {
-re ".*[child_array_type_description $CU_field_1 $SS].*" {
pass "explore type union ComplexUnion field 1"
gdb_test_multiple "\0" "return to ComplexUnion array" {
-re ".*[compound_type_description $CU {union}].*$CU_fields_types.*" {
pass "return to ComplexUnion from field 1"
}
}
}
}
gdb_test_multiple "\0" "return to GDB prompt from ComplexUnion type exploration" {
-re "$gdb_prompt" {
pass "return to GDB prompt from ComplexUnion type exploration"
}
}
}
}
gdb_test_multiple "explore type cu" "" {
-re "'cu' is of type 'union ComplexUnion'.*[compound_type_description $CU {union}].*$CU_fields_types.*" {
pass "explore type union ComplexUnion"
gdb_test_multiple "0" "explore type union ComplexStruct field 0" {
-re ".*[child_compound_type_description $CU_field_0 $SS {struct/class}].*$SS_fields_types.*" {
pass "explore type union ComplexUnion field 0"
gdb_test_multiple "\0" "return to ComplexUnion from field 0" {
-re ".*[compound_type_description $CU {union}].*$CU_fields_types.*" {
pass "return to ComplexUnion from field 0"
}
}
}
}
gdb_test_multiple "1" "explore type union ComplexUnion field 1" {
-re ".*[child_array_type_description $CU_field_1 $SS].*" {
pass "explore type union ComplexUnion field 1"
gdb_test_multiple "\0" "return to ComplexUnion array" {
-re ".*[compound_type_description $CU {union}].*$CU_fields_types.*" {
pass "return to ComplexUnion from field 1"
}
}
}
}
gdb_test_multiple "\0" "return to GDB prompt from ComplexUnion type exploration" {
-re "$gdb_prompt" {
pass "return to GDB prompt from ComplexUnion type exploration"
}
}
}
}