X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Fdebug.c;h=dad45593c8281b8fe4f385588f609989f509bed3;hb=4cc782b5919b187ce44ea9d4a66793105aeb07da;hp=91235c177514b9e7b25fcc6f5dff83e51eb0685b;hpb=796369aa9636aa1a745886abd07f77eeac63762e;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/debug.c b/binutils/debug.c index 91235c1775..dad45593c8 100644 --- a/binutils/debug.c +++ b/binutils/debug.c @@ -1,5 +1,5 @@ /* debug.c -- Handle generic debugging information. - Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Written by Ian Lance Taylor . This file is part of GNU Binutils. @@ -52,12 +52,18 @@ struct debug_handle struct debug_lineno *current_lineno; /* Mark. This is used by debug_write. */ 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; + /* The current line number in debug_write. */ + struct debug_lineno *current_write_lineno; + unsigned int current_write_lineno_index; + /* A list of classes which have assigned ID's during debug_write. + This is linked through the next_id field of debug_class_type. */ + struct debug_class_id *id_list; + /* A list used to avoid recursion during debug_type_samep. */ + struct debug_type_compare_list *compare_list; }; /* Information we keep for a single compilation unit. */ @@ -152,7 +158,8 @@ struct debug_class_type { /* NULL terminated array of fields. */ debug_field *fields; - /* A mark field used to avoid recursively printing out structs. */ + /* A mark field which indicates whether the struct has already been + printed. */ unsigned int mark; /* This is used to uniquely identify unnamed structs when printing. */ unsigned int id; @@ -334,7 +341,7 @@ struct debug_method_variant /* The offset to the function in the virtual function table. */ bfd_vma voffset; /* If voffset is VOFFSET_STATIC_METHOD, this is a static method. */ -#define VOFFSET_STATIC_METHOD (1) +#define VOFFSET_STATIC_METHOD ((bfd_vma) -1) /* Context of a virtual method function. */ struct debug_type *context; }; @@ -509,6 +516,42 @@ struct debug_name } u; }; +/* During debug_write, a linked list of these structures is used to + keep track of ID numbers that have been assigned to classes. */ + +struct debug_class_id +{ + /* Next ID number. */ + struct debug_class_id *next; + /* The type with the ID. */ + struct debug_type *type; + /* The tag; NULL if no tag. */ + const char *tag; +}; + +/* During debug_type_samep, a linked list of these structures is kept + on the stack to avoid infinite recursion. */ + +struct debug_type_compare_list +{ + /* Next type on list. */ + struct debug_type_compare_list *next; + /* The types we are comparing. */ + struct debug_type *t1; + struct debug_type *t2; +}; + +/* During debug_get_real_type, a linked list of these structures is + kept on the stack to avoid infinite recursion. */ + +struct debug_type_real_list +{ + /* Next type on list. */ + struct debug_type_real_list *next; + /* The type we are checking. */ + struct debug_type *t; +}; + /* Local functions. */ static void debug_error PARAMS ((const char *)); @@ -520,7 +563,8 @@ 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 struct debug_type *debug_get_real_type + PARAMS ((PTR, debug_type, struct debug_type_real_list *)); static boolean debug_write_name PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, struct debug_name *)); @@ -536,6 +580,15 @@ static boolean debug_write_function static boolean debug_write_block PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, struct debug_block *)); +static boolean debug_write_linenos + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + bfd_vma)); +static boolean debug_set_class_id + PARAMS ((struct debug_handle *, const char *, struct debug_type *)); +static boolean debug_type_samep + PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *)); +static boolean debug_class_type_samep + PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *)); /* Issue an error message. */ @@ -550,7 +603,7 @@ debug_error (message) static struct debug_name * debug_add_to_namespace (info, nsp, name, kind, linkage) - struct debug_handle *info; + struct debug_handle *info ATTRIBUTE_UNUSED; struct debug_namespace **nsp; const char *name; enum debug_object_kind kind; @@ -597,7 +650,7 @@ debug_add_to_current_namespace (info, name, kind, linkage) if (info->current_unit == NULL || info->current_file == NULL) { - debug_error ("debug_add_to_current_namespace: no current file"); + debug_error (_("debug_add_to_current_namespace: no current file")); return NULL; } @@ -680,7 +733,7 @@ debug_start_source (handle, name) if (info->current_unit == NULL) { - debug_error ("debug_start_source: no debug_set_filename call"); + debug_error (_("debug_start_source: no debug_set_filename call")); return false; } @@ -717,8 +770,7 @@ debug_start_source (handle, name) The bfd_vma is the address of the start of the function. Currently the parameter types are specified by calls to debug_record_parameter. FIXME: There is no way to specify nested - functions. FIXME: I don't think there is any way to record where a - function ends. */ + functions. */ boolean debug_record_function (handle, name, return_type, global, addr) @@ -740,7 +792,7 @@ debug_record_function (handle, name, return_type, global, addr) if (info->current_unit == NULL) { - debug_error ("debug_record_function: no debug_set_filename call"); + debug_error (_("debug_record_function: no debug_set_filename call")); return false; } @@ -796,7 +848,7 @@ debug_record_parameter (handle, name, type, kind, val) if (info->current_unit == NULL || info->current_function == NULL) { - debug_error ("debug_record_parameter: no current function"); + debug_error (_("debug_record_parameter: no current function")); return false; } @@ -830,13 +882,13 @@ debug_end_function (handle, addr) || info->current_block == NULL || info->current_function == NULL) { - debug_error ("debug_end_function: no current function"); + debug_error (_("debug_end_function: no current function")); return false; } if (info->current_block->parent != NULL) { - debug_error ("debug_end_function: some blocks were not closed"); + debug_error (_("debug_end_function: some blocks were not closed")); return false; } @@ -866,7 +918,7 @@ debug_start_block (handle, addr) if (info->current_unit == NULL || info->current_block == NULL) { - debug_error ("debug_start_block: no current block"); + debug_error (_("debug_start_block: no current block")); return false; } @@ -904,14 +956,14 @@ debug_end_block (handle, addr) if (info->current_unit == NULL || info->current_block == NULL) { - debug_error ("debug_end_block: no current block"); + debug_error (_("debug_end_block: no current block")); return false; } parent = info->current_block->parent; if (parent == NULL) { - debug_error ("debug_end_block: attempt to close top level block"); + debug_error (_("debug_end_block: attempt to close top level block")); return false; } @@ -937,7 +989,7 @@ debug_record_line (handle, lineno, addr) if (info->current_unit == NULL) { - debug_error ("debug_record_line: no current unit"); + debug_error (_("debug_record_line: no current unit")); return false; } @@ -987,11 +1039,11 @@ debug_record_line (handle, lineno, addr) boolean debug_start_common_block (handle, name) - PTR handle; - const char *name; + PTR handle ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; { /* FIXME */ - debug_error ("debug_start_common_block: not implemented"); + debug_error (_("debug_start_common_block: not implemented")); return false; } @@ -999,11 +1051,11 @@ debug_start_common_block (handle, name) boolean debug_end_common_block (handle, name) - PTR handle; - const char *name; + PTR handle ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; { /* FIXME */ - debug_error ("debug_end_common_block: not implemented"); + debug_error (_("debug_end_common_block: not implemented")); return false; } @@ -1091,13 +1143,13 @@ debug_record_typed_const (handle, name, type, val) boolean debug_record_label (handle, name, type, addr) - PTR handle; - const char *name; - debug_type type; - bfd_vma addr; + PTR handle ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; + debug_type type ATTRIBUTE_UNUSED; + bfd_vma addr ATTRIBUTE_UNUSED; { /* FIXME. */ - debug_error ("debug_record_label not implemented"); + debug_error (_("debug_record_label not implemented")); return false; } @@ -1123,7 +1175,7 @@ debug_record_variable (handle, name, type, kind, val) if (info->current_unit == NULL || info->current_file == NULL) { - debug_error ("debug_record_variable: no current file"); + debug_error (_("debug_record_variable: no current file")); return false; } @@ -1139,7 +1191,7 @@ debug_record_variable (handle, name, type, kind, val) { if (info->current_block == NULL) { - debug_error ("debug_record_variable: no current block"); + debug_error (_("debug_record_variable: no current block")); return false; } nsp = &info->current_block->locals; @@ -1167,7 +1219,7 @@ debug_record_variable (handle, name, type, kind, val) /*ARGSUSED*/ static struct debug_type * debug_make_type (info, kind, size) - struct debug_handle *info; + struct debug_handle *info ATTRIBUTE_UNUSED; enum debug_type_kind kind; unsigned int size; { @@ -1709,7 +1761,7 @@ debug_make_undefined_tagged_type (handle, name, kind) break; default: - debug_error ("debug_make_undefined_type: unsupported kind"); + debug_error (_("debug_make_undefined_type: unsupported kind")); return DEBUG_TYPE_NULL; } @@ -1729,7 +1781,7 @@ debug_make_undefined_tagged_type (handle, name, kind) /*ARGSUSED*/ debug_baseclass debug_make_baseclass (handle, type, bitpos, virtual, visibility) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; debug_type type; bfd_vma bitpos; boolean virtual; @@ -1757,7 +1809,7 @@ debug_make_baseclass (handle, type, bitpos, virtual, visibility) /*ARGSUSED*/ debug_field debug_make_field (handle, name, type, bitpos, bitsize, visibility) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; const char *name; debug_type type; bfd_vma bitpos; @@ -1788,7 +1840,7 @@ debug_make_field (handle, name, type, bitpos, bitsize, visibility) /*ARGSUSED*/ debug_field debug_make_static_member (handle, name, type, physname, visibility) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; const char *name; debug_type type; const char *physname; @@ -1814,7 +1866,7 @@ debug_make_static_member (handle, name, type, physname, visibility) /*ARGSUSED*/ debug_method debug_make_method (handle, name, variants) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; const char *name; debug_method_variant *variants; { @@ -1842,7 +1894,7 @@ debug_make_method (handle, name, variants) debug_method_variant debug_make_method_variant (handle, physname, type, visibility, constp, volatilep, voffset, context) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; const char *physname; debug_type type; enum debug_visibility visibility; @@ -1874,7 +1926,7 @@ debug_make_method_variant (handle, physname, type, visibility, constp, debug_method_variant debug_make_static_method_variant (handle, physname, type, visibility, constp, volatilep) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; const char *physname; debug_type type; enum debug_visibility visibility; @@ -1915,8 +1967,8 @@ debug_name_type (handle, name, type) if (info->current_unit == NULL || info->current_file == NULL) { - debug_error ("debug_record_variable: no current file"); - return false; + debug_error (_("debug_name_type: no current file")); + return DEBUG_TYPE_NULL; } t = debug_make_type (info, DEBUG_KIND_NAMED, 0); @@ -1963,7 +2015,7 @@ debug_tag_type (handle, name, type) if (info->current_file == NULL) { - debug_error ("debug_tag_type: no current file"); + debug_error (_("debug_tag_type: no current file")); return DEBUG_TYPE_NULL; } @@ -1971,7 +2023,7 @@ debug_tag_type (handle, name, type) { if (strcmp (type->u.knamed->name->name, name) == 0) return type; - debug_error ("debug_tag_type: extra tag attempted"); + debug_error (_("debug_tag_type: extra tag attempted")); return DEBUG_TYPE_NULL; } @@ -2006,12 +2058,12 @@ debug_tag_type (handle, name, type) /*ARGSUSED*/ boolean debug_record_type_size (handle, type, size) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; debug_type type; unsigned int size; { if (type->size != 0 && type->size != size) - fprintf (stderr, "Warning: changing type size from %d to %d\n", + fprintf (stderr, _("Warning: changing type size from %d to %d\n"), type->size, size); type->size = size; @@ -2035,7 +2087,7 @@ debug_find_named_type (handle, name) if (info->current_unit == NULL) { - debug_error ("debug_find_named_type: no current compilation unit"); + debug_error (_("debug_find_named_type: no current compilation unit")); return DEBUG_TYPE_NULL; } @@ -2114,24 +2166,54 @@ debug_find_tagged_type (handle, name, kind) return DEBUG_TYPE_NULL; } -/* Get a base type. */ +/* Get a base type. We build a linked list on the stack to avoid + crashing if the type is defined circularly. */ static struct debug_type * -debug_get_real_type (handle, type) +debug_get_real_type (handle, type, list) PTR handle; debug_type type; + struct debug_type_real_list *list; { + struct debug_type_real_list *l; + struct debug_type_real_list rl; + switch (type->kind) { default: return type; + + case DEBUG_KIND_INDIRECT: + case DEBUG_KIND_NAMED: + case DEBUG_KIND_TAGGED: + break; + } + + for (l = list; l != NULL; l = l->next) + { + if (l->t == type) + { + fprintf (stderr, + _("debug_get_real_type: circular debug information for %s\n"), + debug_get_type_name (handle, type)); + return NULL; + } + } + + rl.next = list; + rl.t = type; + + switch (type->kind) + { + /* The default case is just here to avoid warnings. */ + default: case DEBUG_KIND_INDIRECT: if (*type->u.kindirect->slot != NULL) - return debug_get_real_type (handle, *type->u.kindirect->slot); + return debug_get_real_type (handle, *type->u.kindirect->slot, &rl); return type; case DEBUG_KIND_NAMED: case DEBUG_KIND_TAGGED: - return debug_get_real_type (handle, type->u.knamed->type); + return debug_get_real_type (handle, type->u.knamed->type, &rl); } /*NOTREACHED*/ } @@ -2145,7 +2227,9 @@ debug_get_type_kind (handle, type) { if (type == NULL) return DEBUG_KIND_ILLEGAL; - type = debug_get_real_type (handle, type); + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return DEBUG_KIND_ILLEGAL; return type->kind; } @@ -2208,7 +2292,9 @@ debug_get_return_type (handle, type) { if (type == NULL) return DEBUG_TYPE_NULL; - type = debug_get_real_type (handle, type); + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return DEBUG_TYPE_NULL; switch (type->kind) { default: @@ -2232,11 +2318,16 @@ debug_get_parameter_types (handle, type, pvarargs) { if (type == NULL) return NULL; - type = debug_get_real_type (handle, type); + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return NULL; switch (type->kind) { default: return NULL; + case DEBUG_KIND_FUNCTION: + *pvarargs = type->u.kfunction->varargs; + return type->u.kfunction->arg_types; case DEBUG_KIND_METHOD: *pvarargs = type->u.kmethod->varargs; return type->u.kmethod->arg_types; @@ -2253,7 +2344,9 @@ debug_get_target_type (handle, type) { if (type == NULL) return NULL; - type = debug_get_real_type (handle, type); + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return NULL; switch (type->kind) { default: @@ -2280,7 +2373,9 @@ debug_get_fields (handle, type) { if (type == NULL) return NULL; - type = debug_get_real_type (handle, type); + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return NULL; switch (type->kind) { default: @@ -2299,7 +2394,7 @@ debug_get_fields (handle, type) /*ARGSUSED*/ debug_type debug_get_field_type (handle, field) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; debug_field field; { if (field == NULL) @@ -2312,7 +2407,7 @@ debug_get_field_type (handle, field) /*ARGSUSED*/ const char * debug_get_field_name (handle, field) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; debug_field field; { if (field == NULL) @@ -2325,7 +2420,7 @@ debug_get_field_name (handle, field) /*ARGSUSED*/ bfd_vma debug_get_field_bitpos (handle, field) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; debug_field field; { if (field == NULL || field->static_member) @@ -2338,7 +2433,7 @@ debug_get_field_bitpos (handle, field) /*ARGSUSED*/ bfd_vma debug_get_field_bitsize (handle, field) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; debug_field field; { if (field == NULL || field->static_member) @@ -2351,7 +2446,7 @@ debug_get_field_bitsize (handle, field) /*ARGSUSED*/ enum debug_visibility debug_get_field_visibility (handle, field) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; debug_field field; { if (field == NULL) @@ -2363,7 +2458,7 @@ debug_get_field_visibility (handle, field) const char * debug_get_field_physname (handle, field) - PTR handle; + PTR handle ATTRIBUTE_UNUSED; debug_field field; { if (field == NULL || ! field->static_member) @@ -2394,11 +2489,17 @@ debug_write (handle, fns, fhandle) to debug_write. */ info->base_id = info->class_id; + /* We keep a linked list of classes for which was have assigned ID's + during this call to debug_write. */ + info->id_list = NULL; + for (u = info->units; u != NULL; u = u->next) { struct debug_file *f; boolean first_file; - struct debug_lineno *l; + + info->current_write_lineno = u->linenos; + info->current_write_lineno_index = 0; if (! (*fns->start_compilation_unit) (fhandle, u->files->filename)) return false; @@ -2426,19 +2527,10 @@ debug_write (handle, fns, fhandle) } } - for (l = u->linenos; l != NULL; l = l->next) - { - unsigned int i; - - for (i = 0; i < DEBUG_LINENO_COUNT; i++) - { - if (l->linenos[i] == (unsigned long) -1) - break; - if (! (*fns->lineno) (fhandle, l->file->filename, l->linenos[i], - l->addrs[i])) - return false; - } - } + /* Output any line number information which hasn't already been + handled. */ + if (! debug_write_linenos (info, fns, fhandle, (bfd_vma) -1)) + return false; } return true; @@ -2453,10 +2545,6 @@ debug_write_name (info, fns, fhandle, n) PTR fhandle; struct debug_name *n; { - /* The class_mark field is used to prevent recursively outputting a - struct or class. */ - ++info->class_mark; - switch (n->kind) { case DEBUG_OBJECT_TYPE: @@ -2510,7 +2598,7 @@ debug_write_type (info, fns, fhandle, type, name) { unsigned int i; int is; - const char *tag; + const char *tag = NULL; /* If we have a name for this type, just output it. We only output typedef names after they have been defined. We output type tags @@ -2526,9 +2614,29 @@ debug_write_type (info, fns, fhandle, type, name) else { struct debug_type *real; + unsigned int id; + + real = debug_get_real_type ((PTR) info, type, NULL); + if (real == NULL) + return (*fns->empty_type) (fhandle); + id = 0; + if ((real->kind == DEBUG_KIND_STRUCT + || real->kind == DEBUG_KIND_UNION + || real->kind == DEBUG_KIND_CLASS + || real->kind == DEBUG_KIND_UNION_CLASS) + && real->u.kclass != NULL) + { + if (real->u.kclass->id <= info->base_id) + { + if (! debug_set_class_id (info, + type->u.knamed->name->name, + real)) + return false; + } + id = real->u.kclass->id; + } - real = debug_get_real_type ((PTR) info, type); - return (*fns->tag_type) (fhandle, type->u.knamed->name->name, 0, + return (*fns->tag_type) (fhandle, type->u.knamed->name->name, id, real->kind); } } @@ -2540,7 +2648,6 @@ debug_write_type (info, fns, fhandle, type, name) if (name != NULL) name->mark = info->mark; - tag = NULL; if (name != NULL && type->kind != DEBUG_KIND_NAMED && type->kind != DEBUG_KIND_TAGGED) @@ -2552,7 +2659,7 @@ debug_write_type (info, fns, fhandle, type, name) switch (type->kind) { case DEBUG_KIND_ILLEGAL: - debug_error ("debug_write_type: illegal type encountered"); + debug_error (_("debug_write_type: illegal type encountered")); return false; case DEBUG_KIND_INDIRECT: if (*type->u.kindirect->slot == DEBUG_TYPE_NULL) @@ -2573,8 +2680,13 @@ 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 - || type->u.kclass->id > info->base_id) + if (type->u.kclass->id <= info->base_id) + { + if (! debug_set_class_id (info, tag, type)) + return false; + } + + if (info->mark == type->u.kclass->mark) { /* We are currently outputting this struct, or we have already output it. I don't know if this can happen, @@ -2583,9 +2695,7 @@ debug_write_type (info, fns, fhandle, type, name) 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; + type->u.kclass->mark = info->mark; } if (! (*fns->start_struct_type) (fhandle, tag, @@ -2626,6 +2736,10 @@ debug_write_type (info, fns, fhandle, type, name) return false; return (*fns->pointer_type) (fhandle); case DEBUG_KIND_FUNCTION: + if (! debug_write_type (info, fns, fhandle, + type->u.kfunction->return_type, + (struct debug_name *) NULL)) + return false; if (type->u.kfunction->arg_types == NULL) is = -1; else @@ -2636,10 +2750,6 @@ debug_write_type (info, fns, fhandle, type, name) (struct debug_name *) NULL)) return false; } - if (! debug_write_type (info, fns, fhandle, - type->u.kfunction->return_type, - (struct debug_name *) NULL)) - return false; return (*fns->function_type) (fhandle, is, type->u.kfunction->varargs); case DEBUG_KIND_REFERENCE: @@ -2745,8 +2855,13 @@ debug_write_class_type (info, fns, fhandle, type, tag) } else { - if (info->class_mark == type->u.kclass->mark - || type->u.kclass->id > info->base_id) + if (type->u.kclass->id <= info->base_id) + { + if (! debug_set_class_id (info, tag, type)) + return false; + } + + if (info->mark == type->u.kclass->mark) { /* We are currently outputting this class, or we have already output it. This can happen when there are @@ -2755,10 +2870,8 @@ debug_write_class_type (info, fns, fhandle, type, tag) 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; + type->u.kclass->mark = info->mark; + id = type->u.kclass->id; vptrbase = type->u.kclass->vptrbase; if (vptrbase != NULL && vptrbase != type) @@ -2887,6 +3000,9 @@ debug_write_function (info, fns, fhandle, name, linkage, function) struct debug_parameter *p; struct debug_block *b; + if (! debug_write_linenos (info, fns, fhandle, function->blocks->start)) + return false; + if (! debug_write_type (info, fns, fhandle, function->return_type, (struct debug_name *) NULL)) return false; @@ -2924,9 +3040,17 @@ debug_write_block (info, fns, fhandle, block) struct debug_name *n; struct debug_block *b; - if (! (*fns->start_block) (fhandle, block->start)) + if (! debug_write_linenos (info, fns, fhandle, block->start)) return false; + /* I can't see any point to writing out a block with no local + variables, so we don't bother, except for the top level block. */ + if (block->locals != NULL || block->parent == NULL) + { + if (! (*fns->start_block) (fhandle, block->start)) + return false; + } + if (block->locals != NULL) { for (n = block->locals->list; n != NULL; n = n->next) @@ -2942,5 +3066,502 @@ debug_write_block (info, fns, fhandle, block) return false; } - return (*fns->end_block) (fhandle, block->end); + if (! debug_write_linenos (info, fns, fhandle, block->end)) + return false; + + if (block->locals != NULL || block->parent == NULL) + { + if (! (*fns->end_block) (fhandle, block->end)) + return false; + } + + return true; +} + +/* Write out line number information up to ADDRESS. */ + +static boolean +debug_write_linenos (info, fns, fhandle, address) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + bfd_vma address; +{ + while (info->current_write_lineno != NULL) + { + struct debug_lineno *l; + + l = info->current_write_lineno; + + while (info->current_write_lineno_index < DEBUG_LINENO_COUNT) + { + if (l->linenos[info->current_write_lineno_index] + == (unsigned long) -1) + break; + + if (l->addrs[info->current_write_lineno_index] >= address) + return true; + + if (! (*fns->lineno) (fhandle, l->file->filename, + l->linenos[info->current_write_lineno_index], + l->addrs[info->current_write_lineno_index])) + return false; + + ++info->current_write_lineno_index; + } + + info->current_write_lineno = l->next; + info->current_write_lineno_index = 0; + } + + return true; +} + +/* Get the ID number for a class. If during the same call to + debug_write we find a struct with the same definition with the same + name, we use the same ID. This type of things happens because the + same struct will be defined by multiple compilation units. */ + +static boolean +debug_set_class_id (info, tag, type) + struct debug_handle *info; + const char *tag; + struct debug_type *type; +{ + struct debug_class_type *c; + struct debug_class_id *l; + + assert (type->kind == DEBUG_KIND_STRUCT + || type->kind == DEBUG_KIND_UNION + || type->kind == DEBUG_KIND_CLASS + || type->kind == DEBUG_KIND_UNION_CLASS); + + c = type->u.kclass; + + if (c->id > info->base_id) + return true; + + for (l = info->id_list; l != NULL; l = l->next) + { + if (l->type->kind != type->kind) + continue; + + if (tag == NULL) + { + if (l->tag != NULL) + continue; + } + else + { + if (l->tag == NULL + || l->tag[0] != tag[0] + || strcmp (l->tag, tag) != 0) + continue; + } + + if (debug_type_samep (info, l->type, type)) + { + c->id = l->type->u.kclass->id; + return true; + } + } + + /* There are no identical types. Use a new ID, and add it to the + list. */ + ++info->class_id; + c->id = info->class_id; + + l = (struct debug_class_id *) xmalloc (sizeof *l); + memset (l, 0, sizeof *l); + + l->type = type; + l->tag = tag; + + l->next = info->id_list; + info->id_list = l; + + return true; +} + +/* See if two types are the same. At this point, we don't care about + tags and the like. */ + +static boolean +debug_type_samep (info, t1, t2) + struct debug_handle *info; + struct debug_type *t1; + struct debug_type *t2; +{ + struct debug_type_compare_list *l; + struct debug_type_compare_list top; + boolean ret; + + if (t1 == NULL) + return t2 == NULL; + if (t2 == NULL) + return false; + + while (t1->kind == DEBUG_KIND_INDIRECT) + { + t1 = *t1->u.kindirect->slot; + if (t1 == NULL) + return false; + } + while (t2->kind == DEBUG_KIND_INDIRECT) + { + t2 = *t2->u.kindirect->slot; + if (t2 == NULL) + return false; + } + + if (t1 == t2) + return true; + + /* As a special case, permit a typedef to match a tag, since C++ + debugging output will sometimes add a typedef where C debugging + output will not. */ + if (t1->kind == DEBUG_KIND_NAMED + && t2->kind == DEBUG_KIND_TAGGED) + return debug_type_samep (info, t1->u.knamed->type, t2); + else if (t1->kind == DEBUG_KIND_TAGGED + && t2->kind == DEBUG_KIND_NAMED) + return debug_type_samep (info, t1, t2->u.knamed->type); + + if (t1->kind != t2->kind + || t1->size != t2->size) + return false; + + /* Get rid of the trivial cases first. */ + switch (t1->kind) + { + default: + break; + case DEBUG_KIND_VOID: + case DEBUG_KIND_FLOAT: + case DEBUG_KIND_COMPLEX: + case DEBUG_KIND_BOOL: + return true; + case DEBUG_KIND_INT: + return t1->u.kint == t2->u.kint; + } + + /* We have to avoid an infinite recursion. We do this by keeping a + list of types which we are comparing. We just keep the list on + the stack. If we encounter a pair of types we are currently + comparing, we just assume that they are equal. */ + for (l = info->compare_list; l != NULL; l = l->next) + { + if (l->t1 == t1 && l->t2 == t2) + return true; + } + + top.t1 = t1; + top.t2 = t2; + top.next = info->compare_list; + info->compare_list = ⊤ + + switch (t1->kind) + { + default: + abort (); + ret = false; + break; + + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_UNION: + case DEBUG_KIND_CLASS: + case DEBUG_KIND_UNION_CLASS: + if (t1->u.kclass == NULL) + ret = t2->u.kclass == NULL; + else if (t2->u.kclass == NULL) + ret = false; + else if (t1->u.kclass->id > info->base_id + && t1->u.kclass->id == t2->u.kclass->id) + ret = true; + else + ret = debug_class_type_samep (info, t1, t2); + break; + + case DEBUG_KIND_ENUM: + if (t1->u.kenum == NULL) + ret = t2->u.kenum == NULL; + else if (t2->u.kenum == NULL) + ret = false; + else + { + const char **pn1, **pn2; + bfd_signed_vma *pv1, *pv2; + + pn1 = t1->u.kenum->names; + pn2 = t2->u.kenum->names; + pv1 = t1->u.kenum->values; + pv2 = t2->u.kenum->values; + while (*pn1 != NULL && *pn2 != NULL) + { + if (**pn1 != **pn2 + || *pv1 != *pv2 + || strcmp (*pn1, *pn2) != 0) + break; + ++pn1; + ++pn2; + ++pv1; + ++pv2; + } + ret = *pn1 == NULL && *pn2 == NULL; + } + break; + + case DEBUG_KIND_POINTER: + ret = debug_type_samep (info, t1->u.kpointer, t2->u.kpointer); + break; + + case DEBUG_KIND_FUNCTION: + if (t1->u.kfunction->varargs != t2->u.kfunction->varargs + || ! debug_type_samep (info, t1->u.kfunction->return_type, + t2->u.kfunction->return_type) + || ((t1->u.kfunction->arg_types == NULL) + != (t2->u.kfunction->arg_types == NULL))) + ret = false; + else if (t1->u.kfunction->arg_types == NULL) + ret = true; + else + { + struct debug_type **a1, **a2; + + a1 = t1->u.kfunction->arg_types; + a2 = t2->u.kfunction->arg_types; + while (*a1 != NULL && *a2 != NULL) + { + if (! debug_type_samep (info, *a1, *a2)) + break; + ++a1; + ++a2; + } + ret = *a1 == NULL && *a2 == NULL; + } + break; + + case DEBUG_KIND_REFERENCE: + ret = debug_type_samep (info, t1->u.kreference, t2->u.kreference); + break; + + case DEBUG_KIND_RANGE: + ret = (t1->u.krange->lower == t2->u.krange->lower + && t1->u.krange->upper == t2->u.krange->upper + && debug_type_samep (info, t1->u.krange->type, + t2->u.krange->type)); + + case DEBUG_KIND_ARRAY: + ret = (t1->u.karray->lower == t2->u.karray->lower + && t1->u.karray->upper == t2->u.karray->upper + && t1->u.karray->stringp == t2->u.karray->stringp + && debug_type_samep (info, t1->u.karray->element_type, + t2->u.karray->element_type)); + break; + + case DEBUG_KIND_SET: + ret = (t1->u.kset->bitstringp == t2->u.kset->bitstringp + && debug_type_samep (info, t1->u.kset->type, t2->u.kset->type)); + break; + + case DEBUG_KIND_OFFSET: + ret = (debug_type_samep (info, t1->u.koffset->base_type, + t2->u.koffset->base_type) + && debug_type_samep (info, t1->u.koffset->target_type, + t2->u.koffset->target_type)); + break; + + case DEBUG_KIND_METHOD: + if (t1->u.kmethod->varargs != t2->u.kmethod->varargs + || ! debug_type_samep (info, t1->u.kmethod->return_type, + t2->u.kmethod->return_type) + || ! debug_type_samep (info, t1->u.kmethod->domain_type, + t2->u.kmethod->domain_type) + || ((t1->u.kmethod->arg_types == NULL) + != (t2->u.kmethod->arg_types == NULL))) + ret = false; + else if (t1->u.kmethod->arg_types == NULL) + ret = true; + else + { + struct debug_type **a1, **a2; + + a1 = t1->u.kmethod->arg_types; + a2 = t2->u.kmethod->arg_types; + while (*a1 != NULL && *a2 != NULL) + { + if (! debug_type_samep (info, *a1, *a2)) + break; + ++a1; + ++a2; + } + ret = *a1 == NULL && *a2 == NULL; + } + break; + + case DEBUG_KIND_CONST: + ret = debug_type_samep (info, t1->u.kconst, t2->u.kconst); + break; + + case DEBUG_KIND_VOLATILE: + ret = debug_type_samep (info, t1->u.kvolatile, t2->u.kvolatile); + break; + + case DEBUG_KIND_NAMED: + case DEBUG_KIND_TAGGED: + ret = (strcmp (t1->u.knamed->name->name, t2->u.knamed->name->name) == 0 + && debug_type_samep (info, t1->u.knamed->type, + t2->u.knamed->type)); + break; + } + + info->compare_list = top.next; + + return ret; +} + +/* See if two classes are the same. This is a subroutine of + debug_type_samep. */ + +static boolean +debug_class_type_samep (info, t1, t2) + struct debug_handle *info; + struct debug_type *t1; + struct debug_type *t2; +{ + struct debug_class_type *c1, *c2; + + c1 = t1->u.kclass; + c2 = t2->u.kclass; + + if ((c1->fields == NULL) != (c2->fields == NULL) + || (c1->baseclasses == NULL) != (c2->baseclasses == NULL) + || (c1->methods == NULL) != (c2->methods == NULL) + || (c1->vptrbase == NULL) != (c2->vptrbase == NULL)) + return false; + + if (c1->fields != NULL) + { + struct debug_field **pf1, **pf2; + + for (pf1 = c1->fields, pf2 = c2->fields; + *pf1 != NULL && *pf2 != NULL; + pf1++, pf2++) + { + struct debug_field *f1, *f2; + + f1 = *pf1; + f2 = *pf2; + if (f1->name[0] != f2->name[0] + || f1->visibility != f2->visibility + || f1->static_member != f2->static_member) + return false; + if (f1->static_member) + { + if (strcmp (f1->u.s.physname, f2->u.s.physname) != 0) + return false; + } + else + { + if (f1->u.f.bitpos != f2->u.f.bitpos + || f1->u.f.bitsize != f2->u.f.bitsize) + return false; + } + /* We do the checks which require function calls last. We + don't require that the types of fields have the same + names, since that sometimes fails in the presence of + typedefs and we really don't care. */ + if (strcmp (f1->name, f2->name) != 0 + || ! debug_type_samep (info, + debug_get_real_type ((PTR) info, + f1->type, NULL), + debug_get_real_type ((PTR) info, + f2->type, NULL))) + return false; + } + if (*pf1 != NULL || *pf2 != NULL) + return false; + } + + if (c1->vptrbase != NULL) + { + if (! debug_type_samep (info, c1->vptrbase, c2->vptrbase)) + return false; + } + + if (c1->baseclasses != NULL) + { + struct debug_baseclass **pb1, **pb2; + + for (pb1 = c1->baseclasses, pb2 = c2->baseclasses; + *pb1 != NULL && *pb2 != NULL; + ++pb1, ++pb2) + { + struct debug_baseclass *b1, *b2; + + b1 = *pb1; + b2 = *pb2; + if (b1->bitpos != b2->bitpos + || b1->virtual != b2->virtual + || b1->visibility != b2->visibility + || ! debug_type_samep (info, b1->type, b2->type)) + return false; + } + if (*pb1 != NULL || *pb2 != NULL) + return false; + } + + if (c1->methods != NULL) + { + struct debug_method **pm1, **pm2; + + for (pm1 = c1->methods, pm2 = c2->methods; + *pm1 != NULL && *pm2 != NULL; + ++pm1, ++pm2) + { + struct debug_method *m1, *m2; + + m1 = *pm1; + m2 = *pm2; + if (m1->name[0] != m2->name[0] + || strcmp (m1->name, m2->name) != 0 + || (m1->variants == NULL) != (m2->variants == NULL)) + return false; + if (m1->variants == NULL) + { + struct debug_method_variant **pv1, **pv2; + + for (pv1 = m1->variants, pv2 = m2->variants; + *pv1 != NULL && *pv2 != NULL; + ++pv1, ++pv2) + { + struct debug_method_variant *v1, *v2; + + v1 = *pv1; + v2 = *pv2; + if (v1->physname[0] != v2->physname[0] + || v1->visibility != v2->visibility + || v1->constp != v2->constp + || v1->volatilep != v2->volatilep + || v1->voffset != v2->voffset + || (v1->context == NULL) != (v2->context == NULL) + || strcmp (v1->physname, v2->physname) != 0 + || ! debug_type_samep (info, v1->type, v2->type)) + return false; + if (v1->context != NULL) + { + if (! debug_type_samep (info, v1->context, + v2->context)) + return false; + } + } + if (*pv1 != NULL || *pv2 != NULL) + return false; + } + } + if (*pm1 != NULL || *pm2 != NULL) + return false; + } + + return true; }