X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Fecofflink.c;h=d7bb817f6760f11e0f4149b05aa5675d4fcc6e0b;hb=3b86368e684638af5c127b90e9aba12061fa9073;hp=2d1f99b8c8851e99199a9cc60d1ebbdb80e26a4d;hpb=ef79dba3c39b6edcf4d1e343457bfd29ec868069;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/ecofflink.c b/bfd/ecofflink.c index 2d1f99b8c8..d7bb817f67 100644 --- a/bfd/ecofflink.c +++ b/bfd/ecofflink.c @@ -1,55 +1,260 @@ /* Routines to link ECOFF debugging information. - Copyright 1993 Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, + 2004, 2005 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support, . -This file is part of BFD, the Binary File Descriptor library. + 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 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. + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "bfd.h" #include "sysdep.h" #include "bfdlink.h" #include "libbfd.h" -#include "obstack.h" +#include "objalloc.h" +#include "aout/stab_gnu.h" #include "coff/internal.h" #include "coff/sym.h" #include "coff/symconst.h" #include "coff/ecoff.h" +#include "libcoff.h" +#include "libecoff.h" -static boolean ecoff_add_bytes PARAMS ((char **buf, char **bufend, - size_t need)); +static bfd_boolean ecoff_add_bytes + PARAMS ((char **buf, char **bufend, size_t need)); static struct bfd_hash_entry *string_hash_newfunc PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); -static void ecoff_align_debug PARAMS ((bfd *abfd, - struct ecoff_debug_info *debug, - const struct ecoff_debug_swap *swap)); -static boolean ecoff_write_symhdr PARAMS ((bfd *, struct ecoff_debug_info *, - const struct ecoff_debug_swap *, - file_ptr where)); - -/* Obstack allocation and deallocation routines. */ -#define obstack_chunk_alloc malloc -#define obstack_chunk_free free +static void ecoff_align_debug + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap)); +static bfd_boolean ecoff_write_symhdr + PARAMS ((bfd *, struct ecoff_debug_info *, const struct ecoff_debug_swap *, + file_ptr where)); +static int cmp_fdrtab_entry + PARAMS ((const PTR, const PTR)); +static bfd_boolean mk_fdrtab + PARAMS ((bfd *, struct ecoff_debug_info * const, + const struct ecoff_debug_swap * const, struct ecoff_find_line *)); +static long fdrtab_lookup + PARAMS ((struct ecoff_find_line *, bfd_vma)); +static bfd_boolean lookup_line + PARAMS ((bfd *, struct ecoff_debug_info * const, + const struct ecoff_debug_swap * const, struct ecoff_find_line *)); + +/* Routines to swap auxiliary information in and out. I am assuming + that the auxiliary information format is always going to be target + independent. */ + +/* Swap in a type information record. + BIGEND says whether AUX symbols are big-endian or little-endian; this + info comes from the file header record (fh-fBigendian). */ + +void +_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern) + int bigend; + const struct tir_ext *ext_copy; + TIR *intern; +{ + struct tir_ext ext[1]; + + *ext = *ext_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG); + intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG); + intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_BIG) + >> TIR_BITS1_BT_SH_BIG; + intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG) + >> TIR_BITS_TQ4_SH_BIG; + intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG) + >> TIR_BITS_TQ5_SH_BIG; + intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG) + >> TIR_BITS_TQ0_SH_BIG; + intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG) + >> TIR_BITS_TQ1_SH_BIG; + intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG) + >> TIR_BITS_TQ2_SH_BIG; + intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG) + >> TIR_BITS_TQ3_SH_BIG; + } else { + intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE); + intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE); + intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE) + >> TIR_BITS1_BT_SH_LITTLE; + intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE) + >> TIR_BITS_TQ4_SH_LITTLE; + intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE) + >> TIR_BITS_TQ5_SH_LITTLE; + intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE) + >> TIR_BITS_TQ0_SH_LITTLE; + intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE) + >> TIR_BITS_TQ1_SH_LITTLE; + intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE) + >> TIR_BITS_TQ2_SH_LITTLE; + intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE) + >> TIR_BITS_TQ3_SH_LITTLE; + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort (); +#endif +} + +/* Swap out a type information record. + BIGEND says whether AUX symbols are big-endian or little-endian; this + info comes from the file header record (fh-fBigendian). */ + +void +_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext) + int bigend; + const TIR *intern_copy; + struct tir_ext *ext; +{ + TIR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0) + | (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0) + | ((intern->bt << TIR_BITS1_BT_SH_BIG) + & TIR_BITS1_BT_BIG)); + ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG) + & TIR_BITS_TQ4_BIG) + | ((intern->tq5 << TIR_BITS_TQ5_SH_BIG) + & TIR_BITS_TQ5_BIG)); + ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG) + & TIR_BITS_TQ0_BIG) + | ((intern->tq1 << TIR_BITS_TQ1_SH_BIG) + & TIR_BITS_TQ1_BIG)); + ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG) + & TIR_BITS_TQ2_BIG) + | ((intern->tq3 << TIR_BITS_TQ3_SH_BIG) + & TIR_BITS_TQ3_BIG)); + } else { + ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0) + | (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0) + | ((intern->bt << TIR_BITS1_BT_SH_LITTLE) + & TIR_BITS1_BT_LITTLE)); + ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE) + & TIR_BITS_TQ4_LITTLE) + | ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE) + & TIR_BITS_TQ5_LITTLE)); + ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE) + & TIR_BITS_TQ0_LITTLE) + | ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE) + & TIR_BITS_TQ1_LITTLE)); + ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE) + & TIR_BITS_TQ2_LITTLE) + | ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE) + & TIR_BITS_TQ3_LITTLE)); + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort (); +#endif +} + +/* Swap in a relative symbol record. BIGEND says whether it is in + big-endian or little-endian format.*/ + +void +_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern) + int bigend; + const struct rndx_ext *ext_copy; + RNDXR *intern; +{ + struct rndx_ext ext[1]; + + *ext = *ext_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG) + | ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG) + >> RNDX_BITS1_RFD_SH_BIG); + intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG) + << RNDX_BITS1_INDEX_SH_LEFT_BIG) + | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG) + | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG); + } else { + intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE) + | ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE) + << RNDX_BITS1_RFD_SH_LEFT_LITTLE); + intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE) + >> RNDX_BITS1_INDEX_SH_LITTLE) + | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE) + | ((unsigned int) ext->r_bits[3] + << RNDX_BITS3_INDEX_SH_LEFT_LITTLE); + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort (); +#endif +} + +/* Swap out a relative symbol record. BIGEND says whether it is in + big-endian or little-endian format.*/ + +void +_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext) + int bigend; + const RNDXR *intern_copy; + struct rndx_ext *ext; +{ + RNDXR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG; + ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG) + & RNDX_BITS1_RFD_BIG) + | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG) + & RNDX_BITS1_INDEX_BIG)); + ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG; + ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG; + } else { + ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE; + ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE) + & RNDX_BITS1_RFD_LITTLE) + | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE) + & RNDX_BITS1_INDEX_LITTLE)); + ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE; + ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE; + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort (); +#endif +} /* The minimum amount of data to allocate. */ #define ALLOC_SIZE (4064) /* Add bytes to a buffer. Return success. */ -static boolean +static bfd_boolean ecoff_add_bytes (buf, bufend, need) char **buf; char **bufend; @@ -68,18 +273,12 @@ ecoff_add_bytes (buf, bufend, need) if (want < ALLOC_SIZE) want = ALLOC_SIZE; } - if (*buf == NULL) - newbuf = (char *) malloc (have + want); - else - newbuf = (char *) realloc (*buf, have + want); + newbuf = (char *) bfd_realloc (*buf, (bfd_size_type) have + want); if (newbuf == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return FALSE; *buf = newbuf; *bufend = *buf + have + want; - return true; + return TRUE; } /* We keep a hash table which maps strings to numbers. We use it to @@ -116,10 +315,7 @@ string_hash_newfunc (entry, table, string) ret = ((struct string_hash_entry *) bfd_hash_allocate (table, sizeof (struct string_hash_entry))); if (ret == (struct string_hash_entry *) NULL) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } + return NULL; /* Call the allocation method of the superclass. */ ret = ((struct string_hash_entry *) @@ -152,7 +348,7 @@ struct shuffle /* The length of the information. */ unsigned long size; /* Whether this information comes from a file or not. */ - boolean filep; + bfd_boolean filep; union { struct @@ -199,18 +395,17 @@ struct accumulate struct shuffle *rfd_end; /* The size of the largest file shuffle. */ unsigned long largest_file_shuffle; - /* An obstack for debugging information. */ - struct obstack memory; + /* An objalloc for debugging information. */ + struct objalloc *memory; }; /* Add a file entry to a shuffle list. */ -static boolean add_file_shuffle PARAMS ((struct accumulate *, - struct shuffle **, - struct shuffle **, bfd *, file_ptr, - unsigned long)); +static bfd_boolean add_file_shuffle + PARAMS ((struct accumulate *, struct shuffle **, struct shuffle **, + bfd *, file_ptr, unsigned long)); -static boolean +static bfd_boolean add_file_shuffle (ainfo, head, tail, input_bfd, offset, size) struct accumulate *ainfo; struct shuffle **head; @@ -224,25 +419,25 @@ add_file_shuffle (ainfo, head, tail, input_bfd, offset, size) if (*tail != (struct shuffle *) NULL && (*tail)->filep && (*tail)->u.file.input_bfd == input_bfd - && (*tail)->u.file.offset + (*tail)->size == offset) + && (*tail)->u.file.offset + (*tail)->size == (unsigned long) offset) { /* Just merge this entry onto the existing one. */ (*tail)->size += size; if ((*tail)->size > ainfo->largest_file_shuffle) ainfo->largest_file_shuffle = (*tail)->size; - return true; + return TRUE; } - n = (struct shuffle *) obstack_alloc (&ainfo->memory, - sizeof (struct shuffle)); + n = (struct shuffle *) objalloc_alloc (ainfo->memory, + sizeof (struct shuffle)); if (!n) { bfd_set_error (bfd_error_no_memory); - return false; + return FALSE; } n->next = NULL; n->size = size; - n->filep = true; + n->filep = TRUE; n->u.file.input_bfd = input_bfd; n->u.file.offset = offset; if (*head == (struct shuffle *) NULL) @@ -252,17 +447,16 @@ add_file_shuffle (ainfo, head, tail, input_bfd, offset, size) *tail = n; if (size > ainfo->largest_file_shuffle) ainfo->largest_file_shuffle = size; - return true; + return TRUE; } /* Add a memory entry to a shuffle list. */ -static boolean add_memory_shuffle PARAMS ((struct accumulate *, - struct shuffle **head, - struct shuffle **tail, - bfd_byte *data, unsigned long size)); +static bfd_boolean add_memory_shuffle + PARAMS ((struct accumulate *, struct shuffle **head, struct shuffle **tail, + bfd_byte *data, unsigned long size)); -static boolean +static bfd_boolean add_memory_shuffle (ainfo, head, tail, data, size) struct accumulate *ainfo; struct shuffle **head; @@ -271,45 +465,42 @@ add_memory_shuffle (ainfo, head, tail, data, size) unsigned long size; { struct shuffle *n; - - n = (struct shuffle *) obstack_alloc (&ainfo->memory, - sizeof (struct shuffle)); + + n = (struct shuffle *) objalloc_alloc (ainfo->memory, + sizeof (struct shuffle)); if (!n) { bfd_set_error (bfd_error_no_memory); - return false; + return FALSE; } n->next = NULL; n->size = size; - n->filep = false; + n->filep = FALSE; n->u.memory = (PTR) data; if (*head == (struct shuffle *) NULL) *head = n; if (*tail != (struct shuffle *) NULL) (*tail)->next = n; *tail = n; - return true; + return TRUE; } /* Initialize the FDR hash table. This returns a handle which is then passed in to bfd_ecoff_debug_accumulate, et. al. */ -/*ARGSUSED*/ PTR bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info) - bfd *output_bfd; + bfd *output_bfd ATTRIBUTE_UNUSED; struct ecoff_debug_info *output_debug; - const struct ecoff_debug_swap *output_swap; + const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED; struct bfd_link_info *info; { struct accumulate *ainfo; + bfd_size_type amt = sizeof (struct accumulate); - ainfo = (struct accumulate *) malloc (sizeof (struct accumulate)); + ainfo = (struct accumulate *) bfd_malloc (amt); if (!ainfo) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } + return NULL; if (! bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc, 1021)) return NULL; @@ -335,7 +526,7 @@ bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info) ainfo->largest_file_shuffle = 0; - if (! info->relocateable) + if (! info->relocatable) { if (! bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc)) return NULL; @@ -344,7 +535,8 @@ bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info) output_debug->symbolic_header.issMax = 1; } - if (!obstack_begin (&ainfo->memory, 4050)) + ainfo->memory = objalloc_create (); + if (ainfo->memory == NULL) { bfd_set_error (bfd_error_no_memory); return NULL; @@ -355,23 +547,22 @@ bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info) /* Free the accumulated debugging information. */ -/*ARGSUSED*/ void bfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info) PTR handle; - bfd *output_bfd; - struct ecoff_debug_info *output_debug; - const struct ecoff_debug_swap *output_swap; + bfd *output_bfd ATTRIBUTE_UNUSED; + struct ecoff_debug_info *output_debug ATTRIBUTE_UNUSED; + const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED; struct bfd_link_info *info; { struct accumulate *ainfo = (struct accumulate *) handle; - + bfd_hash_table_free (&ainfo->fdr_hash.table); - if (! info->relocateable) + if (! info->relocatable) bfd_hash_table_free (&ainfo->str_hash.table); - obstack_free (&ainfo->memory, (PTR) NULL); + objalloc_free (ainfo->memory); free (ainfo); } @@ -384,8 +575,7 @@ bfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info) linker information structure. HANDLE is returned by bfd_ecoff_debug_init. */ -/*ARGSUSED*/ -boolean +bfd_boolean bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, input_bfd, input_debug, input_swap, info) @@ -431,6 +621,7 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, long newrfdbase = 0; long oldrfdbase = 0; bfd_byte *fdr_out; + bfd_size_type amt; /* Use section_adjust to hold the value to add to a symbol in a particular section. */ @@ -453,6 +644,7 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, SET (".rodata", scRData); SET (".init", scInit); SET (".fini", scFini); + SET (".rconst", scRConst); #undef SET @@ -470,19 +662,19 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, } fdr_end = fdr_start + input_symhdr->ifdMax * fdr_add; - input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd, - (input_symhdr->ifdMax - * sizeof (RFDT))); + amt = input_symhdr->ifdMax; + amt *= sizeof (RFDT); + input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd, amt); sz = (input_symhdr->crfd + input_symhdr->ifdMax) * external_rfd_size; - rfd_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + rfd_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz); if (!input_debug->ifdmap || !rfd_out) { bfd_set_error (bfd_error_no_memory); - return false; + return FALSE; } if (!add_memory_shuffle (ainfo, &ainfo->rfd, &ainfo->rfd_end, rfd_out, sz)) - return false; + return FALSE; copied = 0; @@ -513,25 +705,23 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, struct string_hash_entry *fh; /* We look up a string formed from the file name and the - number of symbols. Sometimes an include file will - conditionally define a typedef or something based on the - order of include files. Using the number of symbols as a - hash reduces the chance that we will merge symbol - information that should not be merged. */ + number of symbols and aux entries. Sometimes an include + file will conditionally define a typedef or something + based on the order of include files. Using the number of + symbols and aux entries as a hash reduces the chance that + we will merge symbol information that should not be + merged. */ name = input_debug->ss + fdr.issBase + fdr.rss; - lookup = (char *) malloc (strlen (name) + 20); + lookup = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 20); if (lookup == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } - sprintf (lookup, "%s %lx", name, fdr.csym); + return FALSE; + sprintf (lookup, "%s %lx %lx", name, fdr.csym, fdr.caux); - fh = string_hash_lookup (&ainfo->fdr_hash, lookup, true, true); + fh = string_hash_lookup (&ainfo->fdr_hash, lookup, TRUE, TRUE); free (lookup); if (fh == (struct string_hash_entry *) NULL) - return false; + return FALSE; if (fh->val != -1) { @@ -578,14 +768,14 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, /* Look through the FDR's and copy over all associated debugging information. */ sz = copied * external_fdr_size; - fdr_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + fdr_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz); if (!fdr_out) { bfd_set_error (bfd_error_no_memory); - return false; + return FALSE; } if (!add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, fdr_out, sz)) - return false; + return FALSE; for (fdr_ptr = fdr_start, i = 0; fdr_ptr < fdr_end; fdr_ptr += fdr_add, i++) @@ -595,7 +785,7 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, bfd_byte *sym_out; bfd_byte *lraw_src; bfd_byte *lraw_end; - boolean fgotfilename; + bfd_boolean fgotfilename; if (input_debug->ifdmap[i] < output_symhdr->ifdMax) { @@ -610,20 +800,6 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, fdr_adr = fdr.adr; - /* Adjust the FDR address for any changes that may have been - made by relaxing. */ - if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) - { - struct ecoff_value_adjust *adjust; - - for (adjust = input_debug->adjust; - adjust != (struct ecoff_value_adjust *) NULL; - adjust = adjust->next) - if (fdr_adr >= adjust->start - && fdr_adr < adjust->end) - fdr.adr += adjust->adjust; - } - /* FIXME: It is conceivable that this FDR points to the .init or .fini section, in which case this will not do the right thing. */ @@ -631,17 +807,17 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, /* Swap in the local symbols, adjust their values, and swap them out again. */ - fgotfilename = false; + fgotfilename = FALSE; sz = fdr.csym * external_sym_size; - sym_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + sym_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz); if (!sym_out) { bfd_set_error (bfd_error_no_memory); - return false; + return FALSE; } if (!add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out, sz)) - return false; + return FALSE; lraw_src = ((bfd_byte *) input_debug->external_sym + fdr.isymBase * input_swap->external_sym_size); lraw_end = lraw_src + fdr.csym * input_swap->external_sym_size; @@ -666,19 +842,6 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, case stLabel: case stProc: case stStaticProc: - if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) - { - bfd_vma value; - struct ecoff_value_adjust *adjust; - - value = internal_sym.value; - for (adjust = input_debug->adjust; - adjust != (struct ecoff_value_adjust *) NULL; - adjust = adjust->next) - if (value >= adjust->start - && value < adjust->end) - internal_sym.value += adjust->adjust; - } internal_sym.value += section_adjust[internal_sym.sc]; break; @@ -689,17 +852,17 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, /* If we are doing a final link, we hash all the strings in the local symbol table together. This reduces the amount of space required by debugging information. We don't do - this when performing a relocateable link because it would + this when performing a relocatable link because it would prevent us from easily merging different FDR's. */ - if (! info->relocateable) + if (! info->relocatable) { - boolean ffilename; + bfd_boolean ffilename; const char *name; if (! fgotfilename && internal_sym.iss == fdr.rss) - ffilename = true; + ffilename = TRUE; else - ffilename = false; + ffilename = FALSE; /* Hash the name into the string table. */ name = input_debug->ss + fdr.issBase + internal_sym.iss; @@ -709,9 +872,9 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, { struct string_hash_entry *sh; - sh = string_hash_lookup (&ainfo->str_hash, name, true, true); + sh = string_hash_lookup (&ainfo->str_hash, name, TRUE, TRUE); if (sh == (struct string_hash_entry *) NULL) - return false; + return FALSE; if (sh->val == -1) { sh->val = output_symhdr->issMax; @@ -729,7 +892,7 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, if (ffilename) { fdr.rss = internal_sym.iss; - fgotfilename = true; + fgotfilename = TRUE; } } @@ -748,11 +911,10 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, stabs are adjusted correctly. */ if (fdr.cbLine > 0) { + file_ptr pos = input_symhdr->cbLineOffset + fdr.cbLineOffset; if (!add_file_shuffle (ainfo, &ainfo->line, &ainfo->line_end, - input_bfd, - input_symhdr->cbLineOffset + fdr.cbLineOffset, - fdr.cbLine)) - return false; + input_bfd, pos, (unsigned long) fdr.cbLine)) + return FALSE; fdr.ilineBase = output_symhdr->ilineMax; fdr.cbLineOffset = output_symhdr->cbLine; output_symhdr->ilineMax += fdr.cline; @@ -760,16 +922,16 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, } if (fdr.caux > 0) { + file_ptr pos = (input_symhdr->cbAuxOffset + + fdr.iauxBase * sizeof (union aux_ext)); if (!add_file_shuffle (ainfo, &ainfo->aux, &ainfo->aux_end, - input_bfd, - (input_symhdr->cbAuxOffset - + fdr.iauxBase * sizeof (union aux_ext)), + input_bfd, pos, fdr.caux * sizeof (union aux_ext))) - return false; + return FALSE; fdr.iauxBase = output_symhdr->iauxMax; output_symhdr->iauxMax += fdr.caux; } - if (! info->relocateable) + if (! info->relocatable) { /* When are are hashing strings, we lie about the number of @@ -781,18 +943,16 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, } else if (fdr.cbSs > 0) { + file_ptr pos = input_symhdr->cbSsOffset + fdr.issBase; if (!add_file_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, - input_bfd, - input_symhdr->cbSsOffset + fdr.issBase, - fdr.cbSs)) - return false; + input_bfd, pos, (unsigned long) fdr.cbSs)) + return FALSE; fdr.issBase = output_symhdr->issMax; output_symhdr->issMax += fdr.cbSs; } - if ((output_bfd->xvec->header_byteorder_big_p - == input_bfd->xvec->header_byteorder_big_p) - && input_debug->adjust == (struct ecoff_value_adjust *) NULL) + if (output_bfd->xvec->header_byteorder + == input_bfd->xvec->header_byteorder) { /* The two BFD's have the same endianness, and we don't have to adjust the PDR addresses, so simply copying the @@ -800,22 +960,22 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, BFD_ASSERT (external_pdr_size == input_swap->external_pdr_size); if (fdr.cpd > 0) { + file_ptr pos = (input_symhdr->cbPdOffset + + fdr.ipdFirst * external_pdr_size); + unsigned long size = fdr.cpd * external_pdr_size; if (!add_file_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, - input_bfd, - (input_symhdr->cbPdOffset - + fdr.ipdFirst * external_pdr_size), - fdr.cpd * external_pdr_size)) - return false; + input_bfd, pos, size)) + return FALSE; } BFD_ASSERT (external_opt_size == input_swap->external_opt_size); if (fdr.copt > 0) { + file_ptr pos = (input_symhdr->cbOptOffset + + fdr.ioptBase * external_opt_size); + unsigned long size = fdr.copt * external_opt_size; if (!add_file_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, - input_bfd, - (input_symhdr->cbOptOffset - + fdr.ioptBase * external_opt_size), - fdr.copt * external_opt_size)) - return false; + input_bfd, pos, size)) + return FALSE; } } else @@ -834,37 +994,20 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, + fdr.ipdFirst * insz); end = in + fdr.cpd * insz; sz = fdr.cpd * outsz; - out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz); if (!out) { bfd_set_error (bfd_error_no_memory); - return false; + return FALSE; } if (!add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out, sz)) - return false; + return FALSE; for (; in < end; in += insz, out += outsz) { PDR pdr; (*input_swap->swap_pdr_in) (input_bfd, (PTR) in, &pdr); - - /* If we have been relaxing, we may have to adjust the - address. */ - if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) - { - bfd_vma adr; - struct ecoff_value_adjust *adjust; - - adr = fdr_adr + pdr.adr; - for (adjust = input_debug->adjust; - adjust != (struct ecoff_value_adjust *) NULL; - adjust = adjust->next) - if (adr >= adjust->start - && adr < adjust->end) - pdr.adr += adjust->adjust; - } - (*output_swap->swap_pdr_out) (output_bfd, &pdr, (PTR) out); } @@ -875,15 +1018,15 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, + fdr.ioptBase * insz); end = in + fdr.copt * insz; sz = fdr.copt * outsz; - out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz); if (!out) { bfd_set_error (bfd_error_no_memory); - return false; + return FALSE; } if (!add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out, sz)) - return false; + return FALSE; for (; in < end; in += insz, out += outsz) { OPTR opt; @@ -915,16 +1058,15 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, ++output_symhdr->ifdMax; } - return true; + return TRUE; } /* Add a string to the debugging information we are accumulating. Return the offset from the fdr string base. */ -static long ecoff_add_string PARAMS ((struct accumulate *, - struct bfd_link_info *, - struct ecoff_debug_info *, - FDR *fdr, const char *string)); +static long ecoff_add_string + PARAMS ((struct accumulate *, struct bfd_link_info *, + struct ecoff_debug_info *, FDR *fdr, const char *string)); static long ecoff_add_string (ainfo, info, debug, fdr, string) @@ -940,7 +1082,7 @@ ecoff_add_string (ainfo, info, debug, fdr, string) symhdr = &debug->symbolic_header; len = strlen (string); - if (info->relocateable) + if (info->relocatable) { if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, (PTR) string, len + 1)) @@ -953,7 +1095,7 @@ ecoff_add_string (ainfo, info, debug, fdr, string) { struct string_hash_entry *sh; - sh = string_hash_lookup (&ainfo->str_hash, string, true, true); + sh = string_hash_lookup (&ainfo->str_hash, string, TRUE, TRUE); if (sh == (struct string_hash_entry *) NULL) return -1; if (sh->val == -1) @@ -975,7 +1117,7 @@ ecoff_add_string (ainfo, info, debug, fdr, string) /* Add debugging information from a non-ECOFF file. */ -boolean +bfd_boolean bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, output_swap, input_bfd, info) PTR handle; @@ -1012,24 +1154,21 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, fdr.issBase = output_symhdr->issMax; fdr.cbSs = 0; fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr, - bfd_get_filename (input_bfd)); + input_bfd->filename); if (fdr.rss == -1) - return false; + return FALSE; fdr.isymBase = output_symhdr->isymMax; /* Get the local symbols from the input BFD. */ symsize = bfd_get_symtab_upper_bound (input_bfd); if (symsize < 0) - return false; - symbols = (asymbol **) bfd_alloc (output_bfd, symsize); + return FALSE; + symbols = (asymbol **) bfd_alloc (output_bfd, (bfd_size_type) symsize); if (symbols == (asymbol **) NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return FALSE; symcount = bfd_canonicalize_symtab (input_bfd, symbols); if (symcount < 0) - return false; + return FALSE; sym_end = symbols + symcount; /* Handle the local symbols. Any external symbols are handled @@ -1047,9 +1186,9 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, (*sym_ptr)->name); if (internal_sym.iss == -1) - return false; + return FALSE; if (bfd_is_com_section ((*sym_ptr)->section) - || (*sym_ptr)->section == &bfd_und_section) + || bfd_is_und_section ((*sym_ptr)->section)) internal_sym.value = (*sym_ptr)->value; else internal_sym.value = ((*sym_ptr)->value @@ -1059,16 +1198,17 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, internal_sym.sc = scUndefined; internal_sym.index = indexNil; - external_sym = (PTR) obstack_alloc (&ainfo->memory, - output_swap->external_sym_size); + external_sym = (PTR) objalloc_alloc (ainfo->memory, + output_swap->external_sym_size); if (!external_sym) { bfd_set_error (bfd_error_no_memory); - return false; + return FALSE; } (*swap_sym_out) (output_bfd, &internal_sym, external_sym); add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, - external_sym, output_swap->external_sym_size); + external_sym, + (unsigned long) output_swap->external_sym_size); ++fdr.csym; ++output_symhdr->isymMax; } @@ -1079,20 +1219,21 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, the lang field to be langC. The fBigendian field will indicate little endian format, but it doesn't matter because it only applies to aux fields and there are none. */ - external_fdr = (PTR) obstack_alloc (&ainfo->memory, - output_swap->external_fdr_size); + external_fdr = (PTR) objalloc_alloc (ainfo->memory, + output_swap->external_fdr_size); if (!external_fdr) { bfd_set_error (bfd_error_no_memory); - return false; + return FALSE; } (*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr); add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, - external_fdr, output_swap->external_fdr_size); + external_fdr, + (unsigned long) output_swap->external_fdr_size); ++output_symhdr->ifdMax; - return true; + return TRUE; } /* Set up ECOFF debugging information for the external symbols. @@ -1100,14 +1241,14 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, probably be changed to use a shuffle structure. The assembler uses this interface, so that must be changed to do something else. */ -boolean -bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr, +bfd_boolean +bfd_ecoff_debug_externals (abfd, debug, swap, relocatable, get_extr, set_index) bfd *abfd; struct ecoff_debug_info *debug; const struct ecoff_debug_swap *swap; - boolean relocateable; - boolean (*get_extr) PARAMS ((asymbol *, EXTR *)); + bfd_boolean relocatable; + bfd_boolean (*get_extr) PARAMS ((asymbol *, EXTR *)); void (*set_index) PARAMS ((asymbol *, bfd_size_type)); { HDRR * const symhdr = &debug->symbolic_header; @@ -1116,7 +1257,7 @@ bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr, sym_ptr_ptr = bfd_get_outsymbols (abfd); if (sym_ptr_ptr == NULL) - return true; + return TRUE; for (c = bfd_get_symcount (abfd); c > 0; c--, sym_ptr_ptr++) { @@ -1126,12 +1267,12 @@ bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr, sym_ptr = *sym_ptr_ptr; /* Get the external symbol information. */ - if ((*get_extr) (sym_ptr, &esym) == false) + if (! (*get_extr) (sym_ptr, &esym)) continue; /* If we're producing an executable, move common symbols into bss. */ - if (relocateable == false) + if (! relocatable) { if (esym.asym.sc == scCommon) esym.asym.sc = scBss; @@ -1140,7 +1281,8 @@ bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr, } if (bfd_is_com_section (sym_ptr->section) - || sym_ptr->section == &bfd_und_section) + || bfd_is_und_section (sym_ptr->section) + || sym_ptr->section->output_section == (asection *) NULL) { /* FIXME: gas does not keep the value of a small undefined symbol in the symbol itself, because of relocation @@ -1160,15 +1302,15 @@ bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr, if (! bfd_ecoff_debug_one_external (abfd, debug, swap, sym_ptr->name, &esym)) - return false; + return FALSE; } - return true; + return TRUE; } /* Add a single external symbol to the debugging information. */ -boolean +bfd_boolean bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym) bfd *abfd; struct ecoff_debug_info *debug; @@ -1184,23 +1326,26 @@ bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym) namelen = strlen (name); - if (debug->ssext_end - debug->ssext + if ((size_t) (debug->ssext_end - debug->ssext) < symhdr->issExtMax + namelen + 1) { - if (ecoff_add_bytes ((char **) &debug->ssext, - (char **) &debug->ssext_end, - symhdr->issExtMax + namelen + 1) - == false) - return false; + if (! ecoff_add_bytes ((char **) &debug->ssext, + (char **) &debug->ssext_end, + symhdr->issExtMax + namelen + 1)) + return FALSE; } - if ((char *) debug->external_ext_end - (char *) debug->external_ext + if ((size_t) ((char *) debug->external_ext_end + - (char *) debug->external_ext) < (symhdr->iextMax + 1) * external_ext_size) { - if (ecoff_add_bytes ((char **) &debug->external_ext, - (char **) &debug->external_ext_end, - (symhdr->iextMax + 1) * external_ext_size) - == false) - return false; + char *external_ext = debug->external_ext; + char *external_ext_end = debug->external_ext_end; + if (! ecoff_add_bytes ((char **) &external_ext, + (char **) &external_ext_end, + (symhdr->iextMax + 1) * (size_t) external_ext_size)) + return FALSE; + debug->external_ext = external_ext; + debug->external_ext_end = external_ext_end; } esym->asym.iss = symhdr->issExtMax; @@ -1214,15 +1359,14 @@ bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym) strcpy (debug->ssext + symhdr->issExtMax, name); symhdr->issExtMax += namelen + 1; - return true; + return TRUE; } /* Align the ECOFF debugging information. */ -/*ARGSUSED*/ static void ecoff_align_debug (abfd, debug, swap) - bfd *abfd; + bfd *abfd ATTRIBUTE_UNUSED; struct ecoff_debug_info *debug; const struct ecoff_debug_swap *swap; { @@ -1274,7 +1418,7 @@ ecoff_align_debug (abfd, debug, swap) if (debug->external_rfd != (PTR) NULL) memset ((PTR) ((char *) debug->external_rfd + symhdr->crfd * swap->external_rfd_size), - 0, add * swap->external_rfd_size); + 0, (size_t) (add * swap->external_rfd_size)); symhdr->crfd += add; } } @@ -1316,7 +1460,7 @@ bfd_ecoff_debug_size (abfd, debug, swap) going to be placed at. This assumes that the counts are set correctly. */ -static boolean +static bfd_boolean ecoff_write_symhdr (abfd, debug, swap, where) bfd *abfd; struct ecoff_debug_info *debug; @@ -1330,7 +1474,7 @@ ecoff_write_symhdr (abfd, debug, swap, where) /* Go to the right location in the file. */ if (bfd_seek (abfd, where, SEEK_SET) != 0) - return false; + return FALSE; where += swap->external_hdr_size; @@ -1359,25 +1503,22 @@ ecoff_write_symhdr (abfd, debug, swap, where) SET (cbExtOffset, iextMax, swap->external_ext_size); #undef SET - buff = (PTR) malloc (swap->external_hdr_size); + buff = (PTR) bfd_malloc (swap->external_hdr_size); if (buff == NULL && swap->external_hdr_size != 0) - { - bfd_set_error (bfd_error_no_memory); - goto error_return; - } + goto error_return; (*swap->swap_hdr_out) (abfd, symhdr, buff); - if (bfd_write (buff, 1, swap->external_hdr_size, abfd) + if (bfd_bwrite (buff, swap->external_hdr_size, abfd) != swap->external_hdr_size) goto error_return; if (buff != NULL) free (buff); - return true; + return TRUE; error_return: if (buff != NULL) free (buff); - return false; + return FALSE; } /* Write out the ECOFF debugging information. This function assumes @@ -1386,7 +1527,7 @@ ecoff_write_symhdr (abfd, debug, swap, where) information to. This function fills in the file offsets in the symbolic header. */ -boolean +bfd_boolean bfd_ecoff_write_debug (abfd, debug, swap, where) bfd *abfd; struct ecoff_debug_info *debug; @@ -1396,20 +1537,22 @@ bfd_ecoff_write_debug (abfd, debug, swap, where) HDRR * const symhdr = &debug->symbolic_header; if (! ecoff_write_symhdr (abfd, debug, swap, where)) - return false; + return FALSE; #define WRITE(ptr, count, size, offset) \ - BFD_ASSERT (symhdr->offset == 0 || bfd_tell (abfd) == symhdr->offset); \ - if (bfd_write ((PTR) debug->ptr, size, symhdr->count, abfd) \ + BFD_ASSERT (symhdr->offset == 0 \ + || (bfd_vma) bfd_tell (abfd) == symhdr->offset); \ + if (bfd_bwrite ((PTR) debug->ptr, (bfd_size_type) size * symhdr->count, abfd)\ != size * symhdr->count) \ - return false; + return FALSE; WRITE (line, cbLine, sizeof (unsigned char), cbLineOffset); WRITE (external_dnr, idnMax, swap->external_dnr_size, cbDnOffset); WRITE (external_pdr, ipdMax, swap->external_pdr_size, cbPdOffset); WRITE (external_sym, isymMax, swap->external_sym_size, cbSymOffset); WRITE (external_opt, ioptMax, swap->external_opt_size, cbOptOffset); - WRITE (external_aux, iauxMax, sizeof (union aux_ext), cbAuxOffset); + WRITE (external_aux, iauxMax, (bfd_size_type) sizeof (union aux_ext), + cbAuxOffset); WRITE (ss, issMax, sizeof (char), cbSsOffset); WRITE (ssext, issExtMax, sizeof (char), cbSsExtOffset); WRITE (external_fdr, ifdMax, swap->external_fdr_size, cbFdOffset); @@ -1417,16 +1560,16 @@ bfd_ecoff_write_debug (abfd, debug, swap, where) WRITE (external_ext, iextMax, swap->external_ext_size, cbExtOffset); #undef WRITE - return true; + return TRUE; } /* Write out a shuffle list. */ -static boolean ecoff_write_shuffle PARAMS ((bfd *, - const struct ecoff_debug_swap *, - struct shuffle *, PTR space)); +static bfd_boolean ecoff_write_shuffle + PARAMS ((bfd *, const struct ecoff_debug_swap *, struct shuffle *, + PTR space)); -static boolean +static bfd_boolean ecoff_write_shuffle (abfd, swap, shuffle, space) bfd *abfd; const struct ecoff_debug_swap *swap; @@ -1441,48 +1584,46 @@ ecoff_write_shuffle (abfd, swap, shuffle, space) { if (! l->filep) { - if (bfd_write (l->u.memory, 1, l->size, abfd) != l->size) - return false; + if (bfd_bwrite (l->u.memory, (bfd_size_type) l->size, abfd) + != l->size) + return FALSE; } else { if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0 - || bfd_read (space, 1, l->size, l->u.file.input_bfd) != l->size - || bfd_write (space, 1, l->size, abfd) != l->size) - return false; + || bfd_bread (space, (bfd_size_type) l->size, + l->u.file.input_bfd) != l->size + || bfd_bwrite (space, (bfd_size_type) l->size, abfd) != l->size) + return FALSE; } total += l->size; } if ((total & (swap->debug_align - 1)) != 0) { - int i; + unsigned int i; bfd_byte *s; i = swap->debug_align - (total & (swap->debug_align - 1)); - s = (bfd_byte *) malloc (i); + s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i); if (s == NULL && i != 0) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return FALSE; - memset ((PTR) s, 0, i); - if (bfd_write ((PTR) s, 1, i, abfd) != i) + if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i) { free (s); - return false; + return FALSE; } free (s); } - return true; + return TRUE; } /* Write out debugging information using accumulated linker information. */ -boolean +bfd_boolean bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) PTR handle; bfd *abfd; @@ -1493,16 +1634,15 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) { struct accumulate *ainfo = (struct accumulate *) handle; PTR space = NULL; + bfd_size_type amt; if (! ecoff_write_symhdr (abfd, debug, swap, where)) goto error_return; - space = (PTR) malloc (ainfo->largest_file_shuffle); + amt = ainfo->largest_file_shuffle; + space = (PTR) bfd_malloc (amt); if (space == NULL && ainfo->largest_file_shuffle != 0) - { - bfd_set_error (bfd_error_no_memory); - goto error_return; - } + goto error_return; if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space) || ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space) @@ -1513,7 +1653,7 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) /* The string table is written out from the hash table if this is a final link. */ - if (info->relocateable) + if (info->relocatable) { BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL); if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space)) @@ -1527,7 +1667,7 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL); null = 0; - if (bfd_write ((PTR) &null, 1, 1, abfd) != 1) + if (bfd_bwrite ((PTR) &null, (bfd_size_type) 1, abfd) != 1) goto error_return; total = 1; BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1); @@ -1538,25 +1678,23 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) size_t len; len = strlen (sh->root.string); - if (bfd_write ((PTR) sh->root.string, 1, len + 1, abfd) != len + 1) + amt = len + 1; + if (bfd_bwrite ((PTR) sh->root.string, amt, abfd) != amt) goto error_return; total += len + 1; } if ((total & (swap->debug_align - 1)) != 0) { - int i; + unsigned int i; bfd_byte *s; i = swap->debug_align - (total & (swap->debug_align - 1)); - s = (bfd_byte *) malloc (i); + s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i); if (s == NULL && i != 0) - { - bfd_set_error (bfd_error_no_memory); - goto error_return; - } - memset ((PTR) s, 0, i); - if (bfd_write ((PTR) s, 1, i, abfd) != i) + goto error_return; + + if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i) { free (s); goto error_return; @@ -1567,24 +1705,21 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) /* The external strings and symbol are not converted over to using shuffles. FIXME: They probably should be. */ - if (bfd_write (debug->ssext, 1, debug->symbolic_header.issExtMax, abfd) - != debug->symbolic_header.issExtMax) + amt = debug->symbolic_header.issExtMax; + if (bfd_bwrite (debug->ssext, amt, abfd) != amt) goto error_return; if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0) { - int i; + unsigned int i; bfd_byte *s; i = (swap->debug_align - (debug->symbolic_header.issExtMax & (swap->debug_align - 1))); - s = (bfd_byte *) malloc (i); + s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i); if (s == NULL && i != 0) - { - bfd_set_error (bfd_error_no_memory); - goto error_return; - } - memset ((PTR) s, 0, i); - if (bfd_write ((PTR) s, 1, i, abfd) != i) + goto error_return; + + if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i) { free (s); goto error_return; @@ -1597,19 +1732,819 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) goto error_return; BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0 - || debug->symbolic_header.cbExtOffset == bfd_tell (abfd)); + || (debug->symbolic_header.cbExtOffset + == (bfd_vma) bfd_tell (abfd))); - if (bfd_write (debug->external_ext, swap->external_ext_size, - debug->symbolic_header.iextMax, abfd) - != debug->symbolic_header.iextMax * swap->external_ext_size) + amt = debug->symbolic_header.iextMax * swap->external_ext_size; + if (bfd_bwrite (debug->external_ext, amt, abfd) != amt) goto error_return; if (space != NULL) free (space); - return true; + return TRUE; error_return: if (space != NULL) free (space); - return false; + return FALSE; +} + +/* Handle the find_nearest_line function for both ECOFF and MIPS ELF + files. */ + +/* Compare FDR entries. This is called via qsort. */ + +static int +cmp_fdrtab_entry (leftp, rightp) + const PTR leftp; + const PTR rightp; +{ + const struct ecoff_fdrtab_entry *lp = + (const struct ecoff_fdrtab_entry *) leftp; + const struct ecoff_fdrtab_entry *rp = + (const struct ecoff_fdrtab_entry *) rightp; + + if (lp->base_addr < rp->base_addr) + return -1; + if (lp->base_addr > rp->base_addr) + return 1; + return 0; +} + +/* Each file descriptor (FDR) has a memory address, to simplify + looking up an FDR by address, we build a table covering all FDRs + that have a least one procedure descriptor in them. The final + table will be sorted by address so we can look it up via binary + search. */ + +static bfd_boolean +mk_fdrtab (abfd, debug_info, debug_swap, line_info) + bfd *abfd; + struct ecoff_debug_info * const debug_info; + const struct ecoff_debug_swap * const debug_swap; + struct ecoff_find_line *line_info; +{ + struct ecoff_fdrtab_entry *tab; + FDR *fdr_ptr; + FDR *fdr_start; + FDR *fdr_end; + bfd_boolean stabs; + long len; + bfd_size_type amt; + + fdr_start = debug_info->fdr; + fdr_end = fdr_start + debug_info->symbolic_header.ifdMax; + + /* First, let's see how long the table needs to be. */ + for (len = 0, fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) + { + if (fdr_ptr->cpd == 0) /* Skip FDRs that have no PDRs. */ + continue; + ++len; + } + + /* Now, create and fill in the table. */ + amt = (bfd_size_type) len * sizeof (struct ecoff_fdrtab_entry); + line_info->fdrtab = (struct ecoff_fdrtab_entry*) bfd_zalloc (abfd, amt); + if (line_info->fdrtab == NULL) + return FALSE; + line_info->fdrtab_len = len; + + tab = line_info->fdrtab; + for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) + { + if (fdr_ptr->cpd == 0) + continue; + + /* Check whether this file has stabs debugging information. In + a file with stabs debugging information, the second local + symbol is named @stabs. */ + stabs = FALSE; + if (fdr_ptr->csym >= 2) + { + char *sym_ptr; + SYMR sym; + + sym_ptr = ((char *) debug_info->external_sym + + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size); + (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); + if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss, + STABS_SYMBOL) == 0) + stabs = TRUE; + } + + if (!stabs) + { + /* eraxxon: There are at least two problems with this computation: + 1) PDRs do *not* contain offsets but full vma's; and typically the + address of the first PDR is the address of the FDR, which will + make (most) of the results of the original computation 0! + 2) Once in a wacky while, the Compaq compiler generated PDR + addresses do not equal the FDR vma, but they (the PDR address) + are still vma's and not offsets. Cf. comments in + 'lookup_line'. */ + /* The address of the first PDR is the offset of that + procedure relative to the beginning of file FDR. */ + tab->base_addr = fdr_ptr->adr; + } + else + { + /* XXX I don't know about stabs, so this is a guess + (davidm@cs.arizona.edu). */ + tab->base_addr = fdr_ptr->adr; + } + tab->fdr = fdr_ptr; + ++tab; + } + + /* Finally, the table is sorted in increasing memory-address order. + The table is mostly sorted already, but there are cases (e.g., + static functions in include files), where this does not hold. + Use "odump -PFv" to verify... */ + qsort ((PTR) line_info->fdrtab, (size_t) len, + sizeof (struct ecoff_fdrtab_entry), cmp_fdrtab_entry); + + return TRUE; +} + +/* Return index of first FDR that covers to OFFSET. */ + +static long +fdrtab_lookup (line_info, offset) + struct ecoff_find_line *line_info; + bfd_vma offset; +{ + long low, high, len; + long mid = -1; + struct ecoff_fdrtab_entry *tab; + + len = line_info->fdrtab_len; + if (len == 0) + return -1; + + tab = line_info->fdrtab; + for (low = 0, high = len - 1 ; low != high ;) + { + mid = (high + low) / 2; + if (offset >= tab[mid].base_addr && offset < tab[mid + 1].base_addr) + goto find_min; + + if (tab[mid].base_addr > offset) + high = mid; + else + low = mid + 1; + } + + /* eraxxon: at this point 'offset' is either lower than the lowest entry or + higher than the highest entry. In the former case high = low = mid = 0; + we want to return -1. In the latter case, low = high and mid = low - 1; + we want to return the index of the highest entry. Only in former case + will the following 'catch-all' test be true. */ + ++mid; + + /* Last entry is catch-all for all higher addresses. */ + if (offset < tab[mid].base_addr) + return -1; + + find_min: + + /* eraxxon: There may be multiple FDRs in the table with the + same base_addr; make sure that we are at the first one. */ + while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr) + --mid; + + return mid; +} + +/* Look up a line given an address, storing the information in + LINE_INFO->cache. */ + +static bfd_boolean +lookup_line (abfd, debug_info, debug_swap, line_info) + bfd *abfd; + struct ecoff_debug_info * const debug_info; + const struct ecoff_debug_swap * const debug_swap; + struct ecoff_find_line *line_info; +{ + struct ecoff_fdrtab_entry *tab; + bfd_vma offset; + bfd_boolean stabs; + FDR *fdr_ptr; + int i; + + /* eraxxon: note that 'offset' is the full vma, not a section offset. */ + offset = line_info->cache.start; + + /* Build FDR table (sorted by object file's base-address) if we + don't have it already. */ + if (line_info->fdrtab == NULL + && !mk_fdrtab (abfd, debug_info, debug_swap, line_info)) + return FALSE; + + tab = line_info->fdrtab; + + /* Find first FDR for address OFFSET. */ + i = fdrtab_lookup (line_info, offset); + if (i < 0) + return FALSE; /* no FDR, no fun... */ + + /* eraxxon: 'fdrtab_lookup' doesn't give what we want, at least for Compaq's + C++ compiler 6.2. Consider three FDRs with starting addresses of x, y, + and z, respectively, such that x < y < z. Assume further that + y < 'offset' < z. It is possible at times that the PDR for 'offset' is + associated with FDR x and *not* with FDR y. Erg!! + + From a binary dump of my C++ test case 'moo' using Compaq's coffobjanl + (output format has been edited for our purposes): + + FDR [2]: (main.C): First instruction: 0x12000207c + PDR [5] for File [2]: LoopTest__Xv <0x1200020a0> (a) + PDR [7] for File [2]: foo__Xv <0x120002168> + FDR [1]: (-1): First instruction: 0x1200020e8 + PDR [3] for File [1]: <0x120001ad0> (b) + FDR [6]: (-1): First instruction: 0x1200026f0 + + (a) In the case of PDR5, the vma is such that the first few instructions + of the procedure can be found. But since the size of this procedure is + 160b, the vma will soon cross into the 'address space' of FDR1 and no + debugging info will be found. How repugnant! + + (b) It is also possible for a PDR to have a *lower* vma than its associated + FDR; see FDR1 and PDR3. Gross! + + Since the FDRs that are causing so much havok (in this case) 1) do not + describe actual files (fdr.rss == -1), and 2) contain only compiler + generated routines, I thought a simple fix would be to exclude them from + the FDR table in 'mk_fdrtab'. But, besides not knowing for certain + whether this would be correct, it creates an additional problem. If we + happen to ask for source file info on a compiler generated (procedure) + symbol -- which is still in the symbol table -- the result can be + information from a real procedure! This is because compiler generated + procedures with vma's higher than the last FDR in the fdr table will be + associated with a PDR from this FDR, specifically the PDR with the + highest vma. This wasn't a problem before, because each procedure had a + PDR. (Yes, this problem could be eliminated if we kept the size of the + last PDR around, but things are already getting ugly). + + Probably, a better solution would be to have a sorted PDR table. Each + PDR would have a pointer to its FDR so file information could still be + obtained. A FDR table could still be constructed if necessary -- since + it only contains pointers, not much extra memory would be used -- but + the PDR table would be searched to locate debugging info. + + There is still at least one remaining issue. Sometimes a FDR can have a + bogus name, but contain PDRs that should belong to another FDR with a + real name. E.g: + + FDR [3]: 0000000120001b50 (/home/.../Array.H~alt~deccxx_5E5A62AD) + PDR [a] for File [3]: 0000000120001b50 + PDR [b] for File [3]: 0000000120001cf0 + PDR [c] for File [3]: 0000000120001dc8 + PDR [d] for File [3]: 0000000120001e40 + PDR [e] for File [3]: 0000000120001eb8 + PDR [f] for File [3]: 0000000120001f4c + FDR [4]: 0000000120001b50 (/home/.../Array.H) + + Here, FDR4 has the correct name, but should (seemingly) contain PDRa-f. + The symbol table for PDR4 does contain symbols for PDRa-f, but so does + the symbol table for FDR3. However the former is different; perhaps this + can be detected easily. (I'm not sure at this point.) This problem only + seems to be associated with files with templates. I am assuming the idea + is that there is a 'fake' FDR (with PDRs) for each differently typed set + of templates that must be generated. Currently, FDR4 is completely + excluded from the FDR table in 'mk_fdrtab' because it contains no PDRs. + + Since I don't have time to prepare a real fix for this right now, be + prepared for 'A Horrible Hack' to force the inspection of all non-stabs + FDRs. It's coming... */ + fdr_ptr = tab[i].fdr; + + /* Check whether this file has stabs debugging information. In a + file with stabs debugging information, the second local symbol is + named @stabs. */ + stabs = FALSE; + if (fdr_ptr->csym >= 2) + { + char *sym_ptr; + SYMR sym; + + sym_ptr = ((char *) debug_info->external_sym + + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size); + (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); + if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss, + STABS_SYMBOL) == 0) + stabs = TRUE; + } + + if (!stabs) + { + bfd_size_type external_pdr_size; + char *pdr_ptr; + char *best_pdr = NULL; + FDR *best_fdr; + bfd_signed_vma best_dist = -1; + PDR pdr; + unsigned char *line_ptr; + unsigned char *line_end; + int lineno; + /* This file uses ECOFF debugging information. Each FDR has a + list of procedure descriptors (PDR). The address in the FDR + is the absolute address of the first procedure. The address + in the first PDR gives the offset of that procedure relative + to the object file's base-address. The addresses in + subsequent PDRs specify each procedure's address relative to + the object file's base-address. To make things more juicy, + whenever the PROF bit in the PDR is set, the real entry point + of the procedure may be 16 bytes below what would normally be + the procedure's entry point. Instead, DEC came up with a + wicked scheme to create profiled libraries "on the fly": + instead of shipping a regular and a profiled version of each + library, they insert 16 bytes of unused space in front of + each procedure and set the "prof" bit in the PDR to indicate + that there is a gap there (this is done automagically by "as" + when option "-pg" is specified). Thus, normally, you link + against such a library and, except for lots of 16 byte gaps + between functions, things will behave as usual. However, + when invoking "ld" with option "-pg", it will fill those gaps + with code that calls mcount(). It then moves the function's + entry point down by 16 bytes, and out pops a binary that has + all functions profiled. + + NOTE: Neither FDRs nor PDRs are strictly sorted in memory + order. For example, when including header-files that + define functions, the FDRs follow behind the including + file, even though their code may have been generated at + a lower address. File coff-alpha.c from libbfd + illustrates this (use "odump -PFv" to look at a file's + FDR/PDR). Similarly, PDRs are sometimes out of order + as well. An example of this is OSF/1 v3.0 libc's + malloc.c. I'm not sure why this happens, but it could + be due to optimizations that reorder a function's + position within an object-file. + + Strategy: + + On the first call to this function, we build a table of FDRs + that is sorted by the base-address of the object-file the FDR + is referring to. Notice that each object-file may contain + code from multiple source files (e.g., due to code defined in + include files). Thus, for any given base-address, there may + be multiple FDRs (but this case is, fortunately, uncommon). + lookup(addr) guarantees to return the first FDR that applies + to address ADDR. Thus, after invoking lookup(), we have a + list of FDRs that may contain the PDR for ADDR. Next, we + walk through the PDRs of these FDRs and locate the one that + is closest to ADDR (i.e., for which the difference between + ADDR and the PDR's entry point is positive and minimal). + Once, the right FDR and PDR are located, we simply walk + through the line-number table to lookup the line-number that + best matches ADDR. Obviously, things could be sped up by + keeping a sorted list of PDRs instead of a sorted list of + FDRs. However, this would increase space requirements + considerably, which is undesirable. */ + external_pdr_size = debug_swap->external_pdr_size; + + /* eraxxon: The Horrible Hack: Because of the problems above, set 'i' + to 0 so we look through all FDRs. + + Because FDR's without any symbols are assumed to be non-stabs, + searching through all FDRs may cause the following code to try to + read stabs FDRs as ECOFF ones. However, I don't think this will + harm anything. */ + i = 0; + + /* Search FDR list starting at tab[i] for the PDR that best matches + OFFSET. Normally, the FDR list is only one entry long. */ + best_fdr = NULL; + do + { + /* eraxxon: 'dist' and 'min_dist' can be negative now + because we iterate over every FDR rather than just ones + with a base address less than or equal to 'offset'. */ + bfd_signed_vma dist = -1, min_dist = -1; + char *pdr_hold; + char *pdr_end; + + fdr_ptr = tab[i].fdr; + + pdr_ptr = ((char *) debug_info->external_pdr + + fdr_ptr->ipdFirst * external_pdr_size); + pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size; + (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + /* Find PDR that is closest to OFFSET. If pdr.prof is set, + the procedure entry-point *may* be 0x10 below pdr.adr. We + simply pretend that pdr.prof *implies* a lower entry-point. + This is safe because it just means that may identify 4 NOPs + in front of the function as belonging to the function. */ + for (pdr_hold = NULL; + pdr_ptr < pdr_end; + (pdr_ptr += external_pdr_size, + (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr))) + { + if (offset >= (pdr.adr - 0x10 * pdr.prof)) + { + dist = offset - (pdr.adr - 0x10 * pdr.prof); + + /* eraxxon: 'dist' can be negative now. Note that + 'min_dist' can be negative if 'pdr_hold' below is NULL. */ + if (!pdr_hold || (dist >= 0 && dist < min_dist)) + { + min_dist = dist; + pdr_hold = pdr_ptr; + } + } + } + + if (!best_pdr || (min_dist >= 0 && min_dist < best_dist)) + { + best_dist = (bfd_vma) min_dist; + best_fdr = fdr_ptr; + best_pdr = pdr_hold; + } + /* Continue looping until base_addr of next entry is different. */ + } + /* eraxxon: We want to iterate over all FDRs. + See previous comment about 'fdrtab_lookup'. */ + while (++i < line_info->fdrtab_len); + + if (!best_fdr || !best_pdr) + return FALSE; /* Shouldn't happen... */ + + /* Phew, finally we got something that we can hold onto. */ + fdr_ptr = best_fdr; + pdr_ptr = best_pdr; + (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + /* Now we can look for the actual line number. The line numbers + are stored in a very funky format, which I won't try to + describe. The search is bounded by the end of the FDRs line + number entries. */ + line_end = debug_info->line + fdr_ptr->cbLineOffset + fdr_ptr->cbLine; + + /* Make offset relative to procedure entry. */ + offset -= pdr.adr - 0x10 * pdr.prof; + lineno = pdr.lnLow; + line_ptr = debug_info->line + fdr_ptr->cbLineOffset + pdr.cbLineOffset; + while (line_ptr < line_end) + { + int delta; + unsigned int count; + + delta = *line_ptr >> 4; + if (delta >= 0x8) + delta -= 0x10; + count = (*line_ptr & 0xf) + 1; + ++line_ptr; + if (delta == -8) + { + delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff); + if (delta >= 0x8000) + delta -= 0x10000; + line_ptr += 2; + } + lineno += delta; + if (offset < count * 4) + { + line_info->cache.stop += count * 4 - offset; + break; + } + offset -= count * 4; + } + + /* If fdr_ptr->rss is -1, then this file does not have full + symbols, at least according to gdb/mipsread.c. */ + if (fdr_ptr->rss == -1) + { + line_info->cache.filename = NULL; + if (pdr.isym == -1) + line_info->cache.functionname = NULL; + else + { + EXTR proc_ext; + + (*debug_swap->swap_ext_in) + (abfd, + ((char *) debug_info->external_ext + + pdr.isym * debug_swap->external_ext_size), + &proc_ext); + line_info->cache.functionname = (debug_info->ssext + + proc_ext.asym.iss); + } + } + else + { + SYMR proc_sym; + + line_info->cache.filename = (debug_info->ss + + fdr_ptr->issBase + + fdr_ptr->rss); + (*debug_swap->swap_sym_in) + (abfd, + ((char *) debug_info->external_sym + + ((fdr_ptr->isymBase + pdr.isym) + * debug_swap->external_sym_size)), + &proc_sym); + line_info->cache.functionname = (debug_info->ss + + fdr_ptr->issBase + + proc_sym.iss); + } + if (lineno == ilineNil) + lineno = 0; + line_info->cache.line_num = lineno; + } + else + { + bfd_size_type external_sym_size; + const char *directory_name; + const char *main_file_name; + const char *current_file_name; + const char *function_name; + const char *line_file_name; + bfd_vma low_func_vma; + bfd_vma low_line_vma; + bfd_boolean past_line; + bfd_boolean past_fn; + char *sym_ptr, *sym_ptr_end; + size_t len, funclen; + char *buffer = NULL; + + /* This file uses stabs debugging information. When gcc is not + optimizing, it will put the line number information before + the function name stabs entry. When gcc is optimizing, it + will put the stabs entry for all the function first, followed + by the line number information. (This appears to happen + because of the two output files used by the -mgpopt switch, + which is implied by -O). This means that we must keep + looking through the symbols until we find both a line number + and a function name which are beyond the address we want. */ + + line_info->cache.filename = NULL; + line_info->cache.functionname = NULL; + line_info->cache.line_num = 0; + + directory_name = NULL; + main_file_name = NULL; + current_file_name = NULL; + function_name = NULL; + line_file_name = NULL; + low_func_vma = 0; + low_line_vma = 0; + past_line = FALSE; + past_fn = FALSE; + + external_sym_size = debug_swap->external_sym_size; + + sym_ptr = ((char *) debug_info->external_sym + + (fdr_ptr->isymBase + 2) * external_sym_size); + sym_ptr_end = sym_ptr + (fdr_ptr->csym - 2) * external_sym_size; + for (; + sym_ptr < sym_ptr_end && (! past_line || ! past_fn); + sym_ptr += external_sym_size) + { + SYMR sym; + + (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); + + if (ECOFF_IS_STAB (&sym)) + { + switch (ECOFF_UNMARK_STAB (sym.index)) + { + case N_SO: + main_file_name = current_file_name = + debug_info->ss + fdr_ptr->issBase + sym.iss; + + /* Check the next symbol to see if it is also an + N_SO symbol. */ + if (sym_ptr + external_sym_size < sym_ptr_end) + { + SYMR nextsym; + + (*debug_swap->swap_sym_in) (abfd, + sym_ptr + external_sym_size, + &nextsym); + if (ECOFF_IS_STAB (&nextsym) + && ECOFF_UNMARK_STAB (nextsym.index) == N_SO) + { + directory_name = current_file_name; + main_file_name = current_file_name = + debug_info->ss + fdr_ptr->issBase + nextsym.iss; + sym_ptr += external_sym_size; + } + } + break; + + case N_SOL: + current_file_name = + debug_info->ss + fdr_ptr->issBase + sym.iss; + break; + + case N_FUN: + if (sym.value > offset) + past_fn = TRUE; + else if (sym.value >= low_func_vma) + { + low_func_vma = sym.value; + function_name = + debug_info->ss + fdr_ptr->issBase + sym.iss; + } + break; + } + } + else if (sym.st == stLabel && sym.index != indexNil) + { + if (sym.value > offset) + past_line = TRUE; + else if (sym.value >= low_line_vma) + { + low_line_vma = sym.value; + line_file_name = current_file_name; + line_info->cache.line_num = sym.index; + } + } + } + + if (line_info->cache.line_num != 0) + main_file_name = line_file_name; + + /* We need to remove the stuff after the colon in the function + name. We also need to put the directory name and the file + name together. */ + if (function_name == NULL) + len = funclen = 0; + else + len = funclen = strlen (function_name) + 1; + + if (main_file_name != NULL + && directory_name != NULL + && main_file_name[0] != '/') + len += strlen (directory_name) + strlen (main_file_name) + 1; + + if (len != 0) + { + if (line_info->find_buffer != NULL) + free (line_info->find_buffer); + buffer = (char *) bfd_malloc ((bfd_size_type) len); + if (buffer == NULL) + return FALSE; + line_info->find_buffer = buffer; + } + + if (function_name != NULL) + { + char *colon; + + strcpy (buffer, function_name); + colon = strchr (buffer, ':'); + if (colon != NULL) + *colon = '\0'; + line_info->cache.functionname = buffer; + } + + if (main_file_name != NULL) + { + if (directory_name == NULL || main_file_name[0] == '/') + line_info->cache.filename = main_file_name; + else + { + sprintf (buffer + funclen, "%s%s", directory_name, + main_file_name); + line_info->cache.filename = buffer + funclen; + } + } + } + + return TRUE; +} + +/* Do the work of find_nearest_line. */ + +bfd_boolean +_bfd_ecoff_locate_line (abfd, section, offset, debug_info, debug_swap, + line_info, filename_ptr, functionname_ptr, retline_ptr) + bfd *abfd; + asection *section; + bfd_vma offset; + struct ecoff_debug_info * const debug_info; + const struct ecoff_debug_swap * const debug_swap; + struct ecoff_find_line *line_info; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *retline_ptr; +{ + offset += section->vma; + + if (line_info->cache.sect == NULL + || line_info->cache.sect != section + || offset < line_info->cache.start + || offset >= line_info->cache.stop) + { + line_info->cache.sect = section; + line_info->cache.start = offset; + line_info->cache.stop = offset; + if (! lookup_line (abfd, debug_info, debug_swap, line_info)) + { + line_info->cache.sect = NULL; + return FALSE; + } + } + + *filename_ptr = line_info->cache.filename; + *functionname_ptr = line_info->cache.functionname; + *retline_ptr = line_info->cache.line_num; + + return TRUE; +} + +/* These routines copy symbolic information into a memory buffer. + + FIXME: The whole point of the shuffle code is to avoid storing + everything in memory, since the linker is such a memory hog. This + code makes that effort useless. It is only called by the MIPS ELF + code when generating a shared library, so it is not that big a + deal, but it should be fixed eventually. */ + +/* Collect a shuffle into a memory buffer. */ + +static bfd_boolean ecoff_collect_shuffle + PARAMS ((struct shuffle *, bfd_byte *)); + +static bfd_boolean +ecoff_collect_shuffle (l, buff) + struct shuffle *l; + bfd_byte *buff; +{ + unsigned long total; + + total = 0; + for (; l != (struct shuffle *) NULL; l = l->next) + { + if (! l->filep) + memcpy (buff, l->u.memory, l->size); + else + { + if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0 + || (bfd_bread (buff, (bfd_size_type) l->size, l->u.file.input_bfd) + != l->size)) + return FALSE; + } + total += l->size; + buff += l->size; + } + + return TRUE; +} + +/* Copy PDR information into a memory buffer. */ + +bfd_boolean +_bfd_ecoff_get_accumulated_pdr (handle, buff) + PTR handle; + bfd_byte *buff; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + + return ecoff_collect_shuffle (ainfo->pdr, buff); +} + +/* Copy symbol information into a memory buffer. */ + +bfd_boolean +_bfd_ecoff_get_accumulated_sym (handle, buff) + PTR handle; + bfd_byte *buff; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + + return ecoff_collect_shuffle (ainfo->sym, buff); +} + +/* Copy the string table into a memory buffer. */ + +bfd_boolean +_bfd_ecoff_get_accumulated_ss (handle, buff) + PTR handle; + bfd_byte *buff; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + struct string_hash_entry *sh; + unsigned long total; + + /* The string table is written out from the hash table if this is a + final link. */ + BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL); + *buff++ = '\0'; + total = 1; + BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1); + for (sh = ainfo->ss_hash; + sh != (struct string_hash_entry *) NULL; + sh = sh->next) + { + size_t len; + + len = strlen (sh->root.string); + memcpy (buff, (PTR) sh->root.string, len + 1); + total += len + 1; + buff += len + 1; + } + + return TRUE; }