mirror of
https://github.com/bebbo/amigaos-binutils-2.14.git
synced 2025-12-08 22:38:24 +00:00
4845 lines
139 KiB
C
4845 lines
139 KiB
C
/* Generic ECOFF (Extended-COFF) routines.
|
||
Copyright 1990, 1991, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||
2002, 2003 Free Software Foundation, Inc.
|
||
Original version by Per Bothner.
|
||
Full support added by Ian Lance Taylor, ian@cygnus.com.
|
||
|
||
This file is part of BFD, the Binary File Descriptor library.
|
||
|
||
This program is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 2 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program; if not, write to the Free Software
|
||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||
|
||
#include "bfd.h"
|
||
#include "sysdep.h"
|
||
#include "bfdlink.h"
|
||
#include "libbfd.h"
|
||
#include "aout/ar.h"
|
||
#include "aout/ranlib.h"
|
||
#include "aout/stab_gnu.h"
|
||
|
||
/* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines
|
||
some other stuff which we don't want and which conflicts with stuff
|
||
we do want. */
|
||
#include "libaout.h"
|
||
#include "aout/aout64.h"
|
||
#undef N_ABS
|
||
#undef exec_hdr
|
||
#undef obj_sym_filepos
|
||
|
||
#include "coff/internal.h"
|
||
#include "coff/sym.h"
|
||
#include "coff/symconst.h"
|
||
#include "coff/ecoff.h"
|
||
#include "libcoff.h"
|
||
#include "libecoff.h"
|
||
|
||
/* Prototypes for static functions. */
|
||
|
||
static int ecoff_get_magic
|
||
PARAMS ((bfd *));
|
||
static long ecoff_sec_to_styp_flags
|
||
PARAMS ((const char *, flagword));
|
||
static bfd_boolean ecoff_slurp_symbolic_header
|
||
PARAMS ((bfd *));
|
||
static bfd_boolean ecoff_set_symbol_info
|
||
PARAMS ((bfd *, SYMR *, asymbol *, int, int));
|
||
static void ecoff_emit_aggregate
|
||
PARAMS ((bfd *, FDR *, char *, RNDXR *, long, const char *));
|
||
static char *ecoff_type_to_string
|
||
PARAMS ((bfd *, FDR *, unsigned int));
|
||
static bfd_boolean ecoff_slurp_reloc_table
|
||
PARAMS ((bfd *, asection *, asymbol **));
|
||
static int ecoff_sort_hdrs
|
||
PARAMS ((const PTR, const PTR));
|
||
static bfd_boolean ecoff_compute_section_file_positions
|
||
PARAMS ((bfd *));
|
||
static bfd_size_type ecoff_compute_reloc_file_positions
|
||
PARAMS ((bfd *));
|
||
static bfd_boolean ecoff_get_extr
|
||
PARAMS ((asymbol *, EXTR *));
|
||
static void ecoff_set_index
|
||
PARAMS ((asymbol *, bfd_size_type));
|
||
static unsigned int ecoff_armap_hash
|
||
PARAMS ((const char *, unsigned int *, unsigned int, unsigned int));
|
||
|
||
/* This stuff is somewhat copied from coffcode.h. */
|
||
|
||
static asection bfd_debug_section =
|
||
{
|
||
/* name, id, index, next, flags, user_set_vma, reloc_done, */
|
||
"*DEBUG*", 0, 0, NULL, 0, 0, 0,
|
||
/* linker_mark, linker_has_input, gc_mark, segment_mark, */
|
||
0, 0, 0, 0,
|
||
/* sec_info_type, use_rela_p, has_tls_reloc, flag11, flag12, */
|
||
0, 0, 0, 0, 0,
|
||
/* flag13, flag14, flag15, flag16, flag20, flag24, */
|
||
0, 0, 0, 0, 0, 0,
|
||
/* vma, lma, _cooked_size, _raw_size, */
|
||
0, 0, 0, 0,
|
||
/* output_offset, output_section, alignment_power, */
|
||
0, NULL, 0,
|
||
/* relocation, orelocation, reloc_count, filepos, rel_filepos, */
|
||
NULL, NULL, 0, 0, 0,
|
||
/* line_filepos, userdata, contents, lineno, lineno_count, */
|
||
0, NULL, NULL, NULL, 0,
|
||
/* entsize, comdat, moving_line_filepos, */
|
||
0, NULL, 0,
|
||
/* target_index, used_by_bfd, constructor_chain, owner, */
|
||
0, NULL, NULL, NULL,
|
||
/* symbol, */
|
||
(struct symbol_cache_entry *) NULL,
|
||
/* symbol_ptr_ptr, */
|
||
(struct symbol_cache_entry **) NULL,
|
||
/* link_order_head, link_order_tail */
|
||
NULL, NULL
|
||
};
|
||
|
||
/* Create an ECOFF object. */
|
||
|
||
bfd_boolean
|
||
_bfd_ecoff_mkobject (abfd)
|
||
bfd *abfd;
|
||
{
|
||
bfd_size_type amt = sizeof (ecoff_data_type);
|
||
|
||
abfd->tdata.ecoff_obj_data = (struct ecoff_tdata *) bfd_zalloc (abfd, amt);
|
||
if (abfd->tdata.ecoff_obj_data == NULL)
|
||
return FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* This is a hook called by coff_real_object_p to create any backend
|
||
specific information. */
|
||
|
||
PTR
|
||
_bfd_ecoff_mkobject_hook (abfd, filehdr, aouthdr)
|
||
bfd *abfd;
|
||
PTR filehdr;
|
||
PTR aouthdr;
|
||
{
|
||
struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
|
||
struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr;
|
||
ecoff_data_type *ecoff;
|
||
|
||
if (! _bfd_ecoff_mkobject (abfd))
|
||
return NULL;
|
||
|
||
ecoff = ecoff_data (abfd);
|
||
ecoff->gp_size = 8;
|
||
ecoff->sym_filepos = internal_f->f_symptr;
|
||
|
||
if (internal_a != (struct internal_aouthdr *) NULL)
|
||
{
|
||
int i;
|
||
|
||
ecoff->text_start = internal_a->text_start;
|
||
ecoff->text_end = internal_a->text_start + internal_a->tsize;
|
||
ecoff->gp = internal_a->gp_value;
|
||
ecoff->gprmask = internal_a->gprmask;
|
||
for (i = 0; i < 4; i++)
|
||
ecoff->cprmask[i] = internal_a->cprmask[i];
|
||
ecoff->fprmask = internal_a->fprmask;
|
||
if (internal_a->magic == ECOFF_AOUT_ZMAGIC)
|
||
abfd->flags |= D_PAGED;
|
||
else
|
||
abfd->flags &=~ D_PAGED;
|
||
}
|
||
|
||
/* It turns out that no special action is required by the MIPS or
|
||
Alpha ECOFF backends. They have different information in the
|
||
a.out header, but we just copy it all (e.g., gprmask, cprmask and
|
||
fprmask) and let the swapping routines ensure that only relevant
|
||
information is written out. */
|
||
|
||
return (PTR) ecoff;
|
||
}
|
||
|
||
/* Initialize a new section. */
|
||
|
||
bfd_boolean
|
||
_bfd_ecoff_new_section_hook (abfd, section)
|
||
bfd *abfd ATTRIBUTE_UNUSED;
|
||
asection *section;
|
||
{
|
||
section->alignment_power = 4;
|
||
|
||
if (strcmp (section->name, _TEXT) == 0
|
||
|| strcmp (section->name, _INIT) == 0
|
||
|| strcmp (section->name, _FINI) == 0)
|
||
section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
|
||
else if (strcmp (section->name, _DATA) == 0
|
||
|| strcmp (section->name, _SDATA) == 0)
|
||
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, _RCONST) == 0
|
||
|| strcmp (section->name, _PDATA) == 0)
|
||
section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
|
||
else if (strcmp (section->name, _BSS) == 0
|
||
|| strcmp (section->name, _SBSS) == 0)
|
||
section->flags |= SEC_ALLOC;
|
||
else if (strcmp (section->name, _LIB) == 0)
|
||
/* An Irix 4 shared libary. */
|
||
section->flags |= SEC_COFF_SHARED_LIBRARY;
|
||
|
||
/* Probably any other section name is SEC_NEVER_LOAD, but I'm
|
||
uncertain about .init on some systems and I don't know how shared
|
||
libraries work. */
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* Determine the machine architecture and type. This is called from
|
||
the generic COFF routines. It is the inverse of ecoff_get_magic,
|
||
below. This could be an ECOFF backend routine, with one version
|
||
for each target, but there aren't all that many ECOFF targets. */
|
||
|
||
bfd_boolean
|
||
_bfd_ecoff_set_arch_mach_hook (abfd, filehdr)
|
||
bfd *abfd;
|
||
PTR filehdr;
|
||
{
|
||
struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
|
||
enum bfd_architecture arch;
|
||
unsigned long mach;
|
||
|
||
switch (internal_f->f_magic)
|
||
{
|
||
case MIPS_MAGIC_1:
|
||
case MIPS_MAGIC_LITTLE:
|
||
case MIPS_MAGIC_BIG:
|
||
arch = bfd_arch_mips;
|
||
mach = bfd_mach_mips3000;
|
||
break;
|
||
|
||
case MIPS_MAGIC_LITTLE2:
|
||
case MIPS_MAGIC_BIG2:
|
||
/* MIPS ISA level 2: the r6000. */
|
||
arch = bfd_arch_mips;
|
||
mach = bfd_mach_mips6000;
|
||
break;
|
||
|
||
case MIPS_MAGIC_LITTLE3:
|
||
case MIPS_MAGIC_BIG3:
|
||
/* MIPS ISA level 3: the r4000. */
|
||
arch = bfd_arch_mips;
|
||
mach = bfd_mach_mips4000;
|
||
break;
|
||
|
||
case ALPHA_MAGIC:
|
||
arch = bfd_arch_alpha;
|
||
mach = 0;
|
||
break;
|
||
|
||
default:
|
||
arch = bfd_arch_obscure;
|
||
mach = 0;
|
||
break;
|
||
}
|
||
|
||
return bfd_default_set_arch_mach (abfd, arch, mach);
|
||
}
|
||
|
||
/* Get the magic number to use based on the architecture and machine.
|
||
This is the inverse of _bfd_ecoff_set_arch_mach_hook, above. */
|
||
|
||
static int
|
||
ecoff_get_magic (abfd)
|
||
bfd *abfd;
|
||
{
|
||
int big, little;
|
||
|
||
switch (bfd_get_arch (abfd))
|
||
{
|
||
case bfd_arch_mips:
|
||
switch (bfd_get_mach (abfd))
|
||
{
|
||
default:
|
||
case 0:
|
||
case bfd_mach_mips3000:
|
||
big = MIPS_MAGIC_BIG;
|
||
little = MIPS_MAGIC_LITTLE;
|
||
break;
|
||
|
||
case bfd_mach_mips6000:
|
||
big = MIPS_MAGIC_BIG2;
|
||
little = MIPS_MAGIC_LITTLE2;
|
||
break;
|
||
|
||
case bfd_mach_mips4000:
|
||
big = MIPS_MAGIC_BIG3;
|
||
little = MIPS_MAGIC_LITTLE3;
|
||
break;
|
||
}
|
||
|
||
return bfd_big_endian (abfd) ? big : little;
|
||
|
||
case bfd_arch_alpha:
|
||
return ALPHA_MAGIC;
|
||
|
||
default:
|
||
abort ();
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/* Get the section s_flags to use for a section. */
|
||
|
||
static long
|
||
ecoff_sec_to_styp_flags (name, flags)
|
||
const char *name;
|
||
flagword flags;
|
||
{
|
||
long styp;
|
||
|
||
styp = 0;
|
||
|
||
if (strcmp (name, _TEXT) == 0)
|
||
styp = STYP_TEXT;
|
||
else if (strcmp (name, _DATA) == 0)
|
||
styp = STYP_DATA;
|
||
else if (strcmp (name, _SDATA) == 0)
|
||
styp = STYP_SDATA;
|
||
else if (strcmp (name, _RDATA) == 0)
|
||
styp = STYP_RDATA;
|
||
else if (strcmp (name, _LITA) == 0)
|
||
styp = STYP_LITA;
|
||
else if (strcmp (name, _LIT8) == 0)
|
||
styp = STYP_LIT8;
|
||
else if (strcmp (name, _LIT4) == 0)
|
||
styp = STYP_LIT4;
|
||
else if (strcmp (name, _BSS) == 0)
|
||
styp = STYP_BSS;
|
||
else if (strcmp (name, _SBSS) == 0)
|
||
styp = STYP_SBSS;
|
||
else if (strcmp (name, _INIT) == 0)
|
||
styp = STYP_ECOFF_INIT;
|
||
else if (strcmp (name, _FINI) == 0)
|
||
styp = STYP_ECOFF_FINI;
|
||
else if (strcmp (name, _PDATA) == 0)
|
||
styp = STYP_PDATA;
|
||
else if (strcmp (name, _XDATA) == 0)
|
||
styp = STYP_XDATA;
|
||
else if (strcmp (name, _LIB) == 0)
|
||
styp = STYP_ECOFF_LIB;
|
||
else if (strcmp (name, _GOT) == 0)
|
||
styp = STYP_GOT;
|
||
else if (strcmp (name, _HASH) == 0)
|
||
styp = STYP_HASH;
|
||
else if (strcmp (name, _DYNAMIC) == 0)
|
||
styp = STYP_DYNAMIC;
|
||
else if (strcmp (name, _LIBLIST) == 0)
|
||
styp = STYP_LIBLIST;
|
||
else if (strcmp (name, _RELDYN) == 0)
|
||
styp = STYP_RELDYN;
|
||
else if (strcmp (name, _CONFLIC) == 0)
|
||
styp = STYP_CONFLIC;
|
||
else if (strcmp (name, _DYNSTR) == 0)
|
||
styp = STYP_DYNSTR;
|
||
else if (strcmp (name, _DYNSYM) == 0)
|
||
styp = STYP_DYNSYM;
|
||
else if (strcmp (name, _COMMENT) == 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 = STYP_DATA;
|
||
else if (flags & SEC_READONLY)
|
||
styp = STYP_RDATA;
|
||
else if (flags & SEC_LOAD)
|
||
styp = STYP_REG;
|
||
else
|
||
styp = STYP_BSS;
|
||
|
||
if (flags & SEC_NEVER_LOAD)
|
||
styp |= STYP_NOLOAD;
|
||
|
||
return styp;
|
||
}
|
||
|
||
/* Get the BFD flags to use for a section. */
|
||
|
||
bfd_boolean
|
||
_bfd_ecoff_styp_to_sec_flags (abfd, hdr, name, section, flags_ptr)
|
||
bfd *abfd ATTRIBUTE_UNUSED;
|
||
PTR hdr;
|
||
const char *name ATTRIBUTE_UNUSED;
|
||
asection *section ATTRIBUTE_UNUSED;
|
||
flagword * flags_ptr;
|
||
{
|
||
struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
|
||
long styp_flags = internal_s->s_flags;
|
||
flagword sec_flags = 0;
|
||
|
||
if (styp_flags & STYP_NOLOAD)
|
||
sec_flags |= SEC_NEVER_LOAD;
|
||
|
||
/* For 386 COFF, at least, an unloadable text or data section is
|
||
actually a shared library section. */
|
||
if ((styp_flags & STYP_TEXT)
|
||
|| (styp_flags & STYP_ECOFF_INIT)
|
||
|| (styp_flags & STYP_ECOFF_FINI)
|
||
|| (styp_flags & STYP_DYNAMIC)
|
||
|| (styp_flags & STYP_LIBLIST)
|
||
|| (styp_flags & STYP_RELDYN)
|
||
|| styp_flags == STYP_CONFLIC
|
||
|| (styp_flags & STYP_DYNSTR)
|
||
|| (styp_flags & STYP_DYNSYM)
|
||
|| (styp_flags & STYP_HASH))
|
||
{
|
||
if (sec_flags & SEC_NEVER_LOAD)
|
||
sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY;
|
||
else
|
||
sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
|
||
}
|
||
else if ((styp_flags & STYP_DATA)
|
||
|| (styp_flags & STYP_RDATA)
|
||
|| (styp_flags & STYP_SDATA)
|
||
|| styp_flags == STYP_PDATA
|
||
|| styp_flags == STYP_XDATA
|
||
|| (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_RCONST)
|
||
sec_flags |= SEC_READONLY;
|
||
}
|
||
else if ((styp_flags & STYP_BSS)
|
||
|| (styp_flags & STYP_SBSS))
|
||
sec_flags |= SEC_ALLOC;
|
||
else if ((styp_flags & STYP_INFO) || styp_flags == STYP_COMMENT)
|
||
sec_flags |= SEC_NEVER_LOAD;
|
||
else if ((styp_flags & STYP_LITA)
|
||
|| (styp_flags & STYP_LIT8)
|
||
|| (styp_flags & STYP_LIT4))
|
||
sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
|
||
else if (styp_flags & STYP_ECOFF_LIB)
|
||
sec_flags |= SEC_COFF_SHARED_LIBRARY;
|
||
else
|
||
sec_flags |= SEC_ALLOC | SEC_LOAD;
|
||
|
||
* flags_ptr = sec_flags;
|
||
return TRUE;
|
||
}
|
||
|
||
/* Read in the symbolic header for an ECOFF object file. */
|
||
|
||
static bfd_boolean
|
||
ecoff_slurp_symbolic_header (abfd)
|
||
bfd *abfd;
|
||
{
|
||
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
|
||
bfd_size_type external_hdr_size;
|
||
PTR raw = NULL;
|
||
HDRR *internal_symhdr;
|
||
|
||
/* See if we've already read it in. */
|
||
if (ecoff_data (abfd)->debug_info.symbolic_header.magic ==
|
||
backend->debug_swap.sym_magic)
|
||
return TRUE;
|
||
|
||
/* See whether there is a symbolic header. */
|
||
if (ecoff_data (abfd)->sym_filepos == 0)
|
||
{
|
||
bfd_get_symcount (abfd) = 0;
|
||
return TRUE;
|
||
}
|
||
|
||
/* At this point bfd_get_symcount (abfd) holds the number of symbols
|
||
as read from the file header, but on ECOFF this is always the
|
||
size of the symbolic information header. It would be cleaner to
|
||
handle this when we first read the file in coffgen.c. */
|
||
external_hdr_size = backend->debug_swap.external_hdr_size;
|
||
if (bfd_get_symcount (abfd) != external_hdr_size)
|
||
{
|
||
bfd_set_error (bfd_error_bad_value);
|
||
return FALSE;
|
||
}
|
||
|
||
/* Read the symbolic information header. */
|
||
raw = (PTR) bfd_malloc (external_hdr_size);
|
||
if (raw == NULL)
|
||
goto error_return;
|
||
|
||
if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) != 0
|
||
|| bfd_bread (raw, external_hdr_size, abfd) != external_hdr_size)
|
||
goto error_return;
|
||
internal_symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
|
||
(*backend->debug_swap.swap_hdr_in) (abfd, raw, internal_symhdr);
|
||
|
||
if (internal_symhdr->magic != backend->debug_swap.sym_magic)
|
||
{
|
||
bfd_set_error (bfd_error_bad_value);
|
||
goto error_return;
|
||
}
|
||
|
||
/* Now we can get the correct number of symbols. */
|
||
bfd_get_symcount (abfd) = (internal_symhdr->isymMax
|
||
+ internal_symhdr->iextMax);
|
||
|
||
if (raw != NULL)
|
||
free (raw);
|
||
return TRUE;
|
||
error_return:
|
||
if (raw != NULL)
|
||
free (raw);
|
||
return FALSE;
|
||
}
|
||
|
||
/* Read in and swap the important symbolic information for an ECOFF
|
||
object file. This is called by gdb via the read_debug_info entry
|
||
point in the backend structure. */
|
||
|
||
bfd_boolean
|
||
_bfd_ecoff_slurp_symbolic_info (abfd, ignore, debug)
|
||
bfd *abfd;
|
||
asection *ignore ATTRIBUTE_UNUSED;
|
||
struct ecoff_debug_info *debug;
|
||
{
|
||
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
|
||
HDRR *internal_symhdr;
|
||
bfd_size_type raw_base;
|
||
bfd_size_type raw_size;
|
||
PTR raw;
|
||
bfd_size_type external_fdr_size;
|
||
char *fraw_src;
|
||
char *fraw_end;
|
||
struct fdr *fdr_ptr;
|
||
bfd_size_type raw_end;
|
||
bfd_size_type cb_end;
|
||
bfd_size_type amt;
|
||
file_ptr pos;
|
||
|
||
BFD_ASSERT (debug == &ecoff_data (abfd)->debug_info);
|
||
|
||
/* Check whether we've already gotten it, and whether there's any to
|
||
get. */
|
||
if (ecoff_data (abfd)->raw_syments != (PTR) NULL)
|
||
return TRUE;
|
||
if (ecoff_data (abfd)->sym_filepos == 0)
|
||
{
|
||
bfd_get_symcount (abfd) = 0;
|
||
return TRUE;
|
||
}
|
||
|
||
if (! ecoff_slurp_symbolic_header (abfd))
|
||
return FALSE;
|
||
|
||
internal_symhdr = &debug->symbolic_header;
|
||
|
||
/* Read all the symbolic information at once. */
|
||
raw_base = (ecoff_data (abfd)->sym_filepos
|
||
+ backend->debug_swap.external_hdr_size);
|
||
|
||
/* Alpha ecoff makes the determination of raw_size difficult. It has
|
||
an undocumented debug data section between the symhdr and the first
|
||
documented section. And the ordering of the sections varies between
|
||
statically and dynamically linked executables.
|
||
If bfd supports SEEK_END someday, this code could be simplified. */
|
||
raw_end = 0;
|
||
|
||
#define UPDATE_RAW_END(start, count, size) \
|
||
cb_end = internal_symhdr->start + internal_symhdr->count * (size); \
|
||
if (cb_end > raw_end) \
|
||
raw_end = cb_end
|
||
|
||
UPDATE_RAW_END (cbLineOffset, cbLine, sizeof (unsigned char));
|
||
UPDATE_RAW_END (cbDnOffset, idnMax, backend->debug_swap.external_dnr_size);
|
||
UPDATE_RAW_END (cbPdOffset, ipdMax, backend->debug_swap.external_pdr_size);
|
||
UPDATE_RAW_END (cbSymOffset, isymMax, backend->debug_swap.external_sym_size);
|
||
/* eraxxon@alumni.rice.edu: ioptMax refers to the size of the
|
||
optimization symtab, not the number of entries */
|
||
UPDATE_RAW_END (cbOptOffset, ioptMax, sizeof (char));
|
||
UPDATE_RAW_END (cbAuxOffset, iauxMax, sizeof (union aux_ext));
|
||
UPDATE_RAW_END (cbSsOffset, issMax, sizeof (char));
|
||
UPDATE_RAW_END (cbSsExtOffset, issExtMax, sizeof (char));
|
||
UPDATE_RAW_END (cbFdOffset, ifdMax, backend->debug_swap.external_fdr_size);
|
||
UPDATE_RAW_END (cbRfdOffset, crfd, backend->debug_swap.external_rfd_size);
|
||
UPDATE_RAW_END (cbExtOffset, iextMax, backend->debug_swap.external_ext_size);
|
||
|
||
#undef UPDATE_RAW_END
|
||
|
||
raw_size = raw_end - raw_base;
|
||
if (raw_size == 0)
|
||
{
|
||
ecoff_data (abfd)->sym_filepos = 0;
|
||
return TRUE;
|
||
}
|
||
raw = (PTR) bfd_alloc (abfd, raw_size);
|
||
if (raw == NULL)
|
||
return FALSE;
|
||
|
||
pos = ecoff_data (abfd)->sym_filepos;
|
||
pos += backend->debug_swap.external_hdr_size;
|
||
if (bfd_seek (abfd, pos, SEEK_SET) != 0
|
||
|| bfd_bread (raw, raw_size, abfd) != raw_size)
|
||
{
|
||
bfd_release (abfd, raw);
|
||
return FALSE;
|
||
}
|
||
|
||
ecoff_data (abfd)->raw_syments = raw;
|
||
|
||
/* Get pointers for the numeric offsets in the HDRR structure. */
|
||
#define FIX(off1, off2, type) \
|
||
if (internal_symhdr->off1 == 0) \
|
||
debug->off2 = (type) NULL; \
|
||
else \
|
||
debug->off2 = (type) ((char *) raw \
|
||
+ (internal_symhdr->off1 \
|
||
- raw_base))
|
||
|
||
FIX (cbLineOffset, line, unsigned char *);
|
||
FIX (cbDnOffset, external_dnr, PTR);
|
||
FIX (cbPdOffset, external_pdr, PTR);
|
||
FIX (cbSymOffset, external_sym, PTR);
|
||
FIX (cbOptOffset, external_opt, PTR);
|
||
FIX (cbAuxOffset, external_aux, union aux_ext *);
|
||
FIX (cbSsOffset, ss, char *);
|
||
FIX (cbSsExtOffset, ssext, char *);
|
||
FIX (cbFdOffset, external_fdr, PTR);
|
||
FIX (cbRfdOffset, external_rfd, PTR);
|
||
FIX (cbExtOffset, external_ext, PTR);
|
||
#undef FIX
|
||
|
||
/* I don't want to always swap all the data, because it will just
|
||
waste time and most programs will never look at it. The only
|
||
time the linker needs most of the debugging information swapped
|
||
is when linking big-endian and little-endian MIPS object files
|
||
together, which is not a common occurrence.
|
||
|
||
We need to look at the fdr to deal with a lot of information in
|
||
the symbols, so we swap them here. */
|
||
amt = internal_symhdr->ifdMax;
|
||
amt *= sizeof (struct fdr);
|
||
debug->fdr = (struct fdr *) bfd_alloc (abfd, amt);
|
||
if (debug->fdr == NULL)
|
||
return FALSE;
|
||
external_fdr_size = backend->debug_swap.external_fdr_size;
|
||
fdr_ptr = debug->fdr;
|
||
fraw_src = (char *) debug->external_fdr;
|
||
fraw_end = fraw_src + internal_symhdr->ifdMax * external_fdr_size;
|
||
for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
|
||
(*backend->debug_swap.swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* ECOFF symbol table routines. The ECOFF symbol table is described
|
||
in gcc/mips-tfile.c. */
|
||
|
||
/* ECOFF uses two common sections. One is the usual one, and the
|
||
other is for small objects. All the small objects are kept
|
||
together, and then referenced via the gp pointer, which yields
|
||
faster assembler code. This is what we use for the small common
|
||
section. */
|
||
static asection ecoff_scom_section;
|
||
static asymbol ecoff_scom_symbol;
|
||
static asymbol *ecoff_scom_symbol_ptr;
|
||
|
||
/* Create an empty symbol. */
|
||
|
||
asymbol *
|
||
_bfd_ecoff_make_empty_symbol (abfd)
|
||
bfd *abfd;
|
||
{
|
||
ecoff_symbol_type *new;
|
||
bfd_size_type amt = sizeof (ecoff_symbol_type);
|
||
|
||
new = (ecoff_symbol_type *) bfd_zalloc (abfd, amt);
|
||
if (new == (ecoff_symbol_type *) NULL)
|
||
return (asymbol *) NULL;
|
||
new->symbol.section = (asection *) NULL;
|
||
new->fdr = (FDR *) NULL;
|
||
new->local = FALSE;
|
||
new->native = NULL;
|
||
new->symbol.the_bfd = abfd;
|
||
return &new->symbol;
|
||
}
|
||
|
||
/* Set the BFD flags and section for an ECOFF symbol. */
|
||
|
||
static bfd_boolean
|
||
ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, weak)
|
||
bfd *abfd;
|
||
SYMR *ecoff_sym;
|
||
asymbol *asym;
|
||
int ext;
|
||
int weak;
|
||
{
|
||
asym->the_bfd = abfd;
|
||
asym->value = ecoff_sym->value;
|
||
asym->section = &bfd_debug_section;
|
||
asym->udata.i = 0;
|
||
|
||
/* Most symbol types are just for debugging. */
|
||
switch (ecoff_sym->st)
|
||
{
|
||
case stGlobal:
|
||
case stStatic:
|
||
case stLabel:
|
||
case stProc:
|
||
case stStaticProc:
|
||
break;
|
||
case stNil:
|
||
if (ECOFF_IS_STAB (ecoff_sym))
|
||
{
|
||
asym->flags = BSF_DEBUGGING;
|
||
return TRUE;
|
||
}
|
||
break;
|
||
default:
|
||
asym->flags = BSF_DEBUGGING;
|
||
return TRUE;
|
||
}
|
||
|
||
if (weak)
|
||
asym->flags = BSF_EXPORT | BSF_WEAK;
|
||
else if (ext)
|
||
asym->flags = BSF_EXPORT | BSF_GLOBAL;
|
||
else
|
||
{
|
||
asym->flags = BSF_LOCAL;
|
||
/* Normally, a local stProc symbol will have a corresponding
|
||
external symbol. We mark the local symbol as a debugging
|
||
symbol, in order to prevent nm from printing both out.
|
||
Similarly, we mark stLabel and stabs symbols as debugging
|
||
symbols. In both cases, we do want to set the value
|
||
correctly based on the symbol class. */
|
||
if (ecoff_sym->st == stProc
|
||
|| ecoff_sym->st == stLabel
|
||
|| ECOFF_IS_STAB (ecoff_sym))
|
||
asym->flags |= BSF_DEBUGGING;
|
||
}
|
||
|
||
if (ecoff_sym->st == stProc || ecoff_sym->st == stStaticProc)
|
||
asym->flags |= BSF_FUNCTION;
|
||
|
||
switch (ecoff_sym->sc)
|
||
{
|
||
case scNil:
|
||
/* Used for compiler generated labels. Leave them in the
|
||
debugging section, and mark them as local. If BSF_DEBUGGING
|
||
is set, then nm does not display them for some reason. If no
|
||
flags are set then the linker whines about them. */
|
||
asym->flags = BSF_LOCAL;
|
||
break;
|
||
case scText:
|
||
asym->section = bfd_make_section_old_way (abfd, ".text");
|
||
asym->value -= asym->section->vma;
|
||
break;
|
||
case scData:
|
||
asym->section = bfd_make_section_old_way (abfd, ".data");
|
||
asym->value -= asym->section->vma;
|
||
break;
|
||
case scBss:
|
||
asym->section = bfd_make_section_old_way (abfd, ".bss");
|
||
asym->value -= asym->section->vma;
|
||
break;
|
||
case scRegister:
|
||
asym->flags = BSF_DEBUGGING;
|
||
break;
|
||
case scAbs:
|
||
asym->section = bfd_abs_section_ptr;
|
||
break;
|
||
case scUndefined:
|
||
asym->section = bfd_und_section_ptr;
|
||
asym->flags = 0;
|
||
asym->value = 0;
|
||
break;
|
||
case scCdbLocal:
|
||
case scBits:
|
||
case scCdbSystem:
|
||
case scRegImage:
|
||
case scInfo:
|
||
case scUserStruct:
|
||
asym->flags = BSF_DEBUGGING;
|
||
break;
|
||
case scSData:
|
||
asym->section = bfd_make_section_old_way (abfd, ".sdata");
|
||
asym->value -= asym->section->vma;
|
||
break;
|
||
case scSBss:
|
||
asym->section = bfd_make_section_old_way (abfd, ".sbss");
|
||
asym->value -= asym->section->vma;
|
||
break;
|
||
case scRData:
|
||
asym->section = bfd_make_section_old_way (abfd, ".rdata");
|
||
asym->value -= asym->section->vma;
|
||
break;
|
||
case scVar:
|
||
asym->flags = BSF_DEBUGGING;
|
||
break;
|
||
case scCommon:
|
||
if (asym->value > ecoff_data (abfd)->gp_size)
|
||
{
|
||
asym->section = bfd_com_section_ptr;
|
||
asym->flags = 0;
|
||
break;
|
||
}
|
||
/* Fall through. */
|
||
case scSCommon:
|
||
if (ecoff_scom_section.name == NULL)
|
||
{
|
||
/* Initialize the small common section. */
|
||
ecoff_scom_section.name = SCOMMON;
|
||
ecoff_scom_section.flags = SEC_IS_COMMON;
|
||
ecoff_scom_section.output_section = &ecoff_scom_section;
|
||
ecoff_scom_section.symbol = &ecoff_scom_symbol;
|
||
ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr;
|
||
ecoff_scom_symbol.name = SCOMMON;
|
||
ecoff_scom_symbol.flags = BSF_SECTION_SYM;
|
||
ecoff_scom_symbol.section = &ecoff_scom_section;
|
||
ecoff_scom_symbol_ptr = &ecoff_scom_symbol;
|
||
}
|
||
asym->section = &ecoff_scom_section;
|
||
asym->flags = 0;
|
||
break;
|
||
case scVarRegister:
|
||
case scVariant:
|
||
asym->flags = BSF_DEBUGGING;
|
||
break;
|
||
case scSUndefined:
|
||
asym->section = bfd_und_section_ptr;
|
||
asym->flags = 0;
|
||
asym->value = 0;
|
||
break;
|
||
case scInit:
|
||
asym->section = bfd_make_section_old_way (abfd, ".init");
|
||
asym->value -= asym->section->vma;
|
||
break;
|
||
case scBasedVar:
|
||
case scXData:
|
||
case scPData:
|
||
asym->flags = BSF_DEBUGGING;
|
||
break;
|
||
case scFini:
|
||
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;
|
||
}
|
||
|
||
/* Look for special constructors symbols and make relocation entries
|
||
in a special construction section. These are produced by the
|
||
-fgnu-linker argument to g++. */
|
||
if (ECOFF_IS_STAB (ecoff_sym))
|
||
{
|
||
switch (ECOFF_UNMARK_STAB (ecoff_sym->index))
|
||
{
|
||
default:
|
||
break;
|
||
|
||
case N_SETA:
|
||
case N_SETT:
|
||
case N_SETD:
|
||
case N_SETB:
|
||
{
|
||
/* This code is no longer needed. It used to be used to
|
||
make the linker handle set symbols, but they are now
|
||
handled in the add_symbols routine instead. */
|
||
#if 0
|
||
const char *name;
|
||
asection *section;
|
||
arelent_chain *reloc_chain;
|
||
unsigned int bitsize;
|
||
bfd_size_type amt;
|
||
|
||
/* Get a section with the same name as the symbol (usually
|
||
__CTOR_LIST__ or __DTOR_LIST__). FIXME: gcc uses the
|
||
name ___CTOR_LIST (three underscores). We need
|
||
__CTOR_LIST (two underscores), since ECOFF doesn't use
|
||
a leading underscore. This should be handled by gcc,
|
||
but instead we do it here. Actually, this should all
|
||
be done differently anyhow. */
|
||
name = bfd_asymbol_name (asym);
|
||
if (name[0] == '_' && name[1] == '_' && name[2] == '_')
|
||
{
|
||
++name;
|
||
asym->name = name;
|
||
}
|
||
section = bfd_get_section_by_name (abfd, name);
|
||
if (section == (asection *) NULL)
|
||
{
|
||
char *copy;
|
||
|
||
amt = strlen (name) + 1;
|
||
copy = (char *) bfd_alloc (abfd, amt);
|
||
if (!copy)
|
||
return FALSE;
|
||
strcpy (copy, name);
|
||
section = bfd_make_section (abfd, copy);
|
||
}
|
||
|
||
/* Build a reloc pointing to this constructor. */
|
||
amt = sizeof (arelent_chain);
|
||
reloc_chain = (arelent_chain *) bfd_alloc (abfd, amt);
|
||
if (!reloc_chain)
|
||
return FALSE;
|
||
reloc_chain->relent.sym_ptr_ptr =
|
||
bfd_get_section (asym)->symbol_ptr_ptr;
|
||
reloc_chain->relent.address = section->_raw_size;
|
||
reloc_chain->relent.addend = asym->value;
|
||
reloc_chain->relent.howto =
|
||
ecoff_backend (abfd)->constructor_reloc;
|
||
|
||
/* Set up the constructor section to hold the reloc. */
|
||
section->flags = SEC_CONSTRUCTOR;
|
||
++section->reloc_count;
|
||
|
||
/* Constructor sections must be rounded to a boundary
|
||
based on the bitsize. These are not real sections--
|
||
they are handled specially by the linker--so the ECOFF
|
||
16 byte alignment restriction does not apply. */
|
||
bitsize = ecoff_backend (abfd)->constructor_bitsize;
|
||
section->alignment_power = 1;
|
||
while ((1 << section->alignment_power) < bitsize / 8)
|
||
++section->alignment_power;
|
||
|
||
reloc_chain->next = section->constructor_chain;
|
||
section->constructor_chain = reloc_chain;
|
||
section->_raw_size += bitsize / 8;
|
||
|
||
#endif /* 0 */
|
||
|
||
/* Mark the symbol as a constructor. */
|
||
asym->flags |= BSF_CONSTRUCTOR;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
/* Read an ECOFF symbol table. */
|
||
|
||
bfd_boolean
|
||
_bfd_ecoff_slurp_symbol_table (abfd)
|
||
bfd *abfd;
|
||
{
|
||
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
|
||
const bfd_size_type external_ext_size
|
||
= backend->debug_swap.external_ext_size;
|
||
const bfd_size_type external_sym_size
|
||
= backend->debug_swap.external_sym_size;
|
||
void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
|
||
= backend->debug_swap.swap_ext_in;
|
||
void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
|
||
= backend->debug_swap.swap_sym_in;
|
||
bfd_size_type internal_size;
|
||
ecoff_symbol_type *internal;
|
||
ecoff_symbol_type *internal_ptr;
|
||
char *eraw_src;
|
||
char *eraw_end;
|
||
FDR *fdr_ptr;
|
||
FDR *fdr_end;
|
||
|
||
/* If we've already read in the symbol table, do nothing. */
|
||
if (ecoff_data (abfd)->canonical_symbols != NULL)
|
||
return TRUE;
|
||
|
||
/* Get the symbolic information. */
|
||
if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL,
|
||
&ecoff_data (abfd)->debug_info))
|
||
return FALSE;
|
||
if (bfd_get_symcount (abfd) == 0)
|
||
return TRUE;
|
||
|
||
internal_size = bfd_get_symcount (abfd);
|
||
internal_size *= sizeof (ecoff_symbol_type);
|
||
internal = (ecoff_symbol_type *) bfd_alloc (abfd, internal_size);
|
||
if (internal == NULL)
|
||
return FALSE;
|
||
|
||
internal_ptr = internal;
|
||
eraw_src = (char *) ecoff_data (abfd)->debug_info.external_ext;
|
||
eraw_end = (eraw_src
|
||
+ (ecoff_data (abfd)->debug_info.symbolic_header.iextMax
|
||
* external_ext_size));
|
||
for (; eraw_src < eraw_end; eraw_src += external_ext_size, internal_ptr++)
|
||
{
|
||
EXTR internal_esym;
|
||
|
||
(*swap_ext_in) (abfd, (PTR) eraw_src, &internal_esym);
|
||
internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ssext
|
||
+ internal_esym.asym.iss);
|
||
if (!ecoff_set_symbol_info (abfd, &internal_esym.asym,
|
||
&internal_ptr->symbol, 1,
|
||
internal_esym.weakext))
|
||
return FALSE;
|
||
/* The alpha uses a negative ifd field for section symbols. */
|
||
if (internal_esym.ifd >= 0)
|
||
internal_ptr->fdr = (ecoff_data (abfd)->debug_info.fdr
|
||
+ internal_esym.ifd);
|
||
else
|
||
internal_ptr->fdr = NULL;
|
||
internal_ptr->local = FALSE;
|
||
internal_ptr->native = (PTR) eraw_src;
|
||
}
|
||
|
||
/* The local symbols must be accessed via the fdr's, because the
|
||
string and aux indices are relative to the fdr information. */
|
||
fdr_ptr = ecoff_data (abfd)->debug_info.fdr;
|
||
fdr_end = fdr_ptr + ecoff_data (abfd)->debug_info.symbolic_header.ifdMax;
|
||
for (; fdr_ptr < fdr_end; fdr_ptr++)
|
||
{
|
||
char *lraw_src;
|
||
char *lraw_end;
|
||
|
||
lraw_src = ((char *) ecoff_data (abfd)->debug_info.external_sym
|
||
+ fdr_ptr->isymBase * external_sym_size);
|
||
lraw_end = lraw_src + fdr_ptr->csym * external_sym_size;
|
||
for (;
|
||
lraw_src < lraw_end;
|
||
lraw_src += external_sym_size, internal_ptr++)
|
||
{
|
||
SYMR internal_sym;
|
||
|
||
(*swap_sym_in) (abfd, (PTR) lraw_src, &internal_sym);
|
||
internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ss
|
||
+ fdr_ptr->issBase
|
||
+ internal_sym.iss);
|
||
if (!ecoff_set_symbol_info (abfd, &internal_sym,
|
||
&internal_ptr->symbol, 0, 0))
|
||
return FALSE;
|
||
internal_ptr->fdr = fdr_ptr;
|
||
internal_ptr->local = TRUE;
|
||
internal_ptr->native = (PTR) lraw_src;
|
||
}
|
||
}
|
||
|
||
ecoff_data (abfd)->canonical_symbols = internal;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* Return the amount of space needed for the canonical symbols. */
|
||
|
||
long
|
||
_bfd_ecoff_get_symtab_upper_bound (abfd)
|
||
bfd *abfd;
|
||
{
|
||
if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL,
|
||
&ecoff_data (abfd)->debug_info))
|
||
return -1;
|
||
|
||
if (bfd_get_symcount (abfd) == 0)
|
||
return 0;
|
||
|
||
return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *));
|
||
}
|
||
|
||
/* Get the canonical symbols. */
|
||
|
||
long
|
||
_bfd_ecoff_get_symtab (abfd, alocation)
|
||
bfd *abfd;
|
||
asymbol **alocation;
|
||
{
|
||
unsigned int counter = 0;
|
||
ecoff_symbol_type *symbase;
|
||
ecoff_symbol_type **location = (ecoff_symbol_type **) alocation;
|
||
|
||
if (! _bfd_ecoff_slurp_symbol_table (abfd))
|
||
return -1;
|
||
if (bfd_get_symcount (abfd) == 0)
|
||
return 0;
|
||
|
||
symbase = ecoff_data (abfd)->canonical_symbols;
|
||
while (counter < bfd_get_symcount (abfd))
|
||
{
|
||
*(location++) = symbase++;
|
||
counter++;
|
||
}
|
||
*location++ = (ecoff_symbol_type *) NULL;
|
||
return bfd_get_symcount (abfd);
|
||
}
|
||
|
||
/* Turn ECOFF type information into a printable string.
|
||
ecoff_emit_aggregate and ecoff_type_to_string are from
|
||
gcc/mips-tdump.c, with swapping added and used_ptr removed. */
|
||
|
||
/* Write aggregate information to a string. */
|
||
|
||
static void
|
||
ecoff_emit_aggregate (abfd, fdr, string, rndx, isym, which)
|
||
bfd *abfd;
|
||
FDR *fdr;
|
||
char *string;
|
||
RNDXR *rndx;
|
||
long isym;
|
||
const char *which;
|
||
{
|
||
const struct ecoff_debug_swap * const debug_swap =
|
||
&ecoff_backend (abfd)->debug_swap;
|
||
struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info;
|
||
unsigned int ifd = rndx->rfd;
|
||
unsigned int indx = rndx->index;
|
||
const char *name;
|
||
|
||
if (ifd == 0xfff)
|
||
ifd = isym;
|
||
|
||
/* An ifd of -1 is an opaque type. An escaped index of 0 is a
|
||
struct return type of a procedure compiled without -g. */
|
||
if (ifd == 0xffffffff
|
||
|| (rndx->rfd == 0xfff && indx == 0))
|
||
name = "<undefined>";
|
||
else if (indx == indexNil)
|
||
name = "<no name>";
|
||
else
|
||
{
|
||
SYMR sym;
|
||
|
||
if (debug_info->external_rfd == NULL)
|
||
fdr = debug_info->fdr + ifd;
|
||
else
|
||
{
|
||
RFDT rfd;
|
||
|
||
(*debug_swap->swap_rfd_in) (abfd,
|
||
((char *) debug_info->external_rfd
|
||
+ ((fdr->rfdBase + ifd)
|
||
* debug_swap->external_rfd_size)),
|
||
&rfd);
|
||
fdr = debug_info->fdr + rfd;
|
||
}
|
||
|
||
indx += fdr->isymBase;
|
||
|
||
(*debug_swap->swap_sym_in) (abfd,
|
||
((char *) debug_info->external_sym
|
||
+ indx * debug_swap->external_sym_size),
|
||
&sym);
|
||
|
||
name = debug_info->ss + fdr->issBase + sym.iss;
|
||
}
|
||
|
||
sprintf (string,
|
||
"%s %s { ifd = %u, index = %lu }",
|
||
which, name, ifd,
|
||
((long) indx
|
||
+ debug_info->symbolic_header.iextMax));
|
||
}
|
||
|
||
/* Convert the type information to string format. */
|
||
|
||
static char *
|
||
ecoff_type_to_string (abfd, fdr, indx)
|
||
bfd *abfd;
|
||
FDR *fdr;
|
||
unsigned int indx;
|
||
{
|
||
union aux_ext *aux_ptr;
|
||
int bigendian;
|
||
AUXU u;
|
||
struct qual {
|
||
unsigned int type;
|
||
int low_bound;
|
||
int high_bound;
|
||
int stride;
|
||
} qualifiers[7];
|
||
unsigned int basic_type;
|
||
int i;
|
||
char buffer1[1024];
|
||
static char buffer2[1024];
|
||
char *p1 = buffer1;
|
||
char *p2 = buffer2;
|
||
RNDXR rndx;
|
||
|
||
aux_ptr = ecoff_data (abfd)->debug_info.external_aux + fdr->iauxBase;
|
||
bigendian = fdr->fBigendian;
|
||
|
||
for (i = 0; i < 7; i++)
|
||
{
|
||
qualifiers[i].low_bound = 0;
|
||
qualifiers[i].high_bound = 0;
|
||
qualifiers[i].stride = 0;
|
||
}
|
||
|
||
if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == (bfd_vma) -1)
|
||
return "-1 (no type)";
|
||
_bfd_ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti);
|
||
|
||
basic_type = u.ti.bt;
|
||
qualifiers[0].type = u.ti.tq0;
|
||
qualifiers[1].type = u.ti.tq1;
|
||
qualifiers[2].type = u.ti.tq2;
|
||
qualifiers[3].type = u.ti.tq3;
|
||
qualifiers[4].type = u.ti.tq4;
|
||
qualifiers[5].type = u.ti.tq5;
|
||
qualifiers[6].type = tqNil;
|
||
|
||
/* Go get the basic type. */
|
||
switch (basic_type)
|
||
{
|
||
case btNil: /* Undefined. */
|
||
strcpy (p1, "nil");
|
||
break;
|
||
|
||
case btAdr: /* Address - integer same size as pointer. */
|
||
strcpy (p1, "address");
|
||
break;
|
||
|
||
case btChar: /* Character. */
|
||
strcpy (p1, "char");
|
||
break;
|
||
|
||
case btUChar: /* Unsigned character. */
|
||
strcpy (p1, "unsigned char");
|
||
break;
|
||
|
||
case btShort: /* Short. */
|
||
strcpy (p1, "short");
|
||
break;
|
||
|
||
case btUShort: /* Unsigned short. */
|
||
strcpy (p1, "unsigned short");
|
||
break;
|
||
|
||
case btInt: /* Int. */
|
||
strcpy (p1, "int");
|
||
break;
|
||
|
||
case btUInt: /* Unsigned int. */
|
||
strcpy (p1, "unsigned int");
|
||
break;
|
||
|
||
case btLong: /* Long. */
|
||
strcpy (p1, "long");
|
||
break;
|
||
|
||
case btULong: /* Unsigned long. */
|
||
strcpy (p1, "unsigned long");
|
||
break;
|
||
|
||
case btFloat: /* Float (real). */
|
||
strcpy (p1, "float");
|
||
break;
|
||
|
||
case btDouble: /* Double (real). */
|
||
strcpy (p1, "double");
|
||
break;
|
||
|
||
/* Structures add 1-2 aux words:
|
||
1st word is [ST_RFDESCAPE, offset] pointer to struct def;
|
||
2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
|
||
|
||
case btStruct: /* Structure (Record). */
|
||
_bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
|
||
ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
|
||
(long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
|
||
"struct");
|
||
indx++; /* Skip aux words. */
|
||
break;
|
||
|
||
/* Unions add 1-2 aux words:
|
||
1st word is [ST_RFDESCAPE, offset] pointer to union def;
|
||
2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
|
||
|
||
case btUnion: /* Union. */
|
||
_bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
|
||
ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
|
||
(long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
|
||
"union");
|
||
indx++; /* Skip aux words. */
|
||
break;
|
||
|
||
/* Enumerations add 1-2 aux words:
|
||
1st word is [ST_RFDESCAPE, offset] pointer to enum def;
|
||
2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
|
||
|
||
case btEnum: /* Enumeration. */
|
||
_bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
|
||
ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
|
||
(long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
|
||
"enum");
|
||
indx++; /* Skip aux words. */
|
||
break;
|
||
|
||
case btTypedef: /* Defined via a typedef, isymRef points. */
|
||
strcpy (p1, "typedef");
|
||
break;
|
||
|
||
case btRange: /* Subrange of int. */
|
||
strcpy (p1, "subrange");
|
||
break;
|
||
|
||
case btSet: /* Pascal sets. */
|
||