Skip to content

Instantly share code, notes, and snippets.

@cehoffman
Last active August 29, 2015 13:56
Show Gist options
  • Save cehoffman/9110871 to your computer and use it in GitHub Desktop.
Save cehoffman/9110871 to your computer and use it in GitHub Desktop.
binutils 2.24 avr patches
diff --git a/gas/config/tc-avr.c b/gas/config/tc-avr.c
index 332aa2d..729484b 100644
--- a/gas/config/tc-avr.c
+++ b/gas/config/tc-avr.c
@@ -1452,6 +1452,7 @@ md_assemble (char *str)
dwarf2_emit_insn (0);
+ dwarf2_emit_insn (0);
/* We used to set input_line_pointer to the result of get_operands,
but that is wrong. Our caller assumes we don't change it. */
{
diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index c645563..5ad1952 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -273,6 +273,8 @@ BFD32_BACKENDS = \
coff-apollo.lo \
coff-arm.lo \
coff-aux.lo \
+ coff-avr.lo \
+ coff-ext-avr.lo \
coff-go32.lo \
coff-h8300.lo \
coff-h8500.lo \
@@ -461,6 +463,8 @@ BFD32_BACKENDS_CFILES = \
coff-apollo.c \
coff-arm.c \
coff-aux.c \
+ coff-avr.c \
+ coff-ext-avr.c \
coff-go32.c \
coff-h8300.c \
coff-h8500.c \
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 78d2d2c..952e2bb 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -575,6 +575,8 @@ BFD32_BACKENDS = \
coff-apollo.lo \
coff-arm.lo \
coff-aux.lo \
+ coff-avr.lo \
+ coff-ext-avr.lo \
coff-go32.lo \
coff-h8300.lo \
coff-h8500.lo \
@@ -763,6 +765,8 @@ BFD32_BACKENDS_CFILES = \
coff-apollo.c \
coff-arm.c \
coff-aux.c \
+ coff-avr.c \
+ coff-ext-avr.c \
coff-go32.c \
coff-h8300.c \
coff-h8500.c \
diff --git a/bfd/coff-avr.c b/bfd/coff-avr.c
new file mode 100644
index 0000000..d02e933
--- /dev/null
+++ b/bfd/coff-avr.c
@@ -0,0 +1,613 @@
+/* BFD back-end for Atmel AVR COFF files.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1999, 2000, 2001, 2003
+ Free Software Foundation, Inc.
+ Created mostly by substituting "avr" for "i860" in coff-i860.c
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+#include "coff/avr.h"
+
+#include "coff/internal.h"
+
+#include "libcoff.h"
+
+static bfd_reloc_status_type coff_avr_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static reloc_howto_type *coff_avr_rtype_to_howto
+ PARAMS ((bfd *, asection *, struct internal_reloc *,
+ struct coff_link_hash_entry *, struct internal_syment *,
+ bfd_vma *));
+static const bfd_target * coff_avr_object_p PARAMS ((bfd *));
+
+#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
+/* The page size is a guess based on ELF. */
+
+#define COFF_PAGE_SIZE 0x1000
+
+/* For some reason when using avr COFF the value stored in the .text
+ section for a reference to a common symbol is the value itself plus
+ any desired offset. Ian Taylor, Cygnus Support. */
+
+/* If we are producing relocateable output, we need to do some
+ adjustments to the object file that are not done by the
+ bfd_perform_relocation function. This function is called by every
+ reloc type to make any required adjustments. */
+
+static bfd_reloc_status_type
+coff_avr_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
+ error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section ATTRIBUTE_UNUSED;
+ bfd *output_bfd;
+ char **error_message ATTRIBUTE_UNUSED;
+{
+ symvalue diff;
+
+ if (output_bfd == (bfd *) NULL)
+ return bfd_reloc_continue;
+
+ if (bfd_is_com_section (symbol->section))
+ {
+ /* We are relocating a common symbol. The current value in the
+ object file is ORIG + OFFSET, where ORIG is the value of the
+ common symbol as seen by the object file when it was compiled
+ (this may be zero if the symbol was undefined) and OFFSET is
+ the offset into the common symbol (normally zero, but may be
+ non-zero when referring to a field in a common structure).
+ ORIG is the negative of reloc_entry->addend, which is set by
+ the CALC_ADDEND macro below. We want to replace the value in
+ the object file with NEW + OFFSET, where NEW is the value of
+ the common symbol which we are going to put in the final
+ object file. NEW is symbol->value. */
+ diff = symbol->value + reloc_entry->addend;
+ }
+ else
+ {
+ /* For some reason bfd_perform_relocation always effectively
+ ignores the addend for a COFF target when producing
+ relocateable output. This seems to be always wrong for 860
+ COFF, so we handle the addend here instead. */
+ diff = reloc_entry->addend;
+ }
+
+#define DOIT(x) \
+ x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
+
+ if (diff != 0)
+ {
+ reloc_howto_type *howto = reloc_entry->howto;
+ unsigned char *addr = (unsigned char *) data + reloc_entry->address;
+
+ switch (howto->size)
+ {
+ case 0:
+ {
+ char x = bfd_get_8 (abfd, addr);
+ DOIT (x);
+ bfd_put_8 (abfd, x, addr);
+ }
+ break;
+
+ case 1:
+ {
+ short x = bfd_get_16 (abfd, addr);
+ DOIT (x);
+ bfd_put_16 (abfd, (bfd_vma) x, addr);
+ }
+ break;
+
+ case 2:
+ {
+ long x = bfd_get_32 (abfd, addr);
+ DOIT (x);
+ bfd_put_32 (abfd, (bfd_vma) x, addr);
+ }
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
+ /* Now let bfd_perform_relocation finish everything up. */
+ return bfd_reloc_continue;
+}
+
+#ifndef PCRELOFFSET
+#define PCRELOFFSET FALSE
+#endif
+
+static reloc_howto_type howto_table[] =
+{
+ EMPTY_HOWTO (0),
+ EMPTY_HOWTO (1),
+ EMPTY_HOWTO (2),
+ EMPTY_HOWTO (3),
+ EMPTY_HOWTO (4),
+ EMPTY_HOWTO (5),
+ HOWTO (R_DIR32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_avr_reloc, /* special_function */
+ "dir32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+ /* {7}, */
+ HOWTO (R_IMAGEBASE, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_avr_reloc, /* special_function */
+ "rva32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+ EMPTY_HOWTO (010),
+ EMPTY_HOWTO (011),
+ EMPTY_HOWTO (012),
+ EMPTY_HOWTO (013),
+ EMPTY_HOWTO (014),
+ EMPTY_HOWTO (015),
+ EMPTY_HOWTO (016),
+ HOWTO (R_RELBYTE, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_avr_reloc, /* special_function */
+ "8", /* name */
+ TRUE, /* partial_inplace */
+ 0x000000ff, /* src_mask */
+ 0x000000ff, /* dst_mask */
+ PCRELOFFSET), /* pcrel_offset */
+ HOWTO (R_RELWORD, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_avr_reloc, /* special_function */
+ "16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ PCRELOFFSET), /* pcrel_offset */
+ HOWTO (R_RELLONG, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_avr_reloc, /* special_function */
+ "32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ PCRELOFFSET), /* pcrel_offset */
+ HOWTO (R_PCRBYTE, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ coff_avr_reloc, /* special_function */
+ "DISP8", /* name */
+ TRUE, /* partial_inplace */
+ 0x000000ff, /* src_mask */
+ 0x000000ff, /* dst_mask */
+ PCRELOFFSET), /* pcrel_offset */
+ HOWTO (R_PCRWORD, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ coff_avr_reloc, /* special_function */
+ "DISP16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ PCRELOFFSET), /* pcrel_offset */
+ HOWTO (R_PCRLONG, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ coff_avr_reloc, /* special_function */
+ "DISP32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ PCRELOFFSET) /* pcrel_offset */
+};
+
+/* Turn a howto into a reloc nunmber */
+
+#define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
+#define BADMAG(x) AVRBADMAG(x)
+#define AVR 1 /* Customize coffcode.h */
+
+#define RTYPE2HOWTO(cache_ptr, dst) \
+ (cache_ptr)->howto = howto_table + (dst)->r_type;
+
+/* For AVR COFF a STYP_NOLOAD | STYP_BSS section is part of a shared
+ library. On some other COFF targets STYP_BSS is normally
+ STYP_NOLOAD. */
+#define BSS_NOLOAD_IS_SHARED_LIBRARY
+
+/* Compute the addend of a reloc. If the reloc is to a common symbol,
+ the object file contains the value of the common symbol. By the
+ time this is called, the linker may be using a different symbol
+ from a different object file with a different value. Therefore, we
+ hack wildly to locate the original symbol from this file so that we
+ can make the correct adjustment. This macro sets coffsym to the
+ symbol from the original file, and uses it to set the addend value
+ correctly. If this is not a common symbol, the usual addend
+ calculation is done, except that an additional tweak is needed for
+ PC relative relocs.
+ FIXME: This macro refers to symbols and asect; these are from the
+ calling function, not the macro arguments. */
+
+#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \
+ { \
+ coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \
+ if (ptr && bfd_asymbol_bfd (ptr) != abfd) \
+ coffsym = (obj_symbols (abfd) \
+ + (cache_ptr->sym_ptr_ptr - symbols)); \
+ else if (ptr) \
+ coffsym = coff_symbol_from (abfd, ptr); \
+ if (coffsym != (coff_symbol_type *) NULL \
+ && coffsym->native->u.syment.n_scnum == 0) \
+ cache_ptr->addend = - coffsym->native->u.syment.n_value; \
+ else if (ptr && bfd_asymbol_bfd (ptr) == abfd \
+ && ptr->section != (asection *) NULL) \
+ cache_ptr->addend = - (ptr->section->vma + ptr->value); \
+ else \
+ cache_ptr->addend = 0; \
+ if (ptr && howto_table[reloc.r_type].pc_relative) \
+ cache_ptr->addend += asect->vma; \
+ }
+
+/* We use the special COFF backend linker. */
+#define coff_relocate_section _bfd_coff_generic_relocate_section
+
+static reloc_howto_type *
+coff_avr_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *sec;
+ struct internal_reloc *rel;
+ struct coff_link_hash_entry *h;
+ struct internal_syment *sym;
+ bfd_vma *addendp;
+{
+
+ reloc_howto_type *howto;
+
+ howto = howto_table + rel->r_type;
+
+ if (howto->pc_relative)
+ *addendp += sec->vma;
+
+ if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0)
+ {
+ /* This is a common symbol. The section contents include the
+ size (sym->n_value) as an addend. The relocate_section
+ function will be adding in the final value of the symbol. We
+ need to subtract out the current size in order to get the
+ correct result. */
+
+ BFD_ASSERT (h != NULL);
+
+ /* I think we *do* want to bypass this. If we don't, I have seen some data
+ parameters get the wrong relcation address. If I link two versions
+ with and without this section bypassed and then do a binary comparison,
+ the addresses which are different can be looked up in the map. The
+ case in which this section has been bypassed has addresses which correspond
+ to values I can find in the map. */
+ *addendp -= sym->n_value;
+ }
+
+ /* If the output symbol is common (in which case this must be a
+ relocateable link), we need to add in the final size of the
+ common symbol. */
+ if (h != NULL && h->root.type == bfd_link_hash_common)
+ *addendp += h->root.u.c.size;
+
+ return howto;
+}
+
+#define coff_rtype_to_howto coff_avr_rtype_to_howto
+
+#ifndef bfd_pe_print_pdata
+#define bfd_pe_print_pdata NULL
+#endif
+
+#include "coffcode.h"
+
+static const bfd_target *
+coff_avr_object_p(a)
+ bfd *a;
+{
+ return coff_object_p (a);
+}
+
+/* Handle all the abominations of AVR COFF:
+
+ Generic COFF always uses the D1 slot to indicate the "most
+ important" derived type, and the D2...Dn slots for decreasing
+ importance. E. g., a function symbol will always have its DT_FCN
+ element in D1, an array its DT_ARY (its first DT_ARY in a
+ multi-dimensional array). In contrast, AVR COFF expects this most
+ important derived type specifier in the upmost Dn slot that is
+ allocated at all (i. e. that is != 0).
+
+ Generic COFF says that "Any symbol that satisfies more than one
+ condition [... for AUX entries] should have a union format in its
+ auxiliary entry." AVR COFF uses sepearate AUX entries for multiple
+ derived types, and in some cases (like the ISFCN one), even puts
+ the most important one into the last allocated AUX entry. We
+ join/split them here at the border as well. Note that when
+ generating AUX entries (where we need to split them), the n_numaux
+ field must already have been set up properly (e. g. in
+ binutils/wrcoff.c) since the entry renumbering and pointerization
+ would not work otherwise. Thus, we only split the information into
+ multiple records if n_numaux > 1. For similar reasons, we keep
+ n_numaux > 1 on input to keep the appropriate AUX entries
+ allocated, so a symbol can be reconstructed if it is being passed
+ through one of the GNU tools.
+
+ Note that this adjustment is called after the symbol itself has
+ been swapped in, but before the AUX entries are swapped in. This
+ is the only hook available that could swap (or merge) AUX entries
+ at all, so we have to operate on the external AUX entries still. */
+
+void
+avr_coff_adjust_sym_in_post (abfd, ext, in)
+ bfd *abfd;
+ PTR ext;
+ PTR in;
+{
+ struct internal_syment *dst = (struct internal_syment *)in;
+ unsigned short dt, bt, ndt;
+ dt = dst->n_type & ~N_BTMASK;
+ bt = BTYPE (dst->n_type);
+
+ /* Some AVR COFF producers seem to violate the COFF specs, and
+ produce symbols for tag names that have the C_FOO filled in
+ properly, but T_NULL as the base type value. Patch up here,
+ since some of our generic COFF tools (in particular
+ binutils/rdcoff.c) rely on the correct data. */
+ if (bt == T_NULL)
+ switch (dst->n_sclass)
+ {
+ case C_STRTAG:
+ bt = T_STRUCT;
+ break;
+
+ case C_UNTAG:
+ bt = T_UNION;
+ break;
+
+ case C_ENTAG:
+ bt = T_ENUM;
+ break;
+ }
+
+ /* Swap the derived type slots. */
+ if (dt != 0)
+ {
+ ndt = 0;
+ while (dt != 0)
+ {
+ ndt = (ndt << N_TSHIFT) | (dt & (N_TMASK >> N_BTSHFT));
+ dt >>= N_TSHIFT;
+ }
+ dst->n_type = (ndt << N_BTSHFT) | bt;
+ }
+ else
+ dst->n_type = bt;
+
+ /* If the derived type is function, and there is more than one AUX
+ entry, swap the first and the last AUX entry, so the most
+ interesting one will become the first.
+
+ If the fundamental type is a tagged type (struct/union/enum), try
+ to find the AUX entry describing the tagged type (the one that
+ has x_sym.x_tagndx filled in), and merge the tag index into the
+ first AUX entry. Depending on the actual input file, there might
+ be further DT_PTR entries which we just ignore, since we could
+ not handle that information anyway. */
+ if (dst->n_numaux > 1 && dst->n_sclass != C_FILE)
+ {
+ AUXENT caux, *auxp1, *auxp2;
+ size_t symesz;
+ unsigned int i;
+
+ symesz = bfd_coff_symesz (abfd);
+ i = dst->n_numaux;
+
+ auxp1 = (AUXENT *)((char *)ext + symesz);
+ auxp2 = (AUXENT *)((char *)ext + i * symesz);
+
+ if (ISFCN (dst->n_type)
+ || (ISPTR(dst->n_type)
+ && (bt == T_STRUCT || bt == T_UNION || bt == T_ENUM)))
+ {
+ caux = *auxp2;
+ *auxp2 = *auxp1;
+ *auxp1 = caux;
+ }
+ else
+ caux = *auxp1;
+
+ if ((ISFCN (dst->n_type) || ISARY (dst->n_type))
+ && (bt == T_STRUCT || bt == T_UNION || bt == T_ENUM))
+ {
+ while (i > 1)
+ {
+ auxp2 = (AUXENT *)((char *)ext + i * symesz);
+
+ if (auxp2->x_sym.x_tagndx[0] != 0 || auxp2->x_sym.x_tagndx[1] != 0
+ || auxp2->x_sym.x_tagndx[2] != 0 || auxp2->x_sym.x_tagndx[3] != 0)
+ {
+ memcpy (caux.x_sym.x_tagndx, auxp2->x_sym.x_tagndx,
+ 4 * sizeof (char));
+ break;
+ }
+ i--;
+ }
+ if (i > 1)
+ *auxp1 = caux;
+ }
+ }
+}
+
+/* When exporting an AVR COFF file, just undo all that has been done
+ above. Again, we are called after the symbol itself has been
+ swapped out, but before the AUX entries are being written.
+ Unfortunately, we are only given a pointer to the symbol itself, so
+ we have to derive the pointer to the respective aux entries from
+ that address, which is a bit clumsy. */
+void
+avr_coff_adjust_sym_out_post (abfd, in, ext)
+ bfd *abfd;
+ PTR in;
+ PTR ext;
+{
+ struct internal_syment *src = (struct internal_syment *)(in);
+ struct external_syment *dst = (struct external_syment *)(ext);
+ unsigned short dt, bt, ndt;
+
+ dt = src->n_type & ~N_BTMASK;
+ bt = BTYPE (src->n_type);
+
+ if (dt != 0)
+ {
+ ndt = 0;
+ while (dt != 0)
+ {
+ ndt = (ndt << N_TSHIFT) | (dt & (N_TMASK >> N_BTSHFT));
+ dt >>= N_TSHIFT;
+ }
+ H_PUT_16 (abfd, (ndt << N_BTSHFT) | bt, dst->e_type);
+ }
+
+ if (src->n_numaux > 1 && src->n_sclass != C_FILE)
+ {
+ combined_entry_type *srce, *dste;
+ char *hackp;
+ unsigned int i;
+
+ /* Recover the original combinend_entry_type *. */
+ hackp = (char *)in;
+ hackp -= offsetof(combined_entry_type, u.syment);
+ srce = (combined_entry_type *)hackp;
+ srce++;
+
+ /* We simply duplicate the first AUX entry as many times as
+ needed. Since COFF itself normally uses just a single AUX
+ entry for all the information, this will work -- each COFF
+ consumer will then just pick the fields it is particularly
+ interested in. This would not work for the AVR COFF specific
+ DT_PTR AUX entries, but we don't support them anyway. */
+ for (i = 1; i < src->n_numaux; i++)
+ {
+ dste = srce + i;
+ *dste = *srce;
+ }
+ }
+}
+
+const bfd_target
+#ifdef TARGET_SYM
+ TARGET_SYM =
+#else
+ avrcoff_vec =
+#endif
+{
+#ifdef TARGET_NAME
+ TARGET_NAME,
+#else
+ "coff-avr", /* name */
+#endif
+ bfd_target_coff_flavour,
+ BFD_ENDIAN_LITTLE, /* data byte order is little */
+ BFD_ENDIAN_LITTLE, /* header byte order is little */
+
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | WP_TEXT),
+
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+ 0, /* leading char */
+ '/', /* ar_pad_char */
+ 15, /* ar_max_namelen */
+
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+
+/* Note that we allow an object file to be treated as a core file as well. */
+ {_bfd_dummy_target, coff_avr_object_p, /* bfd_check_format */
+ bfd_generic_archive_p, coff_avr_object_p},
+ {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
+ bfd_false},
+ {bfd_false, coff_write_object_contents, /* bfd_write_contents */
+ _bfd_write_archive_contents, bfd_false},
+
+ BFD_JUMP_TABLE_GENERIC (coff),
+ BFD_JUMP_TABLE_COPY (coff),
+ BFD_JUMP_TABLE_CORE (_bfd_nocore),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
+ BFD_JUMP_TABLE_SYMBOLS (coff),
+ BFD_JUMP_TABLE_RELOCS (coff),
+ BFD_JUMP_TABLE_WRITE (coff),
+ BFD_JUMP_TABLE_LINK (coff),
+ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+ NULL,
+
+ COFF_SWAP_TABLE
+};
diff --git a/bfd/coff-ext-avr.c b/bfd/coff-ext-avr.c
new file mode 100644
index 0000000..717ef8e
--- /dev/null
+++ b/bfd/coff-ext-avr.c
@@ -0,0 +1,428 @@
+/* BFD back-end for Atmel AVR "extended" COFF files.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1999, 2000, 2001, 2003
+ Free Software Foundation, Inc.
+ This is mostly the same as avr-coff, except of the presence of the
+ COFF optional header.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+#define AVR_EXT_COFF 1
+#include "coff/avr.h"
+
+#include "coff/internal.h"
+
+#include "libcoff.h"
+
+static bfd_reloc_status_type coff_ext_avr_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static reloc_howto_type *coff_ext_avr_rtype_to_howto
+ PARAMS ((bfd *, asection *, struct internal_reloc *,
+ struct coff_link_hash_entry *, struct internal_syment *,
+ bfd_vma *));
+static const bfd_target * coff_ext_avr_object_p PARAMS ((bfd *));
+
+#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
+/* The page size is a guess based on ELF. */
+
+#define COFF_PAGE_SIZE 0x1000
+
+/* For some reason when using avr COFF the value stored in the .text
+ section for a reference to a common symbol is the value itself plus
+ any desired offset. Ian Taylor, Cygnus Support. */
+
+/* If we are producing relocateable output, we need to do some
+ adjustments to the object file that are not done by the
+ bfd_perform_relocation function. This function is called by every
+ reloc type to make any required adjustments. */
+
+static bfd_reloc_status_type
+coff_ext_avr_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
+ error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section ATTRIBUTE_UNUSED;
+ bfd *output_bfd;
+ char **error_message ATTRIBUTE_UNUSED;
+{
+ symvalue diff;
+
+ if (output_bfd == (bfd *) NULL)
+ return bfd_reloc_continue;
+
+ if (bfd_is_com_section (symbol->section))
+ {
+ /* We are relocating a common symbol. The current value in the
+ object file is ORIG + OFFSET, where ORIG is the value of the
+ common symbol as seen by the object file when it was compiled
+ (this may be zero if the symbol was undefined) and OFFSET is
+ the offset into the common symbol (normally zero, but may be
+ non-zero when referring to a field in a common structure).
+ ORIG is the negative of reloc_entry->addend, which is set by
+ the CALC_ADDEND macro below. We want to replace the value in
+ the object file with NEW + OFFSET, where NEW is the value of
+ the common symbol which we are going to put in the final
+ object file. NEW is symbol->value. */
+ diff = symbol->value + reloc_entry->addend;
+ }
+ else
+ {
+ /* For some reason bfd_perform_relocation always effectively
+ ignores the addend for a COFF target when producing
+ relocateable output. This seems to be always wrong for 860
+ COFF, so we handle the addend here instead. */
+ diff = reloc_entry->addend;
+ }
+
+#define DOIT(x) \
+ x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
+
+ if (diff != 0)
+ {
+ reloc_howto_type *howto = reloc_entry->howto;
+ unsigned char *addr = (unsigned char *) data + reloc_entry->address;
+
+ switch (howto->size)
+ {
+ case 0:
+ {
+ char x = bfd_get_8 (abfd, addr);
+ DOIT (x);
+ bfd_put_8 (abfd, x, addr);
+ }
+ break;
+
+ case 1:
+ {
+ short x = bfd_get_16 (abfd, addr);
+ DOIT (x);
+ bfd_put_16 (abfd, (bfd_vma) x, addr);
+ }
+ break;
+
+ case 2:
+ {
+ long x = bfd_get_32 (abfd, addr);
+ DOIT (x);
+ bfd_put_32 (abfd, (bfd_vma) x, addr);
+ }
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
+ /* Now let bfd_perform_relocation finish everything up. */
+ return bfd_reloc_continue;
+}
+
+#ifndef PCRELOFFSET
+#define PCRELOFFSET FALSE
+#endif
+
+static reloc_howto_type howto_table[] =
+{
+ EMPTY_HOWTO (0),
+ EMPTY_HOWTO (1),
+ EMPTY_HOWTO (2),
+ EMPTY_HOWTO (3),
+ EMPTY_HOWTO (4),
+ EMPTY_HOWTO (5),
+ HOWTO (R_DIR32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_ext_avr_reloc, /* special_function */
+ "dir32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+ /* {7}, */
+ HOWTO (R_IMAGEBASE, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_ext_avr_reloc, /* special_function */
+ "rva32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+ EMPTY_HOWTO (010),
+ EMPTY_HOWTO (011),
+ EMPTY_HOWTO (012),
+ EMPTY_HOWTO (013),
+ EMPTY_HOWTO (014),
+ EMPTY_HOWTO (015),
+ EMPTY_HOWTO (016),
+ HOWTO (R_RELBYTE, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_ext_avr_reloc, /* special_function */
+ "8", /* name */
+ TRUE, /* partial_inplace */
+ 0x000000ff, /* src_mask */
+ 0x000000ff, /* dst_mask */
+ PCRELOFFSET), /* pcrel_offset */
+ HOWTO (R_RELWORD, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_ext_avr_reloc, /* special_function */
+ "16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ PCRELOFFSET), /* pcrel_offset */
+ HOWTO (R_RELLONG, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ coff_ext_avr_reloc, /* special_function */
+ "32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ PCRELOFFSET), /* pcrel_offset */
+ HOWTO (R_PCRBYTE, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ coff_ext_avr_reloc, /* special_function */
+ "DISP8", /* name */
+ TRUE, /* partial_inplace */
+ 0x000000ff, /* src_mask */
+ 0x000000ff, /* dst_mask */
+ PCRELOFFSET), /* pcrel_offset */
+ HOWTO (R_PCRWORD, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ coff_ext_avr_reloc, /* special_function */
+ "DISP16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ PCRELOFFSET), /* pcrel_offset */
+ HOWTO (R_PCRLONG, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ coff_ext_avr_reloc, /* special_function */
+ "DISP32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ PCRELOFFSET) /* pcrel_offset */
+};
+
+/* Turn a howto into a reloc nunmber */
+
+#define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
+#define BADMAG(x) AVRBADMAG(x)
+#define AVR 1 /* Customize coffcode.h */
+
+#define RTYPE2HOWTO(cache_ptr, dst) \
+ (cache_ptr)->howto = howto_table + (dst)->r_type;
+
+/* For AVR COFF a STYP_NOLOAD | STYP_BSS section is part of a shared
+ library. On some other COFF targets STYP_BSS is normally
+ STYP_NOLOAD. */
+#define BSS_NOLOAD_IS_SHARED_LIBRARY
+
+/* Compute the addend of a reloc. If the reloc is to a common symbol,
+ the object file contains the value of the common symbol. By the
+ time this is called, the linker may be using a different symbol
+ from a different object file with a different value. Therefore, we
+ hack wildly to locate the original symbol from this file so that we
+ can make the correct adjustment. This macro sets coffsym to the
+ symbol from the original file, and uses it to set the addend value
+ correctly. If this is not a common symbol, the usual addend
+ calculation is done, except that an additional tweak is needed for
+ PC relative relocs.
+ FIXME: This macro refers to symbols and asect; these are from the
+ calling function, not the macro arguments. */
+
+#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \
+ { \
+ coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \
+ if (ptr && bfd_asymbol_bfd (ptr) != abfd) \
+ coffsym = (obj_symbols (abfd) \
+ + (cache_ptr->sym_ptr_ptr - symbols)); \
+ else if (ptr) \
+ coffsym = coff_symbol_from (abfd, ptr); \
+ if (coffsym != (coff_symbol_type *) NULL \
+ && coffsym->native->u.syment.n_scnum == 0) \
+ cache_ptr->addend = - coffsym->native->u.syment.n_value; \
+ else if (ptr && bfd_asymbol_bfd (ptr) == abfd \
+ && ptr->section != (asection *) NULL) \
+ cache_ptr->addend = - (ptr->section->vma + ptr->value); \
+ else \
+ cache_ptr->addend = 0; \
+ if (ptr && howto_table[reloc.r_type].pc_relative) \
+ cache_ptr->addend += asect->vma; \
+ }
+
+/* We use the special COFF backend linker. */
+#define coff_relocate_section _bfd_coff_generic_relocate_section
+
+static reloc_howto_type *
+coff_ext_avr_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *sec;
+ struct internal_reloc *rel;
+ struct coff_link_hash_entry *h;
+ struct internal_syment *sym;
+ bfd_vma *addendp;
+{
+
+ reloc_howto_type *howto;
+
+ howto = howto_table + rel->r_type;
+
+ if (howto->pc_relative)
+ *addendp += sec->vma;
+
+ if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0)
+ {
+ /* This is a common symbol. The section contents include the
+ size (sym->n_value) as an addend. The relocate_section
+ function will be adding in the final value of the symbol. We
+ need to subtract out the current size in order to get the
+ correct result. */
+
+ BFD_ASSERT (h != NULL);
+
+ /* I think we *do* want to bypass this. If we don't, I have seen some data
+ parameters get the wrong relcation address. If I link two versions
+ with and without this section bypassed and then do a binary comparison,
+ the addresses which are different can be looked up in the map. The
+ case in which this section has been bypassed has addresses which correspond
+ to values I can find in the map. */
+ *addendp -= sym->n_value;
+ }
+
+ /* If the output symbol is common (in which case this must be a
+ relocateable link), we need to add in the final size of the
+ common symbol. */
+ if (h != NULL && h->root.type == bfd_link_hash_common)
+ *addendp += h->root.u.c.size;
+
+ return howto;
+}
+
+#define coff_rtype_to_howto coff_ext_avr_rtype_to_howto
+
+#ifndef bfd_pe_print_pdata
+#define bfd_pe_print_pdata NULL
+#endif
+
+#include "coffcode.h"
+
+static const bfd_target *
+coff_ext_avr_object_p(a)
+ bfd *a;
+{
+ return coff_object_p (a);
+}
+
+const bfd_target
+#ifdef TARGET_SYM
+ TARGET_SYM =
+#else
+ avrextcoff_vec =
+#endif
+{
+#ifdef TARGET_NAME
+ TARGET_NAME,
+#else
+ "coff-ext-avr", /* name */
+#endif
+ bfd_target_coff_flavour,
+ BFD_ENDIAN_LITTLE, /* data byte order is little */
+ BFD_ENDIAN_LITTLE, /* header byte order is little */
+
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | WP_TEXT),
+
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+ 0, /* leading char */
+ '/', /* ar_pad_char */
+ 15, /* ar_max_namelen */
+
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+
+/* Note that we allow an object file to be treated as a core file as well. */
+ {_bfd_dummy_target, coff_ext_avr_object_p, /* bfd_check_format */
+ bfd_generic_archive_p, coff_ext_avr_object_p},
+ {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
+ bfd_false},
+ {bfd_false, coff_write_object_contents, /* bfd_write_contents */
+ _bfd_write_archive_contents, bfd_false},
+
+ BFD_JUMP_TABLE_GENERIC (coff),
+ BFD_JUMP_TABLE_COPY (coff),
+ BFD_JUMP_TABLE_CORE (_bfd_nocore),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
+ BFD_JUMP_TABLE_SYMBOLS (coff),
+ BFD_JUMP_TABLE_RELOCS (coff),
+ BFD_JUMP_TABLE_WRITE (coff),
+ BFD_JUMP_TABLE_LINK (coff),
+ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+ NULL,
+
+ COFF_SWAP_TABLE
+};
diff --git a/bfd/coffcode.h b/bfd/coffcode.h
index 542b5b7..e2d89d8 100644
--- a/bfd/coffcode.h
+++ b/bfd/coffcode.h
@@ -1,3 +1,4 @@
+
/* Support for the generic parts of most COFF variants, for BFD.
Copyright 1990-2013 Free Software Foundation, Inc.
Written by Cygnus Support.
@@ -1983,6 +1984,17 @@ coff_mkobject (bfd * abfd)
coff->relocbase = 0;
coff->local_toc_sym_map = 0;
+ /* These members communicate important constants about the symbol
+ table to GDB's symbol-reading code. These `constants'
+ unfortunately vary among coff implementations... */
+ coff->local_n_btmask = N_BTMASK;
+ coff->local_n_btshft = N_BTSHFT;
+ coff->local_n_tmask = N_TMASK;
+ coff->local_n_tshift = N_TSHIFT;
+ coff->local_symesz = bfd_coff_symesz (abfd);
+ coff->local_auxesz = bfd_coff_auxesz (abfd);
+ coff->local_linesz = bfd_coff_linesz (abfd);
+
/* make_abs_section(abfd);*/
return TRUE;
@@ -2007,17 +2019,6 @@ coff_mkobject_hook (bfd * abfd,
coff->sym_filepos = internal_f->f_symptr;
- /* These members communicate important constants about the symbol
- table to GDB's symbol-reading code. These `constants'
- unfortunately vary among coff implementations... */
- coff->local_n_btmask = N_BTMASK;
- coff->local_n_btshft = N_BTSHFT;
- coff->local_n_tmask = N_TMASK;
- coff->local_n_tshift = N_TSHIFT;
- coff->local_symesz = bfd_coff_symesz (abfd);
- coff->local_auxesz = bfd_coff_auxesz (abfd);
- coff->local_linesz = bfd_coff_linesz (abfd);
-
coff->timestamp = internal_f->f_timdat;
obj_raw_syment_count (abfd) =
@@ -2149,6 +2150,11 @@ coff_set_arch_mach_hook (bfd *abfd, void * filehdr)
}
break;
#endif
+#ifdef AVRMAGIC
+ case AVRMAGIC:
+ arch = bfd_arch_avr;
+ break;
+#endif
#ifdef MC68MAGIC
case MC68MAGIC:
case M68MAGIC:
@@ -2928,6 +2934,13 @@ coff_set_flags (bfd * abfd,
return TRUE;
#endif
+#ifdef AVRMAGIC
+ case bfd_arch_avr:
+ *magicp = AVRMAGIC;
+ return TRUE;
+ break;
+#endif
+
#ifdef PPCMAGIC
case bfd_arch_powerpc:
*magicp = PPCMAGIC;
@@ -3758,6 +3771,11 @@ coff_write_object_contents (bfd * abfd)
section.s_page = 0;
#endif
+#ifdef AVR
+ /* AVR uses s_paddr the way GNU uses s_vaddr, and effectively
+ ignores s_vaddr. */
+ section.s_paddr = current->vma;
+#endif
#ifdef COFF_WITH_PE
section.s_paddr = 0;
#endif
@@ -4104,6 +4122,17 @@ coff_write_object_contents (bfd * abfd)
internal_a.magic = ZMAGIC;
#endif
+#ifdef AVR
+ /* a.out is a dummy for non-extended COFF */
+ internal_a.magic = AVRAOUTMAGIC;
+ /* Upper nibble of f_flags must be set for historical reasons.
+ The upper byte remains blank on coff-avr, so undo the F_AR32WR
+ setting performed above. */
+ internal_f.f_flags |= F_JUNK;
+ internal_f.f_flags &= ~F_UNUSED;
+#define __A_MAGIC_SET__
+#endif /* AVR */
+
#if defined(PPC_PE)
#define __A_MAGIC_SET__
internal_a.magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
@@ -4166,8 +4195,16 @@ coff_write_object_contents (bfd * abfd)
#endif
}
+#ifdef AVR_EXT_COFF
+ /* Note that we do not set F_PTRINFO because the GNU toolchain
+ doesn't provide any information about the target of a pointer,
+ so we cannot derive which section our pointer target would be
+ in. */
+ internal_a.vstamp = F_FULLPATHS | F_STRUCTINFO;
+#else
/* FIXME: Does anybody ever set this to another value? */
internal_a.vstamp = 0;
+#endif
/* Now should write relocs, strings, syms. */
obj_sym_filepos (abfd) = sym_base;
@@ -4725,6 +4762,10 @@ coff_slurp_symbol_table (bfd * abfd)
/* In PE, 0x69 (105) denotes a weak external symbol. */
case C_NT_WEAK:
#endif
+#ifdef AVR
+ /* Some AVR COFF compilers handle EXTDEF like EXT. */
+ case C_EXTDEF: /* external definition */
+#endif
switch (coff_classify_symbol (abfd, &src->u.syment))
{
case COFF_SYMBOL_GLOBAL:
@@ -4957,7 +4998,9 @@ coff_slurp_symbol_table (bfd * abfd)
break;
#endif
/* Fall through. */
+#if !defined(AVR)
case C_EXTDEF: /* External definition. */
+#endif
case C_ULABEL: /* Undefined label. */
case C_USTATIC: /* Undefined static. */
#ifndef COFF_WITH_PE
diff --git a/bfd/coffgen.c b/bfd/coffgen.c
index 07a527d..4681831 100644
--- a/bfd/coffgen.c
+++ b/bfd/coffgen.c
@@ -773,6 +773,20 @@ coff_renumber_symbols (bfd *bfd_ptr, int *first_undef)
if (last_file != NULL)
last_file->n_value = native_index;
last_file = &(s->u.syment);
+ if (bfd_get_arch (bfd_ptr) == bfd_arch_avr
+ && bfd_coff_long_filenames (bfd_ptr)
+ && s->u.syment.n_numaux > 0)
+ {
+ /* AVR COFF records long filenames in successive aux
+ records. Adjust the number of aux records
+ required here, so the renumbering will account
+ for them. */
+ unsigned int filnmlen = bfd_coff_filnmlen (bfd_ptr);
+ unsigned int namelen = strlen (coff_symbol_ptr->symbol.name);
+ unsigned int n = (namelen + filnmlen - 1) / filnmlen;
+
+ s->u.syment.n_numaux = n > NAUXENTS? NAUXENTS: n;
+ }
}
else
/* Modify the symbol values according to their section and
@@ -901,6 +915,20 @@ coff_fix_symbol_name (bfd *abfd,
{
if (name_length <= filnmlen)
strncpy (auxent->x_file.x_fname, name, filnmlen);
+ else if (bfd_get_arch (abfd) == bfd_arch_avr)
+ {
+ /* AVR COFF records long filenames in successive aux records. */
+ int i = 1;
+ while (name_length > filnmlen && i < NAUXENTS)
+ {
+ strncpy (auxent->x_file.x_fname, name, filnmlen);
+ name += filnmlen;
+ name_length -= filnmlen;
+ i++;
+ auxent = &(native + i)->u.auxent;
+ }
+ strncpy (auxent->x_file.x_fname, name, filnmlen);
+ }
else
{
auxent->x_file.x_n.x_offset = *string_size_p + STRING_SIZE_SIZE;
@@ -1384,6 +1412,10 @@ coff_write_symbols (bfd *abfd)
if (bfd_bwrite (".file", (bfd_size_type) 6, abfd) != 6)
return FALSE;
}
+ if (bfd_get_arch (abfd) == bfd_arch_avr)
+ /* AVR COFF handles long file names in aux records. */
+ maxlen = name_length;
+ else
maxlen = bfd_coff_filnmlen (abfd);
}
else
@@ -1822,14 +1854,27 @@ coff_get_normalized_symtab (bfd *abfd)
{
/* Ordinary short filename, put into memory anyway. The
Microsoft PE tools sometimes store a filename in
- multiple AUX entries. */
+ multiple AUX entries.
+ AVR COFF does it that way, too. */
if (internal_ptr->u.syment.n_numaux > 1
- && coff_data (abfd)->pe)
- internal_ptr->u.syment._n._n_n._n_offset =
- ((bfd_hostptr_t)
- copy_name (abfd,
- (internal_ptr + 1)->u.auxent.x_file.x_fname,
- internal_ptr->u.syment.n_numaux * symesz));
+ && (coff_data (abfd)->pe
+ || (bfd_get_arch (abfd) == bfd_arch_avr)))
+ {
+ char *b;
+ unsigned int i;
+
+ /* We allocate enough storage to fit the contents of
+ this many aux records, and simply append a \0.
+ This ensures the string will always be
+ terminated, even in the case where it just fit
+ into the aux records. */
+ b = (char *) bfd_alloc (abfd,
+ internal_ptr->u.syment.n_numaux * FILNMLEN + 1);
+ internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) b;
+ b[internal_ptr->u.syment.n_numaux * FILNMLEN] = '\0';
+ for (i = 0; i < internal_ptr->u.syment.n_numaux; i++, b += FILNMLEN)
+ memcpy (b, (internal_ptr + i + 1)->u.auxent.x_file.x_fname, FILNMLEN);
+ }
else
internal_ptr->u.syment._n._n_n._n_offset =
((bfd_hostptr_t)
@@ -1935,9 +1980,9 @@ coff_bfd_make_debug_symbol (bfd *abfd,
if (new_symbol == NULL)
return NULL;
- /* @@ The 10 is a guess at a plausible maximum number of aux entries
+ /* @@ The NAUXENTS is a guess at a plausible maximum number of aux entries
(but shouldn't be a constant). */
- amt = sizeof (combined_entry_type) * 10;
+ amt = sizeof (combined_entry_type) * (NAUXENTS + 1);
new_symbol->native = (combined_entry_type *) bfd_zalloc (abfd, amt);
if (!new_symbol->native)
return NULL;
diff --git a/bfd/coffswap.h b/bfd/coffswap.h
index 674fdc7..785f7da 100644
--- a/bfd/coffswap.h
+++ b/bfd/coffswap.h
@@ -383,7 +383,11 @@ coff_swap_aux_in (bfd *abfd,
void * ext1,
int type,
int in_class,
- int indx,
+ int indx
+#if defined(AVR) && __GNUC__
+ __attribute__((unused))
+#endif
+ ,
int numaux,
void * in1)
{
@@ -409,9 +413,13 @@ coff_swap_aux_in (bfd *abfd,
#else
if (numaux > 1)
{
+#if defined(AVR)
+ memcpy (in->x_file.x_fname, ext->x_file.x_fname, sizeof (AUXENT));
+#else
if (indx == 0)
memcpy (in->x_file.x_fname, ext->x_file.x_fname,
numaux * sizeof (AUXENT));
+#endif
}
else
memcpy (in->x_file.x_fname, ext->x_file.x_fname, FILNMLEN);
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 5324d39..45ed8ed 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -352,6 +352,7 @@ case "${targ}" in
avr-*-*)
targ_defvec=bfd_elf32_avr_vec
+ targ_selvecs="bfd_elf32_avr_vec avrcoff_vec avrextcoff_vec"
;;
bfin-*-*)
diff --git a/bfd/configure b/bfd/configure
index 90cd397..5fa4e41 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -15217,6 +15217,8 @@ do
armpe_little_vec) tb="$tb pe-arm.lo peigen.lo cofflink.lo " ;;
armpei_big_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
armpei_little_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
+ avrcoff_vec) tb="$tb coff-avr.lo cofflink.lo " ;;
+ avrextcoff_vec) tb="$tb coff-ext-avr.lo cofflink.lo " ;;
b_out_vec_big_host) tb="$tb bout.lo aout32.lo" ;;
b_out_vec_little_host) tb="$tb bout.lo aout32.lo" ;;
bfd_pei_ia64_vec) tb="$tb pei-ia64.lo pepigen.lo cofflink.lo"; target_size=64 ;;
diff --git a/bfd/configure.in b/bfd/configure.in
index 0e88d78..2adb188 100644
--- a/bfd/configure.in
+++ b/bfd/configure.in
@@ -706,6 +706,8 @@ do
armpe_little_vec) tb="$tb pe-arm.lo peigen.lo cofflink.lo " ;;
armpei_big_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
armpei_little_vec) tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
+ avrcoff_vec) tb="$tb coff-avr.lo cofflink.lo " ;;
+ avrextcoff_vec) tb="$tb coff-ext-avr.lo cofflink.lo " ;;
b_out_vec_big_host) tb="$tb bout.lo aout32.lo" ;;
b_out_vec_little_host) tb="$tb bout.lo aout32.lo" ;;
bfd_pei_ia64_vec) tb="$tb pei-ia64.lo pepigen.lo cofflink.lo"; target_size=64 ;;
diff --git a/bfd/targets.c b/bfd/targets.c
index b117bfe..efba1bf 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -590,6 +590,8 @@ extern const bfd_target armpe_big_vec;
extern const bfd_target armpe_little_vec;
extern const bfd_target armpei_big_vec;
extern const bfd_target armpei_little_vec;
+extern const bfd_target avrcoff_vec;
+extern const bfd_target avrextcoff_vec;
extern const bfd_target b_out_vec_big_host;
extern const bfd_target b_out_vec_little_host;
extern const bfd_target bfd_pei_ia64_vec;
@@ -966,6 +968,8 @@ static const bfd_target * const _bfd_target_vector[] =
&armpe_little_vec,
&armpei_big_vec,
&armpei_little_vec,
+ &avrcoff_vec,
+ &avrextcoff_vec,
&b_out_vec_big_host,
&b_out_vec_little_host,
#ifdef BFD64
diff --git a/binutils/Makefile.am b/binutils/Makefile.am
index e2f8630..66c3182 100644
--- a/binutils/Makefile.am
+++ b/binutils/Makefile.am
@@ -131,7 +131,7 @@ CFILES = \
resbin.c rescoff.c resrc.c resres.c \
size.c srconv.c stabs.c strings.c sysdump.c \
syslex_wrap.c unwind-ia64.c elfedit.c version.c \
- windres.c winduni.c wrstabs.c \
+ windres.c winduni.c wrcoff.c wrstabs.c \
windmc.c mclex.c
GENERATED_CFILES = \
@@ -139,7 +139,7 @@ GENERATED_CFILES = \
defparse.c deflex.c nlmheader.c rcparse.c mcparse.c
DEBUG_SRCS = rddbg.c debug.c stabs.c ieee.c rdcoff.c
-WRITE_DEBUG_SRCS = $(DEBUG_SRCS) wrstabs.c
+WRITE_DEBUG_SRCS = $(DEBUG_SRCS) wrstabs.c wrcoff.c
# Extra object files for objdump
OBJDUMP_PRIVATE_OFILES = @OBJDUMP_PRIVATE_OFILES@
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index e1e61dc..fc3a77f 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -162,7 +162,7 @@ am_nm_new_OBJECTS = nm.$(OBJEXT) $(am__objects_1)
nm_new_OBJECTS = $(am_nm_new_OBJECTS)
nm_new_LDADD = $(LDADD)
am__objects_3 = rddbg.$(OBJEXT) debug.$(OBJEXT) stabs.$(OBJEXT) \
- ieee.$(OBJEXT) rdcoff.$(OBJEXT)
+ ieee.$(OBJEXT) rdcoff.$(OBJEXT) wrcoff.$(OBJEXT)
am__objects_4 = $(am__objects_3) wrstabs.$(OBJEXT)
am_objcopy_OBJECTS = objcopy.$(OBJEXT) not-strip.$(OBJEXT) \
rename.$(OBJEXT) $(am__objects_4) $(am__objects_1)
@@ -507,7 +507,7 @@ CFILES = \
resbin.c rescoff.c resrc.c resres.c \
size.c srconv.c stabs.c strings.c sysdump.c \
syslex_wrap.c unwind-ia64.c elfedit.c version.c \
- windres.c winduni.c wrstabs.c \
+ windres.c winduni.c wrcoff.c wrstabs.c \
windmc.c mclex.c
GENERATED_CFILES = \
@@ -515,7 +515,7 @@ GENERATED_CFILES = \
defparse.c deflex.c nlmheader.c rcparse.c mcparse.c
DEBUG_SRCS = rddbg.c debug.c stabs.c ieee.c rdcoff.c
-WRITE_DEBUG_SRCS = $(DEBUG_SRCS) wrstabs.c
+WRITE_DEBUG_SRCS = $(DEBUG_SRCS) wrstabs.c wrcoff.c
# Code shared by all the binutils.
BULIBS = bucomm.c version.c filemode.c
diff --git a/binutils/bucomm.c b/binutils/bucomm.c
index bb3fb3f..df5ea69 100644
--- a/binutils/bucomm.c
+++ b/binutils/bucomm.c
@@ -562,6 +562,32 @@ parse_vma (const char *s, const char *arg)
return ret;
}
+/* Return the basename of "file", i. e. everything minus whatever
+ directory part has been provided. Stolen from bfd/archive.c.
+ Should we also handle the VMS case (as in bfd/archive.c)? */
+const char *
+bu_basename (file)
+ const char *file;
+{
+ const char *filename = strrchr (file, '/');
+
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ {
+ /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
+ char *bslash = strrchr (file, '\\');
+ if (filename == NULL || (bslash != NULL && bslash > filename))
+ filename = bslash;
+ if (filename == NULL && file[0] != '\0' && file[1] == ':')
+ filename = file + 1;
+ }
+#endif
+ if (filename != (char *) NULL)
+ filename++;
+ else
+ filename = file;
+ return filename;
+}
+
/* Returns the size of the named file. If the file does not
exist, or if it is not a real file, then a suitable non-fatal
error message is printed and (off_t) -1 is returned. */
diff --git a/binutils/bucomm.h b/binutils/bucomm.h
index fcbc32b..3255d52 100644
--- a/binutils/bucomm.h
+++ b/binutils/bucomm.h
@@ -58,6 +58,8 @@ bfd_vma parse_vma (const char *, const char *);
off_t get_file_size (const char *);
+const char *bu_basename PARAMS ((const char *));
+
extern char *program_name;
/* filemode.c */
diff --git a/binutils/budbg.h b/binutils/budbg.h
index b87defb..d6ea74f 100644
--- a/binutils/budbg.h
+++ b/binutils/budbg.h
@@ -50,8 +50,11 @@ extern bfd_boolean parse_ieee (void *, bfd *, const bfd_byte *, bfd_size_type);
extern bfd_boolean write_ieee_debugging_info (bfd *, void *);
-/* Routine used to read COFF debugging information. */
+/* Routine used to read and write COFF debugging information. */
extern bfd_boolean parse_coff (bfd *, asymbol **, long, void *);
+extern bfd_boolean write_coff_debugging_info
+ (bfd *abfd, void *, long *symcountp, asymbol ***);
+
#endif
diff --git a/binutils/debug.c b/binutils/debug.c
index ee0d62e..08c78de 100644
--- a/binutils/debug.c
+++ b/binutils/debug.c
@@ -32,6 +32,7 @@
#include "bfd.h"
#include "libiberty.h"
#include "filenames.h"
+#include "bucomm.h"
#include "debug.h"
/* Global information we keep for debugging. A pointer to this
@@ -553,6 +554,19 @@ struct debug_type_real_list
struct debug_type_s *t;
};
+/* Simple list, used for pathname translations. */
+struct xlat_list
+{
+ /* Next string on list. */
+ struct xlat_list *next;
+ /* Old part to match against. */
+ const char *old;
+ size_t olen;
+ /* New part to replace. */
+ const char *newstr;
+ size_t nlen;
+};
+
/* Local functions. */
static void debug_error (const char *);
@@ -589,6 +603,11 @@ static bfd_boolean debug_type_samep
(struct debug_handle *, struct debug_type_s *, struct debug_type_s *);
static bfd_boolean debug_class_type_samep
(struct debug_handle *, struct debug_type_s *, struct debug_type_s *);
+static const char *debug_xlat_pathname (const char *);
+
+/* List of pathname translations. */
+static struct xlat_list *xlat, *xltail;
+static bfd_boolean xlat_basename;
/* Issue an error message. */
@@ -681,6 +700,8 @@ debug_set_filename (void *handle, const char *name)
if (name == NULL)
name = "";
+ else
+ name = debug_xlat_pathname (name);
nfile = (struct debug_file *) xmalloc (sizeof *nfile);
memset (nfile, 0, sizeof *nfile);
@@ -721,6 +742,8 @@ debug_start_source (void *handle, const char *name)
if (name == NULL)
name = "";
+ else
+ name = debug_xlat_pathname (name);
if (info->current_unit == NULL)
{
@@ -3369,3 +3392,69 @@ debug_class_type_samep (struct debug_handle *info, struct debug_type_s *t1,
return TRUE;
}
+
+/* Register a pathname translation. */
+void
+debug_register_pathname_xlat (oname, nname)
+ const char *oname;
+ const char *nname;
+{
+ struct xlat_list *xlp;
+
+ /* Special case: if oname is given as NULL, this means the
+ --basename option has been given to objcopy. */
+ if (oname == NULL)
+ {
+ xlat_basename = TRUE;
+ return;
+ }
+
+ xlp = (struct xlat_list *) xmalloc (sizeof (struct xlat_list));
+ xlp->next = NULL;
+ if (xlat == NULL)
+ xlat = xltail = xlp;
+ else
+ {
+ xltail->next = xlp;
+ xltail = xlp;
+ }
+ xlp->old = oname;
+ xlp->newstr = nname;
+ xlp->olen = strlen (oname);
+ xlp->nlen = strlen (nname);
+}
+
+/* Try to translate a pathname. */
+static const char *
+debug_xlat_pathname (oname)
+ const char *oname;
+{
+ struct xlat_list *xlp;
+ char *cp;
+ size_t olen;
+
+ if (xlat_basename)
+ return bu_basename (oname);
+
+ olen = strlen (oname);
+ for (xlp = xlat; xlp; xlp = xlp->next)
+ {
+ if (xlp->olen > olen)
+ /* This cannot be our turn. */
+ continue;
+ /* Since we have pre-computed all our length values to avoid
+ repetitively computing them, just use memcmp() since it's
+ faster than strcmp(). */
+ if (memcmp (xlp->old, oname, xlp->olen) == 0)
+ {
+ cp = (char *) xmalloc (olen + xlp->nlen - xlp->olen + 1);
+ memcpy (cp, xlp->newstr, xlp->nlen);
+ memcpy (cp + xlp->nlen, oname + xlp->olen,
+ olen - xlp->olen + 1);
+ return cp;
+ }
+ }
+
+ /* Not found, pass the original name on. */
+ return oname;
+}
diff --git a/binutils/debug.h b/binutils/debug.h
index 1846119..75ea737 100644
--- a/binutils/debug.h
+++ b/binutils/debug.h
@@ -441,6 +441,12 @@ extern bfd_boolean debug_set_filename (void *, const char *);
extern bfd_boolean debug_start_source (void *, const char *);
+/* Register a pathname translation for source (and include) filenames.
+ This is used by the --change-pathname option of objcopy. */
+
+extern void debug_register_pathname_xlat
+ PARAMS ((const char *, const char *));
+
/* Record a function definition. This implicitly starts a function
block. The debug_type argument is the type of the return value.
The bfd_boolean indicates whether the function is globally visible.
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 14f6b96..205c166 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -29,6 +29,7 @@
#include "fnmatch.h"
#include "elf-bfd.h"
#include "libbfd.h"
+#include "debug.h"
#include "coff/internal.h"
#include "libcoff.h"
@@ -307,6 +308,8 @@ enum command_line_switch
OPTION_IMPURE,
OPTION_EXTRACT_SYMBOL,
OPTION_REVERSE_BYTES,
+ OPTION_CHANGE_PATHNAME,
+ OPTION_BASENAME,
OPTION_FILE_ALIGNMENT,
OPTION_HEAP,
OPTION_IMAGE_BASE,
@@ -362,10 +365,12 @@ static struct option copy_options[] =
{"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
{"adjust-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS},
{"alt-machine-code", required_argument, 0, OPTION_ALT_MACH_CODE},
+ {"basename", no_argument, 0, OPTION_BASENAME},
{"binary-architecture", required_argument, 0, 'B'},
{"byte", required_argument, 0, 'b'},
{"change-addresses", required_argument, 0, OPTION_CHANGE_ADDRESSES},
{"change-leading-char", no_argument, 0, OPTION_CHANGE_LEADING_CHAR},
+ {"change-pathname", required_argument, 0, OPTION_CHANGE_PATHNAME},
{"change-section-address", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
{"change-section-lma", required_argument, 0, OPTION_CHANGE_SECTION_LMA},
{"change-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_VMA},
@@ -578,6 +583,8 @@ copy_usage (FILE *stream, int exit_status)
--prefix-alloc-sections <prefix>\n\
Add <prefix> to start of every allocatable\n\
section name\n\
+ --change-pathname <old>=<new> Change debug pathnames from <old> to <new>\n\
+ --basename Strip directory part from debug pathnames\n\
--file-alignment <num> Set PE file alignment to <num>\n\
--heap <reserve>[,<commit>] Set PE reserve/commit heap to <reserve>/\n\
<commit>\n\
@@ -1164,6 +1171,8 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
asymbol **from = isyms, **to = osyms;
long src_count = 0, dst_count = 0;
int relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
+ bfd_boolean need_for_debugging = convert_debugging
+ && bfd_get_arch (abfd) == bfd_arch_avr;
for (; src_count < symcount; src_count++)
{
@@ -1264,7 +1273,8 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
|| bfd_is_com_section (bfd_get_section (sym)))
keep = strip_symbols != STRIP_UNNEEDED;
else if ((flags & BSF_DEBUGGING) != 0) /* Debugging symbol. */
- keep = (strip_symbols != STRIP_DEBUG
+ keep = need_for_debugging
+ || (strip_symbols != STRIP_DEBUG
&& strip_symbols != STRIP_UNNEEDED
&& ! convert_debugging);
else if (bfd_coff_get_comdat_section (abfd, bfd_get_section (sym)))
@@ -3084,6 +3094,10 @@ write_debugging_info (bfd *obfd, void *dhandle,
return write_ieee_debugging_info (obfd, dhandle);
if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
+ && bfd_get_arch (obfd) == bfd_arch_avr)
+ return write_coff_debugging_info (obfd, dhandle, symcountp, symppp);
+
+ if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
|| bfd_get_flavour (obfd) == bfd_target_elf_flavour)
{
bfd_byte *syms, *strings;
@@ -3972,6 +3986,30 @@ copy_main (int argc, char *argv[])
prefix_alloc_sections_string = optarg;
break;
+ case OPTION_CHANGE_PATHNAME:
+ {
+ const char *s;
+ int len;
+ char *name;
+
+ s = strchr (optarg, '=');
+ if (s == NULL)
+ fatal (_("bad format for %s"), "--change-pathname");
+
+ len = s - optarg;
+ name = (char *) xmalloc (len + 1);
+ strncpy (name, optarg, len);
+ name[len] = '\0';
+
+ debug_register_pathname_xlat (name, s + 1);
+ }
+ break;
+
+ case OPTION_BASENAME:
+ /* very special case of pathname translation */
+ debug_register_pathname_xlat (NULL, NULL);
+ break;
+
case OPTION_READONLY_TEXT:
bfd_flags_to_set |= WP_TEXT;
bfd_flags_to_clear &= ~WP_TEXT;
diff --git a/binutils/rdcoff.c b/binutils/rdcoff.c
index 473305e..c3cbf77 100644
--- a/binutils/rdcoff.c
+++ b/binutils/rdcoff.c
@@ -82,6 +82,9 @@ struct coff_types
struct coff_slots *slots;
/* Basic types. */
debug_type basic[T_MAX + 1];
+ /* Some general information, kept here for convenience. */
+ size_t intsize; /* sizeof (int) */
+ size_t doublesize; /* sizeof (double) */
};
static debug_type *coff_get_slot (struct coff_types *, int);
@@ -101,6 +104,7 @@ static bfd_boolean parse_coff_symbol
(bfd *, struct coff_types *, asymbol *, long, struct internal_syment *,
void *, debug_type, bfd_boolean);
static bfd_boolean external_coff_symbol_p (int sym_class);
+static bfd_vma coff_convert_register (bfd *, bfd_vma);
/* Return the slot for a type. */
@@ -271,8 +275,7 @@ parse_coff_base_type (bfd *abfd, struct coff_symbols *symbols,
break;
case T_INT:
- /* FIXME: Perhaps the size should depend upon the architecture. */
- ret = debug_make_int_type (dhandle, 4, FALSE);
+ ret = debug_make_int_type (dhandle, types->intsize, FALSE);
name = "int";
break;
@@ -287,7 +290,7 @@ parse_coff_base_type (bfd *abfd, struct coff_symbols *symbols,
break;
case T_DOUBLE:
- ret = debug_make_float_type (dhandle, 8);
+ ret = debug_make_float_type (dhandle, types->doublesize);
name = "double";
break;
@@ -307,7 +310,7 @@ parse_coff_base_type (bfd *abfd, struct coff_symbols *symbols,
break;
case T_UINT:
- ret = debug_make_int_type (dhandle, 4, TRUE);
+ ret = debug_make_int_type (dhandle, types->intsize, TRUE);
name = "unsigned int";
break;
@@ -565,6 +568,8 @@ parse_coff_symbol (bfd *abfd ATTRIBUTE_UNUSED, struct coff_types *types,
case C_WEAKEXT:
case C_EXT:
+ /* AVR COFF abuses C_EXTDEF */
+ case C_EXTDEF:
if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type,
DEBUG_GLOBAL, bfd_asymbol_value (sym)))
return FALSE;
@@ -580,9 +585,9 @@ parse_coff_symbol (bfd *abfd ATTRIBUTE_UNUSED, struct coff_types *types,
break;
case C_REG:
- /* FIXME: We may need to convert the register number. */
if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type,
- DEBUG_REGISTER, bfd_asymbol_value (sym)))
+ DEBUG_REGISTER,
+ coff_convert_register (abfd, bfd_asymbol_value (sym))))
return FALSE;
break;
@@ -596,9 +601,9 @@ parse_coff_symbol (bfd *abfd ATTRIBUTE_UNUSED, struct coff_types *types,
break;
case C_REGPARM:
- /* FIXME: We may need to convert the register number. */
if (! debug_record_parameter (dhandle, bfd_asymbol_name (sym), type,
- DEBUG_PARM_REG, bfd_asymbol_value (sym)))
+ DEBUG_PARM_REG,
+ coff_convert_register (abfd, bfd_asymbol_value (sym))))
return FALSE;
break;
@@ -648,6 +653,28 @@ external_coff_symbol_p (int sym_class)
return FALSE;
}
+static bfd_vma
+coff_convert_register (abfd, val)
+ bfd *abfd;
+ bfd_vma val;
+{
+
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_avr:
+ /* AVR COFF wants to describe up to four registers by the four
+ bytes of the 32-bit value. Unused bytes are filled with
+ 0xff. In theory, this would allow for non-contiguous
+ register usage to hold a single value, but hopefully, no
+ compiler is going to use that feature. We could not handle
+ it anyway. */
+ return val & 0xff;
+
+ default:
+ return val;
+ }
+}
+
/* This is the main routine. It looks through all the symbols and
handles them. */
@@ -674,6 +701,17 @@ parse_coff (bfd *abfd, asymbol **syms, long symcount, void *dhandle)
types.slots = NULL;
for (i = 0; i <= T_MAX; i++)
types.basic[i] = DEBUG_TYPE_NULL;
+ switch (bfd_get_arch (abfd))
+ {
+ case bfd_arch_avr:
+ types.intsize = 2;
+ types.doublesize = 4;
+ break;
+
+ default:
+ types.intsize = 4;
+ types.doublesize = 8;
+ }
next_c_file = -1;
fnname = NULL;
@@ -734,7 +772,6 @@ parse_coff (bfd *abfd, asymbol **syms, long symcount, void *dhandle)
switch (syment.n_sclass)
{
case C_EFCN:
- case C_EXTDEF:
case C_ULABEL:
case C_USTATIC:
case C_LINE:
@@ -757,6 +794,8 @@ parse_coff (bfd *abfd, asymbol **syms, long symcount, void *dhandle)
/* Fall through. */
case C_WEAKEXT:
case C_EXT:
+ /* AVR COFF abuses C_EXTDEF for C_EXT */
+ case C_EXTDEF:
if (ISFCN (syment.n_type))
{
fnname = name;
diff --git a/binutils/wrcoff.c b/binutils/wrcoff.c
new file mode 100644
index 0000000..07cfbc8
--- /dev/null
+++ b/binutils/wrcoff.c
@@ -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;
+}
diff --git a/include/coff/avr.h b/include/coff/avr.h
new file mode 100644
index 0000000..efecfa7
--- /dev/null
+++ b/include/coff/avr.h
@@ -0,0 +1,110 @@
+/* coff information for Atmel AVR.
+
+ Copyright 2001 Free Software Foundation, Inc.
+
+ 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 was hacked from i860.h */
+
+#define L_LNNO_SIZE 2
+#include "coff/external.h"
+
+/* Bits for f_flags:
+ F_RELFLG relocation info stripped from file
+ F_EXEC file is executable (no unresolved external references)
+ F_LNNO line numbers stripped from file
+ F_LSYMS local symbols stripped from file */
+
+#define F_RELFLG (0x0001)
+#define F_EXEC (0x0002)
+#define F_LNNO (0x0004)
+#define F_LSYMS (0x0008)
+/* Upper nibble of flags always needs to be set. This used to be
+ * undocumented, recent information from Atmel says that bit 7 used to
+ * differentiate between an old vendor-specific deviation of the
+ * format and the current format. */
+#define F_JUNK (0x00f0)
+#define F_UNUSED (0xff00)
+
+#define AVRMAGIC 0xa12
+
+#undef AOUTSZ
+#ifdef AVR_EXT_COFF
+
+/* AVR "extended" COFF format. This uses the optional header ("a.out"
+ header) to inform the consumer about some additional features that
+ are supported. */
+#define COFF_LONG_FILENAMES yes /* long filenames supported in consecutive aux entries */
+#define AOUTSZ 28 /* size of optional header in "extended" COFF */
+
+/* Flags in the optional header; they are stored in the vstamp field. */
+#define F_FULLPATHS 0x0001 /* long filenames supported */
+#define F_STRUCTINFO 0x0002 /* structure information contained */
+#define F_PTRINFO 0x0004 /* inter-segment pointers supported */
+
+#else /* old AVR COFF */
+
+#define AOUTSZ 0 /* no a.out for AVR */
+#endif
+
+/* #define AVRAOUTMAGIC 0x406 */ /* "general" magic number of optional header */
+/*
+ * The following magic number causes AVR Studio 4.x to recognize
+ * avr-gcc/GNU binutils produced AVR extended COFF files. By now,
+ * the only special treatment for them is that the contents of .data
+ * will be appended after .text in the simulator flash.
+ *
+ * 0x9cc has been chosen since it resembles "gcc". ;-)
+ */
+#define AVRAOUTMAGIC 0x9cc /* "gcc" magic number */
+
+/* By matching not only the magic number, but also the size of the
+ optional a.out header, we can differentiate between both
+ formats. */
+#define AVRBADMAG(x) ((x).f_magic != AVRMAGIC || (x).f_opthdr != AOUTSZ)
+
+/* AVR COFF has several anomalities in the way the handle the derived
+ type information, and AUX entries, mainly because they apparently
+ didn't bother to learn how COFF is supposed to work before they
+ started. We fix many of them at the export/import boundary, so all
+ the internal generic COFF handling will work mostly as designed. */
+
+/* NB: these functions are only defined in bfd/coff-avr.c, but also
+ used in coff-ext-avr.c, so the latter can only be configured if the
+ former is also present. This is certainly always the case
+ anyway. */
+extern void avr_coff_adjust_sym_in_post
+ PARAMS((bfd *, PTR, PTR));
+
+extern void avr_coff_adjust_sym_out_post
+ PARAMS((bfd *, PTR, PTR));
+
+#define COFF_ADJUST_SYM_IN_POST(ABFD, EXT, INT) \
+ avr_coff_adjust_sym_in_post (ABFD, EXT, INT)
+
+#define COFF_ADJUST_SYM_OUT_POST(ABFD, INT, EXT) \
+ avr_coff_adjust_sym_out_post (ABFD, INT, EXT)
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+struct external_reloc
+{
+ char r_vaddr[4];
+ char r_symndx[4];
+ char r_type[2];
+};
+
+#define RELOC struct external_reloc
+#define RELSZ 10
diff --git a/include/coff/internal.h b/include/coff/internal.h
index 8b84324..28dee70 100644
--- a/include/coff/internal.h
+++ b/include/coff/internal.h
@@ -651,6 +651,8 @@ union internal_auxent
};
+#define NAUXENTS 10 /* number of pre-allocated aux entries */
+
/********************** RELOCATION DIRECTIVES **********************/
struct internal_reloc
diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c
index 6d6ee2d..9c732bd 100644
--- a/gas/dwarf2dbg.c
+++ b/gas/dwarf2dbg.c
@@ -125,8 +125,11 @@
Note: If you want to change this, you'll have to update the
"standard_opcode_lengths" table that is emitted below in
out_debug_line(). */
+#ifndef TC_AVR
#define DWARF2_LINE_OPCODE_BASE 13
-
+#else
+#define DWARF2_LINE_OPCODE_BASE 10
+#endif
#ifndef DWARF2_LINE_BASE
/* Minimum line offset in a special line info. opcode. This value
was chosen to give a reasonable range of values. */
@@ -1549,9 +1552,11 @@ out_debug_line (segT line_seg)
out_byte (0); /* DW_LNS_set_basic_block */
out_byte (0); /* DW_LNS_const_add_pc */
out_byte (1); /* DW_LNS_fixed_advance_pc */
+#ifndef TC_AVR
out_byte (0); /* DW_LNS_set_prologue_end */
out_byte (0); /* DW_LNS_set_epilogue_begin */
out_byte (1); /* DW_LNS_set_isa */
+#endif
out_file_list ();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment