From: Siva Chandra <sivachandra@google.com>
To: gdb-patches@sourceware.org
Subject: Re: [patch 2/2] New 'explore' command Python implementation (with docs)
Date: Mon, 26 Mar 2012 07:24:00 -0000 [thread overview]
Message-ID: <CAGyQ6gx1QFs2Avhz9Y2KcZJvzKnkt7kbKwSbg_ZmH9tM8cFSjA@mail.gmail.com> (raw)
In-Reply-To: <83haxet7vh.fsf@gnu.org>
[-- Attachment #1: Type: text/plain, Size: 1797 bytes --]
Thanks Eli, for the review. I have fixed according to your suggestion.
Since I have now submitted the patch for Value.referenced_value, I
have added features and tests using this. The patch is attached. There
is no change to gdb.texinfo except for what Eli has suggested. The
ChangeLogs are as follows:
Code ChangeLog:
2012-03-26 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.
Docs ChangeLog:
2012-03-26 Siva Chandra Reddy <sivachandra@google.com>
* gdb.texinfo (Examining Data): Document the 'explore' command.
Testsuite ChangeLog:
2012-03-26 Siva Chandra Reddy <sivachandra@google.com>
* gdb.python/Makefile.in: Add py-explore 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.
Thanks,
Siva Chandra
On Sat, Mar 24, 2012 at 7:32 PM, Eli Zaretskii <eliz@gnu.org> wrote:
>> Date: Wed, 21 Mar 2012 18:04:31 +0530
>> From: Siva Chandra <sivachandra@google.com>
>> Cc: Eli Zaretskii <eliz@gnu.org>
>>
>> +prompted to chose the field you want to explore. Lets say you choose
> ^^^^
> "Let's"
>
> The doco parts of the patch are OK with the above change.
[-- Attachment #2: python_explore_command_patch_v4.text --]
[-- Type: application/octet-stream, Size: 70044 bytes --]
Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.503
diff -c -p -r1.503 NEWS
*** NEWS 25 Mar 2012 13:44:01 -0000 1.503
--- NEWS 26 Mar 2012 07:00:56 -0000
*************** QProgramSignals:
*** 129,134 ****
--- 129,139 ----
--init-eval-command=COMMAND, -iex Like --eval-command=COMMAND, -ex but
execute it before loading inferior.
+ ** "explore" and its sub commands "explore value" and "explore type"
+ can be used to recurrsively explore values and types of
+ expressions. These commands are available only if GDB is
+ configured with '--with-python'.
+
*** Changes in GDB 7.4
* GDB now handles ambiguous linespecs more consistently; the existing
Index: data-directory/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/data-directory/Makefile.in,v
retrieving revision 1.10
diff -c -p -r1.10 Makefile.in
*** data-directory/Makefile.in 4 Jan 2012 08:17:19 -0000 1.10
--- data-directory/Makefile.in 26 Mar 2012 07:00:56 -0000
*************** PYTHON_FILES = \
*** 58,64 ****
gdb/prompt.py \
gdb/command/__init__.py \
gdb/command/pretty_printers.py \
! gdb/command/prompt.py
FLAGS_TO_PASS = \
"prefix=$(prefix)" \
--- 58,65 ----
gdb/prompt.py \
gdb/command/__init__.py \
gdb/command/pretty_printers.py \
! gdb/command/prompt.py \
! gdb/command/explore.py
FLAGS_TO_PASS = \
"prefix=$(prefix)" \
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.936
diff -c -p -r1.936 gdb.texinfo
*** doc/gdb.texinfo 22 Mar 2012 08:10:41 -0000 1.936
--- doc/gdb.texinfo 26 Mar 2012 07:01:01 -0000
*************** fields of a struct or a class are declar
*** 7198,7203 ****
--- 7198,7350 ----
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
Index: python/lib/gdb/command/explore.py
===================================================================
RCS file: python/lib/gdb/command/explore.py
diff -N python/lib/gdb/command/explore.py
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- python/lib/gdb/command/explore.py 26 Mar 2012 07:01:02 -0000
***************
*** 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()
Index: testsuite/gdb.python/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.python/Makefile.in,v
retrieving revision 1.15
diff -c -p -r1.15 Makefile.in
*** testsuite/gdb.python/Makefile.in 22 Mar 2012 08:10:44 -0000 1.15
--- testsuite/gdb.python/Makefile.in 26 Mar 2012 07:01:02 -0000
*************** EXECUTABLES = py-type py-value py-pretty
*** 5,11 ****
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
MISCELLANEOUS = py-shared-sl.sl py-events-shlib.so py-events-shlib-nodebug.so
--- 5,12 ----
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-explore \
! py-explore-cc
MISCELLANEOUS = py-shared-sl.sl py-events-shlib.so py-events-shlib-nodebug.so
Index: testsuite/gdb.python/py-explore-cc.exp
===================================================================
RCS file: testsuite/gdb.python/py-explore-cc.exp
diff -N testsuite/gdb.python/py-explore-cc.exp
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gdb.python/py-explore-cc.exp 26 Mar 2012 07:01:02 -0000
***************
*** 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"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
Index: testsuite/gdb.python/py-explore.c
===================================================================
RCS file: testsuite/gdb.python/py-explore.c
diff -N testsuite/gdb.python/py-explore.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gdb.python/py-explore.c 26 Mar 2012 07:01:02 -0000
***************
*** 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. */
+ }
Index: testsuite/gdb.python/py-explore.cc
===================================================================
RCS file: testsuite/gdb.python/py-explore.cc
diff -N testsuite/gdb.python/py-explore.cc
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gdb.python/py-explore.cc 26 Mar 2012 07:01:02 -0000
***************
*** 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);
+ }
Index: testsuite/gdb.python/py-explore.exp
===================================================================
RCS file: testsuite/gdb.python/py-explore.exp
diff -N testsuite/gdb.python/py-explore.exp
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gdb.python/py-explore.exp 26 Mar 2012 07:01:02 -0000
***************
*** 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"
+ }
+ }
+ }
+ }
next prev parent reply other threads:[~2012-03-26 7:24 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-07 11:29 Siva Chandra
2012-03-09 8:57 ` Eli Zaretskii
2012-03-21 12:35 ` Siva Chandra
2012-03-24 14:02 ` Eli Zaretskii
2012-03-26 7:24 ` Siva Chandra [this message]
2012-03-31 9:58 ` Eli Zaretskii
2012-04-02 5:58 ` Siva Chandra
2012-04-09 18:37 ` Siva Chandra
2012-04-10 17:21 ` Doug Evans
2012-04-10 17:22 ` Eli Zaretskii
2012-04-10 18:59 ` Doug Evans
2012-04-11 6:29 ` Siva Chandra
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAGyQ6gx1QFs2Avhz9Y2KcZJvzKnkt7kbKwSbg_ZmH9tM8cFSjA@mail.gmail.com \
--to=sivachandra@google.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox