This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: more detailed type information


I'm using Eclipse as a front-end for gdb, but I need to be able to get more detailed type information than is currently possible. This is required in order to provide more sophisticated functionality than just displaying the type and value as strings.

There are two problems with the current MI -var comands for extracting type information. First, it's difficult to get a complete description, particularly when typedefs are used. For example:

  struct a {int x;};
  typedef struct a a;
  a var1;

In this situation, -var-info-type returns type="a". To get the actual type information, the front-end needs to resort to using the 'ptype' command and parsing the output.

Another example is an anonymous struct:

struct {int x;} var1;

Here the only information we get from -var-info-type is type="struct {...}" so again we have to resort to parsing the output from 'ptype'.

The second problem is that for structured types there is no way to get the complete type description of an object in a single command. Instead, we have to repeatedly issue -var-list-children commands until the full type description has been built up. For complex types this can be quite time consuming.

I'd like to propose adding a new command, called -var-dump-type (for want of a better name), that will produce a complete type description of a variable object. For the cases above, it will produce:

^done,type={name="a",code="TYPE_CODE_TYPEDEF",length="4",type= {ref="0",tag="a",code="TYPE_CODE_STRUCT",length="4",nfields="1",fields={ field={name="x",bitpos="0",type= {name="int",code="TYPE_CODE_INT",length="4",unsigned="0"}}}}}

and

^done,type= {ref="0",code="TYPE_CODE_STRUCT",length="4",nfields="1",fields={field= {name="x",bitpos="0",type= {name="int",code="TYPE_CODE_INT",length="4",unsigned="0"}}}}

Recursive types are handled using 'ref=' and 'seen=' results. So, in the case of:

struct b {int x; struct b *y};

the result would be:

^done,type= {ref="0",tag="b",code="TYPE_CODE_STRUCT",length="16",nfields="2",fields= {field={name="x",bitpos="0",type= {name="int",code="TYPE_CODE_INT",length="4",unsigned="0"}},field= {name="y",bitpos="64",type={code="TYPE_CODE_PTR",length="8",type= {seen="0"}}}}}

Notice that the final type says 'seen="0"' which indicates that it is referring to a type that we have already seen (ref="0").

Attached is an example patch to add this command to gdb-6.4. One caveat is that I've had to modify ui-out.c slightly to remove the restriction on tuple nesting. This is required because complex types typically nest to greater than the 6 levels currently provided.

Regards,

Greg
---------

diff -ru gdb-6.4-old/gdb/mi/mi-cmds.c gdb-6.4/gdb/mi/mi-cmds.c
--- gdb-6.4-old/gdb/mi/mi-cmds.c 2006-03-09 11:39:20.779863000 -0700
+++ gdb-6.4/gdb/mi/mi-cmds.c 2006-03-09 12:24:57.442101000 -0700
@@ -158,6 +158,7 @@
{ "var-assign", { NULL, 0 }, 0, mi_cmd_var_assign},
{ "var-create", { NULL, 0 }, 0, mi_cmd_var_create},
{ "var-delete", { NULL, 0 }, 0, mi_cmd_var_delete},
+ { "var-dump-type", { NULL, 0 }, 0, mi_cmd_var_dump_type},
{ "var-evaluate-expression", { NULL, 0 }, 0, mi_cmd_var_evaluate_expression},
{ "var-info-expression", { NULL, 0 }, 0, mi_cmd_var_info_expression},
{ "var-info-num-children", { NULL, 0 }, 0, mi_cmd_var_info_num_children},
diff -ru gdb-6.4-old/gdb/mi/mi-cmds.h gdb-6.4/gdb/mi/mi-cmds.h
--- gdb-6.4-old/gdb/mi/mi-cmds.h 2006-03-09 11:39:20.789854000 -0700
+++ gdb-6.4/gdb/mi/mi-cmds.h 2006-03-09 12:24:57.445097000 -0700
@@ -106,6 +106,7 @@
extern mi_cmd_argv_ftype mi_cmd_var_assign;
extern mi_cmd_argv_ftype mi_cmd_var_create;
extern mi_cmd_argv_ftype mi_cmd_var_delete;
+extern mi_cmd_argv_ftype mi_cmd_var_dump_type;
extern mi_cmd_argv_ftype mi_cmd_var_evaluate_expression;
extern mi_cmd_argv_ftype mi_cmd_var_info_expression;
extern mi_cmd_argv_ftype mi_cmd_var_info_num_children;
diff -ru gdb-6.4-old/gdb/mi/mi-cmd-var.c gdb-6.4/gdb/mi/mi-cmd-var.c
--- gdb-6.4-old/gdb/mi/mi-cmd-var.c 2006-03-09 11:39:20.772870000 -0700
+++ gdb-6.4/gdb/mi/mi-cmd-var.c 2006-03-09 12:36:29.375476000 -0700
@@ -29,6 +29,7 @@
#include "value.h"
#include <ctype.h>
#include "gdb_string.h"
+#include "gdb_obstack.h"
const char mi_no_values[] = "--no-values";
const char mi_simple_values[] = "--simple-values";
@@ -590,3 +591,185 @@
}
return 1;
}
+
+static struct obstack seen_type_obstack;
+
+static char *
+typecode_as_string (int code)
+{
+ switch (code)
+ {
+ case TYPE_CODE_UNDEF:
+ return "TYPE_CODE_UNDEF";
+ case TYPE_CODE_PTR:
+ return "TYPE_CODE_PTR";
+ case TYPE_CODE_ARRAY:
+ return "TYPE_CODE_ARRAY";
+ case TYPE_CODE_STRUCT:
+ return "TYPE_CODE_STRUCT";
+ case TYPE_CODE_UNION:
+ return "TYPE_CODE_UNION";
+ case TYPE_CODE_ENUM:
+ return "TYPE_CODE_ENUM";
+ case TYPE_CODE_FUNC:
+ return "TYPE_CODE_FUNC";
+ case TYPE_CODE_INT:
+ return "TYPE_CODE_INT";
+ case TYPE_CODE_FLT:
+ return "TYPE_CODE_FLT";
+ case TYPE_CODE_VOID:
+ return "TYPE_CODE_VOID";
+ case TYPE_CODE_SET:
+ return "TYPE_CODE_SET";
+ case TYPE_CODE_RANGE:
+ return "TYPE_CODE_RANGE";
+ case TYPE_CODE_STRING:
+ return "TYPE_CODE_STRING";
+ case TYPE_CODE_BITSTRING:
+ return "TYPE_CODE_BITSTRING";
+ case TYPE_CODE_ERROR:
+ return "TYPE_CODE_ERROR";
+ case TYPE_CODE_MEMBER:
+ return "TYPE_CODE_MEMBER";
+ case TYPE_CODE_METHOD:
+ return "TYPE_CODE_METHOD";
+ case TYPE_CODE_REF:
+ return "TYPE_CODE_REF";
+ case TYPE_CODE_CHAR:
+ return "TYPE_CODE_CHAR";
+ case TYPE_CODE_BOOL:
+ return "TYPE_CODE_BOOL";
+ case TYPE_CODE_COMPLEX:
+ return "TYPE_CODE_COMPLEX";
+ case TYPE_CODE_TYPEDEF:
+ return "TYPE_CODE_TYPEDEF";
+ case TYPE_CODE_TEMPLATE:
+ return "TYPE_CODE_TEMPLATE";
+ case TYPE_CODE_TEMPLATE_ARG:
+ return "TYPE_CODE_TEMPLATE_ARG";
+ case TYPE_CODE_NAMESPACE:
+ return "TYPE_CODE_NAMESPACE";
+ default:
+ return "UNKNOWN TYPE CODE";
+ }
+}
+
+void
+mi_recursive_dump_type (struct ui_out *uiout, struct type *type)
+{
+ int idx;
+ struct cleanup *cleanup;
+
+ cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, "type");
+
+ if (TYPE_NFIELDS (type) > 0
+ || (TYPE_CPLUS_SPECIFIC (type) && TYPE_NFN_FIELDS (type) > 0))
+ {
+ struct type **seen = (struct type **) obstack_base (&seen_type_obstack);
+ int pos = (struct type **) obstack_next_free (&seen_type_obstack) - seen;
+
+ for (idx = pos-1; idx >= 0; idx--)
+ {
+ if (type == seen[idx])
+ {
+ ui_out_field_int (uiout, "seen", idx);
+ do_cleanups (cleanup);
+ return;
+ }
+ }
+
+ ui_out_field_int (uiout, "ref", pos);
+
+ obstack_ptr_grow (&seen_type_obstack, type);
+ }
+
+ if (TYPE_NAME (type) != NULL)
+ ui_out_field_string (uiout, "name", TYPE_NAME (type));
+ if (TYPE_TAG_NAME (type) != NULL)
+ ui_out_field_string (uiout, "tag", TYPE_TAG_NAME (type));
+ ui_out_field_string (uiout, "code",
+ typecode_as_string (TYPE_CODE (type)));
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ ui_out_field_int (uiout, "length", TYPE_LENGTH (type));
+ if (TYPE_ARRAY_LOWER_BOUND_TYPE (type) == BOUND_SIMPLE)
+ ui_out_field_int (uiout, "lower_bound",
+ (int)TYPE_ARRAY_LOWER_BOUND_VALUE (type));
+ if (TYPE_ARRAY_UPPER_BOUND_TYPE (type) == BOUND_SIMPLE)
+ ui_out_field_int (uiout, "upper_bound",
+ (int)TYPE_ARRAY_UPPER_BOUND_VALUE (type));
+ break;
+ case TYPE_CODE_INT:
+ ui_out_field_int (uiout, "length", TYPE_LENGTH (type));
+ ui_out_field_int (uiout, "unsigned", TYPE_UNSIGNED (type));
+ break;
+ case TYPE_CODE_REF:
+ case TYPE_CODE_TYPEDEF:
+ case TYPE_CODE_TEMPLATE:
+ case TYPE_CODE_TEMPLATE_ARG:
+ case TYPE_CODE_NAMESPACE:
+ break;
+ default:
+ ui_out_field_int (uiout, "length", TYPE_LENGTH (type));
+ }
+
+ if (TYPE_NFIELDS (type) > 0 && TYPE_CODE (type) != TYPE_CODE_ARRAY)
+ {
+ struct cleanup *cleanup_fields;
+
+ ui_out_field_int (uiout, "nfields", TYPE_NFIELDS (type));
+ cleanup_fields = make_cleanup_ui_out_tuple_begin_end (uiout, "fields");
+
+ for (idx = 0; idx < TYPE_NFIELDS (type); idx++)
+ {
+ struct cleanup *cleanup_field;
+ cleanup_field = make_cleanup_ui_out_tuple_begin_end (uiout, "field");
+ if (TYPE_FIELD_NAME (type, idx) != NULL)
+ ui_out_field_string (uiout, "name", TYPE_FIELD_NAME (type, idx));
+ if (TYPE_CODE (type) == TYPE_CODE_ENUM
+ || TYPE_CODE (type) == TYPE_CODE_RANGE)
+ ui_out_field_int (uiout, "value", TYPE_FIELD_BITPOS (type, idx));
+ else
+ ui_out_field_int (uiout, "bitpos", TYPE_FIELD_BITPOS (type, idx));
+ if (TYPE_FIELD_BITSIZE (type, idx) > 0)
+ ui_out_field_int (uiout, "bitsize", TYPE_FIELD_BITSIZE (type, idx));
+ if (TYPE_FIELD_TYPE (type, idx) != NULL)
+ mi_recursive_dump_type (uiout, TYPE_FIELD_TYPE (type, idx));
+ do_cleanups (cleanup_field);
+ }
+
+ do_cleanups (cleanup_fields);
+ }
+
+ if (TYPE_TARGET_TYPE (type) != NULL)
+ mi_recursive_dump_type (uiout, TYPE_TARGET_TYPE (type));
+
+ do_cleanups (cleanup);
+}
+
+enum mi_cmd_result
+mi_cmd_var_dump_type (char *command, char **argv, int argc)
+{
+ struct varobj *var;
+ struct type *type;
+
+ if (argc != 1)
+ error ("mi_cmd_var_dump_type: Usage: NAME.");
+
+ /* Get varobj handle, if a valid var obj name was specified */
+ var = varobj_get_handle (argv[0]);
+ if (var == NULL)
+ error ("mi_cmd_var_dump_type: Variable object not found");
+
+ type = varobj_get_gdb_type (var);
+ if (type != NULL)
+ {
+ obstack_begin (&seen_type_obstack, 0);
+ mi_recursive_dump_type (uiout, type);
+ obstack_free (&seen_type_obstack, NULL);
+ }
+
+ return MI_CMD_DONE;
+}
diff -ru gdb-6.4-old/gdb/ui-out.c gdb-6.4/gdb/ui-out.c
--- gdb-6.4-old/gdb/ui-out.c 2006-03-09 11:39:32.753878000 -0700
+++ gdb-6.4/gdb/ui-out.c 2006-03-09 12:24:57.451094000 -0700
@@ -46,7 +46,7 @@
is always available. Stack/nested level 0 is reserved for the
top-level result. */
-enum { MAX_UI_OUT_LEVELS = 6 };
+enum { INIT_UI_OUT_LEVELS = 6 };
struct ui_out_level
{
@@ -106,7 +106,8 @@
/* Sub structure tracking the ui-out depth. */
int level;
- struct ui_out_level levels[MAX_UI_OUT_LEVELS];
+ int max_level;
+ struct ui_out_level *levels;
/* A table, if any. At present only a single table is supported. */
struct ui_out_table table;
@@ -127,8 +128,15 @@
{
struct ui_out_level *current;
/* We had better not overflow the buffer. */
- uiout->level++;
- gdb_assert (uiout->level >= 0 && uiout->level < MAX_UI_OUT_LEVELS);
+ if (uiout->level++ == uiout->max_level)
+ {
+ struct ui_out_level *old = uiout->levels;
+ uiout->max_level *= 2;
+ uiout->levels = XCALLOC(uiout->max_level, struct ui_out_level);
+ memcpy (uiout->levels, old,
+ sizeof (struct ui_out_level) * uiout->max_level);
+ xfree(old);
+ }
current = current_level (uiout);
current->field_count = 0;
current->type = type;
@@ -142,7 +150,7 @@
enum ui_out_type type)
{
/* We had better not underflow the buffer. */
- gdb_assert (uiout->level > 0 && uiout->level < MAX_UI_OUT_LEVELS);
+ gdb_assert (uiout->level > 0);
gdb_assert (current_level (uiout)->type == type);
uiout->level--;
return uiout->level + 1;
@@ -1150,7 +1158,9 @@
uiout->table.flag = 0;
uiout->table.body_flag = 0;
uiout->level = 0;
- memset (uiout->levels, 0, sizeof (uiout->levels));
+ uiout->max_level = INIT_UI_OUT_LEVELS;
+ uiout->levels = XCALLOC(uiout->max_level, struct ui_out_level);
+ memset (uiout->levels, 0, sizeof (struct ui_out_level) * uiout- >max_level);
uiout->table.header_first = NULL;
uiout->table.header_last = NULL;
uiout->table.header_next = NULL;




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]