aboutsummaryrefslogtreecommitdiff
path: root/binutils/debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'binutils/debug.c')
-rw-r--r--binutils/debug.c317
1 files changed, 280 insertions, 37 deletions
diff --git a/binutils/debug.c b/binutils/debug.c
index 02a80ae..edb5835 100644
--- a/binutils/debug.c
+++ b/binutils/debug.c
@@ -54,6 +54,10 @@ struct debug_handle
unsigned int mark;
/* Another mark used by debug_write. */
unsigned int class_mark;
+ /* A struct/class ID used by debug_write. */
+ unsigned int class_id;
+ /* The base for class_id for this call to debug_write. */
+ unsigned int base_id;
};
/* Information we keep for a single compilation unit. */
@@ -150,6 +154,8 @@ struct debug_class_type
debug_field *fields;
/* A mark field used to avoid recursively printing out structs. */
unsigned int mark;
+ /* This is used to uniquely identify unnamed structs when printing. */
+ unsigned int id;
/* The remaining fields are only used for DEBUG_KIND_CLASS and
DEBUG_KIND_UNION_CLASS. */
/* NULL terminated array of base classes. */
@@ -309,8 +315,8 @@ struct debug_method
struct debug_method_variant
{
- /* The argument types of the function. */
- const char *argtypes;
+ /* The physical name of the function. */
+ const char *physname;
/* The type of the function. */
struct debug_type *type;
/* The visibility of the function. */
@@ -497,6 +503,17 @@ struct debug_name
} u;
};
+/* This variable is an ellipsis type. The contents are not used; its
+ address is returned by debug_make_ellipsis_type, and anything which
+ needs to know whether it is dealing with an ellipsis compares
+ addresses. */
+
+static const struct debug_type debug_ellipsis_type;
+
+#define ELLIPSIS_P(t) ((t) == &debug_ellipsis_type)
+
+/* Local functions. */
+
static void debug_error PARAMS ((const char *));
static struct debug_name *debug_add_to_namespace
PARAMS ((struct debug_handle *, struct debug_namespace **, const char *,
@@ -506,6 +523,7 @@ static struct debug_name *debug_add_to_current_namespace
enum debug_object_linkage));
static struct debug_type *debug_make_type
PARAMS ((struct debug_handle *, enum debug_type_kind, unsigned int));
+static struct debug_type *debug_get_real_type PARAMS ((PTR, debug_type));
static boolean debug_write_name
PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
struct debug_name *));
@@ -1223,6 +1241,18 @@ debug_make_indirect_type (handle, slot, tag)
return t;
}
+/* Make an ellipsis type. This is not a type at all, but is a marker
+ suitable for appearing in the list of argument types passed to
+ debug_make_method_type. It should be used to indicate a method
+ which takes a variable number of arguments. */
+
+debug_type
+debug_make_ellipsis_type (handle)
+ PTR handle;
+{
+ return (debug_type) &debug_ellipsis_type;
+}
+
/* Make a void type. There is only one of these. */
debug_type
@@ -1847,10 +1877,10 @@ debug_make_method (handle, name, variants)
/*ARGSUSED*/
debug_method_variant
-debug_make_method_variant (handle, argtypes, type, visibility, constp,
+debug_make_method_variant (handle, physname, type, visibility, constp,
volatilep, voffset, context)
PTR handle;
- const char *argtypes;
+ const char *physname;
debug_type type;
enum debug_visibility visibility;
boolean constp;
@@ -1863,7 +1893,7 @@ debug_make_method_variant (handle, argtypes, type, visibility, constp,
m = (struct debug_method_variant *) xmalloc (sizeof *m);
memset (m, 0, sizeof *m);
- m->argtypes = argtypes;
+ m->physname = physname;
m->type = type;
m->visibility = visibility;
m->constp = constp;
@@ -1879,10 +1909,10 @@ debug_make_method_variant (handle, argtypes, type, visibility, constp,
since a static method can not also be virtual. */
debug_method_variant
-debug_make_static_method_variant (handle, argtypes, type, visibility,
+debug_make_static_method_variant (handle, physname, type, visibility,
constp, volatilep)
PTR handle;
- const char *argtypes;
+ const char *physname;
debug_type type;
enum debug_visibility visibility;
boolean constp;
@@ -1893,7 +1923,7 @@ debug_make_static_method_variant (handle, argtypes, type, visibility,
m = (struct debug_method_variant *) xmalloc (sizeof *m);
memset (m, 0, sizeof *m);
- m->argtypes = argtypes;
+ m->physname = physname;
m->type = type;
m->visibility = visibility;
m->constp = constp;
@@ -1919,6 +1949,13 @@ debug_name_type (handle, name, type)
if (name == NULL || type == NULL)
return DEBUG_TYPE_NULL;
+ if (info->current_unit == NULL
+ || info->current_file == NULL)
+ {
+ debug_error ("debug_record_variable: no current file");
+ return false;
+ }
+
t = debug_make_type (info, DEBUG_KIND_NAMED, 0);
if (t == NULL)
return DEBUG_TYPE_NULL;
@@ -1930,10 +1967,11 @@ debug_name_type (handle, name, type)
t->u.knamed = n;
- /* We also need to add the name to the current namespace. */
+ /* We always add the name to the global namespace. This is probably
+ wrong in some cases, but it seems to be right for stabs. FIXME. */
- nm = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_TYPE,
- DEBUG_LINKAGE_NONE);
+ nm = debug_add_to_namespace (info, &info->current_file->globals, name,
+ DEBUG_OBJECT_TYPE, DEBUG_LINKAGE_NONE);
if (nm == NULL)
return false;
@@ -2018,6 +2056,61 @@ debug_record_type_size (handle, type, size)
return true;
}
+/* Find a named type. */
+
+debug_type
+debug_find_named_type (handle, name)
+ PTR handle;
+ const char *name;
+{
+ struct debug_handle *info = (struct debug_handle *) handle;
+ struct debug_block *b;
+ struct debug_file *f;
+
+ /* We only search the current compilation unit. I don't know if
+ this is right or not. */
+
+ if (info->current_unit == NULL)
+ {
+ debug_error ("debug_find_named_type: no current compilation unit");
+ return DEBUG_TYPE_NULL;
+ }
+
+ for (b = info->current_block; b != NULL; b = b->parent)
+ {
+ if (b->locals != NULL)
+ {
+ struct debug_name *n;
+
+ for (n = b->locals->list; n != NULL; n = n->next)
+ {
+ if (n->kind == DEBUG_OBJECT_TYPE
+ && n->name[0] == name[0]
+ && strcmp (n->name, name) == 0)
+ return n->u.type;
+ }
+ }
+ }
+
+ for (f = info->current_unit->files; f != NULL; f = f->next)
+ {
+ if (f->globals != NULL)
+ {
+ struct debug_name *n;
+
+ for (n = f->globals->list; n != NULL; n = n->next)
+ {
+ if (n->kind == DEBUG_OBJECT_TYPE
+ && n->name[0] == name[0]
+ && strcmp (n->name, name) == 0)
+ return n->u.type;
+ }
+ }
+ }
+
+ return DEBUG_TYPE_NULL;
+}
+
/* Find a tagged type. */
debug_type
@@ -2045,7 +2138,7 @@ debug_find_tagged_type (handle, name, kind)
for (n = f->globals->list; n != NULL; n = n->next)
{
if (n->kind == DEBUG_OBJECT_TAG
- && (kind == DEBUG_KIND_VOID
+ && (kind == DEBUG_KIND_ILLEGAL
|| n->u.tag->kind == kind)
&& n->name[0] == name[0]
&& strcmp (n->name, name) == 0)
@@ -2058,9 +2151,42 @@ debug_find_tagged_type (handle, name, kind)
return DEBUG_TYPE_NULL;
}
+/* Get a base type. */
+
+static struct debug_type *
+debug_get_real_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ switch (type->kind)
+ {
+ default:
+ return type;
+ case DEBUG_KIND_INDIRECT:
+ if (*type->u.kindirect->slot != NULL)
+ return debug_get_real_type (handle, *type->u.kindirect->slot);
+ return type;
+ case DEBUG_KIND_NAMED:
+ return debug_get_real_type (handle, type->u.knamed->type);
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the kind of a type. */
+
+enum debug_type_kind
+debug_get_type_kind (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return DEBUG_KIND_ILLEGAL;
+ type = debug_get_real_type (handle, type);
+ return type->kind;
+}
+
/* Get the name of a type. */
-/*ARGSUSED*/
const char *
debug_get_type_name (handle, type)
PTR handle;
@@ -2077,6 +2203,86 @@ debug_get_type_name (handle, type)
return type->u.knamed->name->name;
return NULL;
}
+
+/* Get the return type of a function or method type. */
+
+debug_type
+debug_get_return_type (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return DEBUG_TYPE_NULL;
+ type = debug_get_real_type (handle, type);
+ switch (type->kind)
+ {
+ default:
+ return DEBUG_TYPE_NULL;
+ case DEBUG_KIND_FUNCTION:
+ return type->u.kfunction->return_type;
+ case DEBUG_KIND_METHOD:
+ return type->u.kmethod->return_type;
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the parameter types of a function or method type (except that
+ we don't currently store the parameter types of a function). */
+
+const debug_type *
+debug_get_parameter_types (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return NULL;
+ type = debug_get_real_type (handle, type);
+ switch (type->kind)
+ {
+ default:
+ return NULL;
+ case DEBUG_KIND_METHOD:
+ return type->u.kmethod->arg_types;
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the NULL terminated array of fields for a struct, union, or
+ class. */
+
+const debug_field *
+debug_get_fields (handle, type)
+ PTR handle;
+ debug_type type;
+{
+ if (type == NULL)
+ return NULL;
+ type = debug_get_real_type (handle, type);
+ switch (type->kind)
+ {
+ default:
+ return NULL;
+ case DEBUG_KIND_STRUCT:
+ case DEBUG_KIND_UNION:
+ case DEBUG_KIND_CLASS:
+ case DEBUG_KIND_UNION_CLASS:
+ return type->u.kclass->fields;
+ }
+ /*NOTREACHED*/
+}
+
+/* Get the type of a field. */
+
+/*ARGSUSED*/
+debug_type
+debug_get_field_type (handle, field)
+ PTR handle;
+ debug_field field;
+{
+ if (field == NULL)
+ return NULL;
+ return field->type;
+}
/* Write out the debugging information. This is given a handle to
debugging information, and a set of function pointers to call. */
@@ -2096,6 +2302,11 @@ debug_write (handle, fns, fhandle)
information more than once. */
++info->mark;
+ /* The base_id field holds an ID value which will never be used, so
+ that we can tell whether we have assigned an ID during this call
+ to debug_write. */
+ info->base_id = info->class_id;
+
for (u = info->units; u != NULL; u = u->next)
{
struct debug_file *f;
@@ -2225,7 +2436,7 @@ debug_write_type (info, fns, fhandle, type, name)
if (type->kind == DEBUG_KIND_NAMED)
return (*fns->typedef_type) (fhandle, type->u.knamed->name->name);
else
- return (*fns->tag_type) (fhandle, type->u.knamed->name->name,
+ return (*fns->tag_type) (fhandle, type->u.knamed->name->name, 0,
type->u.knamed->type->kind);
}
@@ -2247,6 +2458,9 @@ debug_write_type (info, fns, fhandle, type, name)
switch (type->kind)
{
+ case DEBUG_KIND_ILLEGAL:
+ debug_error ("debug_write_type: illegal type encountered");
+ return false;
case DEBUG_KIND_INDIRECT:
if (*type->u.kindirect->slot == DEBUG_TYPE_NULL)
return (*fns->empty_type) (fhandle);
@@ -2266,17 +2480,25 @@ debug_write_type (info, fns, fhandle, type, name)
case DEBUG_KIND_UNION:
if (type->u.kclass != NULL)
{
- if (info->class_mark == type->u.kclass->mark)
+ if (info->class_mark == type->u.kclass->mark
+ || type->u.kclass->id > info->base_id)
{
- /* We are currently outputting this struct. I don't
- know if this can happen, but it can happen for a
- class. */
- return (*fns->tag_type) (fhandle, "?defining?", type->kind);
+ /* We are currently outputting this struct, or we have
+ already output it. I don't know if this can happen,
+ but it can happen for a class. */
+ assert (type->u.kclass->id > info->base_id);
+ return (*fns->tag_type) (fhandle, tag, type->u.kclass->id,
+ type->kind);
}
type->u.kclass->mark = info->class_mark;
+ ++info->class_id;
+ type->u.kclass->id = info->class_id;
}
if (! (*fns->start_struct_type) (fhandle, tag,
+ (type->u.kclass != NULL
+ ? type->u.kclass->id
+ : 0),
type->kind == DEBUG_KIND_STRUCT,
type->size))
return false;
@@ -2361,10 +2583,18 @@ debug_write_type (info, fns, fhandle, type, name)
{
for (i = 0; type->u.kmethod->arg_types[i] != NULL; i++)
{
- if (! debug_write_type (info, fns, fhandle,
- type->u.kmethod->arg_types[i],
- (struct debug_name *) NULL))
- return false;
+ if (ELLIPSIS_P (type->u.kmethod->arg_types[i]))
+ {
+ if (! (*fns->ellipsis_type) (fhandle))
+ return false;
+ }
+ else
+ {
+ if (! debug_write_type (info, fns, fhandle,
+ type->u.kmethod->arg_types[i],
+ (struct debug_name *) NULL))
+ return false;
+ }
}
}
if (type->u.kmethod->domain_type != NULL)
@@ -2410,32 +2640,45 @@ debug_write_class_type (info, fns, fhandle, type, tag)
const char *tag;
{
unsigned int i;
+ unsigned int id;
+ struct debug_type *vptrbase;
- if (type->u.kclass != NULL)
+ if (type->u.kclass == NULL)
{
- if (info->class_mark == type->u.kclass->mark)
+ id = 0;
+ vptrbase = NULL;
+ }
+ else
+ {
+ if (info->class_mark == type->u.kclass->mark
+ || type->u.kclass->id > info->base_id)
{
- /* We are currently outputting this class. This can happen
- when there are methods for an anonymous class. */
- return (*fns->tag_type) (fhandle, "?defining?", type->kind);
+ /* We are currently outputting this class, or we have
+ already output it. This can happen when there are
+ methods for an anonymous class. */
+ assert (type->u.kclass->id > info->base_id);
+ return (*fns->tag_type) (fhandle, tag, type->u.kclass->id,
+ type->kind);
}
type->u.kclass->mark = info->class_mark;
+ ++info->class_id;
+ id = info->class_id;
+ type->u.kclass->id = id;
- if (type->u.kclass->vptrbase != NULL
- && type->u.kclass->vptrbase != type)
+ vptrbase = type->u.kclass->vptrbase;
+ if (vptrbase != NULL && vptrbase != type)
{
- if (! debug_write_type (info, fns, fhandle,
- type->u.kclass->vptrbase,
+ if (! debug_write_type (info, fns, fhandle, vptrbase,
(struct debug_name *) NULL))
return false;
}
}
- if (! (*fns->start_class_type) (fhandle, tag,
+ if (! (*fns->start_class_type) (fhandle, tag, id,
type->kind == DEBUG_KIND_CLASS,
type->size,
- type->u.kclass->vptrbase != NULL,
- type->u.kclass->vptrbase == type))
+ vptrbase != NULL,
+ vptrbase == type))
return false;
if (type->u.kclass != NULL)
@@ -2508,7 +2751,7 @@ debug_write_class_type (info, fns, fhandle, type, tag)
return false;
if (v->voffset != VOFFSET_STATIC_METHOD)
{
- if (! (*fns->class_method_variant) (fhandle, v->argtypes,
+ if (! (*fns->class_method_variant) (fhandle, v->physname,
v->visibility,
v->constp,
v->volatilep,
@@ -2519,7 +2762,7 @@ debug_write_class_type (info, fns, fhandle, type, tag)
else
{
if (! (*fns->class_static_method_variant) (fhandle,
- v->argtypes,
+ v->physname,
v->visibility,
v->constp,
v->volatilep))