diff -uNdr binutils-2.17.50.0.18-old/bfd/Makefile.am binutils-2.17.50.0.18/bfd/Makefile.am --- binutils-2.17.50.0.18-old/bfd/Makefile.am 2007-08-01 15:11:47.000000000 +0200 +++ binutils-2.17.50.0.18/bfd/Makefile.am 2007-10-20 16:45:33.000000000 +0200 @@ -208,6 +208,8 @@ coff-apollo.lo \ coff-arm.lo \ coff-aux.lo \ + coff-avr.lo \ + coff-ext-avr.lo \ coff-h8300.lo \ coff-h8500.lo \ coff-i386.lo \ @@ -387,6 +389,8 @@ coff-apollo.c \ coff-arm.c \ coff-aux.c \ + coff-avr.c \ + coff-ext-avr.c \ coff-h8300.c \ coff-h8500.c \ coff-i386.c \ @@ -1186,6 +1190,12 @@ coff-m68k.c $(INCDIR)/hashtab.h $(INCDIR)/coff/m68k.h \ $(INCDIR)/coff/internal.h libcoff.h $(INCDIR)/bfdlink.h \ coffcode.h coffswap.h +coff-avr.lo: coff-avr.c $(INCDIR)/filenames.h $(INCDIR)/coff/avr.h \ + $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h +coff-ext-avr.lo: coff-ext-avr.c $(INCDIR)/filenames.h $(INCDIR)/coff/avr.h \ + $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h coff-h8300.lo: coff-h8300.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ $(INCDIR)/bfdlink.h genlink.h $(INCDIR)/coff/h8300.h \ $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \ diff -uNdr binutils-2.17.50.0.18-old/bfd/Makefile.in binutils-2.17.50.0.18/bfd/Makefile.in --- binutils-2.17.50.0.18-old/bfd/Makefile.in 2007-10-20 15:38:12.000000000 +0200 +++ binutils-2.17.50.0.18/bfd/Makefile.in 2007-10-20 16:45:33.000000000 +0200 @@ -458,6 +458,8 @@ coff-apollo.lo \ coff-arm.lo \ coff-aux.lo \ + coff-avr.lo \ + coff-ext-avr.lo \ coff-h8300.lo \ coff-h8500.lo \ coff-i386.lo \ @@ -637,6 +639,8 @@ coff-apollo.c \ coff-arm.c \ coff-aux.c \ + coff-avr.c \ + coff-ext-avr.c \ coff-h8300.c \ coff-h8500.c \ coff-i386.c \ @@ -1767,6 +1771,12 @@ coff-m68k.c $(INCDIR)/hashtab.h $(INCDIR)/coff/m68k.h \ $(INCDIR)/coff/internal.h libcoff.h $(INCDIR)/bfdlink.h \ coffcode.h coffswap.h +coff-avr.lo: coff-avr.c $(INCDIR)/filenames.h $(INCDIR)/coff/avr.h \ + $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h +coff-ext-avr.lo: coff-ext-avr.c $(INCDIR)/filenames.h $(INCDIR)/coff/avr.h \ + $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \ + libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h coff-h8300.lo: coff-h8300.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ $(INCDIR)/bfdlink.h genlink.h $(INCDIR)/coff/h8300.h \ $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \ diff -uNdr binutils-2.17.50.0.18-old/bfd/coff-avr.c binutils-2.17.50.0.18/bfd/coff-avr.c --- binutils-2.17.50.0.18-old/bfd/coff-avr.c 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17.50.0.18/bfd/coff-avr.c 2007-10-20 16:45:33.000000000 +0200 @@ -0,0 +1,609 @@ +/* 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 + +#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 -uNdr binutils-2.17.50.0.18-old/bfd/coff-ext-avr.c binutils-2.17.50.0.18/bfd/coff-ext-avr.c --- binutils-2.17.50.0.18-old/bfd/coff-ext-avr.c 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17.50.0.18/bfd/coff-ext-avr.c 2007-10-20 16:45:33.000000000 +0200 @@ -0,0 +1,424 @@ +/* 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 + +#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 -uNdr binutils-2.17.50.0.18-old/bfd/coffcode.h binutils-2.17.50.0.18/bfd/coffcode.h --- binutils-2.17.50.0.18-old/bfd/coffcode.h 2007-08-01 17:12:02.000000000 +0200 +++ binutils-2.17.50.0.18/bfd/coffcode.h 2007-10-20 16:45:33.000000000 +0200 @@ -1,3 +1,4 @@ + /* Support for the generic parts of most COFF variants, for BFD. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 @@ -1767,6 +1768,17 @@ 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; @@ -1791,17 +1803,6 @@ 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) = @@ -1928,6 +1929,11 @@ } break; #endif +#ifdef AVRMAGIC + case AVRMAGIC: + arch = bfd_arch_avr; + break; +#endif #ifdef MC68MAGIC case MC68MAGIC: case M68MAGIC: @@ -2724,6 +2730,13 @@ return TRUE; #endif +#ifdef AVRMAGIC + case bfd_arch_avr: + *magicp = AVRMAGIC; + return TRUE; + break; +#endif + #ifdef PPCMAGIC case bfd_arch_powerpc: *magicp = PPCMAGIC; @@ -3520,6 +3533,11 @@ section.s_page = coff_get_section_load_page (current); #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 @@ -3864,6 +3882,17 @@ 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; @@ -3931,8 +3960,16 @@ #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; @@ -4118,22 +4155,29 @@ char * buff; bfd_size_type amount = bfd_coff_aoutsz (abfd); - buff = bfd_malloc (amount); - if (buff == NULL) - return FALSE; + /* Do not attempt to malloc() zero bytes. According to the + C standard, the behaviour is implementation-defined, and + malloc() might return NULL in that case, which would confuse + us to assume an error where it actually isn't. */ + if (amount != 0) + { + buff = bfd_malloc (amount); + if (buff == NULL) + return FALSE; - coff_swap_aouthdr_out (abfd, & internal_a, buff); - amount = bfd_bwrite (buff, amount, abfd); + coff_swap_aouthdr_out (abfd, & internal_a, buff); + amount = bfd_bwrite (buff, amount, abfd); - free (buff); + free (buff); - if (amount != bfd_coff_aoutsz (abfd)) - return FALSE; + if (amount != bfd_coff_aoutsz (abfd)) + return FALSE; #ifdef COFF_IMAGE_WITH_PE - if (! coff_apply_checksum (abfd)) - return FALSE; + if (! coff_apply_checksum (abfd)) + return FALSE; #endif + } } #ifdef RS6000COFF_C else @@ -4414,6 +4458,10 @@ /* 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: @@ -4637,7 +4685,9 @@ && src->u.syment.n_scnum == 0) break; /* 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 -uNdr binutils-2.17.50.0.18-old/bfd/coffgen.c binutils-2.17.50.0.18/bfd/coffgen.c --- binutils-2.17.50.0.18-old/bfd/coffgen.c 2007-08-01 15:11:47.000000000 +0200 +++ binutils-2.17.50.0.18/bfd/coffgen.c 2007-10-20 16:45:33.000000000 +0200 @@ -687,6 +687,20 @@ 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 @@ -815,6 +829,20 @@ { 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; @@ -1218,7 +1246,11 @@ if (bfd_bwrite (".file", (bfd_size_type) 6, abfd) != 6) return FALSE; } - maxlen = bfd_coff_filnmlen (abfd); + 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 maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; @@ -1655,14 +1687,27 @@ { /* Ordinary short filename, put into memory anyway. The Microsoft PE tools sometimes store a filename in - multiple AUX entries. */ - 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)); + multiple AUX entries. + AVR COFF does it that way, too. */ + if (internal_ptr->u.syment.n_numaux > 1 + && (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 = (long) 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) @@ -1768,9 +1813,9 @@ if (new == NULL) return NULL; - /* @@ The 10 is a guess at a plausible maximum number of aux entries - (but shouldn't be a constant). */ - amt = sizeof (combined_entry_type) * 10; + /* @@ The NAUXENTS is a guess at a plausible maximum number of aux + entries (but shouldn't be a constant). */ + amt = sizeof (combined_entry_type) * (NAUXENTS + 1); new->native = bfd_zalloc (abfd, amt); if (!new->native) return NULL; diff -uNdr binutils-2.17.50.0.18-old/bfd/coffswap.h binutils-2.17.50.0.18/bfd/coffswap.h --- binutils-2.17.50.0.18-old/bfd/coffswap.h 2007-08-01 15:11:47.000000000 +0200 +++ binutils-2.17.50.0.18/bfd/coffswap.h 2007-10-20 16:45:33.000000000 +0200 @@ -383,7 +383,11 @@ void * ext1, int type, int class, - int indx, + int indx +#if defined(AVR) && __GNUC__ + __attribute__((unused)) +#endif + , int numaux, void * in1) { @@ -409,9 +413,13 @@ #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 -uNdr binutils-2.17.50.0.18-old/bfd/config.bfd binutils-2.17.50.0.18/bfd/config.bfd --- binutils-2.17.50.0.18-old/bfd/config.bfd 2007-08-01 15:11:47.000000000 +0200 +++ binutils-2.17.50.0.18/bfd/config.bfd 2007-10-20 16:45:33.000000000 +0200 @@ -327,6 +327,7 @@ avr-*-*) targ_defvec=bfd_elf32_avr_vec + targ_selvecs="bfd_elf32_avr_vec avrcoff_vec avrextcoff_vec" ;; bfin-*-*) diff -uNdr binutils-2.17.50.0.18-old/bfd/configure binutils-2.17.50.0.18/bfd/configure --- binutils-2.17.50.0.18-old/bfd/configure 2007-08-01 15:11:47.000000000 +0200 +++ binutils-2.17.50.0.18/bfd/configure 2007-10-20 16:45:33.000000000 +0200 @@ -19034,6 +19034,8 @@ 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_efi_app_ia32_vec) tb="$tb efi-app-ia32.lo peigen.lo cofflink.lo" ;; diff -uNdr binutils-2.17.50.0.18-old/bfd/configure.in binutils-2.17.50.0.18/bfd/configure.in --- binutils-2.17.50.0.18-old/bfd/configure.in 2007-08-01 15:11:47.000000000 +0200 +++ binutils-2.17.50.0.18/bfd/configure.in 2007-10-20 16:45:33.000000000 +0200 @@ -612,6 +612,8 @@ 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_efi_app_ia32_vec) tb="$tb efi-app-ia32.lo peigen.lo cofflink.lo" ;; diff -uNdr binutils-2.17.50.0.18-old/bfd/targets.c binutils-2.17.50.0.18/bfd/targets.c --- binutils-2.17.50.0.18-old/bfd/targets.c 2007-08-01 15:11:48.000000000 +0200 +++ binutils-2.17.50.0.18/bfd/targets.c 2007-10-20 16:45:33.000000000 +0200 @@ -558,6 +558,8 @@ 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_efi_app_ia32_vec; @@ -876,6 +878,8 @@ &armpe_little_vec, &armpei_big_vec, &armpei_little_vec, + &avrcoff_vec, + &avrextcoff_vec, &b_out_vec_big_host, &b_out_vec_little_host, &bfd_efi_app_ia32_vec, diff -uNdr binutils-2.17.50.0.18-old/binutils/Makefile.am binutils-2.17.50.0.18/binutils/Makefile.am --- binutils-2.17.50.0.18-old/binutils/Makefile.am 2007-08-01 15:11:48.000000000 +0200 +++ binutils-2.17.50.0.18/binutils/Makefile.am 2007-10-20 16:45:33.000000000 +0200 @@ -98,7 +98,7 @@ resbin.c rescoff.c resrc.c resres.c \ size.c srconv.c stabs.c strings.c sysdump.c \ unwind-ia64.c version.c \ - windres.c winduni.c wrstabs.c \ + windres.c winduni.c wrcoff.c wrstabs.c \ windmc.c mclex.c GENERATED_CFILES = \ @@ -106,7 +106,7 @@ 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 -uNdr binutils-2.17.50.0.18-old/binutils/Makefile.in binutils-2.17.50.0.18/binutils/Makefile.in --- binutils-2.17.50.0.18-old/binutils/Makefile.in 2007-08-01 15:11:48.000000000 +0200 +++ binutils-2.17.50.0.18/binutils/Makefile.in 2007-10-20 16:45:33.000000000 +0200 @@ -129,7 +129,7 @@ nm_new_OBJECTS = $(am_nm_new_OBJECTS) nm_new_LDADD = $(LDADD) am__objects_2 = rddbg.$(OBJEXT) debug.$(OBJEXT) stabs.$(OBJEXT) \ - ieee.$(OBJEXT) rdcoff.$(OBJEXT) + ieee.$(OBJEXT) rdcoff.$(OBJEXT) wrcoff.$(OBJEXT) am__objects_3 = $(am__objects_2) wrstabs.$(OBJEXT) am_objcopy_OBJECTS = objcopy.$(OBJEXT) not-strip.$(OBJEXT) \ rename.$(OBJEXT) $(am__objects_3) $(am__objects_1) @@ -418,7 +418,7 @@ resbin.c rescoff.c resrc.c resres.c \ size.c srconv.c stabs.c strings.c sysdump.c \ unwind-ia64.c version.c \ - windres.c winduni.c wrstabs.c \ + windres.c winduni.c wrcoff.c wrstabs.c \ windmc.c mclex.c GENERATED_CFILES = \ @@ -426,7 +426,7 @@ 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 -uNdr binutils-2.17.50.0.18-old/binutils/bucomm.c binutils-2.17.50.0.18/binutils/bucomm.c --- binutils-2.17.50.0.18-old/binutils/bucomm.c 2007-08-01 15:11:49.000000000 +0200 +++ binutils-2.17.50.0.18/binutils/bucomm.c 2007-10-20 16:45:33.000000000 +0200 @@ -501,6 +501,32 @@ 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 zero is returned. */ diff -uNdr binutils-2.17.50.0.18-old/binutils/bucomm.h binutils-2.17.50.0.18/binutils/bucomm.h --- binutils-2.17.50.0.18-old/binutils/bucomm.h 2007-08-01 15:11:49.000000000 +0200 +++ binutils-2.17.50.0.18/binutils/bucomm.h 2007-10-20 16:45:33.000000000 +0200 @@ -54,6 +54,8 @@ off_t get_file_size (const char *); +const char *bu_basename PARAMS ((const char *)); + extern char *program_name; /* filemode.c */ diff -uNdr binutils-2.17.50.0.18-old/binutils/budbg.h binutils-2.17.50.0.18/binutils/budbg.h --- binutils-2.17.50.0.18-old/binutils/budbg.h 2007-08-01 15:11:49.000000000 +0200 +++ binutils-2.17.50.0.18/binutils/budbg.h 2007-10-20 16:45:33.000000000 +0200 @@ -51,8 +51,11 @@ 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 -uNdr binutils-2.17.50.0.18-old/binutils/debug.c binutils-2.17.50.0.18/binutils/debug.c --- binutils-2.17.50.0.18-old/binutils/debug.c 2007-08-01 15:11:49.000000000 +0200 +++ binutils-2.17.50.0.18/binutils/debug.c 2007-10-20 16:45:33.000000000 +0200 @@ -31,6 +31,7 @@ #include #include "bfd.h" #include "libiberty.h" +#include "bucomm.h" #include "debug.h" /* Global information we keep for debugging. A pointer to this @@ -552,6 +553,19 @@ struct debug_type *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 *); @@ -588,6 +602,11 @@ (struct debug_handle *, struct debug_type *, struct debug_type *); static bfd_boolean debug_class_type_samep (struct debug_handle *, struct debug_type *, struct debug_type *); +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. */ @@ -680,6 +699,8 @@ if (name == NULL) name = ""; + else + name = debug_xlat_pathname (name); nfile = (struct debug_file *) xmalloc (sizeof *nfile); memset (nfile, 0, sizeof *nfile); @@ -720,6 +741,8 @@ if (name == NULL) name = ""; + else + name = debug_xlat_pathname (name); if (info->current_unit == NULL) { @@ -3370,3 +3393,69 @@ 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 -uNdr binutils-2.17.50.0.18-old/binutils/debug.h binutils-2.17.50.0.18/binutils/debug.h --- binutils-2.17.50.0.18-old/binutils/debug.h 2007-08-01 15:11:49.000000000 +0200 +++ binutils-2.17.50.0.18/binutils/debug.h 2007-10-20 16:45:33.000000000 +0200 @@ -440,6 +440,12 @@ 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 -uNdr binutils-2.17.50.0.18-old/binutils/objcopy.c binutils-2.17.50.0.18/binutils/objcopy.c --- binutils-2.17.50.0.18-old/binutils/objcopy.c 2007-08-01 15:11:49.000000000 +0200 +++ binutils-2.17.50.0.18/binutils/objcopy.c 2007-10-20 16:45:33.000000000 +0200 @@ -32,6 +32,7 @@ #include "elf-bfd.h" #include #include "libbfd.h" +#include "debug.h" /* A list of symbols to explicitly strip out, or to keep. A linked list is good enough for a small number from the command line, but @@ -272,7 +273,9 @@ OPTION_PURE, OPTION_IMPURE, OPTION_EXTRACT_SYMBOL, - OPTION_REVERSE_BYTES + OPTION_REVERSE_BYTES, + OPTION_CHANGE_PATHNAME, + OPTION_BASENAME }; /* Options to handle if running as "strip". */ @@ -316,10 +319,12 @@ {"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}, @@ -504,6 +509,8 @@ --prefix-alloc-sections \n\ Add to start of every allocatable\n\ section name\n\ + --change-pathname = Change debug pathnames from to \n\ + --basename Strip directory part from debug pathnames\n\ -v --verbose List all object files modified\n\ @ Read options from \n\ -V --version Display this program's version number\n\ @@ -911,6 +918,8 @@ 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++) { @@ -1010,9 +1019,10 @@ || 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 - && strip_symbols != STRIP_UNNEEDED - && ! convert_debugging); + 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))) /* COMDAT sections store special information in local symbols, so we cannot risk stripping any of them. */ @@ -2579,6 +2589,10 @@ 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; @@ -3280,6 +3294,30 @@ 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 -uNdr binutils-2.17.50.0.18-old/binutils/rdcoff.c binutils-2.17.50.0.18/binutils/rdcoff.c --- binutils-2.17.50.0.18-old/binutils/rdcoff.c 2007-08-01 15:11:49.000000000 +0200 +++ binutils-2.17.50.0.18/binutils/rdcoff.c 2007-10-20 16:45:33.000000000 +0200 @@ -82,6 +82,9 @@ 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 @@ (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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ switch (syment.n_sclass) { case C_EFCN: - case C_EXTDEF: case C_ULABEL: case C_USTATIC: case C_LINE: @@ -757,6 +794,8 @@ /* 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 -uNdr binutils-2.17.50.0.18-old/binutils/wrcoff.c binutils-2.17.50.0.18/binutils/wrcoff.c --- binutils-2.17.50.0.18-old/binutils/wrcoff.c 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17.50.0.18/binutils/wrcoff.c 2007-10-20 16:45:53.000000000 +0200 @@ -0,0 +1,3408 @@ +/* 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 +#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 (""); + 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 -uNdr binutils-2.17.50.0.18-old/include/coff/avr.h binutils-2.17.50.0.18/include/coff/avr.h --- binutils-2.17.50.0.18-old/include/coff/avr.h 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.17.50.0.18/include/coff/avr.h 2007-10-20 16:45:33.000000000 +0200 @@ -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 -uNdr binutils-2.17.50.0.18-old/include/coff/internal.h binutils-2.17.50.0.18/include/coff/internal.h --- binutils-2.17.50.0.18-old/include/coff/internal.h 2007-08-01 15:11:51.000000000 +0200 +++ binutils-2.17.50.0.18/include/coff/internal.h 2007-10-20 16:45:33.000000000 +0200 @@ -630,6 +630,8 @@ }; +#define NAUXENTS 10 /* number of pre-allocated aux entries */ + /********************** RELOCATION DIRECTIVES **********************/ struct internal_reloc