ebcb40e5e1
port, which is also in sync with winavr/avrstudio. Among other things, this adds support for atmega328... which means new arduino boards should work.
3415 lines
94 KiB
Plaintext
3415 lines
94 KiB
Plaintext
$OpenBSD: patch-binutils_wrcoff_c,v 1.3 2010/06/27 20:58:10 ckuethe Exp $
|
||
--- binutils/wrcoff.c.orig Sat Jun 26 11:31:17 2010
|
||
+++ binutils/wrcoff.c Sat Jun 26 11:31:17 2010
|
||
@@ -0,0 +1,3410 @@
|
||
+/* wrcoff.c -- Generate (AVR) COFF debugging information
|
||
+ Copyright 2003 Free Software Foundation, Inc.
|
||
+
|
||
+ Written by Joerg Wunsch.
|
||
+
|
||
+ 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 COFF debugging
|
||
+ information. By now, this has only been tested on the AVR
|
||
+ platform, though any attempt has been made to keep the conversion
|
||
+ applicable to possible other COFF debugging consumers as well. */
|
||
+
|
||
+#include <stdio.h>
|
||
+#include <assert.h>
|
||
+
|
||
+#include "sysdep.h"
|
||
+#include "bfd.h"
|
||
+#include "coff/internal.h"
|
||
+#include "bucomm.h"
|
||
+#include "libiberty.h"
|
||
+#include "safe-ctype.h"
|
||
+#include "debug.h"
|
||
+#include "budbg.h"
|
||
+
|
||
+/* Enabling COFF_DEBUG will trace the internal callback functions and
|
||
+ their parameters as debug_write() calls them. */
|
||
+//#define COFF_DEBUG 1
|
||
+
|
||
+#include "libcoff.h"
|
||
+
|
||
+#define N_TMASK (coff_data (info->abfd)->local_n_tmask)
|
||
+#define N_BTSHFT (coff_data (info->abfd)->local_n_btshft)
|
||
+#define N_BTMASK (coff_data (info->abfd)->local_n_btmask)
|
||
+#define N_TSHIFT (coff_data (info->abfd)->local_n_tshift)
|
||
+
|
||
+/* Structure of local symbols per compilation unit. */
|
||
+struct coff_compilation_unit
|
||
+{
|
||
+ const char *fname;
|
||
+ asymbol **syms;
|
||
+ long nsyms, totsyms;
|
||
+};
|
||
+
|
||
+enum ts_kind
|
||
+{
|
||
+ TS_EMPTY,
|
||
+ TS_VOID,
|
||
+ TS_INT,
|
||
+ TS_FLOAT,
|
||
+ TS_COMPLEX,
|
||
+ TS_ENUM,
|
||
+ TS_POINTER,
|
||
+ TS_FUNC,
|
||
+ TS_ARRAY,
|
||
+ TS_STRUCT,
|
||
+ TS_NONE = -1
|
||
+};
|
||
+
|
||
+/* Structure defining the pre-defined types. */
|
||
+struct coff_predef_type
|
||
+{
|
||
+ enum ts_kind kind;
|
||
+ unsigned int size; /* in bytes */
|
||
+ bfd_boolean isunsigned;
|
||
+ int slot;
|
||
+};
|
||
+
|
||
+struct coff_type_stack;
|
||
+struct coff_hash_entry;
|
||
+
|
||
+struct coff_struct_fields
|
||
+{
|
||
+ const char *name;
|
||
+ bfd_vma bitpos;
|
||
+ bfd_vma bitsize;
|
||
+ enum debug_visibility visibility;
|
||
+ struct coff_type_stack *types;
|
||
+};
|
||
+
|
||
+/* Our type stack. */
|
||
+struct coff_type_stack
|
||
+{
|
||
+ struct coff_type_stack *next;
|
||
+ enum ts_kind tsk;
|
||
+ union
|
||
+ {
|
||
+ /* TS_INT */
|
||
+ struct
|
||
+ {
|
||
+ unsigned int size;
|
||
+ bfd_boolean isunsigned;
|
||
+ }
|
||
+ ts_int;
|
||
+
|
||
+ /* TS_FLOAT */
|
||
+ struct
|
||
+ {
|
||
+ unsigned int size;
|
||
+ }
|
||
+ ts_float;
|
||
+
|
||
+ /* TS_ENUM */
|
||
+ struct
|
||
+ {
|
||
+ union
|
||
+ {
|
||
+ const char *fixtag;
|
||
+ char *malloctag;
|
||
+ }
|
||
+ tag;
|
||
+ bfd_boolean tagismalloced;
|
||
+ const char **names;
|
||
+ bfd_signed_vma *vals;
|
||
+ struct coff_enum_hash_entry *ehash;
|
||
+ }
|
||
+ ts_enum;
|
||
+
|
||
+ /* TS_FUNC */
|
||
+ struct
|
||
+ {
|
||
+ struct coff_type_stack *savedts;
|
||
+ }
|
||
+ ts_func;
|
||
+
|
||
+ /* TS_ARRAY */
|
||
+ struct
|
||
+ {
|
||
+ bfd_signed_vma low;
|
||
+ bfd_signed_vma high;
|
||
+ }
|
||
+ ts_array;
|
||
+
|
||
+ /* TS_STRUCT */
|
||
+ struct
|
||
+ {
|
||
+ union
|
||
+ {
|
||
+ const char *fixtag;
|
||
+ char *malloctag;
|
||
+ }
|
||
+ tag;
|
||
+ bfd_boolean tagismalloced;
|
||
+ unsigned int id;
|
||
+ bfd_boolean isstruct;
|
||
+ unsigned int size;
|
||
+ long nfields;
|
||
+ struct coff_struct_fields *fields;
|
||
+ struct coff_type_stack *savedts;
|
||
+ struct coff_struct_hash_entry *shash;
|
||
+ }
|
||
+ ts_struct;
|
||
+ }
|
||
+ u;
|
||
+};
|
||
+
|
||
+struct coff_name_type_hash_table
|
||
+{
|
||
+ struct bfd_hash_table root;
|
||
+};
|
||
+
|
||
+struct coff_name_type_hash_entry
|
||
+{
|
||
+ struct bfd_hash_entry root;
|
||
+ /* Information for this name. */
|
||
+ struct coff_type_stack *types;
|
||
+ bfd_boolean emitted;
|
||
+};
|
||
+
|
||
+struct coff_struct_hash_table
|
||
+{
|
||
+ struct bfd_hash_table root;
|
||
+};
|
||
+
|
||
+struct coff_struct_hash_entry
|
||
+{
|
||
+ struct bfd_hash_entry root;
|
||
+ /* Information for this name. */
|
||
+ struct coff_type_stack *types;
|
||
+ bfd_boolean emitted;
|
||
+ combined_entry_type *native;
|
||
+ /* list of symbol indices that need fixing */
|
||
+ long *fixidxs;
|
||
+ unsigned nfixidxs;
|
||
+};
|
||
+
|
||
+struct coff_enum_hash_table
|
||
+{
|
||
+ struct bfd_hash_table root;
|
||
+};
|
||
+
|
||
+struct coff_enum_hash_entry
|
||
+{
|
||
+ struct bfd_hash_entry root;
|
||
+ /* Information for this name. */
|
||
+ struct coff_type_stack *types;
|
||
+ bfd_boolean emitted;
|
||
+ combined_entry_type *native;
|
||
+ /* list of symbol indices that need fixing */
|
||
+ long *fixidxs;
|
||
+ unsigned nfixidxs;
|
||
+};
|
||
+
|
||
+/* COFF private symbol data. Used as a cookie to pass data around
|
||
+ between various processing stages. The generic COFF handling code
|
||
+ doesn't use any private data. */
|
||
+struct coff_private_symdata
|
||
+{
|
||
+ unsigned int size; /* size of symbol, used in AVR register
|
||
+ translation */
|
||
+ struct coff_struct_hash_entry *shash; /* TS_STRUCT hash for fixups */
|
||
+ struct coff_enum_hash_entry *ehash; /* TS_ENUM hash for fixups */
|
||
+};
|
||
+
|
||
+/* Stack of tags that need endndx fixing. */
|
||
+struct coff_fix_stack
|
||
+{
|
||
+ struct coff_fix_stack *next;
|
||
+ combined_entry_type *native;
|
||
+};
|
||
+
|
||
+/* This is the handle passed through debug_write. */
|
||
+
|
||
+struct coff_write_handle
|
||
+{
|
||
+ /* The BFD. */
|
||
+ bfd *abfd;
|
||
+ /* Pointers to .text and .data sections, can be used as defaults if
|
||
+ no other information is available. */
|
||
+ asection *textsect;
|
||
+ asection *datasect;
|
||
+ /* Some special flags. */
|
||
+ unsigned long flags;
|
||
+ /* Flags describing architecture options. */
|
||
+#define COFF_FL_AVR 0x0001 /* COFF is for AVR platform. */
|
||
+#define COFF_FL_EXT_AVR 0x0002 /* AVR "extended" COFF */
|
||
+ /* Flags describing internal status information. */
|
||
+#define COFF_FL_FIX_ENDNDX 0x10000 /* apply endndx fix at next symbol */
|
||
+#define COFF_FL_START_FCN 0x20000 /* begin of function pending */
|
||
+#define COFF_FL_FIX_BB 0x40000 /* fix last ".bb" symbol */
|
||
+ /* List of our compilation units, from input symbol table. */
|
||
+ struct coff_compilation_unit *units;
|
||
+ long nunits;
|
||
+ struct coff_compilation_unit *currentfile;
|
||
+ /* Global symbols from input symbol table. */
|
||
+ asymbol **globals;
|
||
+ long nglobals;
|
||
+ /* Section syms for named sections. */
|
||
+ coff_symbol_type **secsyms;
|
||
+ long nsecsyms;
|
||
+ /* Our COFF symbols. */
|
||
+ asymbol **syms;
|
||
+ long nsyms;
|
||
+ /* Total line number count. */
|
||
+ unsigned long totlnos;
|
||
+ /* Size of standard objects on this arch. */
|
||
+ unsigned int pointersize;
|
||
+ unsigned int enumsize;
|
||
+ /* Pending information when starting a function. We have to defer
|
||
+ almost everything, some actions can be taken when seeing the
|
||
+ starting block of that function, some will even have to wait
|
||
+ until we see the end of the function. */
|
||
+ const char *funname; /* name of function */
|
||
+ bfd_boolean funglobal; /* global/local function? */
|
||
+ unsigned int lastlno; /* last line number seen so far */
|
||
+ long funcindex; /* index of ".func" symbol in syms */
|
||
+ unsigned int nlnos; /* line numbers recorded for this function*/
|
||
+ bfd_vma endaddr; /* last .eb address we have seen so far */
|
||
+ unsigned int funlno; /* first line number in function */
|
||
+ coff_symbol_type **fargs; /* function arguments */
|
||
+ unsigned int nfargs;
|
||
+ asection *funcsection; /* section the current function is using */
|
||
+ /* Type information */
|
||
+ struct coff_type_stack *tstack;
|
||
+ struct coff_name_type_hash_table types;
|
||
+ struct coff_struct_hash_table structs;
|
||
+ struct coff_enum_hash_table enums;
|
||
+ unsigned nenums; /* counter for anonymous enum tags */
|
||
+ /* Stack of pending endndx fixes, see coff_record_symbol(). */
|
||
+ struct coff_fix_stack *fixes;
|
||
+};
|
||
+
|
||
+/* Predefined types, default to usual 32-bit architectures.
|
||
+ Arch-dependant different byte sizes will be tuned upon entering
|
||
+ write_coff_debugging_info(). The table is looked up from front to
|
||
+ end, so we put `more popular' types that might have the same size
|
||
+ as other types first (e. g. "int" precedes "long" and "short"). */
|
||
+static struct coff_predef_type coff_predef_types[] =
|
||
+{
|
||
+ { TS_INT, 4, FALSE, 4 }, /* signed int */
|
||
+ { TS_INT, 1, FALSE, 2 }, /* signed char */
|
||
+ { TS_INT, 2, FALSE, 3 }, /* signed short */
|
||
+ { TS_INT, 4, FALSE, 5 }, /* long int */
|
||
+ { TS_FLOAT, 8, FALSE, 7 }, /* double */
|
||
+ { TS_FLOAT, 4, FALSE, 6 }, /* float */
|
||
+ { TS_INT, 4, TRUE, 14 }, /* unsigned int */
|
||
+ { TS_INT, 1, TRUE, 12 }, /* unsigned char */
|
||
+ { TS_INT, 2, TRUE, 13 }, /* unsigned short */
|
||
+ { TS_INT, 4, TRUE, 15 }, /* unsigned long */
|
||
+};
|
||
+
|
||
+static bfd_boolean coff_copy_symbols
|
||
+ PARAMS ((struct coff_write_handle *, long, asymbol **));
|
||
+static asymbol *coff_find_symbol
|
||
+ PARAMS ((struct coff_write_handle *, const char *, bfd_boolean, bfd_boolean));
|
||
+static void coff_record_symbol
|
||
+ PARAMS ((struct coff_write_handle *, coff_symbol_type *));
|
||
+static symvalue coff_fixup_avr_register PARAMS ((symvalue, int));
|
||
+static struct bfd_hash_entry *coff_name_type_newfunc
|
||
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
|
||
+static bfd_boolean coff_free_type_info
|
||
+ PARAMS ((struct coff_name_type_hash_entry *, PTR));
|
||
+static struct bfd_hash_entry *coff_struct_newfunc
|
||
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
|
||
+static bfd_boolean coff_free_struct_info
|
||
+ PARAMS ((struct coff_struct_hash_entry *, PTR));
|
||
+static struct bfd_hash_entry *coff_enum_newfunc
|
||
+ PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
|
||
+static bfd_boolean coff_free_enum_info
|
||
+ PARAMS ((struct coff_enum_hash_entry *, PTR));
|
||
+static unsigned int coff_get_fundamental_type
|
||
+ PARAMS ((struct coff_write_handle *, struct coff_type_stack *));
|
||
+static bfd_boolean coff_make_typed_symbol
|
||
+ PARAMS ((struct coff_write_handle *, coff_symbol_type **, enum ts_kind));
|
||
+static bfd_boolean coff_emit_struct
|
||
+ PARAMS ((struct coff_write_handle *, struct coff_type_stack *,
|
||
+ struct coff_struct_hash_entry *));
|
||
+static bfd_boolean coff_emit_enum
|
||
+ PARAMS ((struct coff_write_handle *, struct coff_type_stack *,
|
||
+ struct coff_enum_hash_entry *));
|
||
+static bfd_boolean coff_emit_ndebug_sym
|
||
+ PARAMS ((struct coff_write_handle *, asymbol *, bfd_boolean));
|
||
+
|
||
+static bfd_boolean coff_start_compilation_unit PARAMS ((PTR, const char *));
|
||
+static bfd_boolean coff_start_source PARAMS ((PTR, const char *));
|
||
+static bfd_boolean coff_empty_type PARAMS ((PTR));
|
||
+static bfd_boolean coff_void_type PARAMS ((PTR));
|
||
+static bfd_boolean coff_int_type PARAMS ((PTR, unsigned int, bfd_boolean));
|
||
+static bfd_boolean coff_float_type PARAMS ((PTR, unsigned int));
|
||
+static bfd_boolean coff_complex_type PARAMS ((PTR, unsigned int));
|
||
+static bfd_boolean coff_bool_type PARAMS ((PTR, unsigned int));
|
||
+static bfd_boolean coff_enum_type
|
||
+ PARAMS ((PTR, const char *, const char **, bfd_signed_vma *));
|
||
+static bfd_boolean coff_pointer_type PARAMS ((PTR));
|
||
+static bfd_boolean coff_function_type PARAMS ((PTR, int, bfd_boolean));
|
||
+static bfd_boolean coff_reference_type PARAMS ((PTR));
|
||
+static bfd_boolean coff_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma));
|
||
+static bfd_boolean coff_array_type
|
||
+ PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, bfd_boolean));
|
||
+static bfd_boolean coff_set_type PARAMS ((PTR, bfd_boolean));
|
||
+static bfd_boolean coff_offset_type PARAMS ((PTR));
|
||
+static bfd_boolean coff_method_type PARAMS ((PTR, bfd_boolean, int, bfd_boolean));
|
||
+static bfd_boolean coff_const_type PARAMS ((PTR));
|
||
+static bfd_boolean coff_volatile_type PARAMS ((PTR));
|
||
+static bfd_boolean coff_start_struct_type
|
||
+ PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int));
|
||
+static bfd_boolean coff_struct_field
|
||
+ PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility));
|
||
+static bfd_boolean coff_end_struct_type PARAMS ((PTR));
|
||
+static bfd_boolean coff_start_class_type
|
||
+ PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int, bfd_boolean,
|
||
+ bfd_boolean));
|
||
+static bfd_boolean coff_class_static_member
|
||
+ PARAMS ((PTR, const char *, const char *, enum debug_visibility));
|
||
+static bfd_boolean coff_class_baseclass
|
||
+ PARAMS ((PTR, bfd_vma, bfd_boolean, enum debug_visibility));
|
||
+static bfd_boolean coff_class_start_method PARAMS ((PTR, const char *));
|
||
+static bfd_boolean coff_class_method_variant
|
||
+ PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, bfd_boolean,
|
||
+ bfd_vma, bfd_boolean));
|
||
+static bfd_boolean coff_class_static_method_variant
|
||
+ PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, bfd_boolean));
|
||
+static bfd_boolean coff_class_end_method PARAMS ((PTR));
|
||
+static bfd_boolean coff_end_class_type PARAMS ((PTR));
|
||
+static bfd_boolean coff_typedef_type PARAMS ((PTR, const char *));
|
||
+static bfd_boolean coff_tag_type
|
||
+ PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind));
|
||
+static bfd_boolean coff_typdef PARAMS ((PTR, const char *));
|
||
+static bfd_boolean coff_tag PARAMS ((PTR, const char *));
|
||
+static bfd_boolean coff_int_constant PARAMS ((PTR, const char *, bfd_vma));
|
||
+static bfd_boolean coff_float_constant PARAMS ((PTR, const char *, double));
|
||
+static bfd_boolean coff_typed_constant PARAMS ((PTR, const char *, bfd_vma));
|
||
+static bfd_boolean coff_variable
|
||
+ PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma));
|
||
+static bfd_boolean coff_start_function PARAMS ((PTR, const char *, bfd_boolean));
|
||
+static bfd_boolean coff_function_parameter
|
||
+ PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma));
|
||
+static bfd_boolean coff_start_block PARAMS ((PTR, bfd_vma));
|
||
+static bfd_boolean coff_end_block PARAMS ((PTR, bfd_vma));
|
||
+static bfd_boolean coff_end_function PARAMS ((PTR));
|
||
+static bfd_boolean coff_lineno
|
||
+ PARAMS ((PTR, const char *, unsigned long, bfd_vma));
|
||
+
|
||
+static const struct debug_write_fns coff_fns =
|
||
+{
|
||
+ coff_start_compilation_unit,
|
||
+ coff_start_source,
|
||
+ coff_empty_type,
|
||
+ coff_void_type,
|
||
+ coff_int_type,
|
||
+ coff_float_type,
|
||
+ coff_complex_type,
|
||
+ coff_bool_type,
|
||
+ coff_enum_type,
|
||
+ coff_pointer_type,
|
||
+ coff_function_type,
|
||
+ coff_reference_type,
|
||
+ coff_range_type,
|
||
+ coff_array_type,
|
||
+ coff_set_type,
|
||
+ coff_offset_type,
|
||
+ coff_method_type,
|
||
+ coff_const_type,
|
||
+ coff_volatile_type,
|
||
+ coff_start_struct_type,
|
||
+ coff_struct_field,
|
||
+ coff_end_struct_type,
|
||
+ coff_start_class_type,
|
||
+ coff_class_static_member,
|
||
+ coff_class_baseclass,
|
||
+ coff_class_start_method,
|
||
+ coff_class_method_variant,
|
||
+ coff_class_static_method_variant,
|
||
+ coff_class_end_method,
|
||
+ coff_end_class_type,
|
||
+ coff_typedef_type,
|
||
+ coff_tag_type,
|
||
+ coff_typdef,
|
||
+ coff_tag,
|
||
+ coff_int_constant,
|
||
+ coff_float_constant,
|
||
+ coff_typed_constant,
|
||
+ coff_variable,
|
||
+ coff_start_function,
|
||
+ coff_function_parameter,
|
||
+ coff_start_block,
|
||
+ coff_end_block,
|
||
+ coff_end_function,
|
||
+ coff_lineno
|
||
+};
|
||
+
|
||
+/*
|
||
+ * Copy our input (non-debugging) symbols. Local symbols will be
|
||
+ * maintained in one bucket per each compilation unit, global (and
|
||
+ * weak) symbols will be kept in a simple array.
|
||
+ */
|
||
+static bfd_boolean
|
||
+coff_copy_symbols (info, count, sympp)
|
||
+ struct coff_write_handle *info;
|
||
+ long count;
|
||
+ asymbol **sympp;
|
||
+{
|
||
+ asymbol *osym;
|
||
+ long i;
|
||
+ struct coff_compilation_unit *up;
|
||
+
|
||
+ up = NULL;
|
||
+
|
||
+ for (i = 0; i < count; i++)
|
||
+ {
|
||
+ osym = sympp[i];
|
||
+
|
||
+ /* Try to figure out the .text and .data sections from our input
|
||
+ symbols as we walk them. Unfortunately, this ought to be the
|
||
+ /input/ section pointers, so their ->output_section is
|
||
+ non-NULL. That's why we can't simply walk through all the
|
||
+ sections of our abfd since this is describing the output
|
||
+ only. */
|
||
+ if (info->textsect == NULL && osym->section->flags & SEC_CODE)
|
||
+ /* Assume this to be our .text section. */
|
||
+ info->textsect = osym->section;
|
||
+ else if (info->datasect == NULL && osym->section->flags & SEC_DATA)
|
||
+ /* Assume this to be our .data section. */
|
||
+ info->datasect = osym->section;
|
||
+
|
||
+ if (osym->flags & BSF_FILE)
|
||
+ {
|
||
+ /* New file name. */
|
||
+ long l;
|
||
+
|
||
+ up = NULL;
|
||
+
|
||
+ /* Well, maybe an old one actually? If so, append it there.
|
||
+ This can happen for files that contribute to multiple
|
||
+ (input) sections that were concatenated by the linker
|
||
+ (like crt1.S). */
|
||
+ for (l = 0; l < info->nunits; l++)
|
||
+ {
|
||
+ if (strcmp (info->units[l].fname, osym->name) == 0)
|
||
+ {
|
||
+ up = info->units + l;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (up == NULL)
|
||
+ {
|
||
+ info->units = (struct coff_compilation_unit *)
|
||
+ xrealloc (info->units,
|
||
+ ++info->nunits * sizeof(struct coff_compilation_unit));
|
||
+ up = info->units + (info->nunits - 1);
|
||
+ up->fname = osym->name;
|
||
+ up->syms = NULL;
|
||
+ up->nsyms = up->totsyms = 0;
|
||
+ }
|
||
+ }
|
||
+ else if (osym->flags & (BSF_GLOBAL | BSF_WEAK))
|
||
+ {
|
||
+ /* Global (or weak) symbols are recorded outside compilation
|
||
+ units. */
|
||
+ info->globals = (asymbol **)
|
||
+ xrealloc (info->globals, ++info->nglobals * sizeof(asymbol *));
|
||
+ info->globals[info->nglobals - 1] = osym;
|
||
+ continue;
|
||
+ }
|
||
+ else if (!bfd_is_const_section(osym->section))
|
||
+ {
|
||
+ if (osym->flags & BSF_SECTION_SYM)
|
||
+ {
|
||
+ coff_symbol_type *csymp;
|
||
+ /* Just record them by now, they'll be fixed up later. */
|
||
+
|
||
+ if (info->nsyms == 0 && (info->flags & COFF_FL_AVR) == 0)
|
||
+ {
|
||
+ /* Very first symbol, fake a compilation unit name
|
||
+ for it. Historical precedence seems to dictate
|
||
+ this, but AVR COFF does not use that. */
|
||
+ csymp = (coff_symbol_type *)
|
||
+ coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (csymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ csymp->symbol.name = xstrdup ("<fake>");
|
||
+ csymp->symbol.value = 0;
|
||
+ csymp->symbol.udata.p = NULL;
|
||
+ csymp->native->u.syment.n_sclass = C_FILE;
|
||
+ /* force filename into aux entry */
|
||
+ csymp->native->u.syment.n_numaux = 1;
|
||
+ coff_record_symbol (info, csymp);
|
||
+ }
|
||
+
|
||
+ /* convert to COFF native section symbol */
|
||
+ csymp = (coff_symbol_type *)
|
||
+ coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (csymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ csymp->symbol.name = xstrdup (osym->section->name);
|
||
+ csymp->symbol.value = osym->section->output_section->vma;
|
||
+ csymp->symbol.flags = BSF_DEBUGGING | BSF_SECTION_SYM;
|
||
+ csymp->symbol.section = osym->section;
|
||
+ csymp->symbol.udata.p = NULL;
|
||
+ csymp->native->fix_scnlen = 1;
|
||
+ csymp->native->u.syment.n_sclass = C_STAT;
|
||
+ csymp->native->u.syment.n_type = T_NULL;
|
||
+ csymp->native->u.syment.n_numaux = 1;
|
||
+
|
||
+ coff_record_symbol (info, csymp);
|
||
+
|
||
+ info->secsyms = (coff_symbol_type **)
|
||
+ xrealloc (info->secsyms,
|
||
+ ++info->nsecsyms * sizeof(coff_symbol_type *));
|
||
+ info->secsyms[info->nsecsyms - 1] = csymp;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Local symbol in a named section, will be recorded
|
||
+ within the respective compilation unit. */
|
||
+ if (up == NULL)
|
||
+ {
|
||
+ fprintf (stderr,
|
||
+ _("Discarding local symbol outside any compilation unit"));
|
||
+ if (osym->name)
|
||
+ fprintf (stderr, ": %s", osym->name);
|
||
+ putc ('\n', stderr);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ up->syms = (asymbol **)
|
||
+ xrealloc (up->syms, ++up->nsyms * sizeof(asymbol *));
|
||
+ up->syms[up->nsyms - 1] = osym;
|
||
+ up->totsyms = up->nsyms;
|
||
+ continue;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Find a name in the symbol table. If found, the respective entry in
|
||
+ the symbol vector is zeroed, so after processing all debugging
|
||
+ symbols, only non-debugging symbols will remain. */
|
||
+static asymbol *
|
||
+coff_find_symbol (info, name, isfunction, global)
|
||
+ struct coff_write_handle *info;
|
||
+ const char *name;
|
||
+ bfd_boolean isfunction;
|
||
+ bfd_boolean global;
|
||
+{
|
||
+ asymbol *symp;
|
||
+ long i;
|
||
+ size_t namelen;
|
||
+
|
||
+ if (global)
|
||
+ {
|
||
+ for (i = 0; i < info->nglobals; i++)
|
||
+ {
|
||
+ symp = info->globals[i];
|
||
+ if (symp == NULL)
|
||
+ continue;
|
||
+ if (strcmp (name, symp->name) == 0
|
||
+ && ((symp->flags & BSF_FUNCTION) != 0) == (isfunction == TRUE))
|
||
+ {
|
||
+ info->globals[i] = NULL;
|
||
+ return symp;
|
||
+ }
|
||
+ }
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ if (info->currentfile == NULL)
|
||
+ return NULL;
|
||
+
|
||
+ /* For local symbols, the match optionally stops at a dot in the
|
||
+ symtab symbol's name; this is used by gcc to indicate
|
||
+ function-scope static symbols (e. g. symbol "foo" will become
|
||
+ "foo.1" in function scope). */
|
||
+ namelen = strlen (name);
|
||
+ for (i = 0; i < info->currentfile->nsyms; i++)
|
||
+ {
|
||
+ symp = info->currentfile->syms[i];
|
||
+ if (symp == NULL)
|
||
+ continue;
|
||
+ if (strncmp (name, symp->name, namelen) == 0
|
||
+ && (symp->name[namelen] == '\0' || symp->name[namelen] == '.')
|
||
+ && ((symp->flags & BSF_FUNCTION) != 0) == (isfunction == TRUE))
|
||
+ {
|
||
+ info->currentfile->syms[i] = NULL;
|
||
+ info->currentfile->totsyms--;
|
||
+ return symp;
|
||
+ }
|
||
+ }
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+static void
|
||
+coff_record_symbol (info, csymp)
|
||
+ struct coff_write_handle *info;
|
||
+ coff_symbol_type *csymp;
|
||
+{
|
||
+ struct coff_private_symdata *priv;
|
||
+
|
||
+ info->syms = (asymbol **) xrealloc (info->syms,
|
||
+ ++info->nsyms * sizeof (asymbol *));
|
||
+ info->syms[info->nsyms - 1] = (asymbol *)csymp;
|
||
+
|
||
+ if ((priv = csymp->symbol.udata.p) != NULL)
|
||
+ {
|
||
+ if (priv->shash != NULL)
|
||
+ {
|
||
+ struct coff_struct_hash_entry *shash = priv->shash;
|
||
+ shash->fixidxs = (long *)
|
||
+ xrealloc (shash->fixidxs, ++shash->nfixidxs * sizeof (long));
|
||
+ shash->fixidxs[shash->nfixidxs - 1] = info->nsyms - 1;
|
||
+ }
|
||
+ if (priv->ehash != NULL)
|
||
+ {
|
||
+ struct coff_enum_hash_entry *ehash = priv->ehash;
|
||
+ ehash->fixidxs = (long *)
|
||
+ xrealloc (ehash->fixidxs, ++ehash->nfixidxs * sizeof (long));
|
||
+ ehash->fixidxs[ehash->nfixidxs - 1] = info->nsyms - 1;
|
||
+ }
|
||
+ free (priv);
|
||
+ csymp->symbol.udata.p = NULL;
|
||
+ }
|
||
+
|
||
+ /* If there are any pending endndx fixes, pop the last element from
|
||
+ that stack, and record the current symbol for fixing. We need to
|
||
+ do this here since we need to record our current csymp->native
|
||
+ (where that csymp is completely unrelated to whatever symbol was
|
||
+ previously generated that requested the fixup). The stack of
|
||
+ pending fixes is required since several endndx fixes could be
|
||
+ nested, e. g. the start of a function has a pending fix that
|
||
+ needs to point to the first symbol after the function, but there
|
||
+ could be an anonymous struct definition inside that function's
|
||
+ local variables where the endndx needs to point after the last
|
||
+ symbol of this struct. Also, structs and unions could be nested.
|
||
+
|
||
+ Each call to coff_record_symbol() can fix at most one endndx
|
||
+ (even if more are pending in the stack), but that's OK.
|
||
+
|
||
+ Note that bfd/coffgen.c converts that csymp->native into a
|
||
+ symtable slot number after coff_renumber_symbols() has been
|
||
+ run. */
|
||
+ if (info->flags & COFF_FL_FIX_ENDNDX)
|
||
+ {
|
||
+ struct coff_fix_stack *fsp, *ofsp;
|
||
+ union internal_auxent *aux;
|
||
+
|
||
+ assert (info->fixes != NULL);
|
||
+
|
||
+ fsp = info->fixes;
|
||
+ ofsp = NULL;
|
||
+ while (fsp->next != NULL)
|
||
+ {
|
||
+ ofsp = fsp;
|
||
+ fsp = fsp->next;
|
||
+ }
|
||
+ if (ofsp == NULL)
|
||
+ info->fixes = NULL;
|
||
+ else
|
||
+ ofsp->next = NULL;
|
||
+
|
||
+ aux = &(fsp->native->u.auxent);
|
||
+ fsp->native->fix_end = 1;
|
||
+ aux->x_sym.x_fcnary.x_fcn.x_endndx.p = csymp->native;
|
||
+ free (fsp);
|
||
+
|
||
+ info->flags &= ~COFF_FL_FIX_ENDNDX;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Fixup AVR COFF register handling: they don't only mention the
|
||
+ starting register number, but all registers, each within one byte
|
||
+ of the value. Unused register positions are filled up with
|
||
+ 0xff. */
|
||
+static symvalue
|
||
+coff_fixup_avr_register (val, size)
|
||
+ symvalue val;
|
||
+ int size;
|
||
+{
|
||
+ union
|
||
+ {
|
||
+ unsigned char c[4];
|
||
+ symvalue v;
|
||
+ } u;
|
||
+
|
||
+ u.c[1] = u.c[2] = u.c[3] = 0xff;
|
||
+ u.c[0] = val;
|
||
+ if (size > 8)
|
||
+ u.c[1] = val + 1;
|
||
+ if (size > 16)
|
||
+ {
|
||
+ u.c[2] = val + 2;
|
||
+ u.c[3] = val + 3;
|
||
+ }
|
||
+
|
||
+ return u.v;
|
||
+}
|
||
+
|
||
+/* Initialize an entry in the hash tables. */
|
||
+
|
||
+static struct bfd_hash_entry *
|
||
+coff_name_type_newfunc (entry, table, string)
|
||
+ struct bfd_hash_entry *entry;
|
||
+ struct bfd_hash_table *table;
|
||
+ const char *string;
|
||
+{
|
||
+ struct coff_name_type_hash_entry *ret =
|
||
+ (struct coff_name_type_hash_entry *) entry;
|
||
+
|
||
+ /* Allocate the structure if it has not already been allocated by a
|
||
+ subclass. */
|
||
+ if (ret == NULL)
|
||
+ ret = ((struct coff_name_type_hash_entry *)
|
||
+ bfd_hash_allocate (table, sizeof *ret));
|
||
+ if (ret == NULL)
|
||
+ return NULL;
|
||
+
|
||
+ /* Call the allocation method of the superclass. */
|
||
+ ret = ((struct coff_name_type_hash_entry *)
|
||
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
|
||
+ if (ret)
|
||
+ {
|
||
+ /* Set local fields. */
|
||
+ ret->types = NULL;
|
||
+ ret->emitted = FALSE;
|
||
+ }
|
||
+
|
||
+ return (struct bfd_hash_entry *) ret;
|
||
+}
|
||
+
|
||
+static struct bfd_hash_entry *
|
||
+coff_struct_newfunc (entry, table, string)
|
||
+ struct bfd_hash_entry *entry;
|
||
+ struct bfd_hash_table *table;
|
||
+ const char *string;
|
||
+{
|
||
+ struct coff_struct_hash_entry *ret =
|
||
+ (struct coff_struct_hash_entry *) entry;
|
||
+
|
||
+ /* Allocate the structure if it has not already been allocated by a
|
||
+ subclass. */
|
||
+ if (ret == NULL)
|
||
+ ret = ((struct coff_struct_hash_entry *)
|
||
+ bfd_hash_allocate (table, sizeof *ret));
|
||
+ if (ret == NULL)
|
||
+ return NULL;
|
||
+
|
||
+ /* Call the allocation method of the superclass. */
|
||
+ ret = ((struct coff_struct_hash_entry *)
|
||
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
|
||
+ if (ret)
|
||
+ {
|
||
+ /* Set local fields. */
|
||
+ ret->types = NULL;
|
||
+ ret->emitted = FALSE;
|
||
+ ret->fixidxs = NULL;
|
||
+ ret->nfixidxs = 0;
|
||
+ ret->native = NULL;
|
||
+ }
|
||
+
|
||
+ return (struct bfd_hash_entry *) ret;
|
||
+}
|
||
+
|
||
+static struct bfd_hash_entry *
|
||
+coff_enum_newfunc (entry, table, string)
|
||
+ struct bfd_hash_entry *entry;
|
||
+ struct bfd_hash_table *table;
|
||
+ const char *string;
|
||
+{
|
||
+ struct coff_enum_hash_entry *ret =
|
||
+ (struct coff_enum_hash_entry *) entry;
|
||
+
|
||
+ /* Allocate the structure if it has not already been allocated by a
|
||
+ subclass. */
|
||
+ if (ret == NULL)
|
||
+ ret = ((struct coff_enum_hash_entry *)
|
||
+ bfd_hash_allocate (table, sizeof *ret));
|
||
+ if (ret == NULL)
|
||
+ return NULL;
|
||
+
|
||
+ /* Call the allocation method of the superclass. */
|
||
+ ret = ((struct coff_enum_hash_entry *)
|
||
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
|
||
+ if (ret)
|
||
+ {
|
||
+ /* Set local fields. */
|
||
+ ret->types = NULL;
|
||
+ ret->emitted = FALSE;
|
||
+ ret->fixidxs = NULL;
|
||
+ ret->nfixidxs = 0;
|
||
+ ret->native = NULL;
|
||
+ }
|
||
+
|
||
+ return (struct bfd_hash_entry *) ret;
|
||
+}
|
||
+
|
||
+/* Look up an entry in the hash tables. */
|
||
+
|
||
+#define coff_name_type_hash_lookup(table, string, create, copy) \
|
||
+ ((struct coff_name_type_hash_entry *) \
|
||
+ bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
|
||
+
|
||
+/* Traverse the hash table. */
|
||
+
|
||
+#define coff_name_type_hash_traverse(table, func, info) \
|
||
+ (bfd_hash_traverse \
|
||
+ (&(table)->root, \
|
||
+ (bfd_boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func), \
|
||
+ (info)))
|
||
+
|
||
+#define coff_struct_hash_lookup(table, string, create, copy) \
|
||
+ ((struct coff_struct_hash_entry *) \
|
||
+ bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
|
||
+
|
||
+/* Traverse the hash table. */
|
||
+
|
||
+#define coff_struct_hash_traverse(table, func, info) \
|
||
+ (bfd_hash_traverse \
|
||
+ (&(table)->root, \
|
||
+ (bfd_boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func), \
|
||
+ (info)))
|
||
+
|
||
+#define coff_enum_hash_lookup(table, string, create, copy) \
|
||
+ ((struct coff_enum_hash_entry *) \
|
||
+ bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
|
||
+
|
||
+/* Traverse the hash table. */
|
||
+
|
||
+#define coff_enum_hash_traverse(table, func, info) \
|
||
+ (bfd_hash_traverse \
|
||
+ (&(table)->root, \
|
||
+ (bfd_boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func), \
|
||
+ (info)))
|
||
+
|
||
+#define coff_push_type(kind) \
|
||
+ tst = (struct coff_type_stack *) xmalloc (sizeof (struct coff_type_stack)); \
|
||
+ memset (tst, 0, sizeof (*tst)); \
|
||
+ tst->next = info->tstack; \
|
||
+ tst->tsk = kind; \
|
||
+ info->tstack = tst
|
||
+
|
||
+#define coff_pop_type() \
|
||
+ tst = info->tstack; \
|
||
+ if (tst == NULL) { \
|
||
+ fprintf (stderr, _("empty type stack in coff_pop_type()\n")); \
|
||
+ return FALSE; \
|
||
+ } \
|
||
+ info->tstack = tst->next; \
|
||
+ tst->next = NULL
|
||
+
|
||
+#define coff_complain_unsupp(s) \
|
||
+ fprintf (stderr, _("%s type not supported in %s\n"), \
|
||
+ s, info->abfd->xvec->name); \
|
||
+ return FALSE
|
||
+
|
||
+/* These function is called via the hash traverse routine when freeing
|
||
+ a hash table (at the end of a translation unit). */
|
||
+static bfd_boolean
|
||
+coff_free_type_info (h, p)
|
||
+ struct coff_name_type_hash_entry *h;
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_type_stack *tst, *otst;
|
||
+
|
||
+ for (tst = h->types; tst != NULL;)
|
||
+ {
|
||
+ otst = tst;
|
||
+ tst = tst->next;
|
||
+ free (otst);
|
||
+ }
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+static bfd_boolean
|
||
+coff_free_struct_info (h, p)
|
||
+ struct coff_struct_hash_entry *h;
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_type_stack *tst, *otst, *xtst, *xotst;
|
||
+ struct coff_struct_fields *fp;
|
||
+ long i;
|
||
+
|
||
+ for (tst = h->types; tst != NULL;)
|
||
+ {
|
||
+ otst = tst;
|
||
+ if (tst->u.ts_struct.tagismalloced)
|
||
+ free (tst->u.ts_struct.tag.malloctag);
|
||
+ for (i = 0, fp = tst->u.ts_struct.fields;
|
||
+ i < tst->u.ts_struct.nfields;
|
||
+ i++, fp++)
|
||
+ {
|
||
+ xtst = fp->types;
|
||
+ while (xtst != NULL)
|
||
+ {
|
||
+ xotst = xtst->next;
|
||
+ free (xtst);
|
||
+ xtst = xotst;
|
||
+ }
|
||
+ }
|
||
+ free (tst->u.ts_struct.fields);
|
||
+ tst = tst->next;
|
||
+ free (otst);
|
||
+ }
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+static bfd_boolean
|
||
+coff_free_enum_info (h, p)
|
||
+ struct coff_enum_hash_entry *h;
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_type_stack *tst, *otst;
|
||
+
|
||
+ for (tst = h->types; tst != NULL;)
|
||
+ {
|
||
+ otst = tst;
|
||
+ if (tst->u.ts_enum.tagismalloced)
|
||
+ free (tst->u.ts_enum.tag.malloctag);
|
||
+ tst = tst->next;
|
||
+ free (otst);
|
||
+ }
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+static unsigned int
|
||
+coff_get_fundamental_type (info, tst)
|
||
+ struct coff_write_handle *info ATTRIBUTE_UNUSED;
|
||
+ struct coff_type_stack *tst;
|
||
+{
|
||
+ size_t i;
|
||
+
|
||
+ /* See if one of our predefined types will fit. */
|
||
+ if (tst->tsk == TS_INT)
|
||
+ {
|
||
+ for (i = 0;
|
||
+ i < sizeof coff_predef_types / sizeof (struct coff_predef_type);
|
||
+ i++)
|
||
+ {
|
||
+ if (coff_predef_types[i].kind == TS_INT
|
||
+ && coff_predef_types[i].size == tst->u.ts_int.size
|
||
+ && coff_predef_types[i].isunsigned == tst->u.ts_int.isunsigned)
|
||
+ return coff_predef_types[i].slot;
|
||
+ }
|
||
+ fprintf (stderr,
|
||
+ _("%ssigned %d-bit integer type not available in COFF\n"),
|
||
+ tst->u.ts_int.isunsigned? "un": "", tst->u.ts_int.size * 8);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ for (i = 0;
|
||
+ i < sizeof coff_predef_types / sizeof (struct coff_predef_type);
|
||
+ i++)
|
||
+ {
|
||
+ if (coff_predef_types[i].kind == TS_FLOAT
|
||
+ && coff_predef_types[i].size == tst->u.ts_float.size)
|
||
+ return coff_predef_types[i].slot;
|
||
+ }
|
||
+ fprintf (stderr, _("%d-bit float type not available in COFF\n"),
|
||
+ tst->u.ts_float.size * 8);
|
||
+ }
|
||
+
|
||
+ return T_NULL;
|
||
+}
|
||
+
|
||
+static bfd_boolean
|
||
+coff_make_typed_symbol (info, csympp, stopat)
|
||
+ struct coff_write_handle *info;
|
||
+ coff_symbol_type **csympp;
|
||
+ enum ts_kind stopat;
|
||
+{
|
||
+ struct coff_type_stack *tst;
|
||
+ union internal_auxent *aux;
|
||
+ struct coff_struct_hash_entry *shash;
|
||
+ struct coff_enum_hash_entry *ehash;
|
||
+ struct coff_private_symdata *priv;
|
||
+ unsigned int type, numaux, arydim, size, i, nele, nderived;
|
||
+ const char *name;
|
||
+ bfd_boolean oldavrcoff = (info->flags & (COFF_FL_AVR | COFF_FL_EXT_AVR))
|
||
+ == COFF_FL_AVR;
|
||
+
|
||
+ /* Synthesize a new internal COFF symbol. */
|
||
+ *csympp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (*csympp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ priv = (struct coff_private_symdata *) xmalloc (sizeof *priv);
|
||
+ memset (priv, 0, sizeof *priv);
|
||
+
|
||
+ type = arydim = size = nderived = 0;
|
||
+
|
||
+ aux = &(((*csympp)->native + 1)->u.auxent);
|
||
+
|
||
+ /* Now, walk the type stack, and see how we could convert the info
|
||
+ we've got to what COFF understands. */
|
||
+ for (;;)
|
||
+ {
|
||
+ if (info->tstack == NULL)
|
||
+ break;
|
||
+
|
||
+ /* If we have been advised to not pop the entire stack, stop
|
||
+ here. */
|
||
+ if (info->tstack->tsk == stopat && info->tstack->next == NULL)
|
||
+ break;
|
||
+
|
||
+ coff_pop_type ();
|
||
+
|
||
+ switch (tst->tsk)
|
||
+ {
|
||
+ case TS_NONE:
|
||
+ /* cannot happen */
|
||
+ break;
|
||
+
|
||
+ case TS_EMPTY:
|
||
+ if (info->tstack != NULL && info->tstack->tsk != stopat)
|
||
+ fprintf (stderr, _("empty type not last on type stack\n"));
|
||
+ /* type |= T_NULL; */
|
||
+ break;
|
||
+
|
||
+ case TS_VOID:
|
||
+ if (info->tstack != NULL && info->tstack->tsk != stopat)
|
||
+ fprintf (stderr, _("void type not last on type stack\n"));
|
||
+ type |= T_VOID;
|
||
+ break;
|
||
+
|
||
+ case TS_INT:
|
||
+ if (info->tstack != NULL && info->tstack->tsk != stopat)
|
||
+ fprintf (stderr, _("int type not last on type stack\n"));
|
||
+ type |= coff_get_fundamental_type (info, tst);
|
||
+ if (size == 0)
|
||
+ size = tst->u.ts_int.size;
|
||
+ break;
|
||
+
|
||
+ case TS_FLOAT:
|
||
+ if (info->tstack != NULL && info->tstack->tsk != stopat)
|
||
+ fprintf (stderr, _("float type not last on type stack\n"));
|
||
+ type |= coff_get_fundamental_type (info, tst);
|
||
+ if (size == 0)
|
||
+ size = tst->u.ts_float.size;
|
||
+ break;
|
||
+
|
||
+ case TS_POINTER:
|
||
+ nderived++;
|
||
+ type = ((type & ~N_BTMASK) << N_TSHIFT) | (DT_PTR << N_BTSHFT);
|
||
+ size = info->pointersize;
|
||
+ break;
|
||
+
|
||
+ case TS_FUNC:
|
||
+ nderived++;
|
||
+ type = ((type & ~N_BTMASK) << N_TSHIFT) | (DT_FCN << N_BTSHFT);
|
||
+ /* AUX entry for DT_FCN will be filled in elsewhere. */
|
||
+ break;
|
||
+
|
||
+ case TS_ARRAY:
|
||
+ /* We need to limit arydim so the assignment below won't
|
||
+ overwrite random locations. */
|
||
+ if (arydim >= DIMNUM)
|
||
+ {
|
||
+ fprintf (stderr,
|
||
+ _("More than %d array dimensions, result is invalid.\n"),
|
||
+ DIMNUM);
|
||
+ arydim = DIMNUM - 1;
|
||
+ }
|
||
+ nderived++;
|
||
+ type = ((type & ~N_BTMASK) << N_TSHIFT) | (DT_ARY << N_BTSHFT);
|
||
+ aux->x_sym.x_fcnary.x_ary.x_dimen[arydim++] =
|
||
+ tst->u.ts_array.high - tst->u.ts_array.low + 1;
|
||
+
|
||
+ break;
|
||
+
|
||
+ case TS_COMPLEX:
|
||
+ coff_complain_unsupp (_("complex"));
|
||
+
|
||
+ case TS_ENUM:
|
||
+ type |= T_ENUM;
|
||
+ if (size == 0)
|
||
+ size = info->enumsize;
|
||
+
|
||
+ if (tst->u.ts_enum.ehash != NULL)
|
||
+ {
|
||
+ /* enum tag will be fixed later. */
|
||
+ priv->ehash = tst->u.ts_enum.ehash;
|
||
+ break;
|
||
+ }
|
||
+ if (tst->u.ts_enum.tagismalloced)
|
||
+ name = tst->u.ts_enum.tag.malloctag;
|
||
+ else
|
||
+ name = tst->u.ts_enum.tag.fixtag;
|
||
+ ehash = coff_enum_hash_lookup (&info->enums, name,
|
||
+ TRUE, tst->u.ts_enum.tagismalloced);
|
||
+ if (ehash == NULL)
|
||
+ return FALSE;
|
||
+ if (!ehash->emitted)
|
||
+ {
|
||
+ if (ehash->types == NULL)
|
||
+ {
|
||
+ ehash->types = (struct coff_type_stack *)
|
||
+ xmalloc (sizeof (struct coff_type_stack));
|
||
+ memcpy (ehash->types, tst, sizeof (struct coff_type_stack));
|
||
+ }
|
||
+ ehash->emitted = TRUE;
|
||
+ coff_emit_enum (info, tst, ehash);
|
||
+ if (ehash->nfixidxs != 0)
|
||
+ {
|
||
+ coff_symbol_type *symp;
|
||
+ unsigned i;
|
||
+
|
||
+ for (i = 0; i < ehash->nfixidxs; i++)
|
||
+ {
|
||
+ combined_entry_type *np;
|
||
+
|
||
+ symp = (coff_symbol_type *) info->syms[ehash->fixidxs[i]];
|
||
+ symp->native->u.syment.n_type &= ~N_BTMASK;
|
||
+ symp->native->u.syment.n_type |= T_ENUM;
|
||
+
|
||
+ if (oldavrcoff)
|
||
+ continue;
|
||
+
|
||
+ np = symp->native + 1;
|
||
+ np->fix_tag = 1;
|
||
+ np->u.auxent.x_sym.x_tagndx.p = ehash->native;
|
||
+ if (np->u.auxent.x_sym.x_misc.x_fsize == 0)
|
||
+ np->u.auxent.x_sym.x_misc.x_lnsz.x_size = size;
|
||
+ }
|
||
+
|
||
+ free (ehash->fixidxs);
|
||
+ ehash->nfixidxs = 0;
|
||
+ }
|
||
+ }
|
||
+ if (!oldavrcoff)
|
||
+ {
|
||
+ ((*csympp)->native + 1)->fix_tag = 1;
|
||
+ aux->x_sym.x_tagndx.p = ehash->native;
|
||
+ if (aux->x_sym.x_misc.x_fsize == 0)
|
||
+ aux->x_sym.x_misc.x_lnsz.x_size = size;
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case TS_STRUCT:
|
||
+ if (tst->u.ts_struct.isstruct)
|
||
+ type |= T_STRUCT;
|
||
+ else
|
||
+ type |= T_UNION;
|
||
+ if (size == 0)
|
||
+ size = tst->u.ts_struct.size;
|
||
+
|
||
+ if (tst->u.ts_struct.shash != NULL)
|
||
+ {
|
||
+ /* struct tag will be fixed later. */
|
||
+ priv->shash = tst->u.ts_struct.shash;
|
||
+ break;
|
||
+ }
|
||
+ if (tst->u.ts_struct.tagismalloced)
|
||
+ name = tst->u.ts_struct.tag.malloctag;
|
||
+ else
|
||
+ name = tst->u.ts_struct.tag.fixtag;
|
||
+ shash = coff_struct_hash_lookup (&info->structs, name,
|
||
+ TRUE, tst->u.ts_struct.tagismalloced);
|
||
+ if (shash == NULL)
|
||
+ return FALSE;
|
||
+ if (!shash->emitted)
|
||
+ {
|
||
+ if (shash->types == NULL)
|
||
+ {
|
||
+ shash->types = (struct coff_type_stack *)
|
||
+ xmalloc (sizeof (struct coff_type_stack));
|
||
+ memcpy (shash->types, tst, sizeof (struct coff_type_stack));
|
||
+ }
|
||
+ shash->emitted = TRUE;
|
||
+ coff_emit_struct (info, tst, shash);
|
||
+ if (shash->nfixidxs != 0)
|
||
+ {
|
||
+ coff_symbol_type *symp;
|
||
+ unsigned i;
|
||
+
|
||
+ for (i = 0; i < shash->nfixidxs; i++)
|
||
+ {
|
||
+ combined_entry_type *np;
|
||
+
|
||
+ symp = (coff_symbol_type *) info->syms[shash->fixidxs[i]];
|
||
+ symp->native->u.syment.n_type &= ~N_BTMASK;
|
||
+ if (tst->u.ts_struct.isstruct)
|
||
+ symp->native->u.syment.n_type |= T_STRUCT;
|
||
+ else
|
||
+ symp->native->u.syment.n_type |= T_UNION;
|
||
+
|
||
+ if (oldavrcoff)
|
||
+ continue;
|
||
+
|
||
+ np = symp->native + 1;
|
||
+ np->fix_tag = 1;
|
||
+ np->u.auxent.x_sym.x_tagndx.p = shash->native;
|
||
+ if (np->u.auxent.x_sym.x_misc.x_fsize == 0)
|
||
+ np->u.auxent.x_sym.x_misc.x_lnsz.x_size = size;
|
||
+ }
|
||
+
|
||
+ free (shash->fixidxs);
|
||
+ shash->nfixidxs = 0;
|
||
+ }
|
||
+ }
|
||
+ if (!oldavrcoff)
|
||
+ {
|
||
+ ((*csympp)->native + 1)->fix_tag = 1;
|
||
+ aux->x_sym.x_tagndx.p = shash->native;
|
||
+ if (aux->x_sym.x_misc.x_fsize == 0)
|
||
+ aux->x_sym.x_misc.x_lnsz.x_size = size;
|
||
+ }
|
||
+ break;
|
||
+ }
|
||
+ free (tst);
|
||
+ }
|
||
+
|
||
+ if (nderived > 6)
|
||
+ fprintf (stderr,
|
||
+ _("More than 6 derived type specifiers, result is invalid.\n"));
|
||
+
|
||
+ /* Our type computation so far used the reverse order for derived
|
||
+ type specifiers. Fix this here if there was more than one
|
||
+ derived type specifier. */
|
||
+ if (nderived > 1)
|
||
+ {
|
||
+ unsigned int nty, bty;
|
||
+ bty = type & N_BTMASK;
|
||
+ type = type >> N_BTSHFT;
|
||
+ nty = 0;
|
||
+ while (nderived-- > 0)
|
||
+ {
|
||
+ nty = (nty << N_TSHIFT) | (type & (N_TMASK >> N_BTSHFT));
|
||
+ type >>= N_TSHIFT;
|
||
+ }
|
||
+ type = (nty << N_BTSHFT) | bty;
|
||
+ }
|
||
+
|
||
+ if (ISARY (type))
|
||
+ {
|
||
+ /* Compute size of entire array. */
|
||
+ for (i = 0, nele = 1; i < arydim; i++)
|
||
+ nele *= aux->x_sym.x_fcnary.x_ary.x_dimen[i];
|
||
+ aux->x_sym.x_misc.x_lnsz.x_size = size * nele;
|
||
+ }
|
||
+
|
||
+ numaux = 0;
|
||
+ if (ISARY (type) || ISFCN (type))
|
||
+ numaux++;
|
||
+ if ((BTYPE (type) == T_STRUCT || BTYPE (type) == T_UNION
|
||
+ || BTYPE (type) == T_ENUM)
|
||
+ && !oldavrcoff)
|
||
+ numaux++;
|
||
+ /* Only AVR COFF uses multiple AUX entries. */
|
||
+ if (numaux > 1 && (info->flags & COFF_FL_AVR) == 0)
|
||
+ numaux = 1;
|
||
+
|
||
+ priv->size = size;
|
||
+ (*csympp)->symbol.udata.p = priv;
|
||
+ (*csympp)->native->u.syment.n_type = type;
|
||
+ (*csympp)->native->u.syment.n_numaux = numaux;
|
||
+
|
||
+ /* If the fundamental type comes out as T_NULL, this means we don't
|
||
+ have any type information. Just don't emit any aux entries in
|
||
+ that case, and drop any derived type information as well. */
|
||
+ if (BTYPE (type) == T_NULL)
|
||
+ {
|
||
+ printf ("coff_make_typed_symbol() -> T_NULL\n");
|
||
+ //(*csympp)->native->u.syment.n_type = T_NULL;
|
||
+ (*csympp)->native->u.syment.n_numaux = 0;
|
||
+ }
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+static bfd_boolean coff_emit_struct (info, tst, shash)
|
||
+ struct coff_write_handle *info;
|
||
+ struct coff_type_stack *tst;
|
||
+ struct coff_struct_hash_entry *shash;
|
||
+{
|
||
+ coff_symbol_type *csymp, *scsymp, *ecsymp;
|
||
+ union internal_auxent *aux;
|
||
+ struct coff_fix_stack *fixp, *ofp;
|
||
+ bfd_boolean isstruct = tst->u.ts_struct.isstruct;
|
||
+ bfd_boolean isbitfield = FALSE;
|
||
+ struct coff_type_stack *savedtst;
|
||
+ struct coff_struct_fields *fp;
|
||
+ unsigned short sclass;
|
||
+ long i;
|
||
+
|
||
+ if ((info->flags & (COFF_FL_AVR | COFF_FL_EXT_AVR)) ==
|
||
+ COFF_FL_AVR)
|
||
+ /* old AVR COFF doesn't support struct debugging */
|
||
+ return TRUE;
|
||
+
|
||
+ /* Synthesize a new internal COFF symbol for the struct/union. */
|
||
+ scsymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (scsymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ if (tst->u.ts_struct.tagismalloced)
|
||
+ scsymp->symbol.name = xstrdup (tst->u.ts_struct.tag.malloctag);
|
||
+ else
|
||
+ scsymp->symbol.name = tst->u.ts_struct.tag.fixtag;
|
||
+ scsymp->symbol.flags = BSF_NOT_AT_END;
|
||
+ scsymp->symbol.section = bfd_und_section_ptr;
|
||
+ scsymp->native->u.syment.n_sclass = isstruct? C_STRTAG: C_UNTAG;
|
||
+ scsymp->native->u.syment.n_type = isstruct? T_STRUCT: T_UNION;
|
||
+ scsymp->native->u.syment.n_numaux = 1;
|
||
+ scsymp->symbol.udata.p = NULL;
|
||
+ scsymp->symbol.value = 0;
|
||
+
|
||
+ shash->native = scsymp->native;
|
||
+
|
||
+ /* Synthesize a new internal COFF symbol for the end of struct/union. */
|
||
+ ecsymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (ecsymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ ecsymp->symbol.name = ".eos";
|
||
+ ecsymp->symbol.flags = BSF_NOT_AT_END;
|
||
+ /* We need to use the com section here since bfd/coffgen.c
|
||
+ translates this into an N_UNDEF one without clobbering the
|
||
+ value. */
|
||
+ ecsymp->symbol.section = bfd_com_section_ptr;
|
||
+ ecsymp->native->u.syment.n_sclass = C_EOS;
|
||
+ ecsymp->symbol.udata.p = NULL;
|
||
+ ecsymp->symbol.value = tst->u.ts_struct.size;
|
||
+ ecsymp->native->u.syment.n_numaux = 1;
|
||
+ (ecsymp->native + 1)->fix_tag = 1;
|
||
+ aux = &((ecsymp->native + 1)->u.auxent);
|
||
+ aux->x_sym.x_tagndx.p = scsymp->native;
|
||
+ aux->x_sym.x_misc.x_lnsz.x_size = tst->u.ts_struct.size;
|
||
+
|
||
+ coff_record_symbol (info, scsymp);
|
||
+
|
||
+ savedtst = info->tstack;
|
||
+
|
||
+ if (isstruct)
|
||
+ {
|
||
+ /* First, make a quick walk along all the fields, and figure out
|
||
+ * whether we've got a genuine struct or a bitfield struct. */
|
||
+ for (i = 0, fp = tst->u.ts_struct.fields;
|
||
+ i < tst->u.ts_struct.nfields;
|
||
+ i++, fp++)
|
||
+ if (fp->bitsize % 8 != 0)
|
||
+ {
|
||
+ isbitfield = TRUE;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ sclass = isstruct? (isbitfield? C_FIELD: C_MOS): C_MOU;
|
||
+
|
||
+ for (i = 0, fp = tst->u.ts_struct.fields;
|
||
+ i < tst->u.ts_struct.nfields;
|
||
+ i++, fp++)
|
||
+ {
|
||
+ if (strlen (fp->name) == 0)
|
||
+ {
|
||
+ /* empty name could happen inside bitfield */
|
||
+ fp->types = NULL;
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ info->tstack = fp->types;
|
||
+ if (!coff_make_typed_symbol (info, &csymp, TS_NONE))
|
||
+ return FALSE;
|
||
+
|
||
+ csymp->symbol.name = xstrdup (fp->name);
|
||
+ csymp->symbol.flags = BSF_NOT_AT_END;
|
||
+ csymp->symbol.section = bfd_com_section_ptr;
|
||
+ csymp->native->u.syment.n_sclass = sclass;
|
||
+ csymp->symbol.value = isbitfield? fp->bitpos: fp->bitpos / 8;
|
||
+ if (isbitfield)
|
||
+ {
|
||
+ csymp->native->u.syment.n_numaux = 1;
|
||
+ aux = &((csymp->native + 1)->u.auxent);
|
||
+ aux->x_sym.x_misc.x_lnsz.x_size = fp->bitsize;
|
||
+ }
|
||
+
|
||
+ coff_record_symbol (info, csymp);
|
||
+
|
||
+ fp->types = NULL;
|
||
+ }
|
||
+
|
||
+ info->tstack = savedtst;
|
||
+
|
||
+ /* Record our endndx field for later fixing. */
|
||
+ fixp = (struct coff_fix_stack *) xmalloc (sizeof (struct coff_fix_stack));
|
||
+ fixp->native = scsymp->native + 1; /* points to first AUX */
|
||
+ fixp->next = NULL;
|
||
+ if (info->fixes == NULL)
|
||
+ info->fixes = fixp;
|
||
+ else
|
||
+ {
|
||
+ for (ofp = info->fixes; ofp->next != NULL;)
|
||
+ ofp = ofp->next;
|
||
+ ofp->next = fixp;
|
||
+ }
|
||
+
|
||
+ coff_record_symbol (info, ecsymp);
|
||
+ info->flags |= COFF_FL_FIX_ENDNDX;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+static bfd_boolean coff_emit_enum (info, tst, ehash)
|
||
+ struct coff_write_handle *info;
|
||
+ struct coff_type_stack *tst;
|
||
+ struct coff_enum_hash_entry *ehash;
|
||
+{
|
||
+ coff_symbol_type *csymp, *scsymp, *ecsymp;
|
||
+ union internal_auxent *aux;
|
||
+ struct coff_fix_stack *fixp, *ofp;
|
||
+ int i;
|
||
+
|
||
+ if ((info->flags & (COFF_FL_AVR | COFF_FL_EXT_AVR)) ==
|
||
+ COFF_FL_AVR)
|
||
+ /* old AVR COFF doesn't support enum debugging */
|
||
+ return TRUE;
|
||
+
|
||
+ /* Synthesize a new internal COFF symbol for the enum. */
|
||
+ scsymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (scsymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ if (tst->u.ts_enum.tagismalloced)
|
||
+ scsymp->symbol.name = xstrdup (tst->u.ts_enum.tag.malloctag);
|
||
+ else
|
||
+ scsymp->symbol.name = tst->u.ts_enum.tag.fixtag;
|
||
+ scsymp->symbol.flags = BSF_NOT_AT_END;
|
||
+ scsymp->symbol.section = bfd_und_section_ptr;
|
||
+ scsymp->native->u.syment.n_sclass = C_ENTAG;
|
||
+ scsymp->native->u.syment.n_type = T_ENUM;
|
||
+ scsymp->native->u.syment.n_numaux = 1;
|
||
+ scsymp->symbol.udata.p = NULL;
|
||
+ scsymp->symbol.value = 0;
|
||
+
|
||
+ ehash->native = scsymp->native;
|
||
+
|
||
+ /* Synthesize a new internal COFF symbol for the end of struct/union. */
|
||
+ ecsymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (ecsymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ ecsymp->symbol.name = ".eos";
|
||
+ ecsymp->symbol.flags = BSF_NOT_AT_END;
|
||
+ /* We need to use the com section here since bfd/coffgen.c
|
||
+ translates this into an N_UNDEF one without clobbering the
|
||
+ value. */
|
||
+ ecsymp->symbol.section = bfd_com_section_ptr;
|
||
+ ecsymp->native->u.syment.n_sclass = C_EOS;
|
||
+ ecsymp->symbol.udata.p = NULL;
|
||
+ ecsymp->symbol.value = info->enumsize;
|
||
+ ecsymp->native->u.syment.n_numaux = 1;
|
||
+ (ecsymp->native + 1)->fix_tag = 1;
|
||
+ aux = &((ecsymp->native + 1)->u.auxent);
|
||
+ aux->x_sym.x_tagndx.p = scsymp->native;
|
||
+ aux->x_sym.x_misc.x_lnsz.x_size = info->enumsize;
|
||
+
|
||
+ coff_record_symbol (info, scsymp);
|
||
+
|
||
+ for (i = 0;; i++)
|
||
+ {
|
||
+ const char *name = tst->u.ts_enum.names[i];
|
||
+ if (name == NULL)
|
||
+ break;
|
||
+
|
||
+ /* Synthesize a new internal COFF symbol for the enum. */
|
||
+ csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (csymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ csymp->symbol.name = xstrdup (name);
|
||
+ csymp->symbol.flags = BSF_NOT_AT_END;
|
||
+ csymp->symbol.section = bfd_com_section_ptr;
|
||
+ csymp->native->u.syment.n_sclass = C_MOE;
|
||
+ csymp->symbol.udata.p = NULL;
|
||
+ csymp->symbol.value = tst->u.ts_enum.vals[i];
|
||
+
|
||
+ coff_record_symbol (info, csymp);
|
||
+ }
|
||
+
|
||
+ /* Record our endndx field for later fixing. */
|
||
+ fixp = (struct coff_fix_stack *) xmalloc (sizeof (struct coff_fix_stack));
|
||
+ fixp->native = scsymp->native + 1; /* points to first AUX */
|
||
+ fixp->next = NULL;
|
||
+ if (info->fixes == NULL)
|
||
+ info->fixes = fixp;
|
||
+ else
|
||
+ {
|
||
+ for (ofp = info->fixes; ofp->next != NULL;)
|
||
+ ofp = ofp->next;
|
||
+ ofp->next = fixp;
|
||
+ }
|
||
+
|
||
+ coff_record_symbol (info, ecsymp);
|
||
+ info->flags |= COFF_FL_FIX_ENDNDX;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Emit a non-debugging symbol that came from the input symbol table,
|
||
+ and has not been claimed by one of the debugging symbols. */
|
||
+static bfd_boolean
|
||
+coff_emit_ndebug_sym (info, osymp, localp)
|
||
+ struct coff_write_handle *info;
|
||
+ asymbol *osymp;
|
||
+ bfd_boolean localp;
|
||
+{
|
||
+ coff_symbol_type *csymp;
|
||
+
|
||
+ /* Create new COFF symbol. */
|
||
+ csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (csymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ csymp->symbol.name = xstrdup (osymp->name);
|
||
+ csymp->symbol.value = osymp->value;
|
||
+ csymp->symbol.flags = localp? BSF_LOCAL: BSF_GLOBAL;
|
||
+ csymp->symbol.section = osymp->section;
|
||
+ csymp->symbol.udata.p = NULL;
|
||
+ csymp->native->u.syment.n_sclass = localp? C_STAT: C_EXT;
|
||
+ csymp->native->u.syment.n_type = T_NULL;
|
||
+
|
||
+ coff_record_symbol (info, csymp);
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* The general routine to write out COFF debugging information. This
|
||
+ synthesizes and accumulates the COFF symbols. Actual symbol table
|
||
+ output is performed later on by the BFD functions. ABFD is the BFD
|
||
+ and DHANDLE is the handle for the debugging information. symcountp
|
||
+ and symppp point to the incoming (parsed) symbol list on entry, and
|
||
+ will be updated to point to the new symbol table's values upon
|
||
+ exit. */
|
||
+
|
||
+bfd_boolean
|
||
+write_coff_debugging_info (abfd, dhandle, symcountp, symppp)
|
||
+ bfd *abfd;
|
||
+ PTR dhandle;
|
||
+ long *symcountp;
|
||
+ asymbol ***symppp;
|
||
+{
|
||
+ struct coff_write_handle info;
|
||
+ long i, l;
|
||
+ asymbol *symp;
|
||
+ struct coff_compilation_unit *up;
|
||
+ coff_symbol_type *csymp;
|
||
+
|
||
+ memset ((void *)&info, 0, sizeof info);
|
||
+
|
||
+ info.abfd = abfd;
|
||
+
|
||
+ info.pointersize = info.enumsize = 4;
|
||
+
|
||
+ switch (bfd_get_arch (abfd))
|
||
+ {
|
||
+ case bfd_arch_avr:
|
||
+ info.flags |= COFF_FL_AVR;
|
||
+ if (strcmp (abfd->xvec->name, "coff-ext-avr") == 0)
|
||
+ info.flags |= COFF_FL_EXT_AVR;
|
||
+ /* Fix the builtin type sizes. */
|
||
+ coff_predef_types[0].size = 2; /* sizeof(int) == 2 */
|
||
+ coff_predef_types[4].size = 4; /* sizeof(double) == 4 */
|
||
+ coff_predef_types[6].size = 2; /* sizeof(unsigned int) == 2 */
|
||
+ info.pointersize = info.enumsize = 2;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ ;
|
||
+ }
|
||
+
|
||
+ coff_copy_symbols(&info, *symcountp, *symppp);
|
||
+
|
||
+ if (info.textsect == NULL)
|
||
+ {
|
||
+ fprintf (stderr, _("Warning: no \"text\" section found in output file\n"));
|
||
+ info.textsect = bfd_abs_section_ptr;
|
||
+ }
|
||
+ if (info.datasect == NULL)
|
||
+ {
|
||
+ fprintf (stderr, _("Warning: no \"data\" section found in output file\n"));
|
||
+ info.datasect = bfd_abs_section_ptr;
|
||
+ }
|
||
+
|
||
+ if (! bfd_hash_table_init (&info.types.root, coff_name_type_newfunc,
|
||
+ sizeof(struct coff_name_type_hash_entry)))
|
||
+ return FALSE;
|
||
+
|
||
+ if (! bfd_hash_table_init (&info.structs.root, coff_struct_newfunc,
|
||
+ sizeof(struct coff_struct_hash_entry)))
|
||
+ return FALSE;
|
||
+
|
||
+ if (! bfd_hash_table_init (&info.enums.root, coff_enum_newfunc,
|
||
+ sizeof(struct coff_enum_hash_entry)))
|
||
+ return FALSE;
|
||
+
|
||
+ if (! debug_write (dhandle, &coff_fns, (PTR) &info))
|
||
+ return FALSE;
|
||
+
|
||
+ /* If there is an old compilation unit that has got any local
|
||
+ non-debugging symbols left over, send them out now. */
|
||
+ if (info.currentfile != NULL && info.currentfile->totsyms != 0)
|
||
+ for (i = 0; i < info.currentfile->nsyms; i++)
|
||
+ {
|
||
+ up = info.currentfile;
|
||
+
|
||
+ if (up->syms[i] != NULL)
|
||
+ {
|
||
+ coff_emit_ndebug_sym (&info, up->syms[i], TRUE);
|
||
+ up->syms[i] = NULL;
|
||
+ up->totsyms--;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* See whether there are any non-debugging symbols left from the
|
||
+ input symbol table. First look at all local symbols which must
|
||
+ be from entire compilation units we didn't see yet in the
|
||
+ debugging information, because anything else has already been
|
||
+ handled at the end of each compilation unit (like in the loop
|
||
+ immediately above). Any compilation unit that has already been
|
||
+ processed that way is supposed to have its "totsyms" counted down
|
||
+ to 0 now, so we can skip them.
|
||
+
|
||
+ Finally, put out all remaining global non-debugging symbols. */
|
||
+ for (l = 0; l < info.nunits; l++)
|
||
+ {
|
||
+ const char *bn;
|
||
+
|
||
+ up = info.units + l;
|
||
+ if (up->totsyms == 0)
|
||
+ continue;
|
||
+
|
||
+ /* Create COFF symbol for this compilation unit. */
|
||
+ csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info.abfd, 0, 0);
|
||
+ if (csymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ bn = bu_basename (up->fname);
|
||
+
|
||
+ if (bfd_coff_long_filenames (info.abfd))
|
||
+ csymp->symbol.name = up->fname;
|
||
+ else
|
||
+ csymp->symbol.name = bn;
|
||
+
|
||
+ csymp->symbol.value = 0;
|
||
+ csymp->symbol.udata.p = NULL;
|
||
+ csymp->native->u.syment.n_sclass = C_FILE;
|
||
+ csymp->native->u.syment.n_numaux = 1; /* force filename into aux entry */
|
||
+ coff_record_symbol (&info, csymp);
|
||
+
|
||
+ for (i = 0; i < up->nsyms; i++)
|
||
+ {
|
||
+ symp = up->syms[i];
|
||
+ if (symp == NULL)
|
||
+ continue;
|
||
+
|
||
+ coff_emit_ndebug_sym (&info, symp, TRUE);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ for (i = 0; i < info.nglobals; i++)
|
||
+ {
|
||
+ symp = info.globals[i];
|
||
+ if (symp == NULL)
|
||
+ continue;
|
||
+
|
||
+ coff_emit_ndebug_sym (&info, symp, FALSE);
|
||
+ }
|
||
+
|
||
+ /* Fixup the AUX entries for the section symbols we have emitted
|
||
+ earlier (so they are guaranteed to be at the beginning of the
|
||
+ symbol table). In particular, the line number count (which we
|
||
+ only have for the text section) is known right now. */
|
||
+ for (i = 0; i < info.nsecsyms; i++)
|
||
+ {
|
||
+ union internal_auxent *aux;
|
||
+
|
||
+ csymp = info.secsyms[i];
|
||
+
|
||
+ aux = &((csymp->native + 1)->u.auxent);
|
||
+ aux->x_scn.x_scnlen = csymp->symbol.section->output_section->rawsize;
|
||
+ aux->x_scn.x_nreloc = csymp->symbol.section->reloc_count;
|
||
+ if (csymp->symbol.section == info.textsect)
|
||
+ aux->x_scn.x_nlinno = info.totlnos;
|
||
+ }
|
||
+ free (info.secsyms);
|
||
+
|
||
+ coff_name_type_hash_traverse (&info.types, coff_free_type_info, NULL);
|
||
+ bfd_hash_table_free (&info.types.root);
|
||
+
|
||
+ coff_struct_hash_traverse (&info.structs, coff_free_struct_info, NULL);
|
||
+ bfd_hash_table_free (&info.structs.root);
|
||
+
|
||
+ coff_enum_hash_traverse (&info.enums, coff_free_enum_info, NULL);
|
||
+ bfd_hash_table_free (&info.enums.root);
|
||
+
|
||
+ /* FIXME: free all the other stuff remembered in "info". */
|
||
+
|
||
+ free (*symppp);
|
||
+
|
||
+ *symcountp = info.nsyms;
|
||
+ *symppp = (asymbol **)info.syms;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Start writing out information for a compilation unit. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_start_compilation_unit (p, filename)
|
||
+ PTR p;
|
||
+ const char *filename;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ long i;
|
||
+ const char *bn;
|
||
+ bfd_boolean found;
|
||
+ coff_symbol_type *csymp;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_start_compilation_unit(%s)\n", filename);
|
||
+#endif
|
||
+
|
||
+ /* If there is an old compilation unit that has got any local
|
||
+ non-debugging symbols left over, send them out now. */
|
||
+ if (info->currentfile != NULL && info->currentfile->totsyms != 0)
|
||
+ for (i = 0; i < info->currentfile->nsyms; i++)
|
||
+ {
|
||
+ struct coff_compilation_unit *up = info->currentfile;
|
||
+
|
||
+ if (up->syms[i] != NULL)
|
||
+ {
|
||
+ coff_emit_ndebug_sym (info, up->syms[i], TRUE);
|
||
+ up->syms[i] = NULL;
|
||
+ up->totsyms--;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* symtab (and thus COFF debugging) symbols can only transfer the
|
||
+ basename of the file, so strip the dirname */
|
||
+ bn = bu_basename (filename);
|
||
+
|
||
+ for (i = 0, found = FALSE; i < info->nunits; i++)
|
||
+ {
|
||
+ if (strcmp (info->units[i].fname, bn) == 0)
|
||
+ {
|
||
+ info->currentfile = info->units + i;
|
||
+ found = TRUE;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ if (!found)
|
||
+ {
|
||
+ fprintf(stderr,
|
||
+ _("Warning: file %s not found in symbol table, ignoring\n"),
|
||
+ filename);
|
||
+ info->currentfile = NULL;
|
||
+ return TRUE;
|
||
+ }
|
||
+
|
||
+ /* Synthesize a new internal COFF symbol. */
|
||
+ csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (csymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ /* Note that coff_fix_symbol_name() [coffgen.c] will fix this for
|
||
+ us: the symbol name will be replaced by ".file", and the filename
|
||
+ will be moved to the aux entries. We use the long name obtained
|
||
+ from the debugging information (that includes the full path) if
|
||
+ our COFF format supports long filenames, otherwise we only use
|
||
+ the basename of the file. */
|
||
+ if (bfd_coff_long_filenames (info->abfd))
|
||
+ csymp->symbol.name = filename;
|
||
+ else
|
||
+ csymp->symbol.name = bn;
|
||
+ csymp->symbol.value = 0;
|
||
+ csymp->symbol.udata.p = NULL;
|
||
+ csymp->native->u.syment.n_sclass = C_FILE;
|
||
+ csymp->native->u.syment.n_numaux = 1; /* force filename into aux entry */
|
||
+ coff_record_symbol (info, csymp);
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Start writing out information for a particular source file. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_start_source (p, filename)
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+ const char *filename ATTRIBUTE_UNUSED;
|
||
+{
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_start_source(%s)\n", filename);
|
||
+#endif
|
||
+
|
||
+ /* COFF cannot handle include filenames. */
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push an empty type. This shouldn't normally happen. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_empty_type (p)
|
||
+ PTR p;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_empty_type()\n");
|
||
+#endif
|
||
+
|
||
+ coff_push_type (TS_EMPTY);
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a void type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_void_type (p)
|
||
+ PTR p;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_void_type()\n");
|
||
+#endif
|
||
+
|
||
+ coff_push_type (TS_VOID);
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push an integer type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_int_type (p, size, unsignedp)
|
||
+ PTR p;
|
||
+ unsigned int size;
|
||
+ bfd_boolean unsignedp;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_int_type(%d, %d)\n", size, unsignedp);
|
||
+#endif
|
||
+
|
||
+ coff_push_type (TS_INT);
|
||
+ tst->u.ts_int.size = size;
|
||
+ tst->u.ts_int.isunsigned = unsignedp;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a floating point type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_float_type (p, size)
|
||
+ PTR p;
|
||
+ unsigned int size;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_float_type(%d)\n", size);
|
||
+#endif
|
||
+
|
||
+ coff_push_type (TS_FLOAT);
|
||
+ tst->u.ts_float.size = size;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a complex type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_complex_type (p, size)
|
||
+ PTR p;
|
||
+ unsigned int size ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_complex_type(%d)\n", size);
|
||
+#endif
|
||
+
|
||
+ coff_push_type (TS_COMPLEX);
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a bfd_boolean type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_bool_type (p, size)
|
||
+ PTR p;
|
||
+ unsigned int size;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_bool_type(%d)\n", size);
|
||
+#endif
|
||
+
|
||
+ coff_push_type (TS_INT);
|
||
+ tst->u.ts_int.size = size;
|
||
+ tst->u.ts_int.isunsigned = TRUE;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push an enum type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_enum_type (p, tag, names, vals)
|
||
+ PTR p;
|
||
+ const char *tag;
|
||
+ const char **names;
|
||
+ bfd_signed_vma *vals;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst;
|
||
+ char buf[20];
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ int idx;
|
||
+ printf ("coff_enum_type(%s [", tag);
|
||
+ for (idx = 0; names[idx] != NULL; idx++)
|
||
+ printf ("%s -> %d, ", names[idx], (int)vals[idx]);
|
||
+ printf ("])\n");
|
||
+#endif
|
||
+
|
||
+ coff_push_type (TS_ENUM);
|
||
+
|
||
+ if (tag == NULL)
|
||
+ {
|
||
+ sprintf(buf, ".%dfake", info->nenums++);
|
||
+ tst->u.ts_enum.tag.malloctag = xstrdup (buf);
|
||
+ tst->u.ts_enum.tagismalloced = TRUE;
|
||
+ }
|
||
+ else
|
||
+ tst->u.ts_enum.tag.fixtag = tag;
|
||
+ tst->u.ts_enum.names = names;
|
||
+ tst->u.ts_enum.vals = vals;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a pointer type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_pointer_type (p)
|
||
+ PTR p;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_pointer_type()\n");
|
||
+#endif
|
||
+
|
||
+ coff_push_type (TS_POINTER);
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a function type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_function_type (p, argcount, varargs)
|
||
+ PTR p;
|
||
+ int argcount;
|
||
+ bfd_boolean varargs ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_function_type(%d, %d)\n", argcount, varargs);
|
||
+#endif
|
||
+
|
||
+ coff_push_type (TS_FUNC);
|
||
+
|
||
+ /* FIXME should properly discard function arguments */
|
||
+ if (argcount > -1)
|
||
+ {
|
||
+ fprintf (stderr,
|
||
+ _("coff_function_type() called with positive argcount\n"));
|
||
+ return FALSE;
|
||
+ }
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a reference type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_reference_type (p)
|
||
+ PTR p;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_reference_type()\n");
|
||
+#endif
|
||
+
|
||
+ coff_complain_unsupp (_("reference"));
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a range type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_range_type (p, low, high)
|
||
+ PTR p;
|
||
+ bfd_signed_vma low ATTRIBUTE_UNUSED;
|
||
+ bfd_signed_vma high ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_range_type([%d..%d)\n", (int)low, (int)high);
|
||
+#endif
|
||
+
|
||
+ coff_complain_unsupp (_("range"));
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push an array type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_array_type (p, low, high, stringp)
|
||
+ PTR p;
|
||
+ bfd_signed_vma low;
|
||
+ bfd_signed_vma high;
|
||
+ bfd_boolean stringp;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_array_type([%d..%d], %d)\n",
|
||
+ (int)low, (int)high, stringp);
|
||
+#endif
|
||
+
|
||
+ /* Pop the range type, but ignore it. COFF doesn't use it. */
|
||
+ coff_pop_type ();
|
||
+
|
||
+ /* FIXME What to do here? */
|
||
+ if (stringp)
|
||
+ {
|
||
+ fprintf(stderr, _("coff_array_type(): stringp == TRUE\n"));
|
||
+ return FALSE;
|
||
+ }
|
||
+
|
||
+ coff_push_type (TS_ARRAY);
|
||
+ tst->u.ts_array.low = low;
|
||
+ tst->u.ts_array.high = high;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a set type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_set_type (p, bitstringp)
|
||
+ PTR p;
|
||
+ bfd_boolean bitstringp ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_set_type(%d)\n", bitstringp);
|
||
+#endif
|
||
+
|
||
+ coff_complain_unsupp (_("set"));
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push an offset type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_offset_type (p)
|
||
+ PTR p;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_offset_type()\n");
|
||
+#endif
|
||
+
|
||
+ coff_complain_unsupp (_("offset"));
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a method type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_method_type (p, domainp, argcount, varargs)
|
||
+ PTR p;
|
||
+ bfd_boolean domainp ATTRIBUTE_UNUSED;
|
||
+ int argcount ATTRIBUTE_UNUSED;
|
||
+ bfd_boolean varargs ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_method_type(%d, %d, %d)\n",
|
||
+ domainp, argcount, varargs);
|
||
+#endif
|
||
+
|
||
+ coff_complain_unsupp (_("method"));
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a const version of a type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_const_type (p)
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+{
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_const_type()\n");
|
||
+#endif
|
||
+
|
||
+ /* const modifier is ignored by COFF */
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a volatile version of a type. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_volatile_type (p)
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+{
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_volatile_type()\n");
|
||
+#endif
|
||
+
|
||
+ /* volatile modifier is ignored by COFF */
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Start outputting a struct. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_start_struct_type (p, tag, id, structp, size)
|
||
+ PTR p;
|
||
+ const char *tag;
|
||
+ unsigned int id;
|
||
+ bfd_boolean structp;
|
||
+ unsigned int size;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst, *savedts;
|
||
+ struct coff_struct_hash_entry *shash;
|
||
+ char buf[20];
|
||
+ const char *name;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_start_struct_type(%s, %d, %d, %d)\n",
|
||
+ tag, id, structp, size);
|
||
+#endif
|
||
+
|
||
+ savedts = info->tstack;
|
||
+ info->tstack = NULL;
|
||
+
|
||
+ coff_push_type (TS_STRUCT);
|
||
+
|
||
+ if (tag == NULL)
|
||
+ {
|
||
+ sprintf(buf, ".%dfake", id);
|
||
+ name = tst->u.ts_struct.tag.malloctag = xstrdup (buf);
|
||
+ tst->u.ts_struct.tagismalloced = TRUE;
|
||
+ }
|
||
+ else
|
||
+ name = tst->u.ts_struct.tag.fixtag = tag;
|
||
+ tst->u.ts_struct.id = id;
|
||
+ tst->u.ts_struct.isstruct = structp;
|
||
+ tst->u.ts_struct.size = size;
|
||
+ tst->u.ts_struct.savedts = savedts;
|
||
+
|
||
+ shash = coff_struct_hash_lookup (&info->structs, name, FALSE, FALSE);
|
||
+ if (shash != NULL && shash->types != NULL)
|
||
+ {
|
||
+#if COFF_DEBUG
|
||
+ printf ("new %s definition for %s\n",
|
||
+ tst->u.ts_struct.isstruct? "struct": "union", name);
|
||
+#endif
|
||
+ coff_free_struct_info (shash, NULL);
|
||
+ shash->types = NULL;
|
||
+ shash->emitted = FALSE;
|
||
+ }
|
||
+ else
|
||
+ (void)coff_struct_hash_lookup (&info->structs, name,
|
||
+ TRUE, tst->u.ts_struct.tagismalloced);
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Add a field to a struct. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_struct_field (p, name, bitpos, bitsize, visibility)
|
||
+ PTR p;
|
||
+ const char *name;
|
||
+ bfd_vma bitpos;
|
||
+ bfd_vma bitsize;
|
||
+ enum debug_visibility visibility;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst, *otst;
|
||
+ struct coff_struct_fields *fp;
|
||
+ struct coff_struct_hash_entry *shash;
|
||
+ struct coff_enum_hash_entry *ehash;
|
||
+ const char *tag;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_struct_field(%s, %d, %d, %d)\n",
|
||
+ name, (int)bitpos, (int)bitsize, (int)visibility);
|
||
+#endif
|
||
+
|
||
+ /* Find the last element on the type stack. */
|
||
+ assert (info->tstack != NULL);
|
||
+ for (tst = info->tstack, otst = NULL; tst->next != NULL;)
|
||
+ {
|
||
+ otst = tst;
|
||
+ tst = tst->next;
|
||
+ }
|
||
+ if (otst != NULL)
|
||
+ otst->next = NULL;
|
||
+
|
||
+ if (tst->tsk != TS_STRUCT)
|
||
+ {
|
||
+ fprintf (stderr, "coff_struct_field() not within structure definition\n");
|
||
+ return FALSE;
|
||
+ }
|
||
+ tst->u.ts_struct.fields = (struct coff_struct_fields *)
|
||
+ xrealloc (tst->u.ts_struct.fields,
|
||
+ ++tst->u.ts_struct.nfields * sizeof (struct coff_struct_fields));
|
||
+ fp = tst->u.ts_struct.fields + (tst->u.ts_struct.nfields - 1);
|
||
+ fp->name = name;
|
||
+ fp->bitpos = bitpos;
|
||
+ fp->bitsize = bitsize;
|
||
+ fp->visibility = visibility;
|
||
+ otst = fp->types = info->tstack;
|
||
+ while (otst->next != NULL)
|
||
+ otst = otst->next;
|
||
+ if (otst->tsk == TS_STRUCT && otst->u.ts_struct.shash == NULL)
|
||
+ {
|
||
+ if (otst->u.ts_struct.tagismalloced)
|
||
+ tag = otst->u.ts_struct.tag.malloctag;
|
||
+ else
|
||
+ tag = otst->u.ts_struct.tag.fixtag;
|
||
+ shash = coff_struct_hash_lookup (&info->structs, tag, FALSE, FALSE);
|
||
+ assert (shash != NULL);
|
||
+ if (!shash->emitted)
|
||
+ {
|
||
+ if (shash->types == NULL)
|
||
+ {
|
||
+ shash->types = (struct coff_type_stack *)
|
||
+ xmalloc (sizeof (struct coff_type_stack));
|
||
+ memcpy (shash->types, otst, sizeof (struct coff_type_stack));
|
||
+ }
|
||
+ shash->emitted = TRUE;
|
||
+ coff_emit_struct (info, otst, shash);
|
||
+ }
|
||
+ }
|
||
+ else if (otst->tsk == TS_ENUM)
|
||
+ {
|
||
+ if (otst->u.ts_enum.tagismalloced)
|
||
+ tag = otst->u.ts_enum.tag.malloctag;
|
||
+ else
|
||
+ tag = otst->u.ts_enum.tag.fixtag;
|
||
+ ehash = coff_enum_hash_lookup (&info->enums, tag, TRUE, FALSE);
|
||
+ assert (ehash != NULL);
|
||
+ if (!ehash->emitted)
|
||
+ {
|
||
+ if (ehash->types == NULL)
|
||
+ {
|
||
+ ehash->types = (struct coff_type_stack *)
|
||
+ xmalloc (sizeof (struct coff_type_stack));
|
||
+ memcpy (ehash->types, otst, sizeof (struct coff_type_stack));
|
||
+ }
|
||
+ ehash->emitted = TRUE;
|
||
+ coff_emit_enum (info, otst, ehash);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ info->tstack = tst;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Finish up a struct. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_end_struct_type (p)
|
||
+ PTR p;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst, *savedts;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_end_struct_type()\n");
|
||
+#endif
|
||
+
|
||
+ /* Our struct definition should be the only type stack element by
|
||
+ now. */
|
||
+ assert (info->tstack != NULL);
|
||
+ tst = info->tstack;
|
||
+ if (tst->tsk != TS_STRUCT || tst->next != NULL)
|
||
+ {
|
||
+ fprintf (stderr, "coff_struct_field() not within structure definition\n");
|
||
+ return FALSE;
|
||
+ }
|
||
+
|
||
+ /* Restore saved type stack, and push our now complete struct
|
||
+ definition on top. */
|
||
+ savedts = tst->u.ts_struct.savedts;
|
||
+ tst->u.ts_struct.savedts = info->tstack;
|
||
+ info->tstack = savedts;
|
||
+ tst->next = info->tstack;
|
||
+ info->tstack = tst;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Start outputting a class. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
|
||
+ PTR p;
|
||
+ const char *tag ATTRIBUTE_UNUSED;
|
||
+ unsigned int id ATTRIBUTE_UNUSED;
|
||
+ bfd_boolean structp ATTRIBUTE_UNUSED;
|
||
+ unsigned int size ATTRIBUTE_UNUSED;
|
||
+ bfd_boolean vptr ATTRIBUTE_UNUSED;
|
||
+ bfd_boolean ownvptr ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_start_class_type(%s, %d, %d, %d, %d, %d)\n",
|
||
+ tag, id, structp, size, vptr, ownvptr);
|
||
+#endif
|
||
+
|
||
+ coff_complain_unsupp (_("class"));
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Add a static member to the class on the type stack. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_class_static_member (p, name, physname, visibility)
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+ const char *name ATTRIBUTE_UNUSED;
|
||
+ const char *physname ATTRIBUTE_UNUSED;
|
||
+ enum debug_visibility visibility ATTRIBUTE_UNUSED;
|
||
+{
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_class_static_member(%s, %s, %d)\n",
|
||
+ name, physname, (int)visibility);
|
||
+#endif
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Add a base class to the class on the type stack. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_class_baseclass (p, bitpos, virtual, visibility)
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+ bfd_vma bitpos ATTRIBUTE_UNUSED;
|
||
+ bfd_boolean virtual ATTRIBUTE_UNUSED;
|
||
+ enum debug_visibility visibility ATTRIBUTE_UNUSED;
|
||
+{
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_class_baseclass(%d, %d, %d)\n",
|
||
+ (int)bitpos, virtual, (int)visibility);
|
||
+#endif
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Start adding a method to the class on the type stack. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_class_start_method (p, name)
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+ const char *name ATTRIBUTE_UNUSED;
|
||
+{
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_class_start_method(%s)\n", name);
|
||
+#endif
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Add a variant to the current method. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_class_method_variant (p, physname, visibility, constp, volatilep,
|
||
+ voffset, contextp)
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+ const char *physname ATTRIBUTE_UNUSED;
|
||
+ enum debug_visibility visibility ATTRIBUTE_UNUSED;
|
||
+ bfd_boolean constp ATTRIBUTE_UNUSED;
|
||
+ bfd_boolean volatilep ATTRIBUTE_UNUSED;
|
||
+ bfd_vma voffset ATTRIBUTE_UNUSED;
|
||
+ bfd_boolean contextp ATTRIBUTE_UNUSED;
|
||
+{
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_class_method_variant(%s, %d, %d, %d, %d, %d)\n",
|
||
+ physname, (int)visibility, constp, volatilep,
|
||
+ (int)voffset, contextp);
|
||
+#endif
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Add a static variant to the current method. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_class_static_method_variant (p, physname, visibility, constp, volatilep)
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+ const char *physname ATTRIBUTE_UNUSED;
|
||
+ enum debug_visibility visibility ATTRIBUTE_UNUSED;
|
||
+ bfd_boolean constp ATTRIBUTE_UNUSED;
|
||
+ bfd_boolean volatilep ATTRIBUTE_UNUSED;
|
||
+{
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_class_static_method_variant(%s, %d, %d, %d)\n",
|
||
+ physname, (int)visibility, constp, volatilep);
|
||
+#endif
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Finish up a method. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_class_end_method (p)
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+{
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_class_end_method()\n");
|
||
+#endif
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Finish up a class. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_end_class_type (p)
|
||
+ PTR p ATTRIBUTE_UNUSED;
|
||
+{
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_end_class_type()\n");
|
||
+#endif
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a typedef which was previously defined. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_typedef_type (p, name)
|
||
+ PTR p;
|
||
+ const char *name;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_name_type_hash_entry *nthash;
|
||
+ struct coff_type_stack *tst, *newchain, *newst, *temp;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_typedef_type(%s)\n", name);
|
||
+#endif
|
||
+
|
||
+ nthash = coff_name_type_hash_lookup (&info->types, name, FALSE, FALSE);
|
||
+
|
||
+ /* nthash should never be NULL, since that would imply that the
|
||
+ generic debugging code has asked for a typedef which it has not
|
||
+ yet defined. */
|
||
+ assert (nthash != NULL);
|
||
+
|
||
+ /* Just push the entire type stack snapshot we've got on top of the
|
||
+ existing typestack. See coff_typdef() below for how this
|
||
+ works. We need to copy over each element however, since anybody
|
||
+ popping elements off the typestack is supposed to free() each of
|
||
+ them. */
|
||
+
|
||
+ for (tst = nthash->types, temp = newst = newchain = NULL; tst != NULL;)
|
||
+ {
|
||
+ temp = newst;
|
||
+ newst = (struct coff_type_stack *) xmalloc (sizeof (*newst));
|
||
+ if (newchain == NULL)
|
||
+ newchain = newst;
|
||
+ memcpy (newst, tst, sizeof (*newst));
|
||
+ if (temp != NULL)
|
||
+ temp->next = newst;
|
||
+
|
||
+ tst = tst->next;
|
||
+ }
|
||
+ newst->next = info->tstack;
|
||
+ info->tstack = newchain;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Push a struct, union or class tag. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_tag_type (p, name, id, kind)
|
||
+ PTR p;
|
||
+ const char *name;
|
||
+ unsigned int id ATTRIBUTE_UNUSED;
|
||
+ enum debug_type_kind kind;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst, *newchain, *newst, *temp;
|
||
+ struct coff_struct_hash_entry *shash;
|
||
+ struct coff_enum_hash_entry *ehash;
|
||
+ char buf[20];
|
||
+ bfd_boolean needcopy = FALSE;
|
||
+ bfd_boolean isstruct = TRUE;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_tag_type(%s, %d, %d)\n",
|
||
+ name, id, kind);
|
||
+#endif
|
||
+
|
||
+ if (name == NULL)
|
||
+ {
|
||
+ sprintf(buf, ".%dfake", id);
|
||
+ needcopy = TRUE;
|
||
+ }
|
||
+
|
||
+ switch (kind)
|
||
+ {
|
||
+ case DEBUG_KIND_UNION:
|
||
+ case DEBUG_KIND_UNION_CLASS:
|
||
+ isstruct = FALSE;
|
||
+ /* FALLTHROUGH */
|
||
+ case DEBUG_KIND_STRUCT:
|
||
+ case DEBUG_KIND_CLASS:
|
||
+ shash = coff_struct_hash_lookup (&info->structs,
|
||
+ name == NULL? buf: name, TRUE, needcopy);
|
||
+ assert (shash != NULL);
|
||
+ tst = shash->types;
|
||
+ if (tst == NULL)
|
||
+ {
|
||
+ /* This is a reference to a tag that has not yet been
|
||
+ defined (i. e., a forward reference). Synthesize a
|
||
+ ts_struct entry by now, and mark it for later fixup. */
|
||
+ tst = (struct coff_type_stack *) xmalloc (sizeof *tst);
|
||
+ memset (tst, 0, sizeof *tst);
|
||
+ tst->tsk = TS_STRUCT;
|
||
+ tst->u.ts_struct.isstruct = isstruct;
|
||
+ tst->u.ts_struct.shash = shash;
|
||
+ }
|
||
+ docopystack:
|
||
+ /* Just push the entire type stack snapshot we've got on top of the
|
||
+ existing typestack. See coff_typdef() below for how this
|
||
+ works. We need to copy over each element however, since anybody
|
||
+ popping elements off the typestack is supposed to free() each of
|
||
+ them. */
|
||
+ for (temp = newst = newchain = NULL; tst != NULL;)
|
||
+ {
|
||
+ temp = newst;
|
||
+ newst = (struct coff_type_stack *) xmalloc (sizeof (*newst));
|
||
+ if (newchain == NULL)
|
||
+ newchain = newst;
|
||
+ memcpy (newst, tst, sizeof (*newst));
|
||
+ if (temp != NULL)
|
||
+ temp->next = newst;
|
||
+
|
||
+ tst = tst->next;
|
||
+ }
|
||
+ if (newst)
|
||
+ {
|
||
+ newst->next = info->tstack;
|
||
+ info->tstack = newchain;
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case DEBUG_KIND_ENUM:
|
||
+ ehash = coff_enum_hash_lookup (&info->enums,
|
||
+ name == NULL? buf: name, TRUE, needcopy);
|
||
+ assert (ehash != NULL);
|
||
+ tst = ehash->types;
|
||
+ if (tst == NULL)
|
||
+ {
|
||
+ /* This is a reference to a tag that has not yet been
|
||
+ defined (i. e., a forward reference). Synthesize a
|
||
+ ts_enum entry by now, and mark it for later fixup. */
|
||
+ tst = (struct coff_type_stack *) xmalloc (sizeof *tst);
|
||
+ memset (tst, 0, sizeof *tst);
|
||
+ tst->tsk = TS_ENUM;
|
||
+ tst->u.ts_enum.ehash = ehash;
|
||
+ }
|
||
+ goto docopystack;
|
||
+
|
||
+ default:
|
||
+ fprintf (stderr, _("illegal kind %d in coff_tag_type()\n"),
|
||
+ (int)kind);
|
||
+ return FALSE;
|
||
+ }
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Define a typedef. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_typdef (p, name)
|
||
+ PTR p;
|
||
+ const char *name;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_name_type_hash_entry *nthash;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_typdef(%s)\n", name);
|
||
+#endif
|
||
+
|
||
+ /* COFF cannot really handle typedefs. While there is the option to
|
||
+ mark a symbol using the storage class C_TPDEF (so the COFF reader
|
||
+ will know that name), there is no way to place a reference to
|
||
+ that typedef into the just 16 bits COFF reserves for all of its
|
||
+ type information. Thus, any use of the typedef must always fully
|
||
+ dereference the typedef again. We do this by "snapshotting" the
|
||
+ current type stack under the name of our typedef, and later on,
|
||
+ when BFD debugging tells us to make use of the typedef (in
|
||
+ coff_typedef_type()), we just look it up, and push all we've got
|
||
+ completely onto the type stack again. */
|
||
+
|
||
+ if (info->tstack == NULL)
|
||
+ {
|
||
+ fprintf (stderr, _("coff_typdef() on an empty type stack\n"));
|
||
+ return FALSE;
|
||
+ }
|
||
+
|
||
+ nthash = coff_name_type_hash_lookup (&info->types, name, FALSE, FALSE);
|
||
+ if (nthash != NULL)
|
||
+ {
|
||
+#if COFF_DEBUG
|
||
+ printf ("new typedef for %s\n", name);
|
||
+#endif
|
||
+ coff_free_type_info (nthash, NULL);
|
||
+ }
|
||
+ else
|
||
+ nthash = coff_name_type_hash_lookup (&info->types, name, TRUE, FALSE);
|
||
+ if (nthash == NULL)
|
||
+ return FALSE;
|
||
+ nthash->types = info->tstack;
|
||
+
|
||
+ /* If the typestack is "sufficiently complex", emit a C_TPDEF symbol
|
||
+ for it. We assume it to be sufficiently complex if there are
|
||
+ either at least two derived types, or one derived type where the
|
||
+ base type is not a simple scalar one. */
|
||
+ if (!nthash->emitted
|
||
+ && info->tstack->next != NULL
|
||
+ && (info->tstack->next->next != NULL || info->tstack->next->tsk >= TS_ENUM))
|
||
+ {
|
||
+ struct coff_type_stack *newchain, *otst, *tst, *ntst;
|
||
+ coff_symbol_type *csymp;
|
||
+
|
||
+ nthash->emitted = TRUE;
|
||
+
|
||
+ for (tst = info->tstack, newchain = otst = NULL;
|
||
+ tst != NULL;
|
||
+ tst = tst->next)
|
||
+ {
|
||
+ ntst = (struct coff_type_stack *)
|
||
+ xmalloc (sizeof (struct coff_type_stack));
|
||
+ memcpy (ntst, tst, sizeof (struct coff_type_stack));
|
||
+ if (otst == NULL)
|
||
+ newchain = ntst;
|
||
+ else
|
||
+ otst->next = ntst;
|
||
+ otst = ntst;
|
||
+ }
|
||
+ info->tstack = newchain;
|
||
+ if (!coff_make_typed_symbol (info, &csymp, TS_NONE))
|
||
+ return FALSE;
|
||
+
|
||
+ csymp->symbol.name = xstrdup (name);
|
||
+ csymp->symbol.flags = BSF_NOT_AT_END;
|
||
+ csymp->symbol.section = bfd_com_section_ptr;
|
||
+ csymp->native->u.syment.n_sclass = C_TPDEF;
|
||
+ csymp->symbol.value = 0;
|
||
+
|
||
+ coff_record_symbol (info, csymp);
|
||
+ }
|
||
+ info->tstack = NULL;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Define a tag. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_tag (p, tag)
|
||
+ PTR p;
|
||
+ const char *tag;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst = NULL;
|
||
+ struct coff_struct_hash_entry *shash;
|
||
+ struct coff_enum_hash_entry *ehash;
|
||
+
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_tag(%s)\n", tag);
|
||
+#endif
|
||
+
|
||
+ if (info->tstack == NULL)
|
||
+ {
|
||
+ fprintf (stderr, _("coff_tag() called on an empty typestack\n"));
|
||
+ return FALSE;
|
||
+ }
|
||
+
|
||
+ switch (info->tstack->tsk)
|
||
+ {
|
||
+ case TS_STRUCT:
|
||
+ shash = coff_struct_hash_lookup (&info->structs, tag, FALSE, FALSE);
|
||
+ assert (shash != NULL);
|
||
+ shash->types = info->tstack;
|
||
+ info->tstack = NULL;
|
||
+ break;
|
||
+
|
||
+ case TS_ENUM:
|
||
+ ehash = coff_enum_hash_lookup (&info->enums, tag, FALSE, FALSE);
|
||
+ if (ehash != NULL && ehash->types != NULL)
|
||
+ {
|
||
+#if COFF_DEBUG
|
||
+ printf ("new enum definition for %s\n", tag);
|
||
+#endif
|
||
+ coff_free_enum_info (ehash, NULL);
|
||
+ }
|
||
+ else
|
||
+ ehash = coff_enum_hash_lookup (&info->enums, tag, TRUE, FALSE);
|
||
+ if (ehash == NULL)
|
||
+ return FALSE;
|
||
+ ehash->types = info->tstack;
|
||
+ info->tstack = NULL;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ fprintf (stderr, _("Illegal typestack (%d) in coff_tag()\n"), tst->tsk);
|
||
+ return FALSE;
|
||
+ }
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Define an integer constant. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_int_constant (p, name, val)
|
||
+ PTR p;
|
||
+ const char *name ATTRIBUTE_UNUSED;
|
||
+ bfd_vma val ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_int_constant(%s, %d)\n", name, (int)val);
|
||
+#endif
|
||
+
|
||
+ coff_complain_unsupp (_("int constant"));
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Define a floating point constant. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_float_constant (p, name, val)
|
||
+ PTR p;
|
||
+ const char *name ATTRIBUTE_UNUSED;
|
||
+ double val ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_float_constant(%s, %g)\n", name, val);
|
||
+#endif
|
||
+
|
||
+ coff_complain_unsupp (_("float constant"));
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Define a typed constant. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_typed_constant (p, name, val)
|
||
+ PTR p;
|
||
+ const char *name ATTRIBUTE_UNUSED;
|
||
+ bfd_vma val ATTRIBUTE_UNUSED;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_typed_constant(%s, %d)\n", name, (int)val);
|
||
+#endif
|
||
+
|
||
+ coff_complain_unsupp (_("typed constant"));
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Record a variable. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_variable (p, name, kind, val)
|
||
+ PTR p;
|
||
+ const char *name;
|
||
+ enum debug_var_kind kind;
|
||
+ bfd_vma val;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ unsigned char class;
|
||
+ asymbol *symp = NULL;
|
||
+ coff_symbol_type *csymp;
|
||
+ bfd_boolean global = FALSE;
|
||
+ flagword flags = BSF_LOCAL;
|
||
+ bfd_vma vmadiff = 0;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_variable(%s, %d, %d)\n",
|
||
+ name, (int)kind, (int)val);
|
||
+#endif
|
||
+
|
||
+ switch (kind)
|
||
+ {
|
||
+ default:
|
||
+ abort ();
|
||
+
|
||
+ case DEBUG_GLOBAL:
|
||
+ flags = BSF_GLOBAL;
|
||
+ global = TRUE;
|
||
+ /* AVR COFF historically used C_EXTDEF for global variables, and
|
||
+ C_EXT for global functions. Since some AVR COFF consumers
|
||
+ apparently depend on this, we mimic this behaviour as
|
||
+ well. */
|
||
+ class = info->flags & COFF_FL_AVR? C_EXTDEF: C_EXT;
|
||
+ break;
|
||
+
|
||
+ case DEBUG_STATIC:
|
||
+ case DEBUG_LOCAL_STATIC:
|
||
+ class = C_STAT;
|
||
+ break;
|
||
+
|
||
+ case DEBUG_LOCAL:
|
||
+ class = C_AUTO;
|
||
+ break;
|
||
+
|
||
+ case DEBUG_REGISTER:
|
||
+ class = C_REG;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (!coff_make_typed_symbol (info, &csymp, TS_NONE))
|
||
+ return FALSE;
|
||
+
|
||
+ if (class == C_REG && (info->flags & COFF_FL_AVR) != 0)
|
||
+ {
|
||
+ struct coff_private_symdata *priv = (struct coff_private_symdata *)
|
||
+ csymp->symbol.udata.p;
|
||
+ val = coff_fixup_avr_register (val, priv->size * 8);
|
||
+ }
|
||
+
|
||
+ csymp->symbol.name = name;
|
||
+ csymp->symbol.flags = flags; /* Note: this clears BSF_DEBUGGING. */
|
||
+
|
||
+ /* Match the debugging symbol against the input symtab symbols. If
|
||
+ we found one, use the section information from it. Otherwise, we
|
||
+ are lost here and just use the absolute section that was
|
||
+ predeclared by coff_bfd_make_debug_symbol(). C_REG and C_AUTO
|
||
+ symbols (which we do not attempt to lookup in the symtab symbols
|
||
+ at all) go into the ABS section anyway. */
|
||
+ if (class != C_REG && class != C_AUTO)
|
||
+ {
|
||
+ symp = coff_find_symbol (info, name, FALSE, global);
|
||
+ if (symp)
|
||
+ {
|
||
+ csymp->symbol.section = symp->section;
|
||
+ vmadiff = symp->section->vma;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Symbols are relative to section vma. */
|
||
+ csymp->symbol.value = val - vmadiff;
|
||
+ csymp->native->u.syment.n_sclass = class;
|
||
+ coff_record_symbol (info, csymp);
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Start outputting a function. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_start_function (p, name, globalp)
|
||
+ PTR p;
|
||
+ const char *name;
|
||
+ bfd_boolean globalp;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst, *savedts;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_start_function(%s, %d)\n",
|
||
+ name, globalp);
|
||
+#endif
|
||
+
|
||
+ savedts = info->tstack;
|
||
+ info->tstack = NULL;
|
||
+
|
||
+ coff_push_type (TS_FUNC);
|
||
+
|
||
+ if (info->funname != NULL)
|
||
+ {
|
||
+ fprintf (stderr,
|
||
+ _("coff_start_function() called twice, pending %s, new %s\n"),
|
||
+ info->funname, name);
|
||
+ return FALSE;
|
||
+ }
|
||
+ info->funname = name;
|
||
+ info->funglobal = globalp;
|
||
+ info->flags |= COFF_FL_START_FCN;
|
||
+ tst->u.ts_func.savedts = savedts;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Output a function parameter. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_function_parameter (p, name, kind, val)
|
||
+ PTR p;
|
||
+ const char *name;
|
||
+ enum debug_parm_kind kind;
|
||
+ bfd_vma val;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ coff_symbol_type *csymp;
|
||
+ unsigned char class;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_function_parameter(%s, %d, %d)\n",
|
||
+ name, (int)kind, (int)val);
|
||
+#endif
|
||
+
|
||
+ switch (kind)
|
||
+ {
|
||
+ default:
|
||
+ abort ();
|
||
+
|
||
+ case DEBUG_PARM_STACK:
|
||
+ class = C_ARG;
|
||
+ break;
|
||
+
|
||
+ case DEBUG_PARM_REG:
|
||
+ class = C_REGPARM;
|
||
+ break;
|
||
+
|
||
+ case DEBUG_PARM_REFERENCE:
|
||
+ case DEBUG_PARM_REF_REG:
|
||
+ fprintf (stderr, _("Reference parameters not available in COFF\n"));
|
||
+ return TRUE;
|
||
+ }
|
||
+
|
||
+ if (!coff_make_typed_symbol (info, &csymp, TS_FUNC))
|
||
+ return FALSE;
|
||
+
|
||
+ if (class == C_REGPARM && (info->flags & COFF_FL_AVR) != 0)
|
||
+ {
|
||
+ struct coff_private_symdata *priv = (struct coff_private_symdata *)
|
||
+ csymp->symbol.udata.p;
|
||
+ val = coff_fixup_avr_register (val, priv->size * 8);
|
||
+ }
|
||
+
|
||
+ csymp->symbol.name = name;
|
||
+ csymp->symbol.value = val;
|
||
+ csymp->symbol.flags |= BSF_LOCAL;
|
||
+ csymp->native->u.syment.n_sclass = class;
|
||
+
|
||
+ /* Since function parameters precede the actual function definition,
|
||
+ defer their output until the function has been created. */
|
||
+ info->fargs = (coff_symbol_type **)
|
||
+ xrealloc (info->fargs, ++info->nfargs * sizeof (coff_symbol_type *));
|
||
+ info->fargs[info->nfargs - 1] = csymp;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Start a block. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_start_block (p, addr)
|
||
+ PTR p;
|
||
+ bfd_vma addr;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ struct coff_type_stack *tst, *otst;
|
||
+ struct coff_fix_stack *fixp, *ofp;
|
||
+ asymbol *symp;
|
||
+ coff_symbol_type *csymp;
|
||
+ unsigned int i;
|
||
+ bfd_boolean is_start_fcn;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_start_block(%#x)\n", (int)addr);
|
||
+#endif
|
||
+
|
||
+ is_start_fcn = info->flags & COFF_FL_START_FCN;
|
||
+
|
||
+ if (is_start_fcn)
|
||
+ {
|
||
+ /* This is the starting block of a function. We are going to
|
||
+ write three symbols here, one for the function itself, one
|
||
+ ".bf" symbol to indicate the begin of the function, and
|
||
+ finally one ".bb" for the first block inside the function. */
|
||
+ info->flags &= ~COFF_FL_START_FCN;
|
||
+
|
||
+ /* Our function definition should be the only type stack element
|
||
+ by now. */
|
||
+ assert (info->tstack != NULL);
|
||
+ tst = info->tstack;
|
||
+ if (tst->tsk != TS_FUNC || tst->next != NULL)
|
||
+ {
|
||
+ fprintf (stderr,
|
||
+ _("coff_start_block() not within function definition\n"));
|
||
+ return FALSE;
|
||
+ }
|
||
+
|
||
+ /* Restore saved type stack, and push our now complete function
|
||
+ definition on top. */
|
||
+ info->tstack = tst->u.ts_func.savedts;
|
||
+ tst->next = info->tstack;
|
||
+ info->tstack = tst;
|
||
+
|
||
+ if (info->currentfile == NULL)
|
||
+ {
|
||
+ fprintf (stderr,
|
||
+ _("Warning: ignoring function %s() outside any compilation unit\n"),
|
||
+ info->funname);
|
||
+ for (tst = info->tstack, otst = NULL; tst != NULL;)
|
||
+ {
|
||
+ otst = tst;
|
||
+ tst = otst->next;
|
||
+ if (otst->tsk == TS_ENUM &&
|
||
+ otst->u.ts_enum.tagismalloced)
|
||
+ free (otst->u.ts_enum.tag.malloctag);
|
||
+ else if (otst->tsk == TS_STRUCT &&
|
||
+ otst->u.ts_struct.tagismalloced)
|
||
+ free (otst->u.ts_struct.tag.malloctag);
|
||
+ free (otst);
|
||
+ }
|
||
+ info->tstack = NULL;
|
||
+ info->funname = NULL;
|
||
+
|
||
+ return TRUE;
|
||
+ }
|
||
+
|
||
+ if (!coff_make_typed_symbol (info, &csymp, TS_NONE))
|
||
+ return FALSE;
|
||
+
|
||
+ csymp->symbol.name = info->funname;
|
||
+ csymp->symbol.flags = BSF_FUNCTION |
|
||
+ (info->funglobal? BSF_GLOBAL: BSF_LOCAL);
|
||
+ symp = coff_find_symbol (info, info->funname, TRUE, info->funglobal);
|
||
+ if (symp == NULL)
|
||
+ {
|
||
+ fprintf (stderr,
|
||
+ _("function %s not found in symbol table, defaulting to \"text\" section\n"),
|
||
+ info->funname);
|
||
+ csymp->symbol.section = info->funcsection = info->textsect;
|
||
+ }
|
||
+ else
|
||
+ csymp->symbol.section = info->funcsection = symp->section;
|
||
+
|
||
+ /* Symbol addresses are relative to section vma. */
|
||
+ csymp->symbol.value = addr - info->funcsection->vma;
|
||
+ csymp->native->u.syment.n_sclass = info->funglobal? C_EXT: C_STAT;
|
||
+ /* Create two initial line number entries. The first one holds
|
||
+ the function symbol, the second one is the trailing record
|
||
+ that is required by coffgen.c::coff_write_native_symbol() to
|
||
+ have a line number of zero. */
|
||
+ csymp->lineno = (alent *) xmalloc (2 * sizeof (alent));
|
||
+ memset (csymp->lineno, 0, 2 * sizeof (alent));
|
||
+ info->nlnos = 2;
|
||
+ info->totlnos++;
|
||
+ csymp->lineno[0].u.sym = (asymbol *)csymp;
|
||
+ coff_record_symbol (info, csymp);
|
||
+ info->funcindex = info->nsyms - 1; /* remember for later */
|
||
+ /* Record our endndx field for later fixing. */
|
||
+ fixp = (struct coff_fix_stack *) xmalloc (sizeof (struct coff_fix_stack));
|
||
+ fixp->native = csymp->native + 1; /* points to first AUX */
|
||
+ fixp->next = NULL;
|
||
+ if (info->fixes == NULL)
|
||
+ info->fixes = fixp;
|
||
+ else
|
||
+ {
|
||
+ for (ofp = info->fixes; ofp->next != NULL;)
|
||
+ ofp = ofp->next;
|
||
+ ofp->next = fixp;
|
||
+ }
|
||
+
|
||
+ csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (csymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ csymp->symbol.name = ".bf";
|
||
+ csymp->native->u.syment.n_sclass = C_FCN;
|
||
+ csymp->native->u.syment.n_numaux = 1;
|
||
+ csymp->symbol.value = addr - info->funcsection->vma;
|
||
+ csymp->symbol.section = info->funcsection;
|
||
+ csymp->symbol.udata.p = NULL;
|
||
+ coff_record_symbol (info, csymp);
|
||
+ }
|
||
+
|
||
+ if (info->funname == NULL)
|
||
+ return TRUE;
|
||
+
|
||
+ csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (csymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ csymp->symbol.name = ".bb";
|
||
+ csymp->native->u.syment.n_sclass = C_BLOCK;
|
||
+ csymp->native->u.syment.n_numaux = 1;
|
||
+ csymp->symbol.value = addr - info->funcsection->vma;
|
||
+ csymp->symbol.section = info->funcsection;
|
||
+ csymp->symbol.udata.p = NULL;
|
||
+ coff_record_symbol (info, csymp);
|
||
+
|
||
+ info->flags |= COFF_FL_FIX_BB;
|
||
+
|
||
+ /* Output any pending function parameters, if any. */
|
||
+ if (is_start_fcn && info->nfargs)
|
||
+ {
|
||
+ for (i = 0; i < info->nfargs; i++)
|
||
+ coff_record_symbol (info, info->fargs[i]);
|
||
+
|
||
+ free (info->fargs);
|
||
+ info->fargs = NULL;
|
||
+ info->nfargs = 0;
|
||
+ }
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* End a block. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_end_block (p, addr)
|
||
+ PTR p;
|
||
+ bfd_vma addr;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ coff_symbol_type *csymp;
|
||
+ union internal_auxent *aux;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_end_block(%#x)\n", (int)addr);
|
||
+#endif
|
||
+
|
||
+ if (info->funname == NULL)
|
||
+ return TRUE;
|
||
+
|
||
+ csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (csymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ csymp->symbol.name = ".eb";
|
||
+ csymp->symbol.value = addr - info->funcsection->vma;
|
||
+ csymp->native->u.syment.n_sclass = C_BLOCK;
|
||
+ csymp->native->u.syment.n_numaux = 1;
|
||
+ csymp->symbol.udata.p = NULL;
|
||
+ csymp->symbol.section = info->funcsection;
|
||
+ aux = &((csymp->native + 1)->u.auxent);
|
||
+ aux->x_sym.x_misc.x_lnsz.x_lnno = info->lastlno;
|
||
+ coff_record_symbol (info, csymp);
|
||
+
|
||
+ info->endaddr = addr;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* End a function. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_end_function (p)
|
||
+ PTR p;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ coff_symbol_type *csymp;
|
||
+ union internal_auxent *aux;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_end_function()\n");
|
||
+#endif
|
||
+
|
||
+ if (info->funname == NULL)
|
||
+ return TRUE;
|
||
+
|
||
+ csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
|
||
+ if (csymp == NULL)
|
||
+ return FALSE;
|
||
+
|
||
+ csymp->symbol.name = ".ef";
|
||
+ csymp->symbol.value = info->endaddr - info->funcsection->vma;
|
||
+ csymp->native->u.syment.n_sclass = C_FCN;
|
||
+ csymp->native->u.syment.n_numaux = 1;
|
||
+ csymp->symbol.udata.p = NULL;
|
||
+ csymp->symbol.section = info->funcsection;
|
||
+ aux = &((csymp->native + 1)->u.auxent);
|
||
+ aux->x_sym.x_misc.x_lnsz.x_lnno = info->lastlno;
|
||
+
|
||
+ coff_record_symbol (info, csymp);
|
||
+
|
||
+ csymp = (coff_symbol_type *) info->syms[info->funcindex];
|
||
+ aux = &((csymp->native + 1)->u.auxent);
|
||
+ aux->x_sym.x_misc.x_fsize = info->endaddr - csymp->symbol.value;
|
||
+
|
||
+ info->flags |= COFF_FL_FIX_ENDNDX;
|
||
+ info->funname = NULL;
|
||
+
|
||
+ return TRUE;
|
||
+}
|
||
+
|
||
+/* Output a line number. */
|
||
+
|
||
+static bfd_boolean
|
||
+coff_lineno (p, file, lineno, addr)
|
||
+ PTR p;
|
||
+ const char *file ATTRIBUTE_UNUSED;
|
||
+ unsigned long lineno;
|
||
+ bfd_vma addr;
|
||
+{
|
||
+ struct coff_write_handle *info = (struct coff_write_handle *) p;
|
||
+ coff_symbol_type *csymp;
|
||
+ union internal_auxent *aux;
|
||
+ long i;
|
||
+
|
||
+#if COFF_DEBUG
|
||
+ printf ("coff_lineno(%s, %ld, %d)\n",
|
||
+ file, lineno, (int)addr);
|
||
+#endif
|
||
+
|
||
+ /* COFF can inherently only handle line numbers inside of functions.
|
||
+ If we are not inside a function, punt. */
|
||
+ if (info->funname == NULL)
|
||
+ return TRUE;
|
||
+
|
||
+ if (info->nlnos == 2)
|
||
+ {
|
||
+ /* This is the first line number of this function. Fix the line
|
||
+ number for the .bf symbol immediately following the start of
|
||
+ function. We also have to remember the starting line number
|
||
+ of our function since all line number entries are relative to
|
||
+ it in COFF. Since regular line numbers must always be
|
||
+ non-zero, we artificially force the function to start one
|
||
+ line earlier. */
|
||
+ csymp = (coff_symbol_type *) info->syms[info->funcindex + 1];
|
||
+ aux = &((csymp->native + 1)->u.auxent);
|
||
+ aux->x_sym.x_misc.x_lnsz.x_lnno = lineno;
|
||
+ info->funlno = lineno - 1;
|
||
+ }
|
||
+
|
||
+ if (info->flags & COFF_FL_FIX_BB)
|
||
+ {
|
||
+ /* This is the first line number after one (or more) .bb
|
||
+ symbols. Fix them. In order to cope with multiple blocks
|
||
+ starting at the same line number, we walk back the list of
|
||
+ symbols until we find a C_BLOCK one that had already been
|
||
+ fixed, or until we find a C_FCN symbol (presumably, the start
|
||
+ of our current function). */
|
||
+ info->flags &= ~COFF_FL_FIX_BB;
|
||
+
|
||
+ for (i = info->nsyms - 1; i >= 0; i--)
|
||
+ {
|
||
+ csymp = (coff_symbol_type *) info->syms[i];
|
||
+ if (csymp->native->u.syment.n_sclass == C_FCN)
|
||
+ break;
|
||
+ if (csymp->native->u.syment.n_sclass == C_BLOCK)
|
||
+ {
|
||
+ aux = &((csymp->native + 1)->u.auxent);
|
||
+ if (aux->x_sym.x_misc.x_lnsz.x_lnno != 0)
|
||
+ /* already set up properly */
|
||
+ break;
|
||
+ aux->x_sym.x_misc.x_lnsz.x_lnno = lineno;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ csymp = (coff_symbol_type *) info->syms[info->funcindex];
|
||
+ csymp->lineno = (alent *) xrealloc (csymp->lineno,
|
||
+ ++info->nlnos * sizeof (alent));
|
||
+ memset (csymp->lineno + info->nlnos - 1, 0, sizeof (alent));
|
||
+ if (lineno > info->funlno)
|
||
+ csymp->lineno[info->nlnos - 2].line_number = lineno - info->funlno;
|
||
+ else
|
||
+ /* Line number unreasonable. Can e. g. happen for a line number
|
||
+ from an include file, which we cannot process in COFF. Just
|
||
+ set it to the first line, to avoid generating a large unsigned
|
||
+ short (~ 65000) line number. */
|
||
+ csymp->lineno[info->nlnos - 2].line_number = 1;
|
||
+ csymp->lineno[info->nlnos - 2].u.offset = addr;
|
||
+
|
||
+ info->lastlno = lineno;
|
||
+ info->totlnos++;
|
||
+
|
||
+ return TRUE;
|
||
+}
|