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
@ -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
|
||||
|
5
gdb/NEWS
5
gdb/NEWS
@ -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
|
||||
|
@ -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)" \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
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()
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
146
gdb/testsuite/gdb.python/py-explore-cc.exp
Normal file
146
gdb/testsuite/gdb.python/py-explore-cc.exp
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
82
gdb/testsuite/gdb.python/py-explore.c
Normal file
82
gdb/testsuite/gdb.python/py-explore.c
Normal 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. */
|
||||
}
|
54
gdb/testsuite/gdb.python/py-explore.cc
Normal file
54
gdb/testsuite/gdb.python/py-explore.cc
Normal 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);
|
||||
}
|
469
gdb/testsuite/gdb.python/py-explore.exp
Normal file
469
gdb/testsuite/gdb.python/py-explore.exp
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user