--- /dev/null
+/* wrstabs.c -- Output stabs debugging information
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@cygnus.com>.
+
+ 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
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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. */
+
+/* This file contains code which writes out stabs debugging
+ information. */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "bfd.h"
+#include "bucomm.h"
+#include "libiberty.h"
+#include "debug.h"
+#include "budbg.h"
+
+/* Meaningless definition needs by aout64.h. FIXME. */
+#define BYTES_IN_WORD 4
+
+#include "aout/aout64.h"
+#include "aout/stab_gnu.h"
+
+/* The size of a stabs symbol. This presumes 32 bit values. */
+
+#define STAB_SYMBOL_SIZE (12)
+
+/* An entry in a string hash table. */
+
+struct string_hash_entry
+{
+ struct bfd_hash_entry root;
+ /* Index in string table. */
+ long index;
+ /* Size of type if this is a typedef. */
+ unsigned int size;
+};
+
+/* A string hash table. */
+
+struct string_hash_table
+{
+ struct bfd_hash_table table;
+};
+
+/* The type stack. Each element on the stack is a string. */
+
+struct stab_type_stack
+{
+ /* The next element on the stack. */
+ struct stab_type_stack *next;
+ /* This element as a string. */
+ char *string;
+ /* The type index of this element. */
+ long index;
+ /* The size of the type. */
+ unsigned int size;
+ /* Whether type string defines a new type. */
+ boolean definition;
+ /* String defining struct fields. */
+ char *fields;
+ /* NULL terminated array of strings defining base classes for a
+ class. */
+ char **baseclasses;
+ /* String defining class methods. */
+ char *methods;
+ /* String defining vtable pointer for a class. */
+ char *vtable;
+};
+
+/* This structure is used to keep track of type indices for tagged
+ types. */
+
+struct stab_tag
+{
+ /* The type index. */
+ long index;
+ /* The tag name. */
+ const char *tag;
+ /* The kind of type. This is set to DEBUG_KIND_ILLEGAL when the
+ type is defined. */
+ enum debug_type_kind kind;
+ /* The size of the struct. */
+ unsigned int size;
+};
+
+/* We remember various sorts of type indices. They are not related,
+ but, for convenience, we keep all the information in this
+ structure. */
+
+struct stab_type_cache
+{
+ /* The void type index. */
+ long void_type;
+ /* Signed integer type indices, indexed by size - 1. */
+ long signed_integer_types[8];
+ /* Unsigned integer type indices, indexed by size - 1. */
+ long unsigned_integer_types[8];
+ /* Floating point types, indexed by size - 1. */
+ long float_types[16];
+ /* Pointers to types, indexed by the type index. */
+ long *pointer_types;
+ size_t pointer_types_alloc;
+ /* Functions returning types, indexed by the type index. */
+ long *function_types;
+ size_t function_types_alloc;
+ /* References to types, indexed by the type index. */
+ long *reference_types;
+ size_t reference_types_alloc;
+ /* Struct/union/class type indices, indexed by the struct id. */
+ struct stab_tag *struct_types;
+ size_t struct_types_alloc;
+};
+
+/* This is the handle passed through debug_write. */
+
+struct stab_write_handle
+{
+ /* The BFD. */
+ bfd *abfd;
+ /* This buffer holds the symbols. */
+ bfd_byte *symbols;
+ size_t symbols_size;
+ size_t symbols_alloc;
+ /* This buffer holds the strings. */
+ bfd_byte *strings;
+ size_t strings_size;
+ size_t strings_alloc;
+ /* This hash table eliminates duplicate strings. */
+ struct string_hash_table strhash;
+ /* The type stack. */
+ struct stab_type_stack *type_stack;
+ /* The next type index. */
+ long type_index;
+ /* The type cache. */
+ struct stab_type_cache type_cache;
+ /* A mapping from typedef names to type indices. */
+ struct string_hash_table typedef_hash;
+ /* If this is not -1, it is the offset to the most recent N_SO
+ symbol, and the value of that symbol needs to be set. */
+ long so_offset;
+ /* If this is not -1, it is the offset to the most recent N_FUN
+ symbol, and the value of that symbol needs to be set. */
+ long fun_offset;
+ /* The last text section address seen. */
+ bfd_vma last_text_address;
+ /* The block nesting depth. */
+ unsigned int nesting;
+ /* The function address. */
+ bfd_vma fnaddr;
+ /* A pending LBRAC symbol. */
+ bfd_vma pending_lbrac;
+ /* The current line number file name. */
+ const char *lineno_filename;
+};
+
+static struct bfd_hash_entry *string_hash_newfunc
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static boolean stab_write_symbol
+ PARAMS ((struct stab_write_handle *, int, int, bfd_vma, const char *));
+static boolean stab_push_string
+ PARAMS ((struct stab_write_handle *, const char *, long, boolean,
+ unsigned int));
+static boolean stab_push_defined_type
+ PARAMS ((struct stab_write_handle *, long, unsigned int));
+static char *stab_pop_type PARAMS ((struct stab_write_handle *));
+static boolean stab_modify_type
+ PARAMS ((struct stab_write_handle *, int, unsigned int, long **, size_t *));
+static long stab_get_struct_index
+ PARAMS ((struct stab_write_handle *, const char *, unsigned int,
+ enum debug_type_kind, unsigned int *));
+static boolean stab_class_method_var
+ PARAMS ((struct stab_write_handle *, const char *, enum debug_visibility,
+ boolean, boolean, boolean, bfd_vma, boolean));
+
+static boolean stab_start_compilation_unit PARAMS ((PTR, const char *));
+static boolean stab_start_source PARAMS ((PTR, const char *));
+static boolean stab_empty_type PARAMS ((PTR));
+static boolean stab_void_type PARAMS ((PTR));
+static boolean stab_int_type PARAMS ((PTR, unsigned int, boolean));
+static boolean stab_float_type PARAMS ((PTR, unsigned int));
+static boolean stab_complex_type PARAMS ((PTR, unsigned int));
+static boolean stab_bool_type PARAMS ((PTR, unsigned int));
+static boolean stab_enum_type
+ PARAMS ((PTR, const char *, const char **, bfd_signed_vma *));
+static boolean stab_pointer_type PARAMS ((PTR));
+static boolean stab_function_type PARAMS ((PTR, int, boolean));
+static boolean stab_reference_type PARAMS ((PTR));
+static boolean stab_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma));
+static boolean stab_array_type
+ PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, boolean));
+static boolean stab_set_type PARAMS ((PTR, boolean));
+static boolean stab_offset_type PARAMS ((PTR));
+static boolean stab_method_type PARAMS ((PTR, boolean, int, boolean));
+static boolean stab_const_type PARAMS ((PTR));
+static boolean stab_volatile_type PARAMS ((PTR));
+static boolean stab_start_struct_type
+ PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int));
+static boolean stab_struct_field
+ PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility));
+static boolean stab_end_struct_type PARAMS ((PTR));
+static boolean stab_start_class_type
+ PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int, boolean,
+ boolean));
+static boolean stab_class_static_member
+ PARAMS ((PTR, const char *, const char *, enum debug_visibility));
+static boolean stab_class_baseclass
+ PARAMS ((PTR, bfd_vma, boolean, enum debug_visibility));
+static boolean stab_class_start_method PARAMS ((PTR, const char *));
+static boolean stab_class_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean,
+ bfd_vma, boolean));
+static boolean stab_class_static_method_variant
+ PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean));
+static boolean stab_class_end_method PARAMS ((PTR));
+static boolean stab_end_class_type PARAMS ((PTR));
+static boolean stab_typedef_type PARAMS ((PTR, const char *));
+static boolean stab_tag_type
+ PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind));
+static boolean stab_typdef PARAMS ((PTR, const char *));
+static boolean stab_tag PARAMS ((PTR, const char *));
+static boolean stab_int_constant PARAMS ((PTR, const char *, bfd_vma));
+static boolean stab_float_constant PARAMS ((PTR, const char *, double));
+static boolean stab_typed_constant PARAMS ((PTR, const char *, bfd_vma));
+static boolean stab_variable
+ PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma));
+static boolean stab_start_function PARAMS ((PTR, const char *, boolean));
+static boolean stab_function_parameter
+ PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma));
+static boolean stab_start_block PARAMS ((PTR, bfd_vma));
+static boolean stab_end_block PARAMS ((PTR, bfd_vma));
+static boolean stab_end_function PARAMS ((PTR));
+static boolean stab_lineno
+ PARAMS ((PTR, const char *, unsigned long, bfd_vma));
+
+static const struct debug_write_fns stab_fns =
+{
+ stab_start_compilation_unit,
+ stab_start_source,
+ stab_empty_type,
+ stab_void_type,
+ stab_int_type,
+ stab_float_type,
+ stab_complex_type,
+ stab_bool_type,
+ stab_enum_type,
+ stab_pointer_type,
+ stab_function_type,
+ stab_reference_type,
+ stab_range_type,
+ stab_array_type,
+ stab_set_type,
+ stab_offset_type,
+ stab_method_type,
+ stab_const_type,
+ stab_volatile_type,
+ stab_start_struct_type,
+ stab_struct_field,
+ stab_end_struct_type,
+ stab_start_class_type,
+ stab_class_static_member,
+ stab_class_baseclass,
+ stab_class_start_method,
+ stab_class_method_variant,
+ stab_class_static_method_variant,
+ stab_class_end_method,
+ stab_end_class_type,
+ stab_typedef_type,
+ stab_tag_type,
+ stab_typdef,
+ stab_tag,
+ stab_int_constant,
+ stab_float_constant,
+ stab_typed_constant,
+ stab_variable,
+ stab_start_function,
+ stab_function_parameter,
+ stab_start_block,
+ stab_end_block,
+ stab_end_function,
+ stab_lineno
+};
+\f
+/* Routine to create an entry in a string hash table. */
+
+static struct bfd_hash_entry *
+string_hash_newfunc (entry, table, string)
+ struct bfd_hash_entry *entry;
+ struct bfd_hash_table *table;
+ const char *string;
+{
+ struct string_hash_entry *ret = (struct string_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == (struct string_hash_entry *) NULL)
+ ret = ((struct string_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct string_hash_entry)));
+ if (ret == (struct string_hash_entry *) NULL)
+ return NULL;
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct string_hash_entry *)
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+
+ if (ret)
+ {
+ /* Initialize the local fields. */
+ ret->index = -1;
+ ret->size = 0;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Look up an entry in a string hash table. */
+
+#define string_hash_lookup(t, string, create, copy) \
+ ((struct string_hash_entry *) \
+ bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
+
+/* Add a symbol to the stabs debugging information we are building. */
+
+static boolean
+stab_write_symbol (info, type, desc, value, string)
+ struct stab_write_handle *info;
+ int type;
+ int desc;
+ bfd_vma value;
+ const char *string;
+{
+ bfd_size_type strx;
+ bfd_byte sym[STAB_SYMBOL_SIZE];
+
+ if (string == NULL)
+ strx = 0;
+ else
+ {
+ struct string_hash_entry *h;
+
+ h = string_hash_lookup (&info->strhash, string, true, false);
+ if (h == NULL)
+ {
+ fprintf (stderr, "string_hash_lookup failed: %s\n",
+ bfd_errmsg (bfd_get_error ()));
+ return false;
+ }
+ if (h->index != -1)
+ strx = h->index;
+ else
+ {
+ size_t len;
+
+ strx = info->strings_size;
+ h->index = strx;
+
+ len = strlen (string);
+ while (info->strings_size + len + 1 > info->strings_alloc)
+ {
+ info->strings_alloc *= 2;
+ info->strings = (bfd_byte *) xrealloc (info->strings,
+ info->strings_alloc);
+ }
+ strcpy (info->strings + info->strings_size, string);
+ info->strings_size += len + 1;
+ }
+ }
+
+ /* This presumes 32 bit values. */
+ bfd_put_32 (info->abfd, strx, sym);
+ bfd_put_8 (info->abfd, type, sym + 4);
+ bfd_put_8 (info->abfd, 0, sym + 5);
+ bfd_put_16 (info->abfd, desc, sym + 6);
+ bfd_put_32 (info->abfd, value, sym + 8);
+
+ if (info->symbols_size + STAB_SYMBOL_SIZE > info->symbols_alloc)
+ {
+ info->symbols_alloc *= 2;
+ info->symbols = (bfd_byte *) xrealloc (info->symbols,
+ info->symbols_alloc);
+ }
+
+ memcpy (info->symbols + info->symbols_size, sym, STAB_SYMBOL_SIZE);
+
+ info->symbols_size += STAB_SYMBOL_SIZE;
+
+ return true;
+}
+
+/* Push a string on to the type stack. */
+
+static boolean
+stab_push_string (info, string, index, definition, size)
+ struct stab_write_handle *info;
+ const char *string;
+ long index;
+ boolean definition;
+ unsigned int size;
+{
+ struct stab_type_stack *s;
+
+ s = (struct stab_type_stack *) xmalloc (sizeof *s);
+ s->string = xstrdup (string);
+ s->index = index;
+ s->definition = definition;
+ s->size = size;
+
+ s->fields = NULL;
+ s->baseclasses = NULL;
+ s->methods = NULL;
+ s->vtable = NULL;
+
+ s->next = info->type_stack;
+ info->type_stack = s;
+
+ return true;
+}
+
+/* Push a type index which has already been defined. */
+
+static boolean
+stab_push_defined_type (info, index, size)
+ struct stab_write_handle *info;
+ long index;
+ unsigned int size;
+{
+ char buf[20];
+
+ sprintf (buf, "%ld", index);
+ return stab_push_string (info, buf, index, false, size);
+}
+
+/* Pop a type off the type stack. The caller is responsible for
+ freeing the string. */
+
+static char *
+stab_pop_type (info)
+ struct stab_write_handle *info;
+{
+ struct stab_type_stack *s;
+ char *ret;
+
+ s = info->type_stack;
+ assert (s != NULL);
+
+ info->type_stack = s->next;
+
+ ret = s->string;
+
+ free (s);
+
+ return ret;
+}
+\f
+/* The general routine to write out stabs in sections debugging
+ information. This accumulates the stabs symbols and the strings in
+ two obstacks. We can't easily write out the information as we go
+ along, because we need to know the section sizes before we can
+ write out the section contents. ABFD is the BFD and DHANDLE is the
+ handle for the debugging information. This sets *PSYMS to point to
+ the symbols, *PSYMSIZE the size of the symbols, *PSTRINGS to the
+ strings, and *PSTRINGSIZE to the size of the strings. */
+
+boolean
+write_stabs_in_sections_debugging_info (abfd, dhandle, psyms, psymsize,
+ pstrings, pstringsize)
+ bfd *abfd;
+ PTR dhandle;
+ bfd_byte **psyms;
+ bfd_size_type *psymsize;
+ bfd_byte **pstrings;
+ bfd_size_type *pstringsize;
+{
+ struct stab_write_handle info;
+
+ info.abfd = abfd;
+
+ info.symbols_size = 0;
+ info.symbols_alloc = 500;
+ info.symbols = (bfd_byte *) xmalloc (info.symbols_alloc);
+
+ info.strings_size = 1;
+ info.strings_alloc = 500;
+ info.strings = (bfd_byte *) xmalloc (info.strings_alloc);
+ info.strings[0] = '\0';
+
+ if (! bfd_hash_table_init (&info.strhash.table, string_hash_newfunc)
+ || ! bfd_hash_table_init (&info.typedef_hash.table, string_hash_newfunc))
+ {
+ fprintf (stderr, "bfd_hash_table_init_failed: %s\n",
+ bfd_errmsg (bfd_get_error ()));
+ return false;
+ }
+
+ info.type_stack = NULL;
+ info.type_index = 1;
+ memset (&info.type_cache, 0, sizeof info.type_cache);
+ info.so_offset = -1;
+ info.fun_offset = -1;
+ info.last_text_address = 0;
+ info.nesting = 0;
+ info.fnaddr = 0;
+ info.pending_lbrac = (bfd_vma) -1;
+
+ /* The initial symbol holds the string size. */
+ if (! stab_write_symbol (&info, 0, 0, 0, (const char *) NULL))
+ return false;
+
+ /* Output an initial N_SO symbol. */
+ info.so_offset = info.symbols_size;
+ if (! stab_write_symbol (&info, N_SO, 0, 0, bfd_get_filename (abfd)))
+ return false;
+
+ if (! debug_write (dhandle, &stab_fns, (PTR) &info))
+ return false;
+
+ assert (info.pending_lbrac == (bfd_vma) -1);
+
+ /* Output a trailing N_SO. */
+ if (! stab_write_symbol (&info, N_SO, 0, info.last_text_address,
+ (const char *) NULL))
+ return false;
+
+ /* Put the string size in the initial symbol. */
+ bfd_put_32 (abfd, info.strings_size, info.symbols + 8);
+
+ *psyms = info.symbols;
+ *psymsize = info.symbols_size;
+
+ *pstrings = info.strings;
+ *pstringsize = info.strings_size;
+
+ return true;
+}
+
+/* Start writing out information for a compilation unit. */
+
+static boolean
+stab_start_compilation_unit (p, filename)
+ PTR p;
+ const char *filename;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ /* We would normally output an N_SO symbol here. However, that
+ would force us to reset all of our type information. I think we
+ will be better off just outputting an N_SOL symbol, and not
+ worrying about splitting information between files. */
+
+ info->lineno_filename = filename;
+
+ return stab_write_symbol (info, N_SOL, 0, 0, filename);
+}
+
+/* Start writing out information for a particular source file. */
+
+static boolean
+stab_start_source (p, filename)
+ PTR p;
+ const char *filename;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ /* FIXME: The symbol's value is supposed to be the text section
+ address. However, we would have to fill it in later, and gdb
+ doesn't care, so we don't bother with it. */
+
+ info->lineno_filename = filename;
+
+ return stab_write_symbol (info, N_SOL, 0, 0, filename);
+}
+
+/* Push an empty type. This shouldn't normally happen. We just use a
+ void type. */
+
+static boolean
+stab_empty_type (p)
+ PTR p;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ /* We don't call stab_void_type if the type is not yet defined,
+ because that might screw up the typedef. */
+
+ if (info->type_cache.void_type != 0)
+ return stab_push_defined_type (info, info->type_cache.void_type, 0);
+ else
+ {
+ long index;
+ char buf[40];
+
+ index = info->type_index;
+ ++info->type_index;
+
+ sprintf (buf, "%ld=%ld", index, index);
+
+ return stab_push_string (info, buf, index, false, 0);
+ }
+}
+
+/* Push a void type. */
+
+static boolean
+stab_void_type (p)
+ PTR p;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ if (info->type_cache.void_type != 0)
+ return stab_push_defined_type (info, info->type_cache.void_type, 0);
+ else
+ {
+ long index;
+ char buf[40];
+
+ index = info->type_index;
+ ++info->type_index;
+
+ info->type_cache.void_type = index;
+
+ sprintf (buf, "%ld=%ld", index, index);
+
+ return stab_push_string (info, buf, index, true, 0);
+ }
+}
+
+/* Push an integer type. */
+
+static boolean
+stab_int_type (p, size, unsignedp)
+ PTR p;
+ unsigned int size;
+ boolean unsignedp;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ long *cache;
+
+ if (size <= 0 || (size > sizeof (long) && size != 8))
+ {
+ fprintf (stderr, "stab_int_type: bad size %u\n", size);
+ return false;
+ }
+
+ if (unsignedp)
+ cache = info->type_cache.signed_integer_types;
+ else
+ cache = info->type_cache.unsigned_integer_types;
+
+ if (cache[size - 1] != 0)
+ return stab_push_defined_type (info, cache[size - 1], size);
+ else
+ {
+ long index;
+ char buf[100];
+
+ index = info->type_index;
+ ++info->type_index;
+
+ cache[size - 1] = index;
+
+ sprintf (buf, "%ld=r%ld;", index, index);
+ if (unsignedp)
+ {
+ strcat (buf, "0;");
+ if (size < sizeof (long))
+ sprintf (buf + strlen (buf), "%ld;", ((long) 1 << (size * 8)) - 1);
+ else if (size == sizeof (long))
+ strcat (buf, "-1;");
+ else if (size == 8)
+ strcat (buf, "01777777777777777777777;");
+ else
+ abort ();
+ }
+ else
+ {
+ if (size <= sizeof (long))
+ sprintf (buf + strlen (buf), "%ld;%ld;",
+ (long) - ((unsigned long) 1 << (size * 8 - 1)),
+ (long) (((unsigned long) 1 << (size * 8 - 1)) - 1));
+ else if (size == 8)
+ strcat (buf, "01000000000000000000000;0777777777777777777777;");
+ else
+ abort ();
+ }
+
+ return stab_push_string (info, buf, index, true, size);
+ }
+}
+
+/* Push a floating point type. */
+
+static boolean
+stab_float_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ if (size > 0
+ && size - 1 < (sizeof info->type_cache.float_types
+ / sizeof info->type_cache.float_types[0])
+ && info->type_cache.float_types[size - 1] != 0)
+ return stab_push_defined_type (info,
+ info->type_cache.float_types[size - 1],
+ size);
+ else
+ {
+ long index;
+ char *int_type;
+ char buf[50];
+
+ /* Floats are defined as a subrange of int. */
+ if (! stab_int_type (info, 4, false))
+ return false;
+ int_type = stab_pop_type (info);
+
+ index = info->type_index;
+ ++info->type_index;
+
+ if (size > 0
+ && size - 1 < (sizeof info->type_cache.float_types
+ / sizeof info->type_cache.float_types[0]))
+ info->type_cache.float_types[size - 1] = index;
+
+ sprintf (buf, "%ld=r%s;%u;0;", index, int_type, size);
+
+ free (int_type);
+
+ return stab_push_string (info, buf, index, true, size);
+ }
+}
+
+/* Push a complex type. */
+
+static boolean
+stab_complex_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ char buf[50];
+ long index;
+
+ index = info->type_index;
+ ++info->type_index;
+
+ sprintf (buf, "%ld=r%ld;%u;0;", index, index, size);
+
+ return stab_push_string (info, buf, index, true, size * 2);
+}
+
+/* Push a boolean type. We use an XCOFF predefined type, since gdb
+ always recognizes them. */
+
+static boolean
+stab_bool_type (p, size)
+ PTR p;
+ unsigned int size;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ long index;
+
+ switch (size)
+ {
+ case 1:
+ index = -21;
+ break;
+
+ case 2:
+ index = -22;
+ break;
+
+ default:
+ case 4:
+ index = -16;
+ break;
+
+ case 8:
+ index = -33;
+ break;
+ }
+
+ return stab_push_defined_type (info, index, size);
+}
+
+/* Push an enum type. */
+
+static boolean
+stab_enum_type (p, tag, names, vals)
+ PTR p;
+ const char *tag;
+ const char **names;
+ bfd_signed_vma *vals;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ size_t len;
+ const char **pn;
+ char *buf;
+ long index = 0;
+ bfd_signed_vma *pv;
+
+ if (names == NULL)
+ {
+ assert (tag != NULL);
+
+ buf = (char *) xmalloc (10 + strlen (tag));
+ sprintf (buf, "xe%s:", tag);
+ /* FIXME: The size is just a guess. */
+ if (! stab_push_string (info, buf, 0, false, 4))
+ return false;
+ free (buf);
+ return true;
+ }
+
+ len = 10;
+ if (tag != NULL)
+ len += strlen (tag);
+ for (pn = names; *pn != NULL; pn++)
+ len += strlen (*pn) + 20;
+
+ if (tag == NULL)
+ strcpy (buf, "e");
+ else
+ {
+ index = info->type_index;
+ ++info->type_index;
+ sprintf (buf, "%s:T%ld=e", tag, index);
+ }
+
+ buf = (char *) xmalloc (len);
+ for (pn = names, pv = vals; *pn != NULL; pn++, pv++)
+ sprintf (buf + strlen (buf), "%s:%ld,", *pn, (long) *pv);
+ strcat (buf, ";");
+
+ if (tag == NULL)
+ {
+ /* FIXME: The size is just a guess. */
+ if (! stab_push_string (info, buf, 0, false, 4))
+ return false;
+ }
+ else
+ {
+ /* FIXME: The size is just a guess. */
+ if (! stab_write_symbol (info, N_LSYM, 0, 0, buf)
+ || ! stab_push_defined_type (info, index, 4))
+ return false;
+ }
+
+ free (buf);
+
+ return true;
+}
+
+/* Push a modification of the top type on the stack. Cache the
+ results in CACHE and CACHE_ALLOC. */
+
+static boolean
+stab_modify_type (info, mod, size, cache, cache_alloc)
+ struct stab_write_handle *info;
+ int mod;
+ unsigned int size;
+ long **cache;
+ size_t *cache_alloc;
+{
+ long targindex;
+ long index;
+ char *s, *buf;
+
+ assert (info->type_stack != NULL);
+ targindex = info->type_stack->index;
+
+ if (targindex <= 0
+ || cache == NULL)
+ {
+ boolean definition;
+
+ /* Either the target type has no index, or we aren't caching
+ this modifier. Either way we have no way of recording the
+ new type, so we don't bother to define one. */
+ definition = info->type_stack->definition;
+ s = stab_pop_type (info);
+ buf = (char *) xmalloc (strlen (s) + 2);
+ sprintf (buf, "%c%s", mod, s);
+ free (s);
+ if (! stab_push_string (info, buf, 0, definition, size))
+ return false;
+ free (buf);
+ }
+ else
+ {
+ if (targindex >= *cache_alloc)
+ {
+ size_t alloc;
+
+ alloc = *cache_alloc;
+ if (alloc == 0)
+ alloc = 10;
+ while (targindex >= alloc)
+ alloc *= 2;
+ *cache = (long *) xrealloc (*cache, alloc * sizeof (long));
+ memset (*cache + *cache_alloc, 0,
+ (alloc - *cache_alloc) * sizeof (long));
+ *cache_alloc = alloc;
+ }
+
+ index = (*cache)[targindex];
+ if (index != 0)
+ {
+ /* If we have already defined a modification of this type,
+ then the entry on the type stack can not be a definition,
+ so we can safely discard it. */
+ assert (! info->type_stack->definition);
+ free (stab_pop_type (info));
+ if (! stab_push_defined_type (info, index, size))
+ return false;
+ }
+ else
+ {
+ index = info->type_index;
+ ++info->type_index;
+
+ s = stab_pop_type (info);
+ buf = (char *) xmalloc (strlen (s) + 20);
+ sprintf (buf, "%ld=%c%s", index, mod, s);
+ free (s);
+
+ (*cache)[targindex] = index;
+
+ if (! stab_push_string (info, buf, index, true, size))
+ return false;
+
+ free (buf);
+ }
+ }
+
+ return true;
+}
+
+/* Push a pointer type. */
+
+static boolean
+stab_pointer_type (p)
+ PTR p;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ /* FIXME: The size should depend upon the architecture. */
+ return stab_modify_type (info, '*', 4, &info->type_cache.pointer_types,
+ &info->type_cache.pointer_types_alloc);
+}
+
+/* Push a function type. */
+
+static boolean
+stab_function_type (p, argcount, varargs)
+ PTR p;
+ int argcount;
+ boolean varargs;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ int i;
+
+ /* We have no way to represent the argument types, so we just
+ discard them. However, if they define new types, we must output
+ them. We do this by producing meaningless typedefs. */
+ for (i = 0; i < argcount; i++)
+ {
+ if (! info->type_stack->definition)
+ free (stab_pop_type (info));
+ else
+ {
+ char *s, *buf;
+ long index;
+
+ s = stab_pop_type (info);
+
+ buf = (char *) xmalloc (strlen (s) + 40);
+ index = info->type_index;
+ ++info->type_index;
+ sprintf (buf, "__fake_type_%ld:t%s", index, s);
+
+ free (s);
+
+ if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
+ return false;
+
+ free (buf);
+ }
+ }
+
+ return stab_modify_type (info, 'f', 0, &info->type_cache.function_types,
+ &info->type_cache.function_types_alloc);
+}
+
+/* Push a reference type. */
+
+static boolean
+stab_reference_type (p)
+ PTR p;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ /* FIXME: The size should depend upon the architecture. */
+ return stab_modify_type (info, '&', 4, &info->type_cache.reference_types,
+ &info->type_cache.reference_types_alloc);
+}
+
+/* Push a range type. */
+
+static boolean
+stab_range_type (p, low, high)
+ PTR p;
+ bfd_signed_vma low;
+ bfd_signed_vma high;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ boolean definition;
+ unsigned int size;
+ char *s, *buf;
+
+ definition = info->type_stack->definition;
+ size = info->type_stack->size;
+
+ s = stab_pop_type (info);
+ buf = (char *) xmalloc (strlen (s) + 100);
+ sprintf (buf, "r%s;%ld;%ld;", s, (long) low, (long) high);
+ free (s);
+
+ if (! stab_push_string (info, buf, 0, definition, size))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Push an array type. */
+
+static boolean
+stab_array_type (p, low, high, stringp)
+ PTR p;
+ bfd_signed_vma low;
+ bfd_signed_vma high;
+ boolean stringp;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ boolean definition;
+ unsigned int element_size;
+ char *range, *element, *buf;
+ long index;
+ unsigned int size;
+
+ definition = info->type_stack->definition;
+ range = stab_pop_type (info);
+
+ definition = definition || info->type_stack->definition;
+ element_size = info->type_stack->size;
+ element = stab_pop_type (info);
+
+ buf = (char *) xmalloc (strlen (range) + strlen (element) + 100);
+
+ if (! stringp)
+ {
+ index = 0;
+ *buf = '\0';
+ }
+ else
+ {
+ /* We need to define a type in order to include the string
+ attribute. */
+ index = info->type_index;
+ ++info->type_index;
+ definition = true;
+ sprintf (buf, "%ld=@S;", index);
+ }
+
+ sprintf (buf + strlen (buf), "ar%s;%ld;%ld;%s", range, low, high, element);
+ free (range);
+ free (element);
+
+ if (high <= low)
+ size = 0;
+ else
+ size = element_size * ((high - low) + 1);
+ if (! stab_push_string (info, buf, index, definition, size))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Push a set type. */
+
+static boolean
+stab_set_type (p, bitstringp)
+ PTR p;
+ boolean bitstringp;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ boolean definition;
+ char *s, *buf;
+ long index;
+
+ definition = info->type_stack->definition;
+
+ s = stab_pop_type (info);
+ buf = (char *) xmalloc (strlen (s) + 30);
+
+ if (! bitstringp)
+ {
+ *buf = '\0';
+ index = 0;
+ }
+ else
+ {
+ /* We need to define a type in order to include the string
+ attribute. */
+ index = info->type_index;
+ ++info->type_index;
+ definition = true;
+ sprintf (buf, "%ld=@S;", index);
+ }
+
+ sprintf (buf + strlen (buf), "S%s", s);
+ free (s);
+
+ if (! stab_push_string (info, buf, index, definition, 0))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Push an offset type. */
+
+static boolean
+stab_offset_type (p)
+ PTR p;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ boolean definition;
+ char *target, *base, *buf;
+
+ definition = info->type_stack->definition;
+ target = stab_pop_type (info);
+
+ definition = definition || info->type_stack->definition;
+ base = stab_pop_type (info);
+
+ buf = (char *) xmalloc (strlen (target) + strlen (base) + 3);
+ sprintf (buf, "@%s,%s", base, target);
+ free (base);
+ free (target);
+
+ if (! stab_push_string (info, buf, 0, definition, 0))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Push a method type. */
+
+static boolean
+stab_method_type (p, domainp, argcount, varargs)
+ PTR p;
+ boolean domainp;
+ int argcount;
+ boolean varargs;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ boolean definition;
+ char *domain, *return_type, *buf;
+ char **args;
+ int i;
+ size_t len;
+
+ /* We don't bother with stub method types, because that would
+ require a mangler for C++ argument types. This will waste space
+ in the debugging output. */
+
+ /* We need a domain. I'm not sure DOMAINP can ever be false,
+ anyhow. */
+ if (! domainp)
+ {
+ if (! stab_empty_type (p))
+ return false;
+ }
+
+ definition = info->type_stack->definition;
+ domain = stab_pop_type (info);
+
+ /* A non-varargs function is indicated by making the last parameter
+ type be void. */
+
+ if (argcount < 0)
+ {
+ args = NULL;
+ argcount = 0;
+ }
+ else if (argcount == 0)
+ {
+ if (varargs)
+ args = NULL;
+ else
+ {
+ args = (char **) xmalloc (1 * sizeof (*args));
+ if (! stab_empty_type (p))
+ return false;
+ definition = definition || info->type_stack->definition;
+ args[0] = stab_pop_type (info);
+ argcount = 1;
+ }
+ }
+ else
+ {
+ args = (char **) xmalloc ((argcount + 1) * sizeof (*args));
+ for (i = argcount - 1; i >= 0; i--)
+ {
+ definition = definition || info->type_stack->definition;
+ args[i] = stab_pop_type (info);
+ }
+ if (! varargs)
+ {
+ if (! stab_empty_type (p))
+ return false;
+ definition = definition || info->type_stack->definition;
+ args[argcount] = stab_pop_type (info);
+ ++argcount;
+ }
+ }
+
+ definition = definition || info->type_stack->definition;
+ return_type = stab_pop_type (info);
+
+ len = strlen (domain) + strlen (return_type) + 10;
+ for (i = 0; i < argcount; i++)
+ len += strlen (args[i]);
+
+ buf = (char *) xmalloc (len);
+
+ sprintf (buf, "#%s,%s", domain, return_type);
+ free (domain);
+ free (return_type);
+ for (i = 0; i < argcount; i++)
+ {
+ strcat (buf, ",");
+ strcat (buf, args[i]);
+ free (args[i]);
+ }
+ strcat (buf, ";");
+
+ if (args != NULL)
+ free (args);
+
+ if (! stab_push_string (info, buf, 0, definition, 0))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Push a const version of a type. */
+
+static boolean
+stab_const_type (p)
+ PTR p;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ return stab_modify_type (info, 'k', info->type_stack->size,
+ (long **) NULL, (size_t *) NULL);
+}
+
+/* Push a volatile version of a type. */
+
+static boolean
+stab_volatile_type (p)
+ PTR p;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ return stab_modify_type (info, 'B', info->type_stack->size,
+ (long **) NULL, (size_t *) NULL);
+}
+
+/* Get the type index to use for a struct/union/class ID. This should
+ return -1 if it fails. */
+
+static long
+stab_get_struct_index (info, tag, id, kind, psize)
+ struct stab_write_handle *info;
+ const char *tag;
+ unsigned int id;
+ enum debug_type_kind kind;
+ unsigned int *psize;
+{
+ if (id >= info->type_cache.struct_types_alloc)
+ {
+ size_t alloc;
+
+ alloc = info->type_cache.struct_types_alloc;
+ if (alloc == 0)
+ alloc = 10;
+ while (id >= alloc)
+ alloc *= 2;
+ info->type_cache.struct_types =
+ (struct stab_tag *) xrealloc (info->type_cache.struct_types,
+ alloc * sizeof (struct stab_tag));
+ memset ((info->type_cache.struct_types
+ + info->type_cache.struct_types_alloc),
+ 0,
+ ((alloc - info->type_cache.struct_types_alloc)
+ * sizeof (struct stab_tag)));
+ info->type_cache.struct_types_alloc = alloc;
+ }
+
+ if (info->type_cache.struct_types[id].index == 0)
+ {
+ info->type_cache.struct_types[id].index = info->type_index;
+ ++info->type_index;
+ info->type_cache.struct_types[id].tag = tag;
+ info->type_cache.struct_types[id].kind = kind;
+ }
+
+ if (kind == DEBUG_KIND_ILLEGAL)
+ {
+ /* This is a definition of the struct. */
+ info->type_cache.struct_types[id].kind = kind;
+ info->type_cache.struct_types[id].size = *psize;
+ }
+ else
+ *psize = info->type_cache.struct_types[id].size;
+
+ return info->type_cache.struct_types[id].index;
+}
+
+/* Start outputting a struct. We ignore the tag, and handle it in
+ stab_tag. */
+
+/*ARGSUSED*/
+static boolean
+stab_start_struct_type (p, tag, id, structp, size)
+ PTR p;
+ const char *tag;
+ unsigned int id;
+ boolean structp;
+ unsigned int size;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ long index;
+ boolean definition;
+ char *buf;
+
+ buf = (char *) xmalloc (40);
+
+ if (id == 0)
+ {
+ index = 0;
+ *buf = '\0';
+ definition = false;
+ }
+ else
+ {
+ index = stab_get_struct_index (info, tag, id, DEBUG_KIND_ILLEGAL,
+ &size);
+ if (index < 0)
+ return false;
+ sprintf (buf, "%ld=", index);
+ definition = true;
+ }
+
+ sprintf (buf + strlen (buf), "%c%u",
+ structp ? 's' : 'u',
+ size);
+
+ if (! stab_push_string (info, buf, index, definition, size))
+ return false;
+
+ info->type_stack->fields = (char *) xmalloc (1);
+ info->type_stack->fields[0] = '\0';
+
+ return true;
+}
+
+/* Add a field to a struct. */
+
+static boolean
+stab_struct_field (p, name, bitpos, bitsize, visibility)
+ PTR p;
+ const char *name;
+ bfd_vma bitpos;
+ bfd_vma bitsize;
+ enum debug_visibility visibility;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ boolean definition;
+ unsigned int size;
+ char *s, *n;
+ const char *vis;
+
+ definition = info->type_stack->definition;
+ size = info->type_stack->size;
+ s = stab_pop_type (info);
+
+ /* Add this field to the end of the current struct fields, which is
+ currently on the top of the stack. */
+
+ assert (info->type_stack->fields != NULL);
+ n = (char *) xmalloc (strlen (info->type_stack->fields)
+ + strlen (name)
+ + strlen (s)
+ + 50);
+
+ switch (visibility)
+ {
+ default:
+ abort ();
+
+ case DEBUG_VISIBILITY_PUBLIC:
+ vis = "";
+ break;
+
+ case DEBUG_VISIBILITY_PRIVATE:
+ vis = "/0";
+ break;
+
+ case DEBUG_VISIBILITY_PROTECTED:
+ vis = "/1";
+ break;
+ }
+
+ if (bitsize == 0)
+ {
+ bitsize = size * 8;
+ if (bitsize == 0)
+ fprintf (stderr,
+ "%s: warning: unknown size for field `%s' in struct\n",
+ bfd_get_filename (info->abfd), name);
+ }
+
+ sprintf (n, "%s%s:%s%s,%ld,%ld;", info->type_stack->fields, name, vis, s,
+ (long) bitpos, (long) bitsize);
+
+ free (info->type_stack->fields);
+ info->type_stack->fields = n;
+
+ if (definition)
+ info->type_stack->definition = true;
+
+ return true;
+}
+
+/* Finish up a struct. */
+
+static boolean
+stab_end_struct_type (p)
+ PTR p;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ boolean definition;
+ long index;
+ unsigned int size;
+ char *fields, *first, *buf;
+
+ assert (info->type_stack != NULL && info->type_stack->fields != NULL);
+
+ definition = info->type_stack->definition;
+ index = info->type_stack->index;
+ size = info->type_stack->size;
+ fields = info->type_stack->fields;
+ first = stab_pop_type (info);
+
+ buf = (char *) xmalloc (strlen (first) + strlen (fields) + 2);
+ sprintf (buf, "%s%s;", first, fields);
+ free (first);
+ free (fields);
+
+ if (! stab_push_string (info, buf, index, definition, size))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Start outputting a class. */
+
+static boolean
+stab_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
+ PTR p;
+ const char *tag;
+ unsigned int id;
+ boolean structp;
+ unsigned int size;
+ boolean vptr;
+ boolean ownvptr;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ boolean definition;
+ char *vstring;
+
+ if (! vptr || ownvptr)
+ {
+ definition = false;
+ vstring = NULL;
+ }
+ else
+ {
+ definition = info->type_stack->definition;
+ vstring = stab_pop_type (info);
+ }
+
+ if (! stab_start_struct_type (p, tag, id, structp, size))
+ return false;
+
+ if (vptr)
+ {
+ char *vtable;
+
+ if (ownvptr)
+ {
+ assert (info->type_stack->index > 0);
+ vtable = (char *) xmalloc (20);
+ sprintf (vtable, "~%%%ld", info->type_stack->index);
+ }
+ else
+ {
+ vtable = (char *) xmalloc (strlen (vstring) + 3);
+ sprintf (vtable, "~%%%s", vstring);
+ free (vstring);
+ }
+
+ info->type_stack->vtable = vtable;
+ }
+
+ if (definition)
+ info->type_stack->definition = true;
+
+ return true;
+}
+
+/* Add a static member to the class on the type stack. */
+
+static boolean
+stab_class_static_member (p, name, physname, visibility)
+ PTR p;
+ const char *name;
+ const char *physname;
+ enum debug_visibility visibility;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ boolean definition;
+ char *s, *n;
+ const char *vis;
+
+ definition = info->type_stack->definition;
+ s = stab_pop_type (info);
+
+ /* Add this field to the end of the current struct fields, which is
+ currently on the top of the stack. */
+
+ assert (info->type_stack->fields != NULL);
+ n = (char *) xmalloc (strlen (info->type_stack->fields)
+ + strlen (name)
+ + strlen (s)
+ + strlen (physname)
+ + 10);
+
+ switch (visibility)
+ {
+ default:
+ abort ();
+
+ case DEBUG_VISIBILITY_PUBLIC:
+ vis = "";
+ break;
+
+ case DEBUG_VISIBILITY_PRIVATE:
+ vis = "/0";
+ break;
+
+ case DEBUG_VISIBILITY_PROTECTED:
+ vis = "/1";
+ break;
+ }
+
+ sprintf (n, "%s%s:%s%s:%s;", info->type_stack->fields, name, vis, s,
+ physname);
+
+ free (info->type_stack->fields);
+ info->type_stack->fields = n;
+
+ if (definition)
+ info->type_stack->definition = true;
+
+ return true;
+}
+
+/* Add a base class to the class on the type stack. */
+
+static boolean
+stab_class_baseclass (p, bitpos, virtual, visibility)
+ PTR p;
+ bfd_vma bitpos;
+ boolean virtual;
+ enum debug_visibility visibility;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ boolean definition;
+ char *s;
+ char *buf;
+ unsigned int c;
+ char **baseclasses;
+
+ definition = info->type_stack->definition;
+ s = stab_pop_type (info);
+
+ /* Build the base class specifier. */
+
+ buf = (char *) xmalloc (strlen (s) + 25);
+ buf[0] = virtual ? '1' : '0';
+ switch (visibility)
+ {
+ default:
+ abort ();
+
+ case DEBUG_VISIBILITY_PRIVATE:
+ buf[1] = '0';
+ break;
+
+ case DEBUG_VISIBILITY_PROTECTED:
+ buf[1] = '1';
+ break;
+
+ case DEBUG_VISIBILITY_PUBLIC:
+ buf[1] = '2';
+ break;
+ }
+
+ sprintf (buf + 2, "%ld,%s;", (long) bitpos, s);
+ free (s);
+
+ /* Add the new baseclass to the existing ones. */
+
+ assert (info->type_stack != NULL && info->type_stack->fields != NULL);
+
+ if (info->type_stack->baseclasses == NULL)
+ c = 0;
+ else
+ {
+ c = 0;
+ while (info->type_stack->baseclasses[c] != NULL)
+ ++c;
+ }
+
+ baseclasses = (char **) xrealloc (info->type_stack->baseclasses,
+ (c + 2) * sizeof (*baseclasses));
+ baseclasses[c] = buf;
+ baseclasses[c + 1] = NULL;
+
+ info->type_stack->baseclasses = baseclasses;
+
+ if (definition)
+ info->type_stack->definition = true;
+
+ return true;
+}
+
+/* Start adding a method to the class on the type stack. */
+
+static boolean
+stab_class_start_method (p, name)
+ PTR p;
+ const char *name;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ char *m;
+
+ assert (info->type_stack != NULL && info->type_stack->fields != NULL);
+
+ if (info->type_stack->methods == NULL)
+ {
+ m = (char *) xmalloc (strlen (name) + 3);
+ *m = '\0';
+ }
+ else
+ {
+ m = (char *) xrealloc (info->type_stack->methods,
+ (strlen (info->type_stack->methods)
+ + strlen (name)
+ + 4));
+ }
+
+ sprintf (m + strlen (m), "%s::", name);
+
+ info->type_stack->methods = m;
+
+ return true;
+}
+
+/* Add a variant, either static or not, to the current method. */
+
+static boolean
+stab_class_method_var (info, physname, visibility, staticp, constp, volatilep,
+ voffset, contextp)
+ struct stab_write_handle *info;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean staticp;
+ boolean constp;
+ boolean volatilep;
+ bfd_vma voffset;
+ boolean contextp;
+{
+ boolean definition;
+ char *type;
+ char *context = NULL;
+ char visc, qualc, typec;
+
+ definition = info->type_stack->definition;
+ type = stab_pop_type (info);
+
+ if (contextp)
+ {
+ definition = definition || info->type_stack->definition;
+ context = stab_pop_type (info);
+ }
+
+ assert (info->type_stack != NULL && info->type_stack->methods != NULL);
+
+ switch (visibility)
+ {
+ default:
+ abort ();
+
+ case DEBUG_VISIBILITY_PRIVATE:
+ visc = '0';
+ break;
+
+ case DEBUG_VISIBILITY_PROTECTED:
+ visc = '1';
+ break;
+
+ case DEBUG_VISIBILITY_PUBLIC:
+ visc = '2';
+ break;
+ }
+
+ if (constp)
+ {
+ if (volatilep)
+ qualc = 'D';
+ else
+ qualc = 'B';
+ }
+ else
+ {
+ if (volatilep)
+ qualc = 'C';
+ else
+ qualc = 'A';
+ }
+
+ if (staticp)
+ typec = '?';
+ else if (! contextp)
+ typec = '.';
+ else
+ typec = '*';
+
+ info->type_stack->methods =
+ (char *) xrealloc (info->type_stack->methods,
+ (strlen (info->type_stack->methods)
+ + strlen (type)
+ + strlen (physname)
+ + (contextp ? strlen (context) : 0)
+ + 40));
+
+ sprintf (info->type_stack->methods + strlen (info->type_stack->methods),
+ "%s:%s;%c%c%c", type, physname, visc, qualc, typec);
+ free (type);
+
+ if (contextp)
+ {
+ sprintf (info->type_stack->methods + strlen (info->type_stack->methods),
+ "%ld;%s;", (long) voffset, context);
+ free (context);
+ }
+
+ if (definition)
+ info->type_stack->definition = true;
+
+ return true;
+}
+
+/* Add a variant to the current method. */
+
+static boolean
+stab_class_method_variant (p, physname, visibility, constp, volatilep,
+ voffset, contextp)
+ PTR p;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+ bfd_vma voffset;
+ boolean contextp;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ return stab_class_method_var (info, physname, visibility, false, constp,
+ volatilep, voffset, contextp);
+}
+
+/* Add a static variant to the current method. */
+
+static boolean
+stab_class_static_method_variant (p, physname, visibility, constp, volatilep)
+ PTR p;
+ const char *physname;
+ enum debug_visibility visibility;
+ boolean constp;
+ boolean volatilep;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ return stab_class_method_var (info, physname, visibility, true, constp,
+ volatilep, 0, false);
+}
+
+/* Finish up a method. */
+
+static boolean
+stab_class_end_method (p)
+ PTR p;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ assert (info->type_stack != NULL && info->type_stack->methods != NULL);
+
+ /* We allocated enough room on info->type_stack->methods to add the
+ trailing semicolon. */
+ strcat (info->type_stack->methods, ";");
+
+ return true;
+}
+
+/* Finish up a class. */
+
+static boolean
+stab_end_class_type (p)
+ PTR p;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ size_t len;
+ unsigned int i;
+ char *buf;
+
+ assert (info->type_stack != NULL && info->type_stack->fields != NULL);
+
+ /* Work out the size we need to allocate for the class definition. */
+
+ len = (strlen (info->type_stack->string)
+ + strlen (info->type_stack->fields)
+ + 10);
+ if (info->type_stack->baseclasses != NULL)
+ {
+ len += 20;
+ for (i = 0; info->type_stack->baseclasses[i] != NULL; i++)
+ len += strlen (info->type_stack->baseclasses[i]);
+ }
+ if (info->type_stack->methods != NULL)
+ len += strlen (info->type_stack->methods);
+ if (info->type_stack->vtable != NULL)
+ len += strlen (info->type_stack->vtable);
+
+ /* Build the class definition. */
+
+ buf = (char *) xmalloc (len);
+
+ strcpy (buf, info->type_stack->string);
+
+ if (info->type_stack->baseclasses != NULL)
+ {
+ sprintf (buf + strlen (buf), "!%u,", i);
+ for (i = 0; info->type_stack->baseclasses[i] != NULL; i++)
+ {
+ strcat (buf, info->type_stack->baseclasses[i]);
+ free (info->type_stack->baseclasses[i]);
+ }
+ free (info->type_stack->baseclasses);
+ info->type_stack->baseclasses = NULL;
+ }
+
+ strcat (buf, info->type_stack->fields);
+ free (info->type_stack->fields);
+ info->type_stack->fields = NULL;
+
+ if (info->type_stack->methods != NULL)
+ {
+ strcat (buf, info->type_stack->methods);
+ free (info->type_stack->methods);
+ info->type_stack->methods = NULL;
+ }
+
+ strcat (buf, ";");
+
+ if (info->type_stack->vtable != NULL)
+ {
+ strcat (buf, info->type_stack->vtable);
+ free (info->type_stack->vtable);
+ info->type_stack->vtable = NULL;
+ }
+
+ /* Replace the string on the top of the stack with the complete
+ class definition. */
+ free (info->type_stack->string);
+ info->type_stack->string = buf;
+
+ return true;
+}
+
+/* Push a typedef which was previously defined. */
+
+static boolean
+stab_typedef_type (p, name)
+ PTR p;
+ const char *name;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ struct string_hash_entry *h;
+
+ h = string_hash_lookup (&info->typedef_hash, name, false, false);
+ assert (h != NULL && h->index > 0);
+
+ return stab_push_defined_type (info, h->index, h->size);
+}
+
+/* Push a struct, union or class tag. */
+
+static boolean
+stab_tag_type (p, name, id, kind)
+ PTR p;
+ const char *name;
+ unsigned int id;
+ enum debug_type_kind kind;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ long index;
+ unsigned int size;
+
+ index = stab_get_struct_index (info, name, id, kind, &size);
+ if (index < 0)
+ return false;
+
+ return stab_push_defined_type (info, index, size);
+}
+
+/* Define a typedef. */
+
+static boolean
+stab_typdef (p, name)
+ PTR p;
+ const char *name;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ long index;
+ unsigned int size;
+ char *s, *buf;
+ struct string_hash_entry *h;
+
+ index = info->type_stack->index;
+ size = info->type_stack->size;
+ s = stab_pop_type (info);
+
+ buf = (char *) xmalloc (strlen (name) + strlen (s) + 20);
+
+ if (index > 0)
+ sprintf (buf, "%s:t%s", name, s);
+ else
+ {
+ index = info->type_index;
+ ++info->type_index;
+ sprintf (buf, "%s:t%ld=%s", name, index, s);
+ }
+
+ free (s);
+
+ if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
+ return false;
+
+ free (buf);
+
+ h = string_hash_lookup (&info->typedef_hash, name, true, false);
+ if (h == NULL)
+ {
+ fprintf (stderr, "string_hash_lookup failed: %s\n",
+ bfd_errmsg (bfd_get_error ()));
+ return false;
+ }
+
+ /* I don't think we care about redefinitions. */
+
+ h->index = index;
+ h->size = size;
+
+ return true;
+}
+
+/* Define a tag. */
+
+static boolean
+stab_tag (p, tag)
+ PTR p;
+ const char *tag;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ char *s, *buf;
+
+ s = stab_pop_type (info);
+
+ buf = (char *) xmalloc (strlen (tag) + strlen (s) + 3);
+
+ sprintf (buf, "%s:T%s", tag, s);
+ free (s);
+
+ if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Define an integer constant. */
+
+static boolean
+stab_int_constant (p, name, val)
+ PTR p;
+ const char *name;
+ bfd_vma val;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ char *buf;
+
+ buf = (char *) xmalloc (strlen (name) + 20);
+ sprintf (buf, "%s:c=i%ld", name, (long) val);
+
+ if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Define a floating point constant. */
+
+static boolean
+stab_float_constant (p, name, val)
+ PTR p;
+ const char *name;
+ double val;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ char *buf;
+
+ buf = (char *) xmalloc (strlen (name) + 20);
+ sprintf (buf, "%s:c=f%g", name, val);
+
+ if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Define a typed constant. */
+
+static boolean
+stab_typed_constant (p, name, val)
+ PTR p;
+ const char *name;
+ bfd_vma val;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ char *s, *buf;
+
+ s = stab_pop_type (info);
+
+ buf = (char *) xmalloc (strlen (name) + strlen (s) + 20);
+ sprintf (buf, "%s:c=e%s,%ld", name, s, (long) val);
+ free (s);
+
+ if (! stab_write_symbol (info, N_LSYM, 0, 0, buf))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Record a variable. */
+
+static boolean
+stab_variable (p, name, kind, val)
+ PTR p;
+ const char *name;
+ enum debug_var_kind kind;
+ bfd_vma val;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ char *s, *buf;
+ int stab_type;
+ const char *kindstr;
+
+ s = stab_pop_type (info);
+
+ switch (kind)
+ {
+ default:
+ abort ();
+
+ case DEBUG_GLOBAL:
+ stab_type = N_GSYM;
+ kindstr = "G";
+ break;
+
+ case DEBUG_STATIC:
+ stab_type = N_STSYM;
+ kindstr = "S";
+ break;
+
+ case DEBUG_LOCAL_STATIC:
+ stab_type = N_STSYM;
+ kindstr = "V";
+ break;
+
+ case DEBUG_LOCAL:
+ stab_type = N_LSYM;
+ kindstr = "";
+
+ /* Make sure that this is a type reference or definition. */
+ if (! isdigit (*s))
+ {
+ char *n;
+ long index;
+
+ index = info->type_index;
+ ++info->type_index;
+ n = (char *) xmalloc (strlen (s) + 20);
+ sprintf (n, "%ld=%s", index, s);
+ free (s);
+ s = n;
+ }
+ break;
+
+ case DEBUG_REGISTER:
+ stab_type = N_LSYM;
+ kindstr = "r";
+ break;
+ }
+
+ buf = (char *) xmalloc (strlen (name) + strlen (s) + 3);
+ sprintf (buf, "%s:%s%s", name, kindstr, s);
+ free (s);
+
+ if (! stab_write_symbol (info, stab_type, 0, val, buf))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Start outputting a function. */
+
+static boolean
+stab_start_function (p, name, globalp)
+ PTR p;
+ const char *name;
+ boolean globalp;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ char *rettype, *buf;
+
+ assert (info->nesting == 0 && info->fun_offset == -1);
+
+ rettype = stab_pop_type (info);
+
+ buf = (char *) xmalloc (strlen (name) + strlen (rettype) + 3);
+ sprintf (buf, "%s:%c%s", name,
+ globalp ? 'F' : 'f',
+ rettype);
+
+ /* We don't know the value now, so we set it in start_block. */
+ info->fun_offset = info->symbols_size;
+
+ if (! stab_write_symbol (info, N_FUN, 0, 0, buf))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Output a function parameter. */
+
+static boolean
+stab_function_parameter (p, name, kind, val)
+ PTR p;
+ const char *name;
+ enum debug_parm_kind kind;
+ bfd_vma val;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+ char *s, *buf;
+ int stab_type;
+ char kindc;
+
+ s = stab_pop_type (info);
+
+ switch (kind)
+ {
+ default:
+ abort ();
+
+ case DEBUG_PARM_STACK:
+ stab_type = N_PSYM;
+ kindc = 'p';
+ break;
+
+ case DEBUG_PARM_REG:
+ stab_type = N_RSYM;
+ kindc = 'P';
+ break;
+
+ case DEBUG_PARM_REFERENCE:
+ stab_type = N_PSYM;
+ kindc = 'v';
+ break;
+
+ case DEBUG_PARM_REF_REG:
+ stab_type = N_RSYM;
+ kindc = 'a';
+ break;
+ }
+
+ buf = (char *) xmalloc (strlen (name) + strlen (s) + 3);
+ sprintf (buf, "%s:%c%s", name, kindc, s);
+ free (s);
+
+ if (! stab_write_symbol (info, stab_type, 0, val, buf))
+ return false;
+
+ free (buf);
+
+ return true;
+}
+
+/* Start a block. */
+
+static boolean
+stab_start_block (p, addr)
+ PTR p;
+ bfd_vma addr;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ /* Fill in any slots which have been waiting for the first known
+ text address. */
+
+ if (info->so_offset != -1)
+ {
+ bfd_put_32 (info->abfd, addr, info->symbols + info->so_offset + 8);
+ info->so_offset = -1;
+ }
+
+ if (info->fun_offset != -1)
+ {
+ bfd_put_32 (info->abfd, addr, info->symbols + info->fun_offset + 8);
+ info->fun_offset = -1;
+ }
+
+ ++info->nesting;
+
+ /* We will be called with a top level block surrounding the
+ function, but stabs information does not output that block, so we
+ ignore it. */
+
+ if (info->nesting == 1)
+ {
+ info->fnaddr = addr;
+ return true;
+ }
+
+ /* We have to output the LBRAC symbol after any variables which are
+ declared inside the block. We postpone the LBRAC until the next
+ start_block or end_block. */
+
+ /* If we have postponed an LBRAC, output it now. */
+ if (info->pending_lbrac != (bfd_vma) -1)
+ {
+ if (! stab_write_symbol (info, N_LBRAC, 0, info->pending_lbrac,
+ (const char *) NULL))
+ return false;
+ }
+
+ /* Remember the address and output it later. */
+
+ info->pending_lbrac = addr - info->fnaddr;
+
+ return true;
+}
+
+/* End a block. */
+
+static boolean
+stab_end_block (p, addr)
+ PTR p;
+ bfd_vma addr;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ if (addr > info->last_text_address)
+ info->last_text_address = addr;
+
+ /* If we have postponed an LBRAC, output it now. */
+ if (info->pending_lbrac != (bfd_vma) -1)
+ {
+ if (! stab_write_symbol (info, N_LBRAC, 0, info->pending_lbrac,
+ (const char *) NULL))
+ return false;
+ info->pending_lbrac = (bfd_vma) -1;
+ }
+
+ assert (info->nesting > 0);
+
+ --info->nesting;
+
+ /* We ignore the outermost block. */
+ if (info->nesting == 0)
+ return true;
+
+ return stab_write_symbol (info, N_RBRAC, 0, addr - info->fnaddr,
+ (const char *) NULL);
+}
+
+/* End a function. */
+
+/*ARGSUSED*/
+static boolean
+stab_end_function (p)
+ PTR p;
+{
+ return true;
+}
+
+/* Output a line number. */
+
+static boolean
+stab_lineno (p, file, lineno, addr)
+ PTR p;
+ const char *file;
+ unsigned long lineno;
+ bfd_vma addr;
+{
+ struct stab_write_handle *info = (struct stab_write_handle *) p;
+
+ assert (info->lineno_filename != NULL);
+
+ if (addr > info->last_text_address)
+ info->last_text_address = addr;
+
+ if (strcmp (file, info->lineno_filename) != 0)
+ {
+ if (! stab_write_symbol (info, N_SOL, 0, addr, file))
+ return false;
+ info->lineno_filename = file;
+ }
+
+ return stab_write_symbol (info, N_SLINE, lineno, addr - info->fnaddr,
+ (const char *) NULL);
+}