Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [patch 2/2] New 'explore' command Python implementation (with docs)
@ 2012-03-07 11:29 Siva Chandra
  2012-03-09  8:57 ` Eli Zaretskii
  0 siblings, 1 reply; 12+ messages in thread
From: Siva Chandra @ 2012-03-07 11:29 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 827 bytes --]

This is the implementation of the 'explore' command in Python.

2012-03-05 Siva Chandra <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: Add description about the 'explore'
        command in the chapter 'Examining Data'
        * 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.
        * testsuite/gdb-python/py-explore.exp: Tests for the new 'explore'
        command.

[-- Attachment #2: python_explore_command_patch_v2.txt --]
[-- Type: text/plain, Size: 53036 bytes --]

diff -rupN src/gdb/data-directory/Makefile.in src_explore_python/gdb/data-directory/Makefile.in
--- src/gdb/data-directory/Makefile.in	2012-01-04 13:47:19.000000000 +0530
+++ src_explore_python/gdb/data-directory/Makefile.in	2012-02-19 17:59:54.281806521 +0530
@@ -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)" \
diff -rupN src/gdb/doc/gdb.texinfo src_explore_python/gdb/doc/gdb.texinfo
--- src/gdb/doc/gdb.texinfo	2012-02-10 06:54:58.000000000 +0530
+++ src_explore_python/gdb/doc/gdb.texinfo	2012-03-03 17:48:34.952129666 +0530
@@ -7055,8 +7055,10 @@ instruction.
 
 @cindex printing data
 @cindex examining data
+@cindex exploring data
 @kindex print
 @kindex inspect
+@kindex explore
 @c "inspect" is not quite a synonym if you are using Epoch, which we do not
 @c document because it is nonstandard...  Under Epoch it displays in a
 @c different window or something like that.
@@ -7093,6 +7095,33 @@ fields of a struct or a class are declar
 command rather than @code{print}.  @xref{Symbols, ,Examining the Symbol
 Table}.
 
+Another way of examining values of expressions and type information is
+through the Python extension (hence only available if GDB build is
+configured with @code{--with-python}) command @code{explore}.  It offers
+an interactive way to start at the highest level (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 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.
+
+@item explore value @var{expr}
+@cindex explore value
+This variation lets one explicitly specify that value exploration is
+being invoked on the expression @var{expr}.  @var{expr} should be an
+expression valid in the current context of the program being debugged.
+
+@item explore type @var{arg}
+@cindex explore type
+This variation lets one explicitly specify that type exploration is
+being invoked on @var{arg} which can be either be an expression or a
+type.  If it were an expression, then the type of value of the
+expression is explored.
+@end table
+
 @menu
 * Expressions::                 Expressions
 * Ambiguous Expressions::       Ambiguous Expressions
diff -rupN src/gdb/NEWS src_explore_python/gdb/NEWS
--- src/gdb/NEWS	2012-03-05 16:55:36.652342189 +0530
+++ src_explore_python/gdb/NEWS	2012-03-05 16:58:49.922290874 +0530
@@ -20,6 +20,12 @@
      frame in order to compute its value, and the latter computes the
      symbol's value.
 
+  ** A new command 'explore' implemented using the GBD Python API. It
+     enables one to explore values (of expressions) and types top down.
+     Top down here means to start at the highest data structure and
+     explore down to the leaf scalar value/types enclosed in the higher
+     data structures.
+
 * GDBserver now supports stdio connections.
   E.g. (gdb) target remote | ssh myhost gdbserver - hello
 
@@ -49,6 +55,12 @@
   ** "catch load" and "catch unload" can be used to stop when a shared
      library is loaded or unloaded, respectively.
 
+  ** "explore" and its sub commands "explore value" and "explore type"
+     can be used to recurrsively explore values and types of
+     expressions. The command "explore type" can be used to explore
+     types directly. 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
diff -rupN src/gdb/python/lib/gdb/command/explore.py src_explore_python/gdb/python/lib/gdb/command/explore.py
--- src/gdb/python/lib/gdb/command/explore.py	1970-01-01 05:30:00.000000000 +0530
+++ src_explore_python/gdb/python/lib/gdb/command/explore.py	2012-03-05 17:10:56.872378786 +0530
@@ -0,0 +1,694 @@
+# 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_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'.\n" %
+               (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 ("\n'%s' is a pointer to a value of type '%s'" %
+               (expr, str(value.type.target())))
+        option  = raw_input("Do you want to explore it as an array or a "
+                            "single value pointer [a/s] : ")
+        if option == "s":
+            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)
+        if option == "a":
+            while True:
+                index = 0
+                try:
+                    index = int(raw_input("Enter the index you want to "
+                                          "explore in '%s': " % expr))
+                except ValueError:
+                    break
+                element_expr = "%s[%d]" % (Explorer.guard_expr(expr), index)
+                element = gdb.parse_and_eval(element_expr)
+                try:
+                    str(element)
+                except gdb.MemoryError:
+                    print "Cannot read value at index %d." % index
+                    continue
+                Explorer.explore_expr(element_expr, element, True)
+        if option != "s" and option != "a":    
+            if is_child:
+                Explorer.retur_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 of a pointer type pointing 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 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 elements of type '%s'." %
+               (expr, str(target_type)))
+        index = 0
+        try:
+            index = int(raw_input("Enter the index 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 type with elements of type '%s'." % 
+               (name, str(target_type)))
+
+        explore_type(target_type, "the array element of %s" % name, 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 explore_expr(expr, value, is_child):
+        """Function to explore structs/classes and union values.
+        See Explorer.explore_expr for more information.
+        """
+        type_code = value.type.code
+        type_desc = ""
+        if type_code == gdb.TYPE_CODE_STRUCT:
+            type_desc = "struct/class"
+        else:
+            type_desc = "union"
+        print("The value of '%s' is a %s of type '%s' with the following "
+              "fields:\n" % (expr, type_desc, str(value.type)))
+
+        fields = value.type.fields()
+        has_explorable_fields = False
+        choice_to_compound_field_map = { }
+        current_choice = 0
+        print_list = [ ]
+        for field in fields:
+            field_full_name = Explorer.guard_expr(expr) + "." + field.name
+            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"
+
+        if is_child:
+            print ("\n%s is a %s of type '%s' "
+                   "with the following fields:\n" %
+                   (name, type_desc, str(datatype)))
+        else:
+            print ("\n'%s' is a %s with the following "
+                   "fields:\n" %
+                   (name, type_desc))
+
+        fields = datatype.fields()
+        has_explorable_fields = False
+        current_choice = 0
+        choice_to_compound_field_map = { }
+        print_list = [ ]
+        for field in fields:
+            rhs = ("<Enter %d to explore this field of type %s>" %
+                   (current_choice, str(field.type)))
+            print_list.append((field.name, rhs))
+            choice_to_compound_field_map[str(current_choice)] = (
+                field.name, field.type)
+            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:
+                    Explorer.explore_type(
+                        ("field '%s' of %s" %
+                         (choice_to_compound_field_map[choice][0], name)),
+                        choice_to_compound_field_map[choice][1],
+                        True)
+                else:
+                    Explorer.explore_type(
+                        ("field '%s' of '%s'" %
+                         (choice_to_compound_field_map[choice][0], 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 ("\nThe 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("\nThe type of %s is a typedef of type '%s'." %
+                  (name, str(actual_type)))
+        else:
+            print("\nThe 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' command 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. Entering
+           an invalid input will also result in similar behaviour.
+    """
+
+    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. Entering
+           an invalid input will also result in similar behaviour.
+    """
+ 
+    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. Entering
+           an invalid input will also result in similar behaviour.
+    """
+
+    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()
diff -rupN src/gdb/testsuite/gdb.python/Makefile.in src_explore_python/gdb/testsuite/gdb.python/Makefile.in
--- src/gdb/testsuite/gdb.python/Makefile.in	2011-12-23 22:36:16.000000000 +0530
+++ src_explore_python/gdb/testsuite/gdb.python/Makefile.in	2012-02-19 17:51:28.783055525 +0530
@@ -5,7 +5,7 @@ EXECUTABLES = py-type py-value py-pretty
 	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-finish-breakpoint py-finish-breakpoint2 py-explore
 
 MISCELLANEOUS = py-shared-sl.sl py-events-shlib.so py-events-shlib-nodebug.so 
 
diff -rupN src/gdb/testsuite/gdb.python/py-explore.c src_explore_python/gdb/testsuite/gdb.python/py-explore.c
--- src/gdb/testsuite/gdb.python/py-explore.c	1970-01-01 05:30:00.000000000 +0530
+++ src_explore_python/gdb/testsuite/gdb.python/py-explore.c	2012-02-20 18:17:18.534828901 +0530
@@ -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. */
+}
diff -rupN src/gdb/testsuite/gdb.python/py-explore.exp src_explore_python/gdb/testsuite/gdb.python/py-explore.exp
--- src/gdb/testsuite/gdb.python/py-explore.exp	1970-01-01 05:30:00.000000000 +0530
+++ src_explore_python/gdb/testsuite/gdb.python/py-explore.exp	2012-02-26 17:42:44.460496395 +0530
@@ -0,0 +1,464 @@
+# 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 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 elements of type '$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 "Do you want to explore it as an array or a single value pointer \[\[\]a/s\[\]\] : " 
+    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 "s" "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 "a" "explore_as_array" {
+            -re ".*Enter the index 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 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 type with elements of type '$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"
+            }
+        }
+    }
+}

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 2/2] New 'explore' command Python implementation (with docs)
  2012-03-07 11:29 [patch 2/2] New 'explore' command Python implementation (with docs) Siva Chandra
@ 2012-03-09  8:57 ` Eli Zaretskii
  2012-03-21 12:35   ` Siva Chandra
  0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2012-03-09  8:57 UTC (permalink / raw)
  To: Siva Chandra; +Cc: gdb-patches

> Date: Wed, 7 Mar 2012 16:58:29 +0530
> From: Siva Chandra <sivachandra@google.com>
> 
> +Another way of examining values of expressions and type information is
> +through the Python extension (hence only available if GDB build is

@value{GDBN} instead of a literal "GDB".

The rest of the documentation text is identical to what I already
reviewed.

Thanks.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 2/2] New 'explore' command Python implementation (with docs)
  2012-03-09  8:57 ` Eli Zaretskii
@ 2012-03-21 12:35   ` Siva Chandra
  2012-03-24 14:02     ` Eli Zaretskii
  0 siblings, 1 reply; 12+ messages in thread
From: Siva Chandra @ 2012-03-21 12:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Eli Zaretskii

[-- Attachment #1: Type: text/plain, Size: 1702 bytes --]

Hello,

I was hoping to submit the other patch on Value.referenced_value
before sending this one over. Since I could not yet submit (though
approved), I am sending over the 'explore' command patch with
suggested changes.

Thanks to Eli for reviewing. I have modified according to your
suggestions. However, since there is a lot of new material, it will
require another close review.

Docs ChangeLog:

2012-03-21 Siva Chandra <sivachandra@google.com>

        * gdb.texinfo (Examining Data): Document the 'explore' command.

Code ChangeLog:

2012-03-21 Siva Chandra <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.

Testsuite ChangeLog:

2012-03-21 Siva Chandra <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.
        * gdb-python/py-explore.exp: Tests for the new 'explore'
        command.

Thanks,
Siva Chandra

On Fri, Mar 9, 2012 at 2:26 PM, Eli Zaretskii <eliz@gnu.org> wrote:
>> Date: Wed, 7 Mar 2012 16:58:29 +0530
>> From: Siva Chandra <sivachandra@google.com>
>>
>> +Another way of examining values of expressions and type information is
>> +through the Python extension (hence only available if GDB build is
>
> @value{GDBN} instead of a literal "GDB".
>
> The rest of the documentation text is identical to what I already
> reviewed.
>
> Thanks.

[-- Attachment #2: python_explore_command_patch_v3.txt --]
[-- Type: text/plain, Size: 56612 bytes --]

diff -rupN src/gdb/data-directory/Makefile.in src_explore_python/gdb/data-directory/Makefile.in
--- src/gdb/data-directory/Makefile.in	2012-01-04 13:47:19.000000000 +0530
+++ src_explore_python/gdb/data-directory/Makefile.in	2012-02-19 17:59:54.281806521 +0530
@@ -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)" \
diff -rupN src/gdb/doc/gdb.texinfo src_explore_python/gdb/doc/gdb.texinfo
--- src/gdb/doc/gdb.texinfo	2012-02-10 06:54:58.000000000 +0530
+++ src_explore_python/gdb/doc/gdb.texinfo	2012-03-21 16:21:39.289254155 +0530
@@ -7093,6 +7093,153 @@ fields of a struct or a class are declar
 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.  Lets 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
diff -rupN src/gdb/NEWS src_explore_python/gdb/NEWS
--- src/gdb/NEWS	2012-03-05 16:55:36.652342189 +0530
+++ src_explore_python/gdb/NEWS	2012-03-21 17:26:15.485697544 +0530
@@ -49,6 +49,11 @@
   ** "catch load" and "catch unload" can be used to stop when a shared
      library is loaded or unloaded, respectively.
 
+  ** "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
diff -rupN src/gdb/python/lib/gdb/command/explore.py src_explore_python/gdb/python/lib/gdb/command/explore.py
--- src/gdb/python/lib/gdb/command/explore.py	1970-01-01 05:30:00.000000000 +0530
+++ src_explore_python/gdb/python/lib/gdb/command/explore.py	2012-03-21 11:16:41.938146046 +0530
@@ -0,0 +1,694 @@
+# 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_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'.\n" %
+               (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 ("\n'%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 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 explore_expr(expr, value, is_child):
+        """Function to explore structs/classes and union values.
+        See Explorer.explore_expr for more information.
+        """
+        type_code = value.type.code
+        type_desc = ""
+        if type_code == gdb.TYPE_CODE_STRUCT:
+            type_desc = "struct/class"
+        else:
+            type_desc = "union"
+        print("The value of '%s' is a %s of type '%s' with the following "
+              "fields:\n" % (expr, type_desc, str(value.type)))
+
+        fields = value.type.fields()
+        has_explorable_fields = False
+        choice_to_compound_field_map = { }
+        current_choice = 0
+        print_list = [ ]
+        for field in fields:
+            field_full_name = Explorer.guard_expr(expr) + "." + field.name
+            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"
+
+        if is_child:
+            print ("\n%s is a %s of type '%s' "
+                   "with the following fields:\n" %
+                   (name, type_desc, str(datatype)))
+        else:
+            print ("\n'%s' is a %s with the following "
+                   "fields:\n" %
+                   (name, type_desc))
+
+        fields = datatype.fields()
+        has_explorable_fields = False
+        current_choice = 0
+        choice_to_compound_field_map = { }
+        print_list = [ ]
+        for field in fields:
+            rhs = ("<Enter %d to explore this field of type '%s'>" %
+                   (current_choice, str(field.type)))
+            print_list.append((field.name, rhs))
+            choice_to_compound_field_map[str(current_choice)] = (
+                field.name, field.type)
+            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:
+                    Explorer.explore_type(
+                        ("field '%s' of %s" %
+                         (choice_to_compound_field_map[choice][0], name)),
+                        choice_to_compound_field_map[choice][1],
+                        True)
+                else:
+                    Explorer.explore_type(
+                        ("field '%s' of '%s'" %
+                         (choice_to_compound_field_map[choice][0], 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 ("\nThe 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("\nThe type of %s is a typedef of type '%s'." %
+                  (name, str(actual_type)))
+        else:
+            print("\nThe 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()
diff -rupN src/gdb/testsuite/gdb.python/Makefile.in src_explore_python/gdb/testsuite/gdb.python/Makefile.in
--- src/gdb/testsuite/gdb.python/Makefile.in	2011-12-23 22:36:16.000000000 +0530
+++ src_explore_python/gdb/testsuite/gdb.python/Makefile.in	2012-02-19 17:51:28.783055525 +0530
@@ -5,7 +5,7 @@ EXECUTABLES = py-type py-value py-pretty
 	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-finish-breakpoint py-finish-breakpoint2 py-explore
 
 MISCELLANEOUS = py-shared-sl.sl py-events-shlib.so py-events-shlib-nodebug.so 
 
diff -rupN src/gdb/testsuite/gdb.python/py-explore.c src_explore_python/gdb/testsuite/gdb.python/py-explore.c
--- src/gdb/testsuite/gdb.python/py-explore.c	1970-01-01 05:30:00.000000000 +0530
+++ src_explore_python/gdb/testsuite/gdb.python/py-explore.c	2012-02-20 18:17:18.534828901 +0530
@@ -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. */
+}
diff -rupN src/gdb/testsuite/gdb.python/py-explore.exp src_explore_python/gdb/testsuite/gdb.python/py-explore.exp
--- src/gdb/testsuite/gdb.python/py-explore.exp	1970-01-01 05:30:00.000000000 +0530
+++ src_explore_python/gdb/testsuite/gdb.python/py-explore.exp	2012-03-18 12:50:34.212131820 +0530
@@ -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"
+            }
+        }
+    }
+}

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 2/2] New 'explore' command Python implementation (with docs)
  2012-03-21 12:35   ` Siva Chandra
@ 2012-03-24 14:02     ` Eli Zaretskii
  2012-03-26  7:24       ` Siva Chandra
  0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2012-03-24 14:02 UTC (permalink / raw)
  To: Siva Chandra; +Cc: gdb-patches

> 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.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 2/2] New 'explore' command Python implementation (with docs)
  2012-03-24 14:02     ` Eli Zaretskii
@ 2012-03-26  7:24       ` Siva Chandra
  2012-03-31  9:58         ` Eli Zaretskii
  0 siblings, 1 reply; 12+ messages in thread
From: Siva Chandra @ 2012-03-26  7:24 UTC (permalink / raw)
  To: gdb-patches

[-- 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"
+             }
+         }
+     }
+ }

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 2/2] New 'explore' command Python implementation (with docs)
  2012-03-26  7:24       ` Siva Chandra
@ 2012-03-31  9:58         ` Eli Zaretskii
  2012-04-02  5:58           ` Siva Chandra
  0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2012-03-31  9:58 UTC (permalink / raw)
  To: Siva Chandra; +Cc: gdb-patches

> Date: Mon, 26 Mar 2012 12:53:56 +0530
> From: Siva Chandra <sivachandra@google.com>
> 
> +   ** "explore" and its sub commands "explore value" and "explore type"
> +      can be used to recurrsively explore values and types of
                        ^^^^^^^^^^^^
A typo.

Thanks.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 2/2] New 'explore' command Python implementation (with docs)
  2012-03-31  9:58         ` Eli Zaretskii
@ 2012-04-02  5:58           ` Siva Chandra
  2012-04-09 18:37             ` Siva Chandra
  0 siblings, 1 reply; 12+ messages in thread
From: Siva Chandra @ 2012-04-02  5:58 UTC (permalink / raw)
  To: gdb-patches; +Cc: Eli Zaretskii

[-- Attachment #1: Type: text/plain, Size: 1511 bytes --]

Thanks Eli, I have fixed it. The complete patch is attached.

Code ChangeLog:

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.

Docs ChangeLog:

2012-04-02  Siva Chandra Reddy  <sivachandra@google.com>

	* gdb.texinfo (Examining Data): Document the 'explore' command.

Testsuite ChangeLog:

2012-04-02  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 31, 2012 at 3:27 PM, Eli Zaretskii <eliz@gnu.org> wrote:
>> Date: Mon, 26 Mar 2012 12:53:56 +0530
>> From: Siva Chandra <sivachandra@google.com>
>>
>> +   ** "explore" and its sub commands "explore value" and "explore type"
>> +      can be used to recurrsively explore values and types of
>                        ^^^^^^^^^^^^
> A typo.
>
> Thanks.

[-- Attachment #2: python_explore_command_patch_v5.text --]
[-- Type: application/octet-stream, Size: 69918 bytes --]

Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.505
diff -c -p -r1.505 NEWS
*** NEWS	28 Mar 2012 21:31:56 -0000	1.505
--- NEWS	1 Apr 2012 18:55:25 -0000
***************
*** 93,98 ****
--- 93,103 ----
    ** "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
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.939
diff -c -p -r1.939 gdb.texinfo
*** doc/gdb.texinfo	28 Mar 2012 21:31:46 -0000	1.939
--- doc/gdb.texinfo	1 Apr 2012 18:55:53 -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	1 Apr 2012 18:55:54 -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: 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	1 Apr 2012 18:55:54 -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: 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	1 Apr 2012 18:55:54 -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	1 Apr 2012 18:55:54 -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	1 Apr 2012 18:55:54 -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"
+             }
+         }
+     }
+ }
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	1 Apr 2012 18:55:54 -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/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	1 Apr 2012 18:55:54 -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 
  

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 2/2] New 'explore' command Python implementation (with docs)
  2012-04-02  5:58           ` Siva Chandra
@ 2012-04-09 18:37             ` Siva Chandra
  2012-04-10 17:21               ` Doug Evans
  0 siblings, 1 reply; 12+ messages in thread
From: Siva Chandra @ 2012-04-09 18:37 UTC (permalink / raw)
  To: gdb-patches

<ping>

Is there sufficient interest in this?

On Mon, Apr 2, 2012 at 11:28 AM, Siva Chandra <sivachandra@google.com> wrote:
> Thanks Eli, I have fixed it. The complete patch is attached.
>
> Code ChangeLog:
>
> 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.
>
> Docs ChangeLog:
>
> 2012-04-02  Siva Chandra Reddy  <sivachandra@google.com>
>
>        * gdb.texinfo (Examining Data): Document the 'explore' command.
>
> Testsuite ChangeLog:
>
> 2012-04-02  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


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 2/2] New 'explore' command Python implementation (with docs)
  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
  0 siblings, 2 replies; 12+ messages in thread
From: Doug Evans @ 2012-04-10 17:21 UTC (permalink / raw)
  To: Siva Chandra; +Cc: gdb-patches

Hi.
Thanks for persevering!

LGTM

I think all the doc issues are resolved, right Eli?

On Mon, Apr 9, 2012 at 11:37 AM, Siva Chandra <sivachandra@google.com> wrote:
> <ping>
>
> Is there sufficient interest in this?
>
> On Mon, Apr 2, 2012 at 11:28 AM, Siva Chandra <sivachandra@google.com> wrote:
>> Thanks Eli, I have fixed it. The complete patch is attached.
>>
>> Code ChangeLog:
>>
>> 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.
>>
>> Docs ChangeLog:
>>
>> 2012-04-02  Siva Chandra Reddy  <sivachandra@google.com>
>>
>>        * gdb.texinfo (Examining Data): Document the 'explore' command.
>>
>> Testsuite ChangeLog:
>>
>> 2012-04-02  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


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 2/2] New 'explore' command Python implementation (with docs)
  2012-04-10 17:21               ` Doug Evans
@ 2012-04-10 17:22                 ` Eli Zaretskii
  2012-04-10 18:59                 ` Doug Evans
  1 sibling, 0 replies; 12+ messages in thread
From: Eli Zaretskii @ 2012-04-10 17:22 UTC (permalink / raw)
  To: Doug Evans; +Cc: sivachandra, gdb-patches

> Date: Tue, 10 Apr 2012 10:16:30 -0700
> From: Doug Evans <dje@google.com>
> Cc: gdb-patches@sourceware.org
> 
> I think all the doc issues are resolved, right Eli?

I'm quite sure I reviewed it more than once.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 2/2] New 'explore' command Python implementation (with docs)
  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
  1 sibling, 1 reply; 12+ messages in thread
From: Doug Evans @ 2012-04-10 18:59 UTC (permalink / raw)
  To: Siva Chandra; +Cc: gdb-patches

Playing with it a bit, I think we might want to tweak the output a bit
(remove the repetitive "... to explore this field ..."), but I don't
want to hold this patch up any longer, so I'm happy to leave that for
a later pass.

'struct dwarf2_cu' is a struct/class with the following fields:

                 objfile = <Enter 0 to explore this field of type
'struct objfile *'>
                  header = <Enter 1 to explore this field of type
'struct comp_unit_head'>
            base_address = <Enter 2 to explore this field of type 'CORE_ADDR'>
              base_known = <Enter 3 to explore this field of type 'int'>
                language = <Enter 4 to explore this field of type
'enum language'>
           language_defn = <Enter 5 to explore this field of type
'const struct language_defn *'>
                producer = <Enter 6 to explore this field of type
'const char *'>
           list_in_scope = <Enter 7 to explore this field of type
'struct pending **'>
          dwarf2_abbrevs = <Enter 8 to explore this field of type
'struct abbrev_info **'>
          abbrev_obstack = <Enter 9 to explore this field of type
'struct obstack'>
            partial_dies = <Enter 10 to explore this field of type 'htab_t'>
       comp_unit_obstack = <Enter 11 to explore this field of type
'struct obstack'>
           read_in_chain = <Enter 12 to explore this field of type
'struct dwarf2_per_cu_data *'>
                  per_cu = <Enter 13 to explore this field of type
'struct dwarf2_per_cu_data *'>
               last_used = <Enter 14 to explore this field of type 'int'>
                die_hash = <Enter 15 to explore this field of type 'htab_t'>
                    dies = <Enter 16 to explore this field of type
'struct die_info *'>
            dependencies = <Enter 17 to explore this field of type 'htab_t'>
             line_header = <Enter 18 to explore this field of type
'struct line_header *'>
             method_list = <Enter 19 to explore this field of type
'VEC_delayed_method_info *'>
          call_site_htab = <Enter 20 to explore this field of type 'htab_t'>
                    mark = <Enter 21 to explore this field of type
'unsigned int'>
             has_loclist = <Enter 22 to explore this field of type
'unsigned int'>
        checked_producer = <Enter 23 to explore this field of type
'unsigned int'>
  producer_is_gxx_lt_4_6 = <Enter 24 to explore this field of type
'unsigned int'>


On Tue, Apr 10, 2012 at 10:16 AM, Doug Evans <dje@google.com> wrote:
> Hi.
> Thanks for persevering!
>
> LGTM
>
> I think all the doc issues are resolved, right Eli?
>
> On Mon, Apr 9, 2012 at 11:37 AM, Siva Chandra <sivachandra@google.com> wrote:
>> <ping>
>>
>> Is there sufficient interest in this?
>>
>> On Mon, Apr 2, 2012 at 11:28 AM, Siva Chandra <sivachandra@google.com> wrote:
>>> Thanks Eli, I have fixed it. The complete patch is attached.
>>>
>>> Code ChangeLog:
>>>
>>> 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.
>>>
>>> Docs ChangeLog:
>>>
>>> 2012-04-02  Siva Chandra Reddy  <sivachandra@google.com>
>>>
>>>        * gdb.texinfo (Examining Data): Document the 'explore' command.
>>>
>>> Testsuite ChangeLog:
>>>
>>> 2012-04-02  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


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 2/2] New 'explore' command Python implementation (with docs)
  2012-04-10 18:59                 ` Doug Evans
@ 2012-04-11  6:29                   ` Siva Chandra
  0 siblings, 0 replies; 12+ messages in thread
From: Siva Chandra @ 2012-04-11  6:29 UTC (permalink / raw)
  To: Doug Evans, Eli Zaretskii; +Cc: gdb-patches

Thanks a lot Eli and Doug for the reviews.

Doug> Playing with it a bit, I think we might want to tweak the output a bit
Doug> (remove the repetitive "... to explore this field ..."), but I don't
Doug> want to hold this patch up any longer, so I'm happy to leave that for
Doug> a later pass.

Committed the patch.  Will start work on second pass soon.

Thanks,
Siva Chandra


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2012-04-11  5:58 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-07 11:29 [patch 2/2] New 'explore' command Python implementation (with docs) 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
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox