/* 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, <ian@cygnus.com>.
-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"
\f
-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 *));
+\f
+/* 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
+}
\f
/* 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;
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
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 *)
/* The length of the information. */
unsigned long size;
/* Whether this information comes from a file or not. */
- boolean filep;
+ bfd_boolean filep;
union
{
struct
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;
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)
*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;
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;
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;
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;
/* 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);
}
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)
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. */
SET (".rodata", scRData);
SET (".init", scInit);
SET (".fini", scFini);
+ SET (".rconst", scRConst);
#undef SET
}
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;
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 *) alloca (strlen (name) + 20);
- sprintf (lookup, "%s %lx", name, fdr.csym);
- fh = string_hash_lookup (&ainfo->fdr_hash, lookup, true, true);
+ lookup = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 20);
+ if (lookup == NULL)
+ return FALSE;
+ sprintf (lookup, "%s %lx %lx", name, fdr.csym, fdr.caux);
+
+ 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)
{
/* 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++)
{
FDR fdr;
+ bfd_vma fdr_adr;
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)
{
else
(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
+ fdr_adr = fdr.adr;
+
/* FIXME: It is conceivable that this FDR points to the .init or
.fini section, in which case this will not do the right
thing. */
/* 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;
+ if (!add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out,
+ sz))
+ 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;
/* 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;
{
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;
if (ffilename)
{
fdr.rss = internal_sym.iss;
- fgotfilename = true;
+ fgotfilename = TRUE;
}
}
output_symhdr->isymMax += fdr.csym;
/* Copy the information that does not need swapping. */
+
+ /* FIXME: If we are relaxing, we need to adjust the line
+ numbers. Frankly, forget it. Anybody using stabs debugging
+ information will not use this line number information, and
+ 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;
}
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)),
- fdr.caux * sizeof (union aux_ext)))
- return false;
+ input_bfd, pos,
+ fdr.caux * sizeof (union aux_ext)))
+ 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
}
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)
+ if (output_bfd->xvec->header_byteorder
+ == input_bfd->xvec->header_byteorder)
{
- /* The two BFD's have the same endianness, so simply copying
- the information will suffice. */
+ /* The two BFD's have the same endianness, and we don't have
+ to adjust the PDR addresses, so simply copying the
+ information will suffice. */
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
+ 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;
+ if (!add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out,
+ sz))
+ return FALSE;
for (; in < end; in += insz, out += outsz)
{
PDR pdr;
+ 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;
+ if (!add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out,
+ sz))
+ return FALSE;
for (; in < end; in += insz, out += outsz)
{
OPTR opt;
++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)
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))
{
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)
/* 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;
asymbol **symbols;
asymbol **sym_ptr;
asymbol **sym_end;
+ long symsize;
+ long symcount;
PTR external_fdr;
- memset (&fdr, 0, sizeof fdr);
+ memset ((PTR) &fdr, 0, sizeof fdr);
sec = bfd_get_section_by_name (input_bfd, ".text");
if (sec != NULL)
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. */
- symbols = (asymbol **) bfd_alloc (output_bfd,
- get_symtab_upper_bound (input_bfd));
+ symsize = bfd_get_symtab_upper_bound (input_bfd);
+ if (symsize < 0)
+ 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;
- }
- sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols);
+ return FALSE;
+ symcount = bfd_canonicalize_symtab (input_bfd, symbols);
+ if (symcount < 0)
+ return FALSE;
+ sym_end = symbols + symcount;
/* Handle the local symbols. Any external symbols are handled
separately. */
if (((*sym_ptr)->flags & BSF_EXPORT) != 0)
continue;
- memset (&internal_sym, 0, sizeof internal_sym);
+ memset ((PTR) &internal_sym, 0, sizeof internal_sym);
internal_sym.iss = ecoff_add_string (ainfo, info, output_debug, &fdr,
(*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
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;
}
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.
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;
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++)
{
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;
}
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
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;
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;
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;
{
if (add != debug_align)
{
if (debug->line != (unsigned char *) NULL)
- memset (debug->line + symhdr->cbLine, 0, add);
+ memset ((PTR) (debug->line + symhdr->cbLine), 0, add);
symhdr->cbLine += add;
}
if (add != debug_align)
{
if (debug->ss != (char *) NULL)
- memset (debug->ss + symhdr->issMax, 0, add);
+ memset ((PTR) (debug->ss + symhdr->issMax), 0, add);
symhdr->issMax += add;
}
if (add != debug_align)
{
if (debug->ssext != (char *) NULL)
- memset (debug->ssext + symhdr->issExtMax, 0, add);
+ memset ((PTR) (debug->ssext + symhdr->issExtMax), 0, add);
symhdr->issExtMax += add;
}
if (add != aux_align)
{
if (debug->external_aux != (union aux_ext *) NULL)
- memset (debug->external_aux + symhdr->iauxMax, 0,
+ memset ((PTR) (debug->external_aux + symhdr->iauxMax), 0,
add * sizeof (union aux_ext));
symhdr->iauxMax += add;
}
if (add != rfd_align)
{
if (debug->external_rfd != (PTR) NULL)
- memset (((char *) debug->external_rfd
- + symhdr->crfd * swap->external_rfd_size),
- 0, add * swap->external_rfd_size);
+ memset ((PTR) ((char *) debug->external_rfd
+ + symhdr->crfd * swap->external_rfd_size),
+ 0, (size_t) (add * swap->external_rfd_size));
symhdr->crfd += add;
}
}
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;
file_ptr where;
{
HDRR * const symhdr = &debug->symbolic_header;
- char *buff;
+ char *buff = NULL;
ecoff_align_debug (abfd, debug, swap);
/* 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;
+ symhdr->magic = swap->sym_magic;
+
/* Fill in the file offsets. */
#define SET(offset, count, size) \
if (symhdr->count == 0) \
SET (cbExtOffset, iextMax, swap->external_ext_size);
#undef SET
- buff = (PTR) alloca (swap->external_hdr_size);
+ buff = (PTR) bfd_malloc (swap->external_hdr_size);
+ if (buff == NULL && swap->external_hdr_size != 0)
+ 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)
- return false;
-
- return true;
+ goto error_return;
+
+ if (buff != NULL)
+ free (buff);
+ return TRUE;
+ error_return:
+ if (buff != NULL)
+ free (buff);
+ return FALSE;
}
/* Write out the ECOFF debugging information. This function assumes
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;
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);
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;
{
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 *) alloca (i);
- memset (s, 0, i);
- if (bfd_write ((PTR) s, 1, i, abfd) != i)
- return false;
+ s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
+ if (s == NULL && i != 0)
+ return FALSE;
+
+ if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
+ {
+ free (s);
+ 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;
file_ptr where;
{
struct accumulate *ainfo = (struct accumulate *) handle;
- PTR space;
+ PTR space = NULL;
+ bfd_size_type amt;
if (! ecoff_write_symhdr (abfd, debug, swap, where))
- return false;
+ goto error_return;
- space = (PTR) alloca (ainfo->largest_file_shuffle);
+ amt = ainfo->largest_file_shuffle;
+ space = (PTR) bfd_malloc (amt);
+ if (space == NULL && ainfo->largest_file_shuffle != 0)
+ goto error_return;
if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space)
|| ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space)
|| ! ecoff_write_shuffle (abfd, swap, ainfo->sym, space)
|| ! ecoff_write_shuffle (abfd, swap, ainfo->opt, space)
|| ! ecoff_write_shuffle (abfd, swap, ainfo->aux, space))
- return false;
+ goto error_return;
/* 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))
- return false;
+ goto error_return;
}
else
{
BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
null = 0;
- if (bfd_write ((PTR) &null, 1, 1, abfd) != 1)
- return false;
+ 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);
for (sh = ainfo->ss_hash;
size_t len;
len = strlen (sh->root.string);
- if (bfd_write ((PTR) sh->root.string, 1, len + 1, abfd) != len + 1)
- return false;
+ 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 *) alloca (i);
- memset (s, 0, i);
- if (bfd_write ((PTR) s, 1, i, abfd) != i)
- return false;
+ s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
+ if (s == NULL && i != 0)
+ goto error_return;
+
+ if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
+ {
+ free (s);
+ goto error_return;
+ }
+ free (s);
}
}
/* 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)
- return false;
+ 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 *) alloca (i);
- memset (s, 0, i);
- if (bfd_write ((PTR) s, 1, i, abfd) != i)
- return false;
+ s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i);
+ if (s == NULL && i != 0)
+ goto error_return;
+
+ if (bfd_bwrite ((PTR) s, (bfd_size_type) i, abfd) != i)
+ {
+ free (s);
+ goto error_return;
+ }
+ free (s);
}
if (! ecoff_write_shuffle (abfd, swap, ainfo->fdr, space)
|| ! ecoff_write_shuffle (abfd, swap, ainfo->rfd, space))
- return false;
+ 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)));
+
+ 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;
+
+ error_return:
+ if (space != NULL)
+ free (space);
+ return FALSE;
+}
+\f
+/* 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 <x>
+ PDR [5] for File [2]: LoopTest__Xv <0x1200020a0> (a)
+ PDR [7] for File [2]: foo__Xv <0x120002168>
+ FDR [1]: (-1): First instruction: 0x1200020e8 <y>
+ PDR [3] for File [1]: <0x120001ad0> (b)
+ FDR [6]: (-1): First instruction: 0x1200026f0 <z>
+
+ (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;
+ }
+ }
- if (bfd_write (debug->external_ext, swap->external_ext_size,
- debug->symbolic_header.iextMax, abfd)
- != debug->symbolic_header.iextMax * swap->external_ext_size)
- return false;
+ *filename_ptr = line_info->cache.filename;
+ *functionname_ptr = line_info->cache.functionname;
+ *retline_ptr = line_info->cache.line_num;
+
+ return TRUE;
+}
+\f
+/* 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;
+ return TRUE;
}