Index: gdb/typeprint.c |
diff --git a/gdb/typeprint.c b/gdb/typeprint.c |
index c25e705d1c7154bf5df410ec9eef948f6e885eed..c5e45bea74c812dfd83f69b4e4076c0cafc39ec0 100644 |
--- a/gdb/typeprint.c |
+++ b/gdb/typeprint.c |
@@ -1,7 +1,6 @@ |
/* Language independent support for printing types for GDB, the GNU debugger. |
- Copyright (C) 1986, 1988-1989, 1991-1995, 1998-2001, 2003, 2006-2012 |
- Free Software Foundation, Inc. |
+ Copyright (C) 1986-2013 Free Software Foundation, Inc. |
This file is part of GDB. |
@@ -32,10 +31,14 @@ |
#include "language.h" |
#include "cp-abi.h" |
#include "typeprint.h" |
-#include "gdb_string.h" |
+#include <string.h> |
#include "exceptions.h" |
#include "valprint.h" |
#include <errno.h> |
+#include <ctype.h> |
+#include "cli/cli-utils.h" |
+#include "python/python.h" |
+#include "completer.h" |
extern void _initialize_typeprint (void); |
@@ -45,6 +48,290 @@ static void whatis_command (char *, int); |
static void whatis_exp (char *, int); |
+const struct type_print_options type_print_raw_options = |
+{ |
+ 1, /* raw */ |
+ 1, /* print_methods */ |
+ 1, /* print_typedefs */ |
+ NULL, /* local_typedefs */ |
+ NULL, /* global_table */ |
+ NULL /* global_printers */ |
+}; |
+ |
+/* The default flags for 'ptype' and 'whatis'. */ |
+ |
+static struct type_print_options default_ptype_flags = |
+{ |
+ 0, /* raw */ |
+ 1, /* print_methods */ |
+ 1, /* print_typedefs */ |
+ NULL, /* local_typedefs */ |
+ NULL, /* global_table */ |
+ NULL /* global_printers */ |
+}; |
+ |
+ |
+ |
+/* A hash table holding typedef_field objects. This is more |
+ complicated than an ordinary hash because it must also track the |
+ lifetime of some -- but not all -- of the contained objects. */ |
+ |
+struct typedef_hash_table |
+{ |
+ /* The actual hash table. */ |
+ htab_t table; |
+ |
+ /* Storage for typedef_field objects that must be synthesized. */ |
+ struct obstack storage; |
+}; |
+ |
+/* A hash function for a typedef_field. */ |
+ |
+static hashval_t |
+hash_typedef_field (const void *p) |
+{ |
+ const struct typedef_field *tf = p; |
+ struct type *t = check_typedef (tf->type); |
+ |
+ return htab_hash_string (TYPE_SAFE_NAME (t)); |
+} |
+ |
+/* An equality function for a typedef field. */ |
+ |
+static int |
+eq_typedef_field (const void *a, const void *b) |
+{ |
+ const struct typedef_field *tfa = a; |
+ const struct typedef_field *tfb = b; |
+ |
+ return types_equal (tfa->type, tfb->type); |
+} |
+ |
+/* Add typedefs from T to the hash table TABLE. */ |
+ |
+void |
+recursively_update_typedef_hash (struct typedef_hash_table *table, |
+ struct type *t) |
+{ |
+ int i; |
+ |
+ if (table == NULL) |
+ return; |
+ |
+ for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (t); ++i) |
+ { |
+ struct typedef_field *tdef = &TYPE_TYPEDEF_FIELD (t, i); |
+ void **slot; |
+ |
+ slot = htab_find_slot (table->table, tdef, INSERT); |
+ /* Only add a given typedef name once. Really this shouldn't |
+ happen; but it is safe enough to do the updates breadth-first |
+ and thus use the most specific typedef. */ |
+ if (*slot == NULL) |
+ *slot = tdef; |
+ } |
+ |
+ /* Recurse into superclasses. */ |
+ for (i = 0; i < TYPE_N_BASECLASSES (t); ++i) |
+ recursively_update_typedef_hash (table, TYPE_BASECLASS (t, i)); |
+} |
+ |
+/* Add template parameters from T to the typedef hash TABLE. */ |
+ |
+void |
+add_template_parameters (struct typedef_hash_table *table, struct type *t) |
+{ |
+ int i; |
+ |
+ if (table == NULL) |
+ return; |
+ |
+ for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (t); ++i) |
+ { |
+ struct typedef_field *tf; |
+ void **slot; |
+ |
+ /* We only want type-valued template parameters in the hash. */ |
+ if (SYMBOL_CLASS (TYPE_TEMPLATE_ARGUMENT (t, i)) != LOC_TYPEDEF) |
+ continue; |
+ |
+ tf = XOBNEW (&table->storage, struct typedef_field); |
+ tf->name = SYMBOL_LINKAGE_NAME (TYPE_TEMPLATE_ARGUMENT (t, i)); |
+ tf->type = SYMBOL_TYPE (TYPE_TEMPLATE_ARGUMENT (t, i)); |
+ |
+ slot = htab_find_slot (table->table, tf, INSERT); |
+ if (*slot == NULL) |
+ *slot = tf; |
+ } |
+} |
+ |
+/* Create a new typedef-lookup hash table. */ |
+ |
+struct typedef_hash_table * |
+create_typedef_hash (void) |
+{ |
+ struct typedef_hash_table *result; |
+ |
+ result = XNEW (struct typedef_hash_table); |
+ result->table = htab_create_alloc (10, hash_typedef_field, eq_typedef_field, |
+ NULL, xcalloc, xfree); |
+ obstack_init (&result->storage); |
+ |
+ return result; |
+} |
+ |
+/* Free a typedef field table. */ |
+ |
+void |
+free_typedef_hash (struct typedef_hash_table *table) |
+{ |
+ if (table != NULL) |
+ { |
+ htab_delete (table->table); |
+ obstack_free (&table->storage, NULL); |
+ xfree (table); |
+ } |
+} |
+ |
+/* A cleanup for freeing a typedef_hash_table. */ |
+ |
+static void |
+do_free_typedef_hash (void *arg) |
+{ |
+ free_typedef_hash (arg); |
+} |
+ |
+/* Return a new cleanup that frees TABLE. */ |
+ |
+struct cleanup * |
+make_cleanup_free_typedef_hash (struct typedef_hash_table *table) |
+{ |
+ return make_cleanup (do_free_typedef_hash, table); |
+} |
+ |
+/* Helper function for copy_typedef_hash. */ |
+ |
+static int |
+copy_typedef_hash_element (void **slot, void *nt) |
+{ |
+ htab_t new_table = nt; |
+ void **new_slot; |
+ |
+ new_slot = htab_find_slot (new_table, *slot, INSERT); |
+ if (*new_slot == NULL) |
+ *new_slot = *slot; |
+ |
+ return 1; |
+} |
+ |
+/* Copy a typedef hash. */ |
+ |
+struct typedef_hash_table * |
+copy_typedef_hash (struct typedef_hash_table *table) |
+{ |
+ struct typedef_hash_table *result; |
+ |
+ if (table == NULL) |
+ return NULL; |
+ |
+ result = create_typedef_hash (); |
+ htab_traverse_noresize (table->table, copy_typedef_hash_element, |
+ result->table); |
+ return result; |
+} |
+ |
+/* A cleanup to free the global typedef hash. */ |
+ |
+static void |
+do_free_global_table (void *arg) |
+{ |
+ struct type_print_options *flags = arg; |
+ |
+ free_typedef_hash (flags->global_typedefs); |
+ free_type_printers (flags->global_printers); |
+} |
+ |
+/* Create the global typedef hash. */ |
+ |
+static struct cleanup * |
+create_global_typedef_table (struct type_print_options *flags) |
+{ |
+ gdb_assert (flags->global_typedefs == NULL && flags->global_printers == NULL); |
+ flags->global_typedefs = create_typedef_hash (); |
+ flags->global_printers = start_type_printers (); |
+ return make_cleanup (do_free_global_table, flags); |
+} |
+ |
+/* Look up the type T in the global typedef hash. If it is found, |
+ return the typedef name. If it is not found, apply the |
+ type-printers, if any, given by start_type_printers and return the |
+ result. A NULL return means that the name was not found. */ |
+ |
+static const char * |
+find_global_typedef (const struct type_print_options *flags, |
+ struct type *t) |
+{ |
+ char *applied; |
+ void **slot; |
+ struct typedef_field tf, *new_tf; |
+ |
+ if (flags->global_typedefs == NULL) |
+ return NULL; |
+ |
+ tf.name = NULL; |
+ tf.type = t; |
+ |
+ slot = htab_find_slot (flags->global_typedefs->table, &tf, INSERT); |
+ if (*slot != NULL) |
+ { |
+ new_tf = *slot; |
+ return new_tf->name; |
+ } |
+ |
+ /* Put an entry into the hash table now, in case apply_type_printers |
+ recurses. */ |
+ new_tf = XOBNEW (&flags->global_typedefs->storage, struct typedef_field); |
+ new_tf->name = NULL; |
+ new_tf->type = t; |
+ |
+ *slot = new_tf; |
+ |
+ applied = apply_type_printers (flags->global_printers, t); |
+ |
+ if (applied != NULL) |
+ { |
+ new_tf->name = obstack_copy0 (&flags->global_typedefs->storage, applied, |
+ strlen (applied)); |
+ xfree (applied); |
+ } |
+ |
+ return new_tf->name; |
+} |
+ |
+/* Look up the type T in the typedef hash table in with FLAGS. If T |
+ is in the table, return its short (class-relative) typedef name. |
+ Otherwise return NULL. If the table is NULL, this always returns |
+ NULL. */ |
+ |
+const char * |
+find_typedef_in_hash (const struct type_print_options *flags, struct type *t) |
+{ |
+ if (flags->local_typedefs != NULL) |
+ { |
+ struct typedef_field tf, *found; |
+ |
+ tf.name = NULL; |
+ tf.type = t; |
+ found = htab_find (flags->local_typedefs->table, &tf); |
+ |
+ if (found != NULL) |
+ return found->name; |
+ } |
+ |
+ return find_global_typedef (flags, t); |
+} |
+ |
+ |
/* Print a description of a type in the format of a |
typedef for the current language. |
@@ -76,7 +363,7 @@ void |
type_print (struct type *type, const char *varstring, struct ui_file *stream, |
int show) |
{ |
- LA_PRINT_TYPE (type, varstring, stream, show, 0); |
+ LA_PRINT_TYPE (type, varstring, stream, show, 0, &default_ptype_flags); |
} |
/* Print TYPE to a string, returning it. The caller is responsible for |
@@ -114,18 +401,57 @@ whatis_exp (char *exp, int show) |
{ |
struct expression *expr; |
struct value *val; |
- struct cleanup *old_chain = NULL; |
+ struct cleanup *old_chain; |
struct type *real_type = NULL; |
struct type *type; |
int full = 0; |
int top = -1; |
int using_enc = 0; |
struct value_print_options opts; |
+ struct type_print_options flags = default_ptype_flags; |
+ |
+ old_chain = make_cleanup (null_cleanup, NULL); |
if (exp) |
{ |
+ if (*exp == '/') |
+ { |
+ int seen_one = 0; |
+ |
+ for (++exp; *exp && !isspace (*exp); ++exp) |
+ { |
+ switch (*exp) |
+ { |
+ case 'r': |
+ flags.raw = 1; |
+ break; |
+ case 'm': |
+ flags.print_methods = 0; |
+ break; |
+ case 'M': |
+ flags.print_methods = 1; |
+ break; |
+ case 't': |
+ flags.print_typedefs = 0; |
+ break; |
+ case 'T': |
+ flags.print_typedefs = 1; |
+ break; |
+ default: |
+ error (_("unrecognized flag '%c'"), *exp); |
+ } |
+ seen_one = 1; |
+ } |
+ |
+ if (!*exp && !seen_one) |
+ error (_("flag expected")); |
+ if (!isspace (*exp)) |
+ error (_("expected space after format")); |
+ exp = skip_spaces (exp); |
+ } |
+ |
expr = parse_expression (exp); |
- old_chain = make_cleanup (free_current_contents, &expr); |
+ make_cleanup (free_current_contents, &expr); |
val = evaluate_type (expr); |
} |
else |
@@ -146,6 +472,9 @@ whatis_exp (char *exp, int show) |
printf_filtered ("type = "); |
+ if (!flags.raw) |
+ create_global_typedef_table (&flags); |
+ |
if (real_type) |
{ |
printf_filtered ("/* real type = "); |
@@ -155,11 +484,10 @@ whatis_exp (char *exp, int show) |
printf_filtered (" */\n"); |
} |
- type_print (type, "", gdb_stdout, show); |
+ LA_PRINT_TYPE (type, "", gdb_stdout, show, 0, &flags); |
printf_filtered ("\n"); |
- if (exp) |
- do_cleanups (old_chain); |
+ do_cleanups (old_chain); |
} |
static void |
@@ -299,17 +627,102 @@ maintenance_print_type (char *typename, int from_tty) |
} |
+struct cmd_list_element *setprinttypelist; |
+ |
+struct cmd_list_element *showprinttypelist; |
+ |
+static void |
+set_print_type (char *arg, int from_tty) |
+{ |
+ printf_unfiltered ( |
+ "\"set print type\" must be followed by the name of a subcommand.\n"); |
+ help_list (setprintlist, "set print type ", -1, gdb_stdout); |
+} |
+ |
+static void |
+show_print_type (char *args, int from_tty) |
+{ |
+ cmd_show_list (showprinttypelist, from_tty, ""); |
+} |
+ |
+static int print_methods = 1; |
+ |
+static void |
+set_print_type_methods (char *args, int from_tty, struct cmd_list_element *c) |
+{ |
+ default_ptype_flags.print_methods = print_methods; |
+} |
+ |
+static void |
+show_print_type_methods (struct ui_file *file, int from_tty, |
+ struct cmd_list_element *c, const char *value) |
+{ |
+ fprintf_filtered (file, _("Printing of methods defined in a class in %s\n"), |
+ value); |
+} |
+ |
+static int print_typedefs = 1; |
+ |
+static void |
+set_print_type_typedefs (char *args, int from_tty, struct cmd_list_element *c) |
+{ |
+ default_ptype_flags.print_typedefs = print_typedefs; |
+} |
+ |
+static void |
+show_print_type_typedefs (struct ui_file *file, int from_tty, |
+ struct cmd_list_element *c, const char *value) |
+{ |
+ fprintf_filtered (file, _("Printing of typedefs defined in a class in %s\n"), |
+ value); |
+} |
+ |
void |
_initialize_typeprint (void) |
{ |
- add_com ("ptype", class_vars, ptype_command, _("\ |
+ struct cmd_list_element *c; |
+ |
+ c = add_com ("ptype", class_vars, ptype_command, _("\ |
Print definition of type TYPE.\n\ |
-Argument may be a type name defined by typedef, or \"struct STRUCT-TAG\"\n\ |
-or \"class CLASS-NAME\" or \"union UNION-TAG\" or \"enum ENUM-TAG\".\n\ |
+Usage: ptype[/FLAGS] TYPE | EXPRESSION\n\ |
+Argument may be any type (for example a type name defined by typedef,\n\ |
+or \"struct STRUCT-TAG\" or \"class CLASS-NAME\" or \"union UNION-TAG\"\n\ |
+or \"enum ENUM-TAG\") or an expression.\n\ |
The selected stack frame's lexical context is used to look up the name.\n\ |
-Contrary to \"whatis\", \"ptype\" always unrolls any typedefs.")); |
- |
- add_com ("whatis", class_vars, whatis_command, |
- _("Print data type of expression EXP.\n\ |
+Contrary to \"whatis\", \"ptype\" always unrolls any typedefs.\n\ |
+\n\ |
+Available FLAGS are:\n\ |
+ /r print in \"raw\" form; do not substitute typedefs\n\ |
+ /m do not print methods defined in a class\n\ |
+ /M print methods defined in a class\n\ |
+ /t do not print typedefs defined in a class\n\ |
+ /T print typedefs defined in a class")); |
+ set_cmd_completer (c, expression_completer); |
+ |
+ c = add_com ("whatis", class_vars, whatis_command, |
+ _("Print data type of expression EXP.\n\ |
Only one level of typedefs is unrolled. See also \"ptype\".")); |
+ set_cmd_completer (c, expression_completer); |
+ |
+ add_prefix_cmd ("type", no_class, show_print_type, |
+ _("Generic command for showing type-printing settings."), |
+ &showprinttypelist, "show print type ", 0, &showprintlist); |
+ add_prefix_cmd ("type", no_class, set_print_type, |
+ _("Generic command for setting how types print."), |
+ &setprinttypelist, "show print type ", 0, &setprintlist); |
+ |
+ add_setshow_boolean_cmd ("methods", no_class, &print_methods, |
+ _("\ |
+Set printing of methods defined in classes."), _("\ |
+Show printing of methods defined in classes."), NULL, |
+ set_print_type_methods, |
+ show_print_type_methods, |
+ &setprinttypelist, &showprinttypelist); |
+ add_setshow_boolean_cmd ("typedefs", no_class, &print_typedefs, |
+ _("\ |
+Set printing of typedefs defined in classes."), _("\ |
+Show printing of typedefs defined in classes."), NULL, |
+ set_print_type_typedefs, |
+ show_print_type_typedefs, |
+ &setprinttypelist, &showprinttypelist); |
} |