* [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