section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
else if (strcmp (section->name, _RDATA) == 0
|| strcmp (section->name, _LIT8) == 0
- || strcmp (section->name, _LIT4) == 0)
+ || strcmp (section->name, _LIT4) == 0
+ || strcmp (section->name, _RCONST) == 0)
section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
else if (strcmp (section->name, _BSS) == 0
|| strcmp (section->name, _SBSS) == 0)
styp = STYP_COMMENT;
flags &=~ SEC_NEVER_LOAD;
}
+ else if (strcmp (name, _RCONST) == 0)
+ styp = STYP_RCONST;
else if (flags & SEC_CODE)
styp = STYP_TEXT;
else if (flags & SEC_DATA)
|| (styp_flags & STYP_SDATA)
|| styp_flags == STYP_PDATA
|| styp_flags == STYP_XDATA
- || (styp_flags & STYP_GOT))
+ || (styp_flags & STYP_GOT)
+ || styp_flags == STYP_RCONST)
{
if (sec_flags & SEC_NEVER_LOAD)
sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY;
else
sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
if ((styp_flags & STYP_RDATA)
- || styp_flags == STYP_PDATA)
+ || styp_flags == STYP_PDATA
+ || styp_flags == STYP_RCONST)
sec_flags |= SEC_READONLY;
}
else if ((styp_flags & STYP_BSS)
asym->section = bfd_make_section_old_way (abfd, ".fini");
asym->value -= asym->section->vma;
break;
+ case scRConst:
+ asym->section = bfd_make_section_old_way (abfd, ".rconst");
+ asym->value -= asym->section->vma;
+ break;
default:
break;
}
case RELOC_SECTION_PDATA: sec_name = ".pdata"; break;
case RELOC_SECTION_FINI: sec_name = ".fini"; break;
case RELOC_SECTION_LITA: sec_name = ".lita"; break;
+ case RELOC_SECTION_RCONST: sec_name = ".rconst"; break;
default: abort ();
}
the data. */
if ((abfd->flags & EXEC_P) != 0
&& (abfd->flags & D_PAGED) != 0
- && first_data != false
+ && ! first_data
&& (current->flags & SEC_CODE) == 0
&& (! ecoff_backend (abfd)->rdata_in_text
|| strcmp (current->name, _RDATA) != 0)
- && strcmp (current->name, _PDATA) != 0)
+ && strcmp (current->name, _PDATA) != 0
+ && strcmp (current->name, _RCONST) != 0)
{
sofar = (sofar + round - 1) &~ (round - 1);
first_data = false;
|| (section.s_flags & STYP_DYNSYM) != 0
|| (section.s_flags & STYP_HASH) != 0
|| (section.s_flags & STYP_ECOFF_INIT) != 0
- || (section.s_flags & STYP_ECOFF_FINI) != 0)
+ || (section.s_flags & STYP_ECOFF_FINI) != 0
+ || section.s_flags == STYP_RCONST)
{
text_size += bfd_get_section_size_before_reloc (current);
if (! set_text_start || text_start > vma)
in.r_symndx = RELOC_SECTION_LITA;
else if (strcmp (name, "*ABS*") == 0)
in.r_symndx = RELOC_SECTION_ABS;
+ else if (strcmp (name, ".rconst") == 0)
+ in.r_symndx = RELOC_SECTION_RCONST;
else
abort ();
in.r_extern = 0;
/* Read in the armap. */
ardata = bfd_ardata (abfd);
- mapdata = _bfd_read_ar_hdr (abfd);
+ mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
if (mapdata == (struct areltdata *) NULL)
return false;
parsed_size = mapdata->parsed_size;
case scSCommon:
case scInit:
case scFini:
+ case scRConst:
def = true;
break;
default:
section = bfd_make_section_old_way (abfd, ".fini");
value -= section->vma;
break;
+ case scRConst:
+ section = bfd_make_section_old_way (abfd, ".rconst");
+ value -= section->vma;
+ break;
}
if (section == (asection *) NULL)
h->esym.asym.sc = scPData;
else if (strcmp (name, _XDATA) == 0)
h->esym.asym.sc = scXData;
+ else if (strcmp (name, _RCONST) == 0)
+ h->esym.asym.sc = scRConst;
else
h->esym.asym.sc = scAbs;
}
asection *output_section;
struct bfd_link_order *link_order;
{
+ enum bfd_link_order_type type;
+ asection *section;
+ bfd_vma addend;
arelent rel;
struct internal_reloc in;
bfd_size_type external_reloc_size;
bfd_byte *rbuf;
boolean ok;
+ type = link_order->type;
+ section = NULL;
+ addend = link_order->u.reloc.p->addend;
+
/* We set up an arelent to pass to the backend adjust_reloc_out
routine. */
rel.address = link_order->offset;
return false;
}
- if (link_order->type == bfd_section_reloc_link_order)
- rel.sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr;
+ if (type == bfd_section_reloc_link_order)
+ {
+ section = link_order->u.reloc.p->u.section;
+ rel.sym_ptr_ptr = section->symbol_ptr_ptr;
+ }
else
{
- /* We can't set up a reloc against a symbol correctly, because
- we have no asymbol structure. Currently no adjust_reloc_out
- routine cases. */
- rel.sym_ptr_ptr = (asymbol **) NULL;
+ struct bfd_link_hash_entry *h;
+
+ /* Treat a reloc against a defined symbol as though it were
+ actually against the section. */
+ h = bfd_link_hash_lookup (info->hash, link_order->u.reloc.p->u.name,
+ false, false, false);
+ if (h != NULL
+ && (h->type == bfd_link_hash_defined
+ || h->type == bfd_link_hash_defweak))
+ {
+ type = bfd_section_reloc_link_order;
+ section = h->u.def.section->output_section;
+ /* It seems that we ought to add the symbol value to the
+ addend here, but in practice it has already been added
+ because it was passed to constructor_callback. */
+ addend += section->vma + h->u.def.section->output_offset;
+ }
+ else
+ {
+ /* We can't set up a reloc against a symbol correctly,
+ because we have no asymbol structure. Currently no
+ adjust_reloc_out routine cares. */
+ rel.sym_ptr_ptr = (asymbol **) NULL;
+ }
}
/* All ECOFF relocs are in-place. Put the addend into the object
file. */
BFD_ASSERT (rel.howto->partial_inplace);
- if (link_order->u.reloc.p->addend != 0)
+ if (addend != 0)
{
bfd_size_type size;
bfd_reloc_status_type rstat;
bfd_set_error (bfd_error_no_memory);
return false;
}
- rstat = _bfd_relocate_contents (rel.howto, output_bfd,
- link_order->u.reloc.p->addend, buf);
+ rstat = _bfd_relocate_contents (rel.howto, output_bfd, addend, buf);
switch (rstat)
{
case bfd_reloc_ok:
if (! ((*info->callbacks->reloc_overflow)
(info,
(link_order->type == bfd_section_reloc_link_order
- ? bfd_section_name (output_bfd,
- link_order->u.reloc.p->u.section)
+ ? bfd_section_name (output_bfd, section)
: link_order->u.reloc.p->u.name),
- rel.howto->name, link_order->u.reloc.p->addend,
- (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
+ rel.howto->name, addend, (bfd *) NULL,
+ (asection *) NULL, (bfd_vma) 0)))
{
free (buf);
return false;
+ bfd_get_section_vma (output_bfd, output_section));
in.r_type = rel.howto->type;
- if (link_order->type == bfd_symbol_reloc_link_order)
+ if (type == bfd_symbol_reloc_link_order)
{
struct ecoff_link_hash_entry *h;
{
CONST char *name;
- name = bfd_get_section_name (output_bfd,
- link_order->u.reloc.p->u.section);
+ name = bfd_get_section_name (output_bfd, section);
if (strcmp (name, ".text") == 0)
in.r_symndx = RELOC_SECTION_TEXT;
else if (strcmp (name, ".rdata") == 0)
in.r_symndx = RELOC_SECTION_LITA;
else if (strcmp (name, "*ABS*") == 0)
in.r_symndx = RELOC_SECTION_ABS;
+ else if (strcmp (name, ".rconst") == 0)
+ in.r_symndx = RELOC_SECTION_RCONST;
else
abort ();
in.r_extern = 0;
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. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "obstack.h"
+#include "aout/stab_gnu.h"
#include "coff/internal.h"
#include "coff/sym.h"
#include "coff/symconst.h"
static 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 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));
/* Obstack allocation and deallocation routines. */
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
\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)
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;
SET (".rodata", scRData);
SET (".init", scInit);
SET (".fini", scFini);
+ SET (".rconst", scRConst);
#undef SET
if (internal_sym.iss == -1)
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
}
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
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,
== false)
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,
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;
}
}
SET (cbExtOffset, iextMax, swap->external_ext_size);
#undef SET
- buff = (PTR) malloc (swap->external_hdr_size);
+ buff = (PTR) malloc ((size_t) swap->external_hdr_size);
if (buff == NULL && swap->external_hdr_size != 0)
{
bfd_set_error (bfd_error_no_memory);
return false;
#define WRITE(ptr, count, size, offset) \
- BFD_ASSERT (symhdr->offset == 0 || bfd_tell (abfd) == symhdr->offset); \
+ BFD_ASSERT (symhdr->offset == 0 \
+ || (bfd_vma) bfd_tell (abfd) == symhdr->offset); \
if (bfd_write ((PTR) debug->ptr, size, symhdr->count, abfd) \
!= size * symhdr->count) \
return false;
if ((total & (swap->debug_align - 1)) != 0)
{
- int i;
+ unsigned int i;
bfd_byte *s;
i = swap->debug_align - (total & (swap->debug_align - 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));
/* 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)
+ != (bfd_size_type) debug->symbolic_header.issExtMax)
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
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)
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 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;
+ boolean stabs;
+ long len;
+
+ 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: */
+
+ line_info->fdrtab = ((struct ecoff_fdrtab_entry*)
+ bfd_zalloc (abfd,
+ len * sizeof (struct ecoff_fdrtab_entry)));
+ if (line_info->fdrtab == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ 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)
+ {
+ bfd_size_type external_pdr_size;
+ char *pdr_ptr;
+ PDR pdr;
+
+ external_pdr_size = debug_swap->external_pdr_size;
+
+ pdr_ptr = ((char *) debug_info->external_pdr
+ + fdr_ptr->ipdFirst * external_pdr_size);
+ (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+ /* 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 - pdr.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, 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;
+ }
+ ++mid;
+
+ /* last entry is catch-all for all higher addresses: */
+ if (offset < tab[mid].base_addr)
+ return -1;
+
+ find_min:
+
+ while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr)
+ --mid;
+
+ return mid;
+}
+
+/* Do the work of find_nearest_line. */
+
+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;
+{
+ struct ecoff_fdrtab_entry *tab;
+ boolean stabs;
+ FDR *fdr_ptr;
+ int i;
+
+ offset += section->vma;
+
+ /* 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... */
+ 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_vma best_dist = ~0;
+ 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;
+
+ /* Make offset relative to object file's start-address: */
+ offset -= tab[i].base_addr;
+ /* 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
+ {
+ bfd_vma dist, min_dist = 0;
+ 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);
+ if (!pdr_hold || dist < min_dist)
+ {
+ min_dist = dist;
+ pdr_hold = pdr_ptr;
+ }
+ }
+ }
+
+ if (!best_pdr || min_dist < best_dist)
+ {
+ best_dist = min_dist;
+ best_fdr = fdr_ptr;
+ best_pdr = pdr_hold;
+ }
+ /* continue looping until base_addr of next entry is different: */
+ }
+ while (++i < line_info->fdrtab_len
+ && tab[i].base_addr == tab[i - 1].base_addr);
+
+ 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)
+ 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)
+ {
+ *filename_ptr = NULL;
+ if (pdr.isym == -1)
+ *functionname_ptr = 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);
+ *functionname_ptr = debug_info->ssext + proc_ext.asym.iss;
+ }
+ }
+ else
+ {
+ SYMR proc_sym;
+
+ *filename_ptr = 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);
+ *functionname_ptr = debug_info->ss + fdr_ptr->issBase + proc_sym.iss;
+ }
+ if (lineno == ilineNil)
+ lineno = 0;
+ *retline_ptr = 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;
+ boolean past_line;
+ 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. */
+
+ *filename_ptr = NULL;
+ *functionname_ptr = NULL;
+ *retline_ptr = 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;
+ *retline_ptr = sym.index;
+ }
+ }
+ }
+
+ if (*retline_ptr != 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 *) malloc (len);
+ if (buffer == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ 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';
+ *functionname_ptr = buffer;
+ }
+
+ if (main_file_name != NULL)
+ {
+ if (directory_name == NULL || main_file_name[0] == '/')
+ *filename_ptr = main_file_name;
+ else
+ {
+ sprintf (buffer + funclen, "%s%s", directory_name,
+ main_file_name);
+ *filename_ptr = buffer + funclen;
+ }
+ }
+ }
+
+ 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 boolean ecoff_collect_shuffle PARAMS ((struct shuffle *, bfd_byte *));
+
+static 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_read (buff, 1, 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. */
+
+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. */
+
+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. */
+
+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;
+}