X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Fdebug.c;h=d6e68a3b141f2686652fc5b433e5e1d108ad1314;hb=9be2ae8fc6b908746d9d7ebaf77aec8abba5dd2c;hp=18eb529818be836444e0f347b8e78c629f9b65ef;hpb=e1c145993ec59ed01a1bbc88c294ac3167fa5c66;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/debug.c b/binutils/debug.c index 18eb529818..d6e68a3b14 100644 --- a/binutils/debug.c +++ b/binutils/debug.c @@ -1,12 +1,12 @@ /* debug.c -- Handle generic debugging information. - Copyright (C) 1995 Free Software Foundation, Inc. + Copyright (C) 1995-2018 Free Software Foundation, Inc. Written by Ian Lance Taylor . This file is part of GNU Binutils. 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 2 of the License, or + 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, @@ -16,21 +16,21 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + /* This file implements a generic debugging format. We may eventually have readers which convert different formats into this generic format, and writers which write it out. The initial impetus for - this was writing a convertor from stabs to HP IEEE-695 debugging + this was writing a converter from stabs to HP IEEE-695 debugging format. */ -#include +#include "sysdep.h" #include - #include "bfd.h" -#include "bucomm.h" #include "libiberty.h" +#include "filenames.h" #include "debug.h" /* Global information we keep for debugging. A pointer to this @@ -48,12 +48,22 @@ struct debug_handle struct debug_function *current_function; /* The current block. */ struct debug_block *current_block; - /* The current line number information for the current block. */ + /* The current line number information for the current unit. */ 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. */ @@ -66,6 +76,10 @@ struct debug_unit file is always the main one, and that is where the main file name is stored. */ struct debug_file *files; + /* Line number information for this compilation unit. This is not + stored by function, because assembler code may have line number + information without function information. */ + struct debug_lineno *linenos; }; /* Information kept for a single source file. */ @@ -82,7 +96,7 @@ struct debug_file /* A type. */ -struct debug_type +struct debug_type_s { /* Kind of type. */ enum debug_type_kind kind; @@ -97,18 +111,18 @@ struct debug_type struct debug_indirect_type *kindirect; /* DEBUG_KIND_INT. */ /* Whether the integer is unsigned. */ - boolean kint; + bfd_boolean kint; /* DEBUG_KIND_STRUCT, DEBUG_KIND_UNION, DEBUG_KIND_CLASS, DEBUG_KIND_UNION_CLASS. */ struct debug_class_type *kclass; /* DEBUG_KIND_ENUM. */ struct debug_enum_type *kenum; /* DEBUG_KIND_POINTER. */ - struct debug_type *kpointer; + struct debug_type_s *kpointer; /* DEBUG_KIND_FUNCTION. */ struct debug_function_type *kfunction; /* DEBUG_KIND_REFERENCE. */ - struct debug_type *kreference; + struct debug_type_s *kreference; /* DEBUG_KIND_RANGE. */ struct debug_range_type *krange; /* DEBUG_KIND_ARRAY. */ @@ -120,9 +134,9 @@ struct debug_type /* DEBUG_KIND_METHOD. */ struct debug_method_type *kmethod; /* DEBUG_KIND_CONST. */ - struct debug_type *kconst; + struct debug_type_s *kconst; /* DEBUG_KIND_VOLATILE. */ - struct debug_type *kvolatile; + struct debug_type_s *kvolatile; /* DEBUG_KIND_NAMED, DEBUG_KIND_TAGGED. */ struct debug_named_type *knamed; } u; @@ -144,8 +158,11 @@ 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; /* The remaining fields are only used for DEBUG_KIND_CLASS and DEBUG_KIND_UNION_CLASS. */ /* NULL terminated array of base classes. */ @@ -174,6 +191,10 @@ struct debug_function_type { /* Return type. */ debug_type return_type; + /* NULL terminated array of argument types. */ + debug_type *arg_types; + /* Whether the function takes a variable number of arguments. */ + bfd_boolean varargs; }; /* Information kept for a range. */ @@ -201,7 +222,7 @@ struct debug_array_type /* Upper bound. */ bfd_signed_vma upper; /* Whether this array is really a string. */ - boolean stringp; + bfd_boolean stringp; }; /* Information kept for a set. */ @@ -211,7 +232,7 @@ struct debug_set_type /* Base type. */ debug_type type; /* Whether this set is really a bitstring. */ - boolean bitstringp; + bfd_boolean bitstringp; }; /* Information kept for an offset type (a based pointer). */ @@ -234,6 +255,8 @@ struct debug_method_type debug_type domain_type; /* A NULL terminated array of argument types. */ debug_type *arg_types; + /* Whether the method takes a variable number of arguments. */ + bfd_boolean varargs; }; /* Information kept for a named type. */ @@ -248,16 +271,16 @@ struct debug_named_type /* A field in a struct or union. */ -struct debug_field +struct debug_field_s { /* Name of the field. */ const char *name; /* Type of the field. */ - struct debug_type *type; + struct debug_type_s *type; /* Visibility of the field. */ enum debug_visibility visibility; /* Whether this is a static member. */ - boolean static_member; + bfd_boolean static_member; union { /* If static_member is false. */ @@ -278,49 +301,49 @@ struct debug_field /* A base class for an object. */ -struct debug_baseclass +struct debug_baseclass_s { /* Type of the base class. */ - struct debug_type *type; + struct debug_type_s *type; /* Bit position of the base class in the object. */ unsigned int bitpos; /* Whether the base class is virtual. */ - boolean virtual; + bfd_boolean is_virtual; /* Visibility of the base class. */ enum debug_visibility visibility; }; /* A method of an object. */ -struct debug_method +struct debug_method_s { /* The name of the method. */ const char *name; /* A NULL terminated array of different types of variants. */ - struct debug_method_variant **variants; + struct debug_method_variant_s **variants; }; /* The variants of a method function of an object. These indicate which method to run. */ -struct debug_method_variant +struct debug_method_variant_s { - /* 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; + struct debug_type_s *type; /* The visibility of the function. */ enum debug_visibility visibility; /* Whether the function is const. */ - boolean constp; + bfd_boolean constp; /* Whether the function is volatile. */ - boolean volatilep; + bfd_boolean volatilep; /* 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; + struct debug_type_s *context; }; /* A variable. This is the information we keep for a variable object. @@ -394,12 +417,11 @@ struct debug_block bfd_vma end; /* Local variables. */ struct debug_namespace *locals; - /* Line number information. */ - struct debug_lineno *linenos; }; -/* Line number information we keep for a function. FIXME: This - structure is easy to create, but can be very space inefficient. */ +/* Line number information we keep for a compilation unit. FIXME: + This structure is easy to create, but can be very space + inefficient. */ struct debug_lineno { @@ -478,9 +500,9 @@ struct debug_name union { /* DEBUG_OBJECT_TYPE. */ - struct debug_type *type; + struct debug_type_s *type; /* DEBUG_OBJECT_TAG. */ - struct debug_type *tag; + struct debug_type_s *tag; /* DEBUG_OBJECT_VARIABLE. */ struct debug_variable *variable; /* DEBUG_OBJECT_FUNCTION. */ @@ -494,36 +516,83 @@ struct debug_name } u; }; -static void debug_error PARAMS ((const char *)); +/* 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_s *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_s *t1; + struct debug_type_s *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_s *t; +}; + +/* Local functions. */ + +static void debug_error (const char *); static struct debug_name *debug_add_to_namespace - PARAMS ((struct debug_handle *, struct debug_namespace **, const char *, - enum debug_object_kind, enum debug_object_linkage)); + (struct debug_handle *, struct debug_namespace **, const char *, + enum debug_object_kind, enum debug_object_linkage); static struct debug_name *debug_add_to_current_namespace - PARAMS ((struct debug_handle *, const char *, enum debug_object_kind, - enum debug_object_linkage)); -static struct debug_type *debug_make_type - PARAMS ((struct debug_handle *, enum debug_type_kind, unsigned int)); -static boolean debug_write_name - PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, - struct debug_name *)); -static boolean debug_write_type - PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, - struct debug_type *, struct debug_name *)); -static boolean debug_write_class_type - PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, - struct debug_type *)); -static boolean debug_write_function - PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, - const char *, enum debug_object_linkage, struct debug_function *)); -static boolean debug_write_block - PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, - struct debug_block *)); + (struct debug_handle *, const char *, enum debug_object_kind, + enum debug_object_linkage); +static struct debug_type_s *debug_make_type + (struct debug_handle *, enum debug_type_kind, unsigned int); +static struct debug_type_s *debug_get_real_type + (void *, debug_type, struct debug_type_real_list *); +static bfd_boolean debug_write_name + (struct debug_handle *, const struct debug_write_fns *, void *, + struct debug_name *); +static bfd_boolean debug_write_type + (struct debug_handle *, const struct debug_write_fns *, void *, + struct debug_type_s *, struct debug_name *); +static bfd_boolean debug_write_class_type + (struct debug_handle *, const struct debug_write_fns *, void *, + struct debug_type_s *, const char *); +static bfd_boolean debug_write_function + (struct debug_handle *, const struct debug_write_fns *, void *, + const char *, enum debug_object_linkage, struct debug_function *); +static bfd_boolean debug_write_block + (struct debug_handle *, const struct debug_write_fns *, void *, + struct debug_block *); +static bfd_boolean debug_write_linenos + (struct debug_handle *, const struct debug_write_fns *, void *, bfd_vma); +static bfd_boolean debug_set_class_id + (struct debug_handle *, const char *, struct debug_type_s *); +static bfd_boolean debug_type_samep + (struct debug_handle *, struct debug_type_s *, struct debug_type_s *); +static bfd_boolean debug_class_type_samep + (struct debug_handle *, struct debug_type_s *, struct debug_type_s *); /* Issue an error message. */ static void -debug_error (message) - const char *message; +debug_error (const char *message) { fprintf (stderr, "%s\n", message); } @@ -531,12 +600,10 @@ debug_error (message) /* Add an object to a namespace. */ static struct debug_name * -debug_add_to_namespace (info, nsp, name, kind, linkage) - struct debug_handle *info; - struct debug_namespace **nsp; - const char *name; - enum debug_object_kind kind; - enum debug_object_linkage linkage; +debug_add_to_namespace (struct debug_handle *info ATTRIBUTE_UNUSED, + struct debug_namespace **nsp, const char *name, + enum debug_object_kind kind, + enum debug_object_linkage linkage) { struct debug_name *n; struct debug_namespace *ns; @@ -568,18 +635,16 @@ debug_add_to_namespace (info, nsp, name, kind, linkage) /* Add an object to the current namespace. */ static struct debug_name * -debug_add_to_current_namespace (info, name, kind, linkage) - struct debug_handle *info; - const char *name; - enum debug_object_kind kind; - enum debug_object_linkage linkage; +debug_add_to_current_namespace (struct debug_handle *info, const char *name, + enum debug_object_kind kind, + enum debug_object_linkage linkage) { struct debug_namespace **nsp; 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; } @@ -593,23 +658,21 @@ debug_add_to_current_namespace (info, name, kind, linkage) /* Return a handle for debugging information. */ -PTR -debug_init () +void * +debug_init (void) { struct debug_handle *ret; ret = (struct debug_handle *) xmalloc (sizeof *ret); memset (ret, 0, sizeof *ret); - return (PTR) ret; + return (void *) ret; } /* Set the source filename. This implicitly starts a new compilation unit. */ -boolean -debug_set_filename (handle, name) - PTR handle; - const char *name; +bfd_boolean +debug_set_filename (void *handle, const char *name) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_file *nfile; @@ -643,44 +706,14 @@ debug_set_filename (handle, name) info->current_block = NULL; info->current_lineno = NULL; - return true; -} - -/* Append a string to the source filename. */ - -boolean -debug_append_filename (handle, string) - PTR handle; - const char *string; -{ - struct debug_handle *info = (struct debug_handle *) handle; - char *n; - - if (string == NULL) - string = ""; - - if (info->current_unit == NULL) - { - debug_error ("debug_append_filename: no current file"); - return false; - } - - n = (char *) xmalloc (strlen (info->current_unit->files->filename) - + strlen (string) - + 1); - sprintf (n, "%s%s", info->current_unit->files->filename, string); - info->current_unit->files->filename = n; - - return true; + return TRUE; } /* Change source files to the given file name. This is used for include files in a single compilation unit. */ -boolean -debug_start_source (handle, name) - PTR handle; - const char *name; +bfd_boolean +debug_start_source (void *handle, const char *name) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_file *f, **pf; @@ -690,18 +723,16 @@ debug_start_source (handle, name) if (info->current_unit == NULL) { - debug_error ("debug_start_source: no debug_set_filename call"); - return false; + debug_error (_("debug_start_source: no debug_set_filename call")); + return FALSE; } for (f = info->current_unit->files; f != NULL; f = f->next) { - if (f->filename[0] == name[0] - && f->filename[1] == name[1] - && strcmp (f->filename, name) == 0) + if (filename_cmp (f->filename, name) == 0) { info->current_file = f; - return true; + return TRUE; } } @@ -718,7 +749,7 @@ debug_start_source (handle, name) info->current_file = f; - return true; + return TRUE; } /* Record a function definition. This implicitly starts a function @@ -727,16 +758,12 @@ 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) - PTR handle; - const char *name; - debug_type return_type; - boolean global; - bfd_vma addr; +bfd_boolean +debug_record_function (void *handle, const char *name, + debug_type return_type, bfd_boolean global, + bfd_vma addr) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_function *f; @@ -746,12 +773,12 @@ debug_record_function (handle, name, return_type, global, addr) if (name == NULL) name = ""; if (return_type == NULL) - return false; + return FALSE; if (info->current_unit == NULL) { - debug_error ("debug_record_function: no debug_set_filename call"); - return false; + debug_error (_("debug_record_function: no debug_set_filename call")); + return FALSE; } f = (struct debug_function *) xmalloc (sizeof *f); @@ -769,7 +796,6 @@ debug_record_function (handle, name, return_type, global, addr) info->current_function = f; info->current_block = b; - info->current_lineno = NULL; /* FIXME: If we could handle nested functions, this would be the place: we would want to use a different namespace. */ @@ -781,34 +807,30 @@ debug_record_function (handle, name, return_type, global, addr) ? DEBUG_LINKAGE_GLOBAL : DEBUG_LINKAGE_STATIC)); if (n == NULL) - return false; + return FALSE; n->u.function = f; - return true; + return TRUE; } /* Record a parameter for the current function. */ -boolean -debug_record_parameter (handle, name, type, kind, val) - PTR handle; - const char *name; - debug_type type; - enum debug_parm_kind kind; - bfd_vma val; +bfd_boolean +debug_record_parameter (void *handle, const char *name, debug_type type, + enum debug_parm_kind kind, bfd_vma val) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_parameter *p, **pp; if (name == NULL || type == NULL) - return false; + return FALSE; if (info->current_unit == NULL || info->current_function == NULL) { - debug_error ("debug_record_parameter: no current function"); - return false; + debug_error (_("debug_record_parameter: no current function")); + return FALSE; } p = (struct debug_parameter *) xmalloc (sizeof *p); @@ -825,15 +847,13 @@ debug_record_parameter (handle, name, type, kind, val) ; *pp = p; - return true; + return TRUE; } /* End a function. FIXME: This should handle function nesting. */ -boolean -debug_end_function (handle, addr) - PTR handle; - bfd_vma addr; +bfd_boolean +debug_end_function (void *handle, bfd_vma addr) { struct debug_handle *info = (struct debug_handle *) handle; @@ -841,23 +861,22 @@ debug_end_function (handle, addr) || info->current_block == NULL || info->current_function == NULL) { - debug_error ("debug_end_function: no current function"); - return false; + 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"); - return false; + debug_error (_("debug_end_function: some blocks were not closed")); + return FALSE; } info->current_block->end = addr; info->current_function = NULL; info->current_block = NULL; - info->current_lineno = NULL; - return true; + return TRUE; } /* Start a block in a function. All local information will be @@ -865,10 +884,8 @@ debug_end_function (handle, addr) debug_start_block and debug_end_block may be nested. The bfd_vma argument is the address at which this block starts. */ -boolean -debug_start_block (handle, addr) - PTR handle; - bfd_vma addr; +bfd_boolean +debug_start_block (void *handle, bfd_vma addr) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_block *b, **pb; @@ -878,8 +895,8 @@ debug_start_block (handle, addr) if (info->current_unit == NULL || info->current_block == NULL) { - debug_error ("debug_start_block: no current block"); - return false; + debug_error (_("debug_start_block: no current block")); + return FALSE; } b = (struct debug_block *) xmalloc (sizeof *b); @@ -897,19 +914,16 @@ debug_start_block (handle, addr) *pb = b; info->current_block = b; - info->current_lineno = NULL; - return true; + return TRUE; } /* Finish a block in a function. This matches the call to debug_start_block. The argument is the address at which this block ends. */ -boolean -debug_end_block (handle, addr) - PTR handle; - bfd_vma addr; +bfd_boolean +debug_end_block (void *handle, bfd_vma addr) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_block *parent; @@ -917,43 +931,38 @@ debug_end_block (handle, addr) if (info->current_unit == NULL || info->current_block == NULL) { - debug_error ("debug_end_block: no current block"); - return false; + 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"); - return false; + debug_error (_("debug_end_block: attempt to close top level block")); + return FALSE; } info->current_block->end = addr; info->current_block = parent; - info->current_lineno = NULL; - return true; + return TRUE; } /* Associate a line number in the current source file and function with a given address. */ -boolean -debug_record_line (handle, lineno, addr) - PTR handle; - unsigned long lineno; - bfd_vma addr; +bfd_boolean +debug_record_line (void *handle, unsigned long lineno, bfd_vma addr) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_lineno *l; unsigned int i; - if (info->current_unit == NULL - || info->current_block == NULL) + if (info->current_unit == NULL) { - debug_error ("debug_record_line: no current block"); - return false; + debug_error (_("debug_record_line: no current unit")); + return FALSE; } l = info->current_lineno; @@ -965,17 +974,18 @@ debug_record_line (handle, lineno, addr) { l->linenos[i] = lineno; l->addrs[i] = addr; - return true; + return TRUE; } } } /* If we get here, then either 1) there is no current_lineno - structure, which means this is the first line number since we got - to this block, 2) the current_lineno structure is for a different - file, or 3) the current_lineno structure is full. Regardless, we - want to allocate a new debug_lineno structure, put it in the - right place, and make it the new current_lineno structure. */ + structure, which means this is the first line number in this + compilation unit, 2) the current_lineno structure is for a + different file, or 3) the current_lineno structure is full. + Regardless, we want to allocate a new debug_lineno structure, put + it in the right place, and make it the new current_lineno + structure. */ l = (struct debug_lineno *) xmalloc (sizeof *l); memset (l, 0, sizeof *l); @@ -989,117 +999,95 @@ debug_record_line (handle, lineno, addr) if (info->current_lineno != NULL) info->current_lineno->next = l; else - { - struct debug_lineno **pl; - - /* We may be back in this block after dealing with child blocks, - which means we may have some line number information for this - block even though current_lineno was NULL. */ - for (pl = &info->current_block->linenos; - *pl != NULL; - pl = &(*pl)->next) - ; - *pl = l; - } + info->current_unit->linenos = l; info->current_lineno = l; - return true; + return TRUE; } /* Start a named common block. This is a block of variables that may move in memory. */ -boolean -debug_start_common_block (handle, name) - PTR handle; - const char *name; +bfd_boolean +debug_start_common_block (void *handle ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED) { /* FIXME */ - debug_error ("debug_start_common_block: not implemented"); - return false; + debug_error (_("debug_start_common_block: not implemented")); + return FALSE; } /* End a named common block. */ -boolean -debug_end_common_block (handle, name) - PTR handle; - const char *name; +bfd_boolean +debug_end_common_block (void *handle ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED) { /* FIXME */ - debug_error ("debug_end_common_block: not implemented"); - return false; + debug_error (_("debug_end_common_block: not implemented")); + return FALSE; } /* Record a named integer constant. */ -boolean -debug_record_int_const (handle, name, val) - PTR handle; - const char *name; - bfd_vma val; +bfd_boolean +debug_record_int_const (void *handle, const char *name, bfd_vma val) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_name *n; if (name == NULL) - return false; + return FALSE; n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_INT_CONSTANT, DEBUG_LINKAGE_NONE); if (n == NULL) - return false; + return FALSE; n->u.int_constant = val; - return true; + return TRUE; } /* Record a named floating point constant. */ -boolean -debug_record_float_const (handle, name, val) - PTR handle; - const char *name; - double val; +bfd_boolean +debug_record_float_const (void *handle, const char *name, double val) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_name *n; if (name == NULL) - return false; + return FALSE; n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_FLOAT_CONSTANT, DEBUG_LINKAGE_NONE); if (n == NULL) - return false; + return FALSE; n->u.float_constant = val; - return true; + return TRUE; } /* Record a typed constant with an integral value. */ -boolean -debug_record_typed_const (handle, name, type, val) - PTR handle; - const char *name; - debug_type type; - bfd_vma val; +bfd_boolean +debug_record_typed_const (void *handle, const char *name, debug_type type, + bfd_vma val) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_name *n; struct debug_typed_constant *tc; if (name == NULL || type == NULL) - return false; + return FALSE; n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_TYPED_CONSTANT, DEBUG_LINKAGE_NONE); if (n == NULL) - return false; + return FALSE; tc = (struct debug_typed_constant *) xmalloc (sizeof *tc); memset (tc, 0, sizeof *tc); @@ -1109,32 +1097,27 @@ debug_record_typed_const (handle, name, type, val) n->u.typed_constant = tc; - return true; + return TRUE; } /* Record a label. */ -boolean -debug_record_label (handle, name, type, addr) - PTR handle; - const char *name; - debug_type type; - bfd_vma addr; +bfd_boolean +debug_record_label (void *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"); - return false; + debug_error (_("debug_record_label: not implemented")); + return FALSE; } /* Record a variable. */ -boolean -debug_record_variable (handle, name, type, kind, val) - PTR handle; - const char *name; - debug_type type; - enum debug_var_kind kind; - bfd_vma val; +bfd_boolean +debug_record_variable (void *handle, const char *name, debug_type type, + enum debug_var_kind kind, bfd_vma val) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_namespace **nsp; @@ -1143,13 +1126,13 @@ debug_record_variable (handle, name, type, kind, val) struct debug_variable *v; if (name == NULL || type == NULL) - return false; + return FALSE; if (info->current_unit == NULL || info->current_file == NULL) { - debug_error ("debug_record_variable: no current file"); - return false; + debug_error (_("debug_record_variable: no current file")); + return FALSE; } if (kind == DEBUG_GLOBAL || kind == DEBUG_STATIC) @@ -1163,17 +1146,15 @@ debug_record_variable (handle, name, type, kind, val) else { if (info->current_block == NULL) - { - debug_error ("debug_record_variable: no current block"); - return false; - } - nsp = &info->current_block->locals; + nsp = &info->current_file->globals; + else + nsp = &info->current_block->locals; linkage = DEBUG_LINKAGE_AUTOMATIC; } n = debug_add_to_namespace (info, nsp, name, DEBUG_OBJECT_VARIABLE, linkage); if (n == NULL) - return false; + return FALSE; v = (struct debug_variable *) xmalloc (sizeof *v); memset (v, 0, sizeof *v); @@ -1184,21 +1165,18 @@ debug_record_variable (handle, name, type, kind, val) n->u.variable = v; - return true; + return TRUE; } /* Make a type with a given kind and size. */ -/*ARGSUSED*/ -static struct debug_type * -debug_make_type (info, kind, size) - struct debug_handle *info; - enum debug_type_kind kind; - unsigned int size; +static struct debug_type_s * +debug_make_type (struct debug_handle *info ATTRIBUTE_UNUSED, + enum debug_type_kind kind, unsigned int size) { - struct debug_type *t; + struct debug_type_s *t; - t = (struct debug_type *) xmalloc (sizeof *t); + t = (struct debug_type_s *) xmalloc (sizeof *t); memset (t, 0, sizeof *t); t->kind = kind; @@ -1211,13 +1189,10 @@ debug_make_type (info, kind, size) which is referenced before it is defined. */ debug_type -debug_make_indirect_type (handle, slot, tag) - PTR handle; - debug_type *slot; - const char *tag; +debug_make_indirect_type (void *handle, debug_type *slot, const char *tag) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_indirect_type *i; t = debug_make_type (info, DEBUG_KIND_INDIRECT, 0); @@ -1238,8 +1213,7 @@ debug_make_indirect_type (handle, slot, tag) /* Make a void type. There is only one of these. */ debug_type -debug_make_void_type (handle) - PTR handle; +debug_make_void_type (void *handle) { struct debug_handle *info = (struct debug_handle *) handle; @@ -1250,13 +1224,10 @@ debug_make_void_type (handle) if the integer is unsigned. */ debug_type -debug_make_int_type (handle, size, unsignedp) - PTR handle; - unsigned int size; - boolean unsignedp; +debug_make_int_type (void *handle, unsigned int size, bfd_boolean unsignedp) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; t = debug_make_type (info, DEBUG_KIND_INT, size); if (t == NULL) @@ -1272,9 +1243,7 @@ debug_make_int_type (handle, size, unsignedp) the format. */ debug_type -debug_make_float_type (handle, size) - PTR handle; - unsigned int size; +debug_make_float_type (void *handle, unsigned int size) { struct debug_handle *info = (struct debug_handle *) handle; @@ -1284,9 +1253,7 @@ debug_make_float_type (handle, size) /* Make a boolean type of a given size. */ debug_type -debug_make_bool_type (handle, size) - PTR handle; - unsigned int size; +debug_make_bool_type (void *handle, unsigned int size) { struct debug_handle *info = (struct debug_handle *) handle; @@ -1296,9 +1263,7 @@ debug_make_bool_type (handle, size) /* Make a complex type of a given size. */ debug_type -debug_make_complex_type (handle, size) - PTR handle; - unsigned int size; +debug_make_complex_type (void *handle, unsigned int size) { struct debug_handle *info = (struct debug_handle *) handle; @@ -1310,14 +1275,11 @@ debug_make_complex_type (handle, size) The fourth argument is a NULL terminated array of fields. */ debug_type -debug_make_struct_type (handle, structp, size, fields) - PTR handle; - boolean structp; - bfd_vma size; - debug_field *fields; +debug_make_struct_type (void *handle, bfd_boolean structp, bfd_vma size, + debug_field *fields) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_class_type *c; t = debug_make_type (info, @@ -1344,19 +1306,13 @@ debug_make_struct_type (handle, structp, size, fields) object has its own virtual function table. */ debug_type -debug_make_object_type (handle, structp, size, fields, baseclasses, - methods, vptrbase, ownvptr) - PTR handle; - boolean structp; - bfd_vma size; - debug_field *fields; - debug_baseclass *baseclasses; - debug_method *methods; - debug_type vptrbase; - boolean ownvptr; +debug_make_object_type (void *handle, bfd_boolean structp, bfd_vma size, + debug_field *fields, debug_baseclass *baseclasses, + debug_method *methods, debug_type vptrbase, + bfd_boolean ownvptr) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_class_type *c; t = debug_make_type (info, @@ -1385,13 +1341,11 @@ debug_make_object_type (handle, structp, size, fields, baseclasses, array of strings, and an array of corresponding values. */ debug_type -debug_make_enum_type (handle, names, values) - PTR handle; - const char **names; - bfd_signed_vma *values; +debug_make_enum_type (void *handle, const char **names, + bfd_signed_vma *values) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_enum_type *e; t = debug_make_type (info, DEBUG_KIND_ENUM, 0); @@ -1412,12 +1366,10 @@ debug_make_enum_type (handle, names, values) /* Make a pointer to a given type. */ debug_type -debug_make_pointer_type (handle, type) - PTR handle; - debug_type type; +debug_make_pointer_type (void *handle, debug_type type) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; if (type == NULL) return DEBUG_TYPE_NULL; @@ -1440,12 +1392,11 @@ debug_make_pointer_type (handle, type) to record the parameter types. */ debug_type -debug_make_function_type (handle, type) - PTR handle; - debug_type type; +debug_make_function_type (void *handle, debug_type type, + debug_type *arg_types, bfd_boolean varargs) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_function_type *f; if (type == NULL) @@ -1459,6 +1410,8 @@ debug_make_function_type (handle, type) memset (f, 0, sizeof *f); f->return_type = type; + f->arg_types = arg_types; + f->varargs = varargs; t->u.kfunction = f; @@ -1468,12 +1421,10 @@ debug_make_function_type (handle, type) /* Make a reference to a given type. */ debug_type -debug_make_reference_type (handle, type) - PTR handle; - debug_type type; +debug_make_reference_type (void *handle, debug_type type) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; if (type == NULL) return DEBUG_TYPE_NULL; @@ -1490,14 +1441,11 @@ debug_make_reference_type (handle, type) /* Make a range of a given type from a lower to an upper bound. */ debug_type -debug_make_range_type (handle, type, lower, upper) - PTR handle; - debug_type type; - bfd_signed_vma lower; - bfd_signed_vma upper; +debug_make_range_type (void *handle, debug_type type, bfd_signed_vma lower, + bfd_signed_vma upper) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_range_type *r; if (type == NULL) @@ -1526,17 +1474,12 @@ debug_make_range_type (handle, type, lower, upper) actually a string, as in C. */ debug_type -debug_make_array_type (handle, element_type, range_type, lower, upper, - stringp) - PTR handle; - debug_type element_type; - debug_type range_type; - bfd_signed_vma lower; - bfd_signed_vma upper; - boolean stringp; +debug_make_array_type (void *handle, debug_type element_type, + debug_type range_type, bfd_signed_vma lower, + bfd_signed_vma upper, bfd_boolean stringp) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_array_type *a; if (element_type == NULL || range_type == NULL) @@ -1565,13 +1508,10 @@ debug_make_array_type (handle, element_type, range_type, lower, upper, CHILL. */ debug_type -debug_make_set_type (handle, type, bitstringp) - PTR handle; - debug_type type; - boolean bitstringp; +debug_make_set_type (void *handle, debug_type type, bfd_boolean bitstringp) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_set_type *s; if (type == NULL) @@ -1598,13 +1538,11 @@ debug_make_set_type (handle, type, bitstringp) to. */ debug_type -debug_make_offset_type (handle, base_type, target_type) - PTR handle; - debug_type base_type; - debug_type target_type; +debug_make_offset_type (void *handle, debug_type base_type, + debug_type target_type) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_offset_type *o; if (base_type == NULL || target_type == NULL) @@ -1630,14 +1568,12 @@ debug_make_offset_type (handle, base_type, target_type) argument is a NULL terminated array of argument types. */ debug_type -debug_make_method_type (handle, return_type, domain_type, arg_types) - PTR handle; - debug_type return_type; - debug_type domain_type; - debug_type *arg_types; +debug_make_method_type (void *handle, debug_type return_type, + debug_type domain_type, debug_type *arg_types, + bfd_boolean varargs) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_method_type *m; if (return_type == NULL) @@ -1653,6 +1589,7 @@ debug_make_method_type (handle, return_type, domain_type, arg_types) m->return_type = return_type; m->domain_type = domain_type; m->arg_types = arg_types; + m->varargs = varargs; t->u.kmethod = m; @@ -1662,12 +1599,10 @@ debug_make_method_type (handle, return_type, domain_type, arg_types) /* Make a const qualified version of a given type. */ debug_type -debug_make_const_type (handle, type) - PTR handle; - debug_type type; +debug_make_const_type (void *handle, debug_type type) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; if (type == NULL) return DEBUG_TYPE_NULL; @@ -1684,12 +1619,10 @@ debug_make_const_type (handle, type) /* Make a volatile qualified version of a given type. */ debug_type -debug_make_volatile_type (handle, type) - PTR handle; - debug_type type; +debug_make_volatile_type (void *handle, debug_type type) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; if (type == NULL) return DEBUG_TYPE_NULL; @@ -1707,17 +1640,29 @@ debug_make_volatile_type (handle, type) been mentioned, but not defined. */ debug_type -debug_make_undefined_tagged_type (handle, name, kind) - PTR handle; - const char *name; - enum debug_type_kind kind; +debug_make_undefined_tagged_type (void *handle, const char *name, + enum debug_type_kind kind) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; if (name == NULL) return DEBUG_TYPE_NULL; + switch (kind) + { + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_UNION: + case DEBUG_KIND_CLASS: + case DEBUG_KIND_UNION_CLASS: + case DEBUG_KIND_ENUM: + break; + + default: + debug_error (_("debug_make_undefined_type: unsupported kind")); + return DEBUG_TYPE_NULL; + } + t = debug_make_type (info, kind, 0); if (t == NULL) return DEBUG_TYPE_NULL; @@ -1731,23 +1676,19 @@ debug_make_undefined_tagged_type (handle, name, kind) The fourth argument is whether this is a virtual class. The fifth argument is the visibility of the base class. */ -/*ARGSUSED*/ debug_baseclass -debug_make_baseclass (handle, type, bitpos, virtual, visibility) - PTR handle; - debug_type type; - bfd_vma bitpos; - boolean virtual; - enum debug_visibility visibility; -{ - struct debug_baseclass *b; - - b = (struct debug_baseclass *) xmalloc (sizeof *b); +debug_make_baseclass (void *handle ATTRIBUTE_UNUSED, debug_type type, + bfd_vma bitpos, bfd_boolean is_virtual, + enum debug_visibility visibility) +{ + struct debug_baseclass_s *b; + + b = (struct debug_baseclass_s *) xmalloc (sizeof *b); memset (b, 0, sizeof *b); b->type = type; b->bitpos = bitpos; - b->virtual = virtual; + b->is_virtual = is_virtual; b->visibility = visibility; return b; @@ -1759,24 +1700,19 @@ debug_make_baseclass (handle, type, bitpos, virtual, visibility) the field (it may be zero). The sixth argument is the visibility of the field. */ -/*ARGSUSED*/ debug_field -debug_make_field (handle, name, type, bitpos, bitsize, visibility) - PTR handle; - const char *name; - debug_type type; - bfd_vma bitpos; - bfd_vma bitsize; - enum debug_visibility visibility; +debug_make_field (void *handle ATTRIBUTE_UNUSED, const char *name, + debug_type type, bfd_vma bitpos, bfd_vma bitsize, + enum debug_visibility visibility) { - struct debug_field *f; + struct debug_field_s *f; - f = (struct debug_field *) xmalloc (sizeof *f); + f = (struct debug_field_s *) xmalloc (sizeof *f); memset (f, 0, sizeof *f); f->name = name; f->type = type; - f->static_member = false; + f->static_member = FALSE; f->u.f.bitpos = bitpos; f->u.f.bitsize = bitsize; f->visibility = visibility; @@ -1790,23 +1726,19 @@ debug_make_field (handle, name, type, bitpos, bitsize, visibility) global variable). The fifth argument is the visibility of the member. */ -/*ARGSUSED*/ debug_field -debug_make_static_member (handle, name, type, physname, visibility) - PTR handle; - const char *name; - debug_type type; - const char *physname; - enum debug_visibility visibility; +debug_make_static_member (void *handle ATTRIBUTE_UNUSED, const char *name, + debug_type type, const char *physname, + enum debug_visibility visibility) { - struct debug_field *f; + struct debug_field_s *f; - f = (struct debug_field *) xmalloc (sizeof *f); + f = (struct debug_field_s *) xmalloc (sizeof *f); memset (f, 0, sizeof *f); f->name = name; f->type = type; - f->static_member = true; + f->static_member = TRUE; f->u.s.physname = physname; f->visibility = visibility; @@ -1816,16 +1748,13 @@ debug_make_static_member (handle, name, type, physname, visibility) /* Make a method. The second argument is the name, and the third argument is a NULL terminated array of method variants. */ -/*ARGSUSED*/ debug_method -debug_make_method (handle, name, variants) - PTR handle; - const char *name; - debug_method_variant *variants; +debug_make_method (void *handle ATTRIBUTE_UNUSED, const char *name, + debug_method_variant *variants) { - struct debug_method *m; + struct debug_method_s *m; - m = (struct debug_method *) xmalloc (sizeof *m); + m = (struct debug_method_s *) xmalloc (sizeof *m); memset (m, 0, sizeof *m); m->name = name; @@ -1843,25 +1772,19 @@ debug_make_method (handle, name, variants) function context. FIXME: Are the const and volatile arguments necessary? Could we just use debug_make_const_type? */ -/*ARGSUSED*/ debug_method_variant -debug_make_method_variant (handle, argtypes, type, visibility, constp, - volatilep, voffset, context) - PTR handle; - const char *argtypes; - debug_type type; - enum debug_visibility visibility; - boolean constp; - boolean volatilep; - bfd_vma voffset; - debug_type context; -{ - struct debug_method_variant *m; - - m = (struct debug_method_variant *) xmalloc (sizeof *m); +debug_make_method_variant (void *handle ATTRIBUTE_UNUSED, + const char *physname, debug_type type, + enum debug_visibility visibility, + bfd_boolean constp, bfd_boolean volatilep, + bfd_vma voffset, debug_type context) +{ + struct debug_method_variant_s *m; + + m = (struct debug_method_variant_s *) xmalloc (sizeof *m); memset (m, 0, sizeof *m); - m->argtypes = argtypes; + m->physname = physname; m->type = type; m->visibility = visibility; m->constp = constp; @@ -1877,21 +1800,17 @@ 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, - constp, volatilep) - PTR handle; - const char *argtypes; - debug_type type; - enum debug_visibility visibility; - boolean constp; - boolean volatilep; -{ - struct debug_method_variant *m; - - m = (struct debug_method_variant *) xmalloc (sizeof *m); +debug_make_static_method_variant (void *handle ATTRIBUTE_UNUSED, + const char *physname, debug_type type, + enum debug_visibility visibility, + bfd_boolean constp, bfd_boolean volatilep) +{ + struct debug_method_variant_s *m; + + m = (struct debug_method_variant_s *) xmalloc (sizeof *m); memset (m, 0, sizeof *m); - m->argtypes = argtypes; + m->physname = physname; m->type = type; m->visibility = visibility; m->constp = constp; @@ -1904,19 +1823,23 @@ debug_make_static_method_variant (handle, argtypes, type, visibility, /* Name a type. */ debug_type -debug_name_type (handle, name, type) - PTR handle; - const char *name; - debug_type type; +debug_name_type (void *handle, const char *name, debug_type type) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_named_type *n; struct debug_name *nm; if (name == NULL || type == NULL) return DEBUG_TYPE_NULL; + if (info->current_unit == NULL + || info->current_file == NULL) + { + debug_error (_("debug_name_type: no current file")); + return DEBUG_TYPE_NULL; + } + t = debug_make_type (info, DEBUG_KIND_NAMED, 0); if (t == NULL) return DEBUG_TYPE_NULL; @@ -1928,12 +1851,13 @@ 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; + return DEBUG_TYPE_NULL; nm->u.type = t; @@ -1945,13 +1869,10 @@ debug_name_type (handle, name, type) /* Tag a type. */ debug_type -debug_tag_type (handle, name, type) - PTR handle; - const char *name; - debug_type type; +debug_tag_type (void *handle, const char *name, debug_type type) { struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; + struct debug_type_s *t; struct debug_named_type *n; struct debug_name *nm; @@ -1960,7 +1881,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; } @@ -1968,7 +1889,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; } @@ -1989,7 +1910,7 @@ debug_tag_type (handle, name, type) nm = debug_add_to_namespace (info, &info->current_file->globals, name, DEBUG_OBJECT_TAG, DEBUG_LINKAGE_NONE); if (nm == NULL) - return false; + return DEBUG_TYPE_NULL; nm->u.tag = t; @@ -2000,29 +1921,77 @@ debug_tag_type (handle, name, type) /* Record the size of a given type. */ -/*ARGSUSED*/ -boolean -debug_record_type_size (handle, type, size) - PTR handle; - debug_type type; - unsigned int size; +bfd_boolean +debug_record_type_size (void *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; - return true; + return TRUE; +} + +/* Find a named type. */ + +debug_type +debug_find_named_type (void *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 -debug_find_tagged_type (handle, name, kind) - PTR handle; - const char *name; - enum debug_type_kind kind; +debug_find_tagged_type (void *handle, const char *name, + enum debug_type_kind kind) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_unit *u; @@ -2043,7 +2012,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) @@ -2056,13 +2025,73 @@ debug_find_tagged_type (handle, name, kind) return DEBUG_TYPE_NULL; } +/* 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_s * +debug_get_real_type (void *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 || l == l->next) + { + 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, &rl); + return type; + case DEBUG_KIND_NAMED: + case DEBUG_KIND_TAGGED: + return debug_get_real_type (handle, type->u.knamed->type, &rl); + } + /*NOTREACHED*/ +} + +/* Get the kind of a type. */ + +enum debug_type_kind +debug_get_type_kind (void *handle, debug_type type) +{ + if (type == NULL) + return DEBUG_KIND_ILLEGAL; + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return DEBUG_KIND_ILLEGAL; + return type->kind; +} + /* Get the name of a type. */ -/*ARGSUSED*/ const char * -debug_get_type_name (handle, type) - PTR handle; - debug_type type; +debug_get_type_name (void *handle, debug_type type) { if (type->kind == DEBUG_KIND_INDIRECT) { @@ -2075,15 +2104,207 @@ debug_get_type_name (handle, type) return type->u.knamed->name->name; return NULL; } + +/* Get the size of a type. */ + +bfd_vma +debug_get_type_size (void *handle, debug_type type) +{ + if (type == NULL) + return 0; + + /* We don't call debug_get_real_type, because somebody might have + called debug_record_type_size on a named or indirect type. */ + + if (type->size != 0) + return type->size; + + switch (type->kind) + { + default: + return 0; + case DEBUG_KIND_INDIRECT: + if (*type->u.kindirect->slot != NULL) + return debug_get_type_size (handle, *type->u.kindirect->slot); + return 0; + case DEBUG_KIND_NAMED: + case DEBUG_KIND_TAGGED: + return debug_get_type_size (handle, type->u.knamed->type); + } + /*NOTREACHED*/ +} + +/* Get the return type of a function or method type. */ + +debug_type +debug_get_return_type (void *handle, debug_type type) +{ + if (type == NULL) + return DEBUG_TYPE_NULL; + + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return DEBUG_TYPE_NULL; + + 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 (void *handle, debug_type type, + bfd_boolean *pvarargs) +{ + if (type == NULL) + return NULL; + + 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; + } + /*NOTREACHED*/ +} + +/* Get the target type of a type. */ + +debug_type +debug_get_target_type (void *handle, debug_type type) +{ + if (type == NULL) + return NULL; + + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return NULL; + + switch (type->kind) + { + default: + return NULL; + case DEBUG_KIND_POINTER: + return type->u.kpointer; + case DEBUG_KIND_REFERENCE: + return type->u.kreference; + case DEBUG_KIND_CONST: + return type->u.kconst; + case DEBUG_KIND_VOLATILE: + return type->u.kvolatile; + } + /*NOTREACHED*/ +} + +/* Get the NULL terminated array of fields for a struct, union, or + class. */ + +const debug_field * +debug_get_fields (void *handle, debug_type type) +{ + if (type == NULL) + return NULL; + + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return NULL; + + 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. */ + +debug_type +debug_get_field_type (void *handle ATTRIBUTE_UNUSED, debug_field field) +{ + if (field == NULL) + return NULL; + return field->type; +} + +/* Get the name of a field. */ + +const char * +debug_get_field_name (void *handle ATTRIBUTE_UNUSED, debug_field field) +{ + if (field == NULL) + return NULL; + return field->name; +} + +/* Get the bit position of a field. */ + +bfd_vma +debug_get_field_bitpos (void *handle ATTRIBUTE_UNUSED, debug_field field) +{ + if (field == NULL || field->static_member) + return (bfd_vma) -1; + return field->u.f.bitpos; +} + +/* Get the bit size of a field. */ + +bfd_vma +debug_get_field_bitsize (void *handle ATTRIBUTE_UNUSED, debug_field field) +{ + if (field == NULL || field->static_member) + return (bfd_vma) -1; + return field->u.f.bitsize; +} + +/* Get the visibility of a field. */ + +enum debug_visibility +debug_get_field_visibility (void *handle ATTRIBUTE_UNUSED, debug_field field) +{ + if (field == NULL) + return DEBUG_VISIBILITY_IGNORE; + return field->visibility; +} + +/* Get the physical name of a field. */ + +const char * +debug_get_field_physname (void *handle ATTRIBUTE_UNUSED, debug_field field) +{ + if (field == NULL || ! field->static_member) + return NULL; + return field->u.s.physname; +} /* Write out the debugging information. This is given a handle to debugging information, and a set of function pointers to call. */ -boolean -debug_write (handle, fns, fhandle) - PTR handle; - const struct debug_write_fns *fns; - PTR fhandle; +bfd_boolean +debug_write (void *handle, const struct debug_write_fns *fns, void *fhandle) { struct debug_handle *info = (struct debug_handle *) handle; struct debug_unit *u; @@ -2094,69 +2315,73 @@ 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; + + /* 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; + bfd_boolean first_file; + + info->current_write_lineno = u->linenos; + info->current_write_lineno_index = 0; if (! (*fns->start_compilation_unit) (fhandle, u->files->filename)) - return false; + return FALSE; - first_file = true; + first_file = TRUE; for (f = u->files; f != NULL; f = f->next) { struct debug_name *n; if (first_file) - first_file = false; - else - { - if (! (*fns->start_source) (fhandle, f->filename)) - return false; - } + first_file = FALSE; + else if (! (*fns->start_source) (fhandle, f->filename)) + return FALSE; if (f->globals != NULL) - { - for (n = f->globals->list; n != NULL; n = n->next) - { - if (! debug_write_name (info, fns, fhandle, n)) - return false; - } - } + for (n = f->globals->list; n != NULL; n = n->next) + if (! debug_write_name (info, fns, fhandle, n)) + 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; + return TRUE; } /* Write out an element in a namespace. */ -static boolean -debug_write_name (info, fns, fhandle, n) - struct debug_handle *info; - const struct debug_write_fns *fns; - PTR fhandle; - struct debug_name *n; +static bfd_boolean +debug_write_name (struct debug_handle *info, + const struct debug_write_fns *fns, void *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: if (! debug_write_type (info, fns, fhandle, n->u.type, n) || ! (*fns->typdef) (fhandle, n->name)) - return false; - return true; + return FALSE; + return TRUE; case DEBUG_OBJECT_TAG: if (! debug_write_type (info, fns, fhandle, n->u.tag, n)) - return false; + return FALSE; return (*fns->tag) (fhandle, n->name); case DEBUG_OBJECT_VARIABLE: if (! debug_write_type (info, fns, fhandle, n->u.variable->type, (struct debug_name *) NULL)) - return false; + return FALSE; return (*fns->variable) (fhandle, n->name, n->u.variable->kind, n->u.variable->val); case DEBUG_OBJECT_FUNCTION: @@ -2169,27 +2394,30 @@ debug_write_name (info, fns, fhandle, n) case DEBUG_OBJECT_TYPED_CONSTANT: if (! debug_write_type (info, fns, fhandle, n->u.typed_constant->type, (struct debug_name *) NULL)) - return false; + return FALSE; return (*fns->typed_constant) (fhandle, n->name, n->u.typed_constant->val); default: abort (); - return false; + return FALSE; } /*NOTREACHED*/ } -/* Write out a type. */ +/* Write out a type. If the type is DEBUG_KIND_NAMED or + DEBUG_KIND_TAGGED, then the name argument is the name for which we + are about to call typedef or tag. If the type is anything else, + then the name argument is a tag from a DEBUG_KIND_TAGGED type which + points to this one. */ -static boolean -debug_write_type (info, fns, fhandle, type, name) - struct debug_handle *info; - const struct debug_write_fns *fns; - PTR fhandle; - struct debug_type *type; - struct debug_name *name; +static bfd_boolean +debug_write_type (struct debug_handle *info, + const struct debug_write_fns *fns, void *fhandle, + struct debug_type_s *type, struct debug_name *name) { unsigned int i; + int is; + 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 @@ -2203,8 +2431,33 @@ 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, - type->u.knamed->type->kind); + { + struct debug_type_s *real; + unsigned int id; + + real = debug_get_real_type ((void *) 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; + } + + return (*fns->tag_type) (fhandle, type->u.knamed->name->name, id, + real->kind); + } } /* Mark the name after we have already looked for a known name, so @@ -2214,13 +2467,24 @@ debug_write_type (info, fns, fhandle, type, name) if (name != NULL) name->mark = info->mark; + if (name != NULL + && type->kind != DEBUG_KIND_NAMED + && type->kind != DEBUG_KIND_TAGGED) + { + assert (name->kind == DEBUG_OBJECT_TAG); + tag = name->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); return debug_write_type (info, fns, fhandle, *type->u.kindirect->slot, - (struct debug_name *) NULL); + name); case DEBUG_KIND_VOID: return (*fns->void_type) (fhandle); case DEBUG_KIND_INT: @@ -2233,59 +2497,89 @@ debug_write_type (info, fns, fhandle, type, name) return (*fns->bool_type) (fhandle, type->size); case DEBUG_KIND_STRUCT: case DEBUG_KIND_UNION: - if (info->class_mark == type->u.kclass->mark) + if (type->u.kclass != NULL) { - /* 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); + 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, + 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->mark; } - type->u.kclass->mark = info->class_mark; - if (! (*fns->start_struct_type) (fhandle, + 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; - if (type->u.kclass->fields != NULL) + return FALSE; + if (type->u.kclass != NULL + && type->u.kclass->fields != NULL) { for (i = 0; type->u.kclass->fields[i] != NULL; i++) { - struct debug_field *f; + struct debug_field_s *f; f = type->u.kclass->fields[i]; if (! debug_write_type (info, fns, fhandle, f->type, (struct debug_name *) NULL) || ! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos, f->u.f.bitsize, f->visibility)) - return false; + return FALSE; } } return (*fns->end_struct_type) (fhandle); case DEBUG_KIND_CLASS: case DEBUG_KIND_UNION_CLASS: - return debug_write_class_type (info, fns, fhandle, type); + return debug_write_class_type (info, fns, fhandle, type, tag); case DEBUG_KIND_ENUM: - return (*fns->enum_type) (fhandle, type->u.kenum->names, + if (type->u.kenum == NULL) + return (*fns->enum_type) (fhandle, tag, (const char **) NULL, + (bfd_signed_vma *) NULL); + return (*fns->enum_type) (fhandle, tag, type->u.kenum->names, type->u.kenum->values); case DEBUG_KIND_POINTER: if (! debug_write_type (info, fns, fhandle, type->u.kpointer, (struct debug_name *) NULL)) - return false; + 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; - return (*fns->function_type) (fhandle); + return FALSE; + if (type->u.kfunction->arg_types == NULL) + is = -1; + else + { + for (is = 0; type->u.kfunction->arg_types[is] != NULL; is++) + if (! debug_write_type (info, fns, fhandle, + type->u.kfunction->arg_types[is], + (struct debug_name *) NULL)) + return FALSE; + } + return (*fns->function_type) (fhandle, is, + type->u.kfunction->varargs); case DEBUG_KIND_REFERENCE: if (! debug_write_type (info, fns, fhandle, type->u.kreference, (struct debug_name *) NULL)) - return false; + return FALSE; return (*fns->reference_type) (fhandle); case DEBUG_KIND_RANGE: if (! debug_write_type (info, fns, fhandle, type->u.krange->type, (struct debug_name *) NULL)) - return false; + return FALSE; return (*fns->range_type) (fhandle, type->u.krange->lower, type->u.krange->upper); case DEBUG_KIND_ARRAY: @@ -2294,14 +2588,14 @@ debug_write_type (info, fns, fhandle, type, name) || ! debug_write_type (info, fns, fhandle, type->u.karray->range_type, (struct debug_name *) NULL)) - return false; + return FALSE; return (*fns->array_type) (fhandle, type->u.karray->lower, type->u.karray->upper, type->u.karray->stringp); case DEBUG_KIND_SET: if (! debug_write_type (info, fns, fhandle, type->u.kset->type, (struct debug_name *) NULL)) - return false; + return FALSE; return (*fns->set_type) (fhandle, type->u.kset->bitstringp); case DEBUG_KIND_OFFSET: if (! debug_write_type (info, fns, fhandle, type->u.koffset->base_type, @@ -2309,175 +2603,199 @@ debug_write_type (info, fns, fhandle, type, name) || ! debug_write_type (info, fns, fhandle, type->u.koffset->target_type, (struct debug_name *) NULL)) - return false; + return FALSE; return (*fns->offset_type) (fhandle); case DEBUG_KIND_METHOD: if (! debug_write_type (info, fns, fhandle, type->u.kmethod->return_type, (struct debug_name *) NULL)) - return false; + return FALSE; if (type->u.kmethod->arg_types == NULL) - i = -1; + is = -1; else { - 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; - } + for (is = 0; type->u.kmethod->arg_types[is] != NULL; is++) + if (! debug_write_type (info, fns, fhandle, + type->u.kmethod->arg_types[is], + (struct debug_name *) NULL)) + return FALSE; } if (type->u.kmethod->domain_type != NULL) { if (! debug_write_type (info, fns, fhandle, type->u.kmethod->domain_type, (struct debug_name *) NULL)) - return false; + return FALSE; } return (*fns->method_type) (fhandle, type->u.kmethod->domain_type != NULL, - i); + is, + type->u.kmethod->varargs); case DEBUG_KIND_CONST: if (! debug_write_type (info, fns, fhandle, type->u.kconst, (struct debug_name *) NULL)) - return false; + return FALSE; return (*fns->const_type) (fhandle); case DEBUG_KIND_VOLATILE: if (! debug_write_type (info, fns, fhandle, type->u.kvolatile, (struct debug_name *) NULL)) - return false; + return FALSE; return (*fns->volatile_type) (fhandle); case DEBUG_KIND_NAMED: - case DEBUG_KIND_TAGGED: return debug_write_type (info, fns, fhandle, type->u.knamed->type, (struct debug_name *) NULL); + case DEBUG_KIND_TAGGED: + return debug_write_type (info, fns, fhandle, type->u.knamed->type, + type->u.knamed->name); default: abort (); - return false; + return FALSE; } } /* Write out a class type. */ -static boolean -debug_write_class_type (info, fns, fhandle, type) - struct debug_handle *info; - const struct debug_write_fns *fns; - PTR fhandle; - struct debug_type *type; +static bfd_boolean +debug_write_class_type (struct debug_handle *info, + const struct debug_write_fns *fns, void *fhandle, + struct debug_type_s *type, const char *tag) { unsigned int i; + unsigned int id; + struct debug_type_s *vptrbase; - if (info->class_mark == type->u.kclass->mark) + if (type->u.kclass == NULL) { - /* 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); + id = 0; + vptrbase = NULL; } - type->u.kclass->mark = info->class_mark; - - if (type->u.kclass->vptrbase != NULL - && type->u.kclass->vptrbase != type) + else { - if (! debug_write_type (info, fns, fhandle, type->u.kclass->vptrbase, - (struct debug_name *) NULL)) - return false; + 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 + 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->mark; + id = type->u.kclass->id; + + vptrbase = type->u.kclass->vptrbase; + if (vptrbase != NULL && vptrbase != type) + { + if (! debug_write_type (info, fns, fhandle, vptrbase, + (struct debug_name *) NULL)) + return FALSE; + } } - if (! (*fns->start_class_type) (fhandle, + 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)) - return false; - if (type->u.kclass->fields != NULL) + vptrbase != NULL, + vptrbase == type)) + return FALSE; + + if (type->u.kclass != NULL) { - for (i = 0; type->u.kclass->fields[i] != NULL; i++) + if (type->u.kclass->fields != NULL) { - struct debug_field *f; - - f = type->u.kclass->fields[i]; - if (! debug_write_type (info, fns, fhandle, f->type, - (struct debug_name *) NULL)) - return false; - if (f->static_member) - { - if (! (*fns->class_static_member) (fhandle, f->name, - f->u.s.physname, - f->visibility)) - return false; - } - else + for (i = 0; type->u.kclass->fields[i] != NULL; i++) { - if (! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos, - f->u.f.bitsize, f->visibility)) - return false; + struct debug_field_s *f; + + f = type->u.kclass->fields[i]; + if (! debug_write_type (info, fns, fhandle, f->type, + (struct debug_name *) NULL)) + return FALSE; + if (f->static_member) + { + if (! (*fns->class_static_member) (fhandle, f->name, + f->u.s.physname, + f->visibility)) + return FALSE; + } + else + { + if (! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos, + f->u.f.bitsize, f->visibility)) + return FALSE; + } } } - } - if (type->u.kclass->baseclasses != NULL) - { - for (i = 0; type->u.kclass->baseclasses[i] != NULL; i++) + if (type->u.kclass->baseclasses != NULL) { - struct debug_baseclass *b; + for (i = 0; type->u.kclass->baseclasses[i] != NULL; i++) + { + struct debug_baseclass_s *b; - b = type->u.kclass->baseclasses[i]; - if (! debug_write_type (info, fns, fhandle, b->type, - (struct debug_name *) NULL)) - return false; - if (! (*fns->class_baseclass) (fhandle, b->bitpos, b->virtual, - b->visibility)) - return false; + b = type->u.kclass->baseclasses[i]; + if (! debug_write_type (info, fns, fhandle, b->type, + (struct debug_name *) NULL)) + return FALSE; + if (! (*fns->class_baseclass) (fhandle, b->bitpos, b->is_virtual, + b->visibility)) + return FALSE; + } } - } - if (type->u.kclass->methods != NULL) - { - for (i = 0; type->u.kclass->methods[i] != NULL; i++) + if (type->u.kclass->methods != NULL) { - struct debug_method *m; - unsigned int j; - - m = type->u.kclass->methods[i]; - if (! (*fns->class_start_method) (fhandle, m->name)) - return false; - for (j = 0; m->variants[j] != NULL; j++) + for (i = 0; type->u.kclass->methods[i] != NULL; i++) { - struct debug_method_variant *v; + struct debug_method_s *m; + unsigned int j; - v = m->variants[j]; - if (v->context != NULL) + m = type->u.kclass->methods[i]; + if (! (*fns->class_start_method) (fhandle, m->name)) + return FALSE; + for (j = 0; m->variants[j] != NULL; j++) { - if (! debug_write_type (info, fns, fhandle, v->context, + struct debug_method_variant_s *v; + + v = m->variants[j]; + if (v->context != NULL) + { + if (! debug_write_type (info, fns, fhandle, v->context, + (struct debug_name *) NULL)) + return FALSE; + } + if (! debug_write_type (info, fns, fhandle, v->type, (struct debug_name *) NULL)) - return false; - } - if (! debug_write_type (info, fns, fhandle, v->type, - (struct debug_name *) NULL)) - return false; - if (v->voffset != VOFFSET_STATIC_METHOD) - { - if (! (*fns->class_method_variant) (fhandle, v->argtypes, - v->visibility, - v->constp, v->volatilep, - v->voffset, - v->context != NULL)) - return false; - } - else - { - if (! (*fns->class_static_method_variant) (fhandle, - v->argtypes, - v->visibility, - v->constp, - v->volatilep)) - return false; + return FALSE; + if (v->voffset != VOFFSET_STATIC_METHOD) + { + if (! (*fns->class_method_variant) (fhandle, v->physname, + v->visibility, + v->constp, + v->volatilep, + v->voffset, + v->context != NULL)) + return FALSE; + } + else + { + if (! (*fns->class_static_method_variant) (fhandle, + v->physname, + v->visibility, + v->constp, + v->volatilep)) + return FALSE; + } } + if (! (*fns->class_end_method) (fhandle)) + return FALSE; } - if (! (*fns->class_end_method) (fhandle)) - return false; } } @@ -2486,38 +2804,38 @@ debug_write_class_type (info, fns, fhandle, type) /* Write out information for a function. */ -static boolean -debug_write_function (info, fns, fhandle, name, linkage, function) - struct debug_handle *info; - const struct debug_write_fns *fns; - PTR fhandle; - const char *name; - enum debug_object_linkage linkage; - struct debug_function *function; +static bfd_boolean +debug_write_function (struct debug_handle *info, + const struct debug_write_fns *fns, void *fhandle, + const char *name, enum debug_object_linkage linkage, + struct debug_function *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; + return FALSE; if (! (*fns->start_function) (fhandle, name, linkage == DEBUG_LINKAGE_GLOBAL)) - return false; + return FALSE; for (p = function->parameters; p != NULL; p = p->next) { if (! debug_write_type (info, fns, fhandle, p->type, (struct debug_name *) NULL) || ! (*fns->function_parameter) (fhandle, p->name, p->kind, p->val)) - return false; + return FALSE; } for (b = function->blocks; b != NULL; b = b->next) { if (! debug_write_block (info, fns, fhandle, b)) - return false; + return FALSE; } return (*fns->end_function) (fhandle); @@ -2525,48 +2843,529 @@ debug_write_function (info, fns, fhandle, name, linkage, function) /* Write out information for a block. */ -static boolean -debug_write_block (info, fns, fhandle, block) - struct debug_handle *info; - const struct debug_write_fns *fns; - PTR fhandle; - struct debug_block *block; +static bfd_boolean +debug_write_block (struct debug_handle *info, + const struct debug_write_fns *fns, void *fhandle, + struct debug_block *block) { struct debug_name *n; - struct debug_lineno *l; struct debug_block *b; - if (! (*fns->start_block) (fhandle, block->start)) - return false; + 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) { if (! debug_write_name (info, fns, fhandle, n)) - return false; + return FALSE; } } - for (l = block->linenos; l != NULL; l = l->next) + for (b = block->children; b != NULL; b = b->next) { - unsigned int i; + if (! debug_write_block (info, fns, fhandle, b)) + return FALSE; + } - for (i = 0; i < DEBUG_LINENO_COUNT; i++) + 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 bfd_boolean +debug_write_linenos (struct debug_handle *info, + const struct debug_write_fns *fns, void *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[i] == (unsigned long) -1) + if (l->linenos[info->current_write_lineno_index] + == (unsigned long) -1) break; - if (! (*fns->lineno) (fhandle, l->file->filename, l->linenos[i], - l->addrs[i])) - return false; + + 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; } - for (b = block->children; b != NULL; b = b->next) + 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 bfd_boolean +debug_set_class_id (struct debug_handle *info, const char *tag, + struct debug_type_s *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 (! debug_write_block (info, fns, fhandle, b)) - return false; + 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 bfd_boolean +debug_type_samep (struct debug_handle *info, struct debug_type_s *t1, + struct debug_type_s *t2) +{ + struct debug_type_compare_list *l; + struct debug_type_compare_list top; + bfd_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_s **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)); + break; + + 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_s **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 bfd_boolean +debug_class_type_samep (struct debug_handle *info, struct debug_type_s *t1, + struct debug_type_s *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_s **pf1, **pf2; + + for (pf1 = c1->fields, pf2 = c2->fields; + *pf1 != NULL && *pf2 != NULL; + pf1++, pf2++) + { + struct debug_field_s *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 ((void *) info, + f1->type, NULL), + debug_get_real_type ((void *) 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_s **pb1, **pb2; + + for (pb1 = c1->baseclasses, pb2 = c2->baseclasses; + *pb1 != NULL && *pb2 != NULL; + ++pb1, ++pb2) + { + struct debug_baseclass_s *b1, *b2; + + b1 = *pb1; + b2 = *pb2; + if (b1->bitpos != b2->bitpos + || b1->is_virtual != b2->is_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_s **pm1, **pm2; + + for (pm1 = c1->methods, pm2 = c2->methods; + *pm1 != NULL && *pm2 != NULL; + ++pm1, ++pm2) + { + struct debug_method_s *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_s **pv1, **pv2; + + for (pv1 = m1->variants, pv2 = m2->variants; + *pv1 != NULL && *pv2 != NULL; + ++pv1, ++pv2) + { + struct debug_method_variant_s *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 (*fns->end_block) (fhandle, block->end); + return TRUE; }