diff -rupN src/gdb/doc/gdb.texinfo src_explore_c/gdb/doc/gdb.texinfo
--- src/gdb/doc/gdb.texinfo 2012-02-10 06:54:58.000000000 +0530
+++ src_explore_c/gdb/doc/gdb.texinfo 2012-03-03 17:49:33.002127001 +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,31 @@ 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 @code{explore} command. 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/explore.c src_explore_c/gdb/explore.c
--- src/gdb/explore.c 1970-01-01 05:30:00.000000000 +0530
+++ src_explore_c/gdb/explore.c 2012-03-05 16:05:11.953541122 +0530
@@ -0,0 +1,1165 @@
+/* Implementation of the 'explore' command.
+
+ Copyright (C) 2012 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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 . */
+
+#include "defs.h"
+
+/* For domain_enum */
+#include "symtab.h"
+
+#include "arch-utils.h"
+#include "command.h"
+#include "exceptions.h"
+#include "gdb_string.h"
+#include "gdbcmd.h"
+#include "gdbtypes.h"
+#include "language.h"
+#include "ui-file.h"
+#include "value.h"
+#include "valprint.h"
+
+static void explore_value (struct value *, const char *, int);
+static void explore_type (struct type *, const char *, int);
+
+/* Different types of exploration. */
+
+enum exploration_type
+{
+ /* For value exploration. */
+ VALUE_EXPLORATION = 0,
+
+ /* For type exploration. */
+ TYPE_EXPLORATION = 1
+};
+
+/* Return 1 if STR is all spaces. O otherwise. */
+
+static int
+is_all_spaces (const char *str)
+{
+ int i;
+ int len = strlen (str);
+
+ for (i = 0; i < len; ++i)
+ {
+ if (str[i] != ' ')
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void
+strip_leading_spaces (char **str_ptr)
+{
+ char *str = *str_ptr;
+ for (; *str != '\0'; str++)
+ {
+ if (*str != ' ')
+ {
+ *str_ptr = str;
+ return;
+ }
+ }
+}
+
+/* Prompt the user to return the state of exploration to the
+ parent value. Used in value exploration. */
+
+static void
+return_to_parent_value_prompt (void)
+{
+ xfree (gdb_readline (_("Press enter to return to parent value: ")));
+ printf_filtered ("\n");
+}
+
+/* Prompt the user to return the state of exploration to the
+ enclosing/parent type. Used in type exploration. */
+
+static void
+return_to_parent_type_prompt (void)
+{
+ xfree (gdb_readline (_("Press enter to return to enclosing type: ")));
+ printf_filtered ("\n");
+}
+
+/* Print a message for the user informing that the the state of
+ exploration is moving to the parent value. */
+
+static void
+return_to_parent_value (void)
+{
+ printf_filtered (_("Returning to parent value...\n"));
+}
+
+/* Print a message for the user informing that the the state of
+ exploration is moving to the parent/enclosing type. */
+
+static void
+return_to_parent_type (void)
+{
+ printf_filtered (_("Returning to parent type...\n"));
+}
+
+/* Retrun the string representation of VAL. The returned value
+ should be cleaned up after use. */
+
+static char *
+get_value_string (struct value *val)
+{
+ struct ui_file *mem_file = mem_fileopen ();
+ struct value_print_options opts;
+ char *val_string;
+
+ get_user_print_options (&opts);
+ common_val_print (val, mem_file, 0, &opts, current_language);
+ val_string = ui_file_xstrdup (mem_file, NULL);
+
+ ui_file_delete (mem_file);
+ return val_string;
+}
+
+/* Add parentheses to an EXP_STR if required. The added parenthesis
+ serves as a guard which ensures proper operator precedence when, for
+ example, dereferencing the value of which EXP_STR evaluates to. The
+ returned value should be cleaned up after use. */
+
+static char *
+guard_exp_str (const char *exp_str)
+{
+ int len = strlen (exp_str);
+ int i, guard = 0;
+ char *new_exp;
+
+ if (exp_str[0] == '(' && exp_str[len - 1] == ')')
+ {
+ ;
+ }
+ else
+ {
+ for (i = 0; i < len; i++)
+ {
+ char c = exp_str[i];
+ if (c == '_' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
+ || ('0' <= c && c <= '9'))
+ {
+ ;
+ }
+ else
+ {
+ guard = 1;
+ break;
+ }
+ }
+ }
+
+ if (guard)
+ {
+ new_exp = xstrprintf (_("(%s)"), exp_str);
+ }
+ else
+ {
+ new_exp = xstrprintf (_("%s"), exp_str);
+ }
+
+ return new_exp;
+}
+
+/* Return 1 if VAL_TYPE is a scalar type, 0 otherwise. */
+
+static int
+is_scalar_type (struct type *val_type)
+{
+ switch (TYPE_CODE (val_type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_ENUM:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Explore scalar value. */
+
+static int
+explore_scalar_value (struct value *val, const char *exp_str, int is_child)
+{
+ struct cleanup *cleanup_obj = make_cleanup (null_cleanup, NULL);
+
+ char *type_name = type_to_string (value_type (val));
+ char *val_str = get_value_string (val);
+ make_cleanup (xfree, type_name);
+ make_cleanup (xfree, val_str);
+
+ printf_filtered (_("'%s' is a scalar value of type '%s'.\n"), exp_str,
+ type_name);
+ printf_filtered (_("%s = %s\n"), exp_str, val_str);
+
+ if (is_child)
+ {
+ return_to_parent_value_prompt ();
+ return_to_parent_value ();
+ }
+
+ do_cleanups (cleanup_obj);
+ return 0;
+}
+
+/* Explore scalar type. */
+
+static int
+explore_scalar_type (struct type *type, const char *path, int is_child)
+{
+ const char *type_desc;
+ if (TYPE_CODE (type) == TYPE_CODE_ENUM)
+ {
+ type_desc = "an enum";
+ }
+ else
+ {
+ type_desc = "a scalar";
+ }
+
+ if (is_child)
+ {
+ char *type_name = type_to_string (type);
+ printf_filtered (_("%s is of %s type '%s'.\n"), path, type_desc,
+ type_name);
+ return_to_parent_type_prompt ();
+ return_to_parent_type ();
+
+ xfree (type_name);
+ }
+ else
+ {
+ printf_filtered (_("'%s' is %s type.\n"), path, type_desc);
+ }
+
+ return 0;
+}
+
+/* Explore pointer value. */
+
+static int
+explore_pointer_value (struct value *val, const char *exp_str, int is_child)
+{
+ struct value *deref_val = value_ind (val);
+ struct type *deref_type = value_type (deref_val);
+ char *resp1, *deref_type_name, *guarded_exp_str;
+ struct cleanup *cleanup_obj = make_cleanup (null_cleanup, NULL);
+
+ deref_type_name = type_to_string (deref_type);
+ make_cleanup (xfree, deref_type_name);
+
+ guarded_exp_str = guard_exp_str (exp_str);
+ make_cleanup (xfree, guarded_exp_str);
+
+ printf_filtered (_("'%s' is a pointer to a value of type '%s'.\n"),
+ exp_str, deref_type_name);
+
+ if (!can_dereference (value_type (val)))
+ {
+ printf_filtered (_("Cannot dereference '%s' for further exploration.\n"),
+ exp_str);
+ if (is_child)
+ {
+ return_to_parent_value_prompt ();
+ }
+
+ return 0;
+ }
+
+ resp1 = gdb_readline (_("Do you want to explore it as an array or a single "
+ "value pointer [a/s] : "));
+ make_cleanup (xfree, resp1);
+ if (strcmp (resp1, "a") == 0)
+ {
+ char *array_index_prompt = xstrprintf (_("Enter the index you want to "
+ "explore in '%s': "), exp_str);
+ make_cleanup (xfree, array_index_prompt);
+
+ while (1)
+ {
+ char *resp2 = gdb_readline (array_index_prompt);
+ make_cleanup (xfree, resp2);
+ strip_leading_spaces (&resp2);
+ if (resp2 && resp2[0] != '\0' && !is_all_spaces (resp2))
+ {
+ struct value *elem_val;
+ char *new_exp;
+
+ const char *endptr;
+ LONGEST index = strtoulst (resp2, &endptr, 10);
+ if (endptr == resp2)
+ {
+ break;
+ }
+
+ elem_val = value_subscript (val, index);
+
+ new_exp = xstrprintf ("%s[%ld]", guarded_exp_str, index);
+ make_cleanup (xfree, new_exp);
+
+ explore_value (elem_val, new_exp, 1);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else if (strcmp (resp1, "s") == 0)
+ {
+ char *new_exp = xstrprintf (_("*%s"), guarded_exp_str);
+ make_cleanup (xfree, new_exp);
+
+ explore_value (deref_val, new_exp, is_child);
+ }
+ else
+ {
+ if (is_child)
+ {
+ return_to_parent_value ();
+ }
+ }
+
+ do_cleanups (cleanup_obj);
+ return 0;
+}
+
+/* Explore pointer type. */
+
+static int
+explore_pointer_type (struct type *type, const char *path, int is_child)
+{
+ struct type *target_type = TYPE_TARGET_TYPE (type);
+ char *type_name = type_to_string (target_type);
+ char *new_path = NULL;
+
+ printf_filtered (_("%s is of a pointer type pointing to a value of type "
+ "'%s'.\n"), path, type_name);
+
+ new_path = xstrprintf (_("the pointee type of %s"), path);
+ explore_type (target_type, new_path, is_child);
+
+ xfree (type_name);
+ xfree (new_path);
+ return 0;
+}
+
+/* Explore array value. */
+
+static int
+explore_array_value (struct value *val, const char *exp_str, int is_child)
+{
+ char *array_index_prompt, *resp, *guarded_exp_str;
+ struct type *elem_type = TYPE_TARGET_TYPE (value_type (val));
+ struct cleanup *cleanup_obj = make_cleanup (null_cleanup, NULL);
+
+ char *elem_type_name = type_to_string (elem_type);
+ make_cleanup (xfree, elem_type_name);
+
+ guarded_exp_str = guard_exp_str (exp_str);
+ make_cleanup (xfree, guarded_exp_str);
+
+ printf_filtered (_("'%s' is an array of elements of type '%s'.\n"), exp_str,
+ elem_type_name);
+
+ array_index_prompt = xstrprintf (_("Enter the index you want to explore "
+ "in '%s': "),
+ exp_str);
+ make_cleanup (xfree, array_index_prompt);
+
+ resp = gdb_readline (array_index_prompt);
+ make_cleanup (xfree, resp);
+ strip_leading_spaces (&resp);
+ if (resp && resp[0] != '\0' && !is_all_spaces(resp))
+ {
+ struct value *elem_val;
+ char *new_exp;
+
+ const char *endptr;
+ LONGEST index = strtoulst (resp, &endptr, 10);
+ if (endptr == resp)
+ {
+ do_cleanups (cleanup_obj);
+ return 0;
+ }
+
+ elem_val = value_subscript (val, index);
+
+ new_exp = xstrprintf ("%s[%ld]", guarded_exp_str, index);
+ make_cleanup (xfree, new_exp);
+
+ explore_value (elem_val, new_exp, 1);
+
+ do_cleanups (cleanup_obj);
+ return 1;
+ }
+ else
+ {
+ if (is_child)
+ {
+ return_to_parent_value();
+ }
+
+ do_cleanups (cleanup_obj);
+ return 0;
+ }
+}
+
+/* Explore array type. */
+
+static int
+explore_array_type (struct type *type, const char *path, int is_child)
+{
+ struct type *target_type = TYPE_TARGET_TYPE (type);
+ char *type_name = type_to_string (target_type);
+ char *new_path = NULL;
+
+ printf_filtered (_("%s is an array type with elements of type '%s'.\n"),
+ path, type_name);
+
+ new_path = xstrprintf (_("the array element of %s"), path);
+ explore_type (target_type, new_path, is_child);
+
+ xfree (type_name);
+ xfree (new_path);
+ return 0;
+}
+
+struct field_desc
+{
+ /* The name of the field. */
+
+ const char *field_name;
+
+ /* The field value. Valid only for value exploration. */
+
+ struct value *field_value;
+
+ /* The field type. */
+
+ struct type *field_type;
+
+ /* 1 if this field corresponds to a base class, 0 otherwise. Used for
+ C++ structs/classes. */
+
+ int is_base_class;
+};
+
+/* Print fields of a compound type/value. FIELDS is an array of size NFIELDS.
+ PARENT_VAL_TYPE is the type_code of the compound type. It is either
+ TYPE_CODE_STRUCT or TYPE_CODE_UNION. EXPLR_TYPE indicates the exploration
+ type, VALUE_EXPLORATION or TYPE_EXPLORATION. */
+
+static void
+print_fields (struct field_desc *fields, int nfields,
+ enum type_code parent_val_type,
+ enum exploration_type explr_type)
+{
+ int max_field_name_length = 0;
+ int i;
+ struct cleanup *cleanup_obj = make_cleanup (null_cleanup, NULL);
+
+ for (i = 0; i < nfields; i++)
+ {
+ int field_name_length = strlen (fields[i].field_name);
+ if (field_name_length > max_field_name_length)
+ {
+ max_field_name_length = field_name_length;
+ }
+ }
+
+ for (i = 0; i < nfields; i++)
+ {
+ int spaces = max_field_name_length - strlen (fields[i].field_name);
+ struct type *field_type = fields[i].field_type;
+ char *field_type_name;
+
+ field_type_name = type_to_string (field_type);
+ make_cleanup (xfree, field_type_name);
+
+ print_spaces_filtered (spaces + 2, gdb_stdout);
+ printf_filtered ("%s = ", fields[i].field_name);
+
+ if (explr_type == VALUE_EXPLORATION && parent_val_type == TYPE_CODE_STRUCT
+ && is_scalar_type (field_type))
+ {
+ char *field_value_string = get_value_string (fields[i].field_value);
+ make_cleanup (xfree, field_value_string);
+
+ printf_filtered (_("%s .. (Value of type '%s')\n"),
+ field_value_string, field_type_name);
+ }
+ else
+ {
+ const char *field_desc_str;
+ if (fields[i].is_base_class)
+ {
+ field_desc_str = "base class";
+ }
+ else
+ {
+ field_desc_str = "field";
+ }
+
+ printf_filtered (_("\n"),
+ i, field_desc_str, field_type_name);
+ }
+ }
+}
+
+/* Explore compound value. A compound value is a struct, class or a union
+ value. */
+
+static int
+explore_compound_value (struct value *val, const char *exp_str, int is_child)
+{
+ struct type *val_type = value_type (val);
+ char *type_name, *type_desc;
+ enum type_code val_type_code = TYPE_CODE (val_type);
+ int nfields = TYPE_NFIELDS (val_type);
+ int n_baseclasses = 0;
+ int i;
+ int further_exploration = (val_type_code == TYPE_CODE_UNION) ? 1 : 0;
+ struct field_desc *fields;
+ struct cleanup *cleanup_obj = make_cleanup (null_cleanup, NULL);
+
+ fields = (struct field_desc *) xzalloc (nfields * sizeof (struct field_desc));
+ make_cleanup (xfree, fields);
+
+ type_name = type_to_string (val_type);
+ make_cleanup (xfree, type_name);
+
+ if (val_type_code == TYPE_CODE_STRUCT)
+ {
+ type_desc = "struct/class";
+ }
+ else
+ {
+ type_desc = "union";
+ }
+
+ printf_filtered (_("The value of '%s' is a %s of type '%s' with the "
+ "following fields:\n"), exp_str, type_desc, type_name);
+
+ if (HAVE_CPLUS_STRUCT (val_type))
+ {
+ n_baseclasses = TYPE_N_BASECLASSES (val_type);
+ }
+
+ for (i = 0; i < nfields; i++)
+ {
+ struct type *field_type = TYPE_FIELD_TYPE (val_type, i);
+ const char *field_name = TYPE_FIELD_NAME (val_type, i);
+
+ fields[i].field_name = field_name;
+ fields[i].field_value = value_field (val, i);
+ fields[i].field_type = field_type;
+ if (i < n_baseclasses)
+ {
+ fields[i].is_base_class = 1;
+ }
+ else
+ {
+ fields[i].is_base_class = 0;
+ }
+
+ if (!is_scalar_type (field_type) && val_type_code == TYPE_CODE_STRUCT)
+ {
+ further_exploration = 1;
+ }
+ }
+
+ print_fields (fields, nfields, val_type_code, VALUE_EXPLORATION);
+
+ if (further_exploration)
+ {
+ char *choice_str = gdb_readline (_("\nEnter the field number of "
+ "choice: "));
+ make_cleanup (xfree, choice_str);
+ strip_leading_spaces (&choice_str);
+
+ if (choice_str && choice_str[0] != '\0' && !is_all_spaces (choice_str))
+ {
+ const char *endptr;
+ LONGEST choice = strtoulst (choice_str, &endptr, 10);
+ if (endptr != choice_str && choice >= 0 && choice < nfields)
+ {
+ char *guarded_exp_str = guard_exp_str (exp_str);
+ char *new_exp = xstrprintf ("%s.%s", guarded_exp_str,
+ fields[choice].field_name);
+ make_cleanup (xfree, new_exp);
+ make_cleanup (xfree, guarded_exp_str);
+
+ explore_value (fields[choice].field_value, new_exp, 1);
+
+ do_cleanups (cleanup_obj);
+ return 1;
+ }
+ }
+ }
+ else
+ {
+ if (is_child)
+ {
+ printf_filtered ("\n");
+ return_to_parent_value_prompt ();
+ }
+ }
+
+ if (is_child)
+ {
+ return_to_parent_value ();
+ printf_filtered (_("\n"));
+ }
+
+ do_cleanups (cleanup_obj);
+ return 0;
+}
+
+/* Explore compound type. A compound type is a struct, class or a union
+ type. */
+
+static int
+explore_compound_type (struct type *type, const char *path, int is_child)
+{
+ char *type_name;
+ const char *type_desc;
+ enum type_code typecode = TYPE_CODE (type);
+ int nfields = TYPE_NFIELDS (type);
+ int n_baseclasses = 0;
+ int i;
+ struct field_desc *fields;
+ struct cleanup *cleanup_obj = make_cleanup (null_cleanup, NULL);
+
+ fields = (struct field_desc *) xzalloc (nfields * sizeof (struct field_desc));
+ make_cleanup (xfree, fields);
+
+ type_name = type_to_string (type);
+ make_cleanup (xfree, type_name);
+
+ if (typecode == TYPE_CODE_STRUCT)
+ {
+ type_desc = "struct/class";
+ }
+ else
+ {
+ type_desc = "union";
+ }
+
+ if (is_child)
+ {
+ printf_filtered (_("%s is a %s of type '%s' with the following "
+ "fields:\n"), path, type_desc, type_name);
+ }
+ else
+ {
+ printf_filtered (_("'%s' is a %s with the following fields:\n"),
+ path, type_desc);
+ }
+
+ if (HAVE_CPLUS_STRUCT (type))
+ {
+ n_baseclasses = TYPE_N_BASECLASSES (type);
+ }
+
+ for (i = 0; i < nfields; i++)
+ {
+ fields[i].field_name = TYPE_FIELD_NAME (type, i);
+ fields[i].field_type = TYPE_FIELD_TYPE (type, i);
+ fields[i].field_value = NULL;
+ if (i < n_baseclasses)
+ {
+ fields[i].is_base_class = 1;
+ }
+ else
+ {
+ fields[i].is_base_class = 0;
+ }
+ }
+
+ print_fields (fields, nfields, typecode, TYPE_EXPLORATION);
+
+ if (nfields)
+ {
+ char *choice_str = gdb_readline (_("\nEnter the field number of "
+ "choice: "));
+ make_cleanup (xfree, choice_str);
+ strip_leading_spaces (&choice_str);
+
+ if (choice_str && choice_str[0] != '\0' && !is_all_spaces (choice_str))
+ {
+ const char *endptr;
+ LONGEST choice = strtoulst (choice_str, &endptr, 10);
+ if (endptr != choice_str && choice >= 0 && choice < nfields)
+ {
+ char *new_path;
+ if (is_child)
+ {
+ new_path = xstrprintf (_("field '%s' of %s"),
+ fields[choice].field_name, path);
+ }
+ else
+ {
+ new_path = xstrprintf (_("field '%s' of '%s'"),
+ fields[choice].field_name, path);
+ }
+ make_cleanup (xfree, new_path);
+
+ explore_type (fields[choice].field_type, new_path, 1);
+
+ do_cleanups (cleanup_obj);
+ return 1;
+ }
+ }
+ }
+ else
+ {
+ if (is_child)
+ {
+ printf_filtered ("\n");
+ return_to_parent_type_prompt ();
+ }
+ }
+
+ if (is_child)
+ {
+ return_to_parent_type ();
+ printf_filtered ("\n");
+ }
+
+ do_cleanups (cleanup_obj);
+ return 0;
+}
+
+/* Explore a reference value (C++). */
+
+static int
+explore_reference_value (struct value *val, const char *exp_str, int is_child)
+{
+ struct type *deref_type = TYPE_TARGET_TYPE (value_type (val));
+ char *deref_type_name = type_to_string (deref_type);
+
+ printf_filtered (_("'%s' is a reference to a value of type '%s'.\n"),
+ exp_str, deref_type_name);
+
+ explore_value (coerce_ref (val), exp_str, is_child);
+
+ xfree (deref_type_name);
+ return 0;
+}
+
+/* Explore a reference type (C++). */
+
+static int
+explore_reference_type (struct type *type, const char *path, int is_child)
+{
+ struct type *target_type = TYPE_TARGET_TYPE (type);
+ char *type_name = type_to_string (target_type);
+ char *new_path = NULL;
+
+ printf_filtered (_("%s is of a reference to a value of type "
+ "'%s'.\n"), path, type_name);
+
+ if (is_child)
+ {
+ new_path = xstrprintf (_("%s"), path);
+ }
+ else
+ {
+ new_path = xstrprintf (_("%s"), type_name);
+ }
+
+ explore_type (target_type, new_path, is_child);
+
+ xfree (type_name);
+ xfree (new_path);
+ return 0;
+}
+
+/* Explore a value which of a typedef type. */
+
+static int
+explore_typedef_value (struct value *val, const char *exp_str, int is_child)
+{
+ struct type *curr_type, *orig_type;
+ char *curr_type_name, *orig_type_name;
+ struct value *cast_value;
+ struct cleanup *cleanup_obj = make_cleanup (null_cleanup, NULL);
+
+ curr_type = value_type (val);
+ curr_type_name = type_to_string (curr_type);
+ make_cleanup (xfree, curr_type_name);
+
+ orig_type = check_typedef (curr_type);
+ orig_type_name = type_to_string (orig_type);
+ make_cleanup (xfree, orig_type_name);
+
+ printf_filtered (_("The value of '%s' is of type '%s' which is a typedef of "
+ "type '%s'.\n"), exp_str, curr_type_name, orig_type_name);
+
+ cast_value = value_cast (orig_type, val);
+ explore_value (cast_value, exp_str, is_child);
+
+ do_cleanups (cleanup_obj);
+ return 0;
+}
+
+/* Explore a type which is a typedef of another type. */
+
+static int
+explore_typedef_type (struct type *type, const char *path, int is_child)
+{
+ struct type *orig_type = check_typedef (type);
+ char *orig_type_name = type_to_string (orig_type);
+
+ if (is_child)
+ {
+ printf_filtered (_("The type of %s is a typedef of type '%s'.\n"), path,
+ orig_type_name);
+ }
+ else
+ {
+ printf_filtered (_("The type '%s' is a typedef of type '%s'.\n"), path,
+ orig_type_name);
+ }
+
+ explore_type (orig_type, path, is_child);
+ return 0;
+}
+
+/* Explore VAL of any type (or type_code). ARG_STR is the expression which
+ evaluates to VAL in the current language. IS_CHILD, in a way, denotes the
+ state of the exploration. IS_CHILD is 0 if ARG_STR is the same as the
+ expression string entered by the user, 1 otherwise. For example, the user
+ is probably exploring a variable 's' which is of a struct type with a
+ field 'a'. Then, during the exploration of s.a, the value of IS_CHILD will
+ be 1. */
+
+static void
+explore_value (struct value *val, const char *arg_str, int is_child)
+{
+ struct type *val_type = value_type (val);
+ int repeat = 0;
+ char *type_name = NULL;
+
+ do
+ {
+ switch (TYPE_CODE (val_type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_ENUM:
+ repeat = explore_scalar_value (val, arg_str, is_child);
+ break;
+ case TYPE_CODE_PTR:
+ repeat = explore_pointer_value (val, arg_str, is_child);
+ break;
+ case TYPE_CODE_ARRAY:
+ repeat = explore_array_value (val, arg_str, is_child);
+ break;
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ repeat = explore_compound_value (val, arg_str, is_child);
+ break;
+ case TYPE_CODE_REF:
+ repeat = explore_reference_value (val, arg_str, is_child);
+ break;
+ case TYPE_CODE_TYPEDEF:
+ repeat = explore_typedef_value (val, arg_str, is_child);
+ break;
+ default:
+ type_name = type_to_string (val_type);
+ printf_filtered (_("Exploration of type '%s' of '%s' is not yet "
+ "available.\n"), type_name, arg_str);
+ xfree (type_name);
+ break;
+ }
+ }
+ while (repeat);
+}
+
+/* Explore any type CURR_TYPE. PATH is the descriptive path to the entity
+ explored. IS_CHILD, in a way, denotes the state of the current exploration.
+ If CURR_TYPE is the type entered by the user, the IS_CHILD is 0, otherwise
+ it is 1. For example, when exploring the type of the field 'a' of a type
+ 'struct S' (which was the actual type entered by the user), the value of
+ IS_CHILD will be 1. */
+
+static void
+explore_type (struct type *curr_type, const char *path, int is_child)
+{
+ char *type_name = NULL;
+ int repeat = 0;
+ do
+ {
+ switch (TYPE_CODE (curr_type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_ENUM:
+ repeat = explore_scalar_type (curr_type, path, is_child);
+ break;
+ case TYPE_CODE_PTR:
+ repeat = explore_pointer_type (curr_type, path, is_child);
+ break;
+ case TYPE_CODE_ARRAY:
+ repeat = explore_array_type (curr_type, path, is_child);
+ break;
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ repeat = explore_compound_type (curr_type, path, is_child);
+ break;
+ case TYPE_CODE_REF:
+ repeat = explore_reference_type (curr_type, path, is_child);
+ break;
+ case TYPE_CODE_TYPEDEF:
+ repeat = explore_typedef_type (curr_type, path, is_child);
+ break;
+ default:
+ type_name = type_to_string (curr_type);
+ if (is_child)
+ {
+ printf_filtered (_("Exploration of type '%s' of %s is not yet "
+ "available.\n"), type_name, path);
+ }
+ else
+ {
+ printf_filtered (_("Exploration of type '%s' is not yet "
+ "available.\n"), type_name);
+ }
+ xfree (type_name);
+ break;
+ }
+ }
+ while (repeat);
+}
+
+/* Parse a string into a value in the current language. Return NULL if the
+ string STR does not evaluate to any value. */
+
+static struct value *
+parse_as_value (char *str)
+{
+ struct gdb_exception except;
+ struct value *str_val = NULL;
+
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ str_val = parse_and_eval (str);
+ }
+ if (except.reason < 0)
+ {
+ return NULL;
+ }
+
+ return str_val;
+}
+
+/* Parse a string into a type in the current language. Return NULL if the
+ string STR does not evaluate to any type. */
+
+static struct type *
+parse_as_type (const char *str)
+{
+ struct type *type = NULL;
+ volatile struct gdb_exception except;
+
+ if (current_language->la_language == language_c
+ || current_language->la_language == language_cplus)
+ {
+ /* This helps in exploring types like int*, int** and the like. */
+ char *exp = xstrprintf (_("(%s *) 0"), str);
+ struct value *dummy_value = parse_as_value (exp);
+
+ xfree (exp);
+
+ if (!dummy_value)
+ {
+ return NULL;
+ }
+
+ return value_type (value_ind (dummy_value));
+ }
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ if (!strncmp (str, "struct ", 7))
+ type = lookup_struct (str + 7, NULL);
+ else if (!strncmp (str, "union ", 6))
+ type = lookup_union (str + 6, NULL);
+ else if (!strncmp (str, "enum ", 5))
+ type = lookup_enum (str + 5, NULL);
+ else
+ type = lookup_typename (current_language, get_current_arch(),
+ str, NULL, 0);
+ }
+ if (except.reason < 0)
+ {
+ return NULL;
+ }
+
+ return type;
+}
+
+static void
+explore_command (char* arg_str, int from_tty)
+{
+ struct value *exp_val;
+ struct type *str_type;
+
+ if (!arg_str)
+ {
+ printf_filtered (_("'explore' command requires an argument.\n"));
+ return;
+ }
+
+ /* Try if ARG_STR can be parsed into a value. */
+ exp_val = parse_as_value (arg_str);
+ if (exp_val)
+ {
+ explore_value (exp_val, arg_str, 0);
+
+ free_all_values ();
+ return;
+ }
+
+ /* Try if ARG_STR can be parsed into a type. */
+ str_type = parse_as_type (arg_str);
+ if (str_type)
+ {
+ explore_type (str_type, arg_str, 0);
+ return;
+ }
+
+ /* If ARG_STR cannot be parsed into a value or a type, print an error
+ message. */
+ printf_filtered (_("'%s' does not evaluate to any value or type in the "
+ "current context.\n"), arg_str);
+}
+
+static void
+explore_value_command (char* arg_str, int from_tty)
+{
+ struct value *exp_val;
+
+ if (!arg_str)
+ {
+ printf_filtered (_("'explore value' command requires an argument.\n"));
+ return;
+ }
+
+ exp_val = parse_as_value (arg_str);
+ if (exp_val)
+ {
+ explore_value (exp_val, arg_str, 0);
+
+ free_all_values ();
+ return;
+ }
+
+ printf_filtered (_("'%s' does not evaluate to any value in the "
+ "current context.\n"), arg_str);
+}
+
+static void
+explore_type_command (char* arg_str, int from_tty)
+{
+ struct type *str_type;
+ struct value *exp_val;
+
+ if (!arg_str)
+ {
+ printf_filtered (_("'explore type' command requires an argument.\n"));
+ return;
+ }
+
+ str_type = parse_as_type (arg_str);
+ if (str_type)
+ {
+ explore_type (str_type, arg_str, 0);
+ return;
+ }
+
+ /* If it cannot be evaluated into a type, try to evaluate it into a
+ value. */
+ exp_val = parse_as_value (arg_str);
+ if (exp_val)
+ {
+ struct type *exp_type = value_type (exp_val);
+ char *type_name = (char *) type_to_string (exp_type);
+
+ printf_filtered (_("'%s' is of type '%s'.\n"), arg_str, type_name);
+ explore_type (exp_type, type_name, 0);
+
+ free_all_values ();
+ xfree (type_name);
+ return;
+ }
+
+ printf_filtered (_("'%s' does not evaluate to any value or type in the "
+ "current context.\n"), arg_str);
+}
+
+struct cmd_list_element *explore_list = NULL;
+
+void
+_initialize_explore (void)
+{
+ add_prefix_cmd (_("explore"), no_class, explore_command, _("\
+Explore a value or a type valid in the current context.\n\
+Usage:\n\n\
+explore ARG\n\n\
+- ARG is either a valid expression or a type name.\n\
+- At any stage of exploration, hit the return key (instead of a\n\
+ choice, if any) to return to the enclosing type or value. Entering\n\
+ an invalid input will also result in similar behaviour."),
+ &explore_list, "explore ", 1, &cmdlist);
+
+ add_cmd (_("value"), no_class, explore_value_command, _("\
+Explore value of an expression valid in the current context.\n\
+Usage:\n\n\
+explore value ARG\n\n\
+- ARG is a valid expression.\n\
+- At any stage of exploration, hit the return key (instead of a\n\
+ choice, if any) to return to the enclosing value. Entering\n\
+ an invalid input will also result in similar behaviour."),
+ &explore_list);
+
+ add_cmd (_("type"), no_class, explore_type_command, _("\
+Explore a type or the type of an expression valid in the current context.\n\
+Usage:\n\n\
+explore type ARG\n\n\
+- ARG is a valid expression or a type name.\n\
+- At any stage of exploration, hit the return key (instead of a\n\
+ choice, if any) to return to the enclosing type. Entering\n\
+ an invalid input will also result in similar behaviour."),
+ &explore_list);
+}
diff -rupN src/gdb/Makefile.in src_explore_c/gdb/Makefile.in
--- src/gdb/Makefile.in 2012-02-09 21:36:43.000000000 +0530
+++ src_explore_c/gdb/Makefile.in 2012-02-19 11:47:43.093098943 +0530
@@ -695,7 +695,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
dwarf2expr.c dwarf2loc.c dwarf2read.c dwarf2-frame.c \
dwarf2-frame-tailcall.c \
elfread.c environ.c eval.c event-loop.c event-top.c \
- exceptions.c expprint.c \
+ exceptions.c explore.c expprint.c \
f-exp.y f-lang.c f-typeprint.c f-valprint.c filesystem.c \
findcmd.c findvar.c frame.c frame-base.c frame-unwind.c \
gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \
@@ -859,7 +859,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
block.o symtab.o psymtab.o symfile.o symmisc.o linespec.o dictionary.o \
infcall.o \
infcmd.o infrun.o \
- expprint.o environ.o stack.o thread.o \
+ explore.o expprint.o environ.o stack.o thread.o \
exceptions.o \
filesystem.o \
inf-child.o \
diff -rupN src/gdb/NEWS src_explore_c/gdb/NEWS
--- src/gdb/NEWS 2012-03-05 16:55:36.652342189 +0530
+++ src_explore_c/gdb/NEWS 2012-03-05 16:58:50.692329574 +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. The command "explore type" can be used to explore
+ types directly.
+
*** Changes in GDB 7.4
* GDB now handles ambiguous linespecs more consistently; the existing
diff -rupN src/gdb/testsuite/gdb.base/explore.c src_explore_c/gdb/testsuite/gdb.base/explore.c
--- src/gdb/testsuite/gdb.base/explore.c 1970-01-01 05:30:00.000000000 +0530
+++ src_explore_c/gdb/testsuite/gdb.base/explore.c 2012-02-19 11:42:27.493097731 +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 .
+*/
+
+#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.base/explore.exp src_explore_c/gdb/testsuite/gdb.base/explore.exp
--- src/gdb/testsuite/gdb.base/explore.exp 1970-01-01 05:30:00.000000000 +0530
+++ src_explore_c/gdb/testsuite/gdb.base/explore.exp 2012-02-26 12:21:09.854970415 +0530
@@ -0,0 +1,461 @@
+# 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 .
+
+set testfile "explore"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+ return -1
+}
+
+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\[ \]+=\[ \]+