#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "objalloc.h"
#include "aout/stab_gnu.h"
#include "coff/internal.h"
#include "coff/sym.h"
#include "coff/symconst.h"
#include "coff/ecoff.h"
#include "libcoff.h"
#include "libecoff.h"
static 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 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 *));
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;
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
}
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;
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
}
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;
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
}
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;
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
}
#define ALLOC_SIZE (4064)
static bfd_boolean
ecoff_add_bytes (buf, bufend, need)
char **buf;
char **bufend;
size_t need;
{
size_t have;
size_t want;
char *newbuf;
have = *bufend - *buf;
if (have > need)
want = ALLOC_SIZE;
else
{
want = need - have;
if (want < ALLOC_SIZE)
want = ALLOC_SIZE;
}
newbuf = (char *) bfd_realloc (*buf, (bfd_size_type) have + want);
if (newbuf == NULL)
return FALSE;
*buf = newbuf;
*bufend = *buf + have + want;
return TRUE;
}
struct string_hash_entry
{
struct bfd_hash_entry root;
long val;
struct string_hash_entry *next;
};
struct string_hash_table
{
struct bfd_hash_table table;
};
static struct bfd_hash_entry *
string_hash_newfunc (entry, table, string)
struct bfd_hash_entry *entry;
struct bfd_hash_table *table;
const char *string;
{
struct string_hash_entry *ret = (struct string_hash_entry *) entry;
if (ret == (struct string_hash_entry *) NULL)
ret = ((struct string_hash_entry *)
bfd_hash_allocate (table, sizeof (struct string_hash_entry)));
if (ret == (struct string_hash_entry *) NULL)
return NULL;
ret = ((struct string_hash_entry *)
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
if (ret)
{
ret->val = -1;
ret->next = NULL;
}
return (struct bfd_hash_entry *) ret;
}
#define string_hash_lookup(t, string, create, copy) \
((struct string_hash_entry *) \
bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
struct shuffle
{
struct shuffle *next;
unsigned long size;
bfd_boolean filep;
union
{
struct
{
bfd *input_bfd;
file_ptr offset;
} file;
PTR memory;
} u;
};
struct accumulate
{
struct string_hash_table fdr_hash;
struct string_hash_table str_hash;
struct shuffle *line;
struct shuffle *line_end;
struct shuffle *pdr;
struct shuffle *pdr_end;
struct shuffle *sym;
struct shuffle *sym_end;
struct shuffle *opt;
struct shuffle *opt_end;
struct shuffle *aux;
struct shuffle *aux_end;
struct shuffle *ss;
struct shuffle *ss_end;
struct string_hash_entry *ss_hash;
struct string_hash_entry *ss_hash_end;
struct shuffle *fdr;
struct shuffle *fdr_end;
struct shuffle *rfd;
struct shuffle *rfd_end;
unsigned long largest_file_shuffle;
struct objalloc *memory;
};
static bfd_boolean add_file_shuffle
PARAMS ((struct accumulate *, struct shuffle **, struct shuffle **,
bfd *, file_ptr, unsigned long));
static bfd_boolean
add_file_shuffle (ainfo, head, tail, input_bfd, offset, size)
struct accumulate *ainfo;
struct shuffle **head;
struct shuffle **tail;
bfd *input_bfd;
file_ptr offset;
unsigned long size;
{
struct shuffle *n;
if (*tail != (struct shuffle *) NULL
&& (*tail)->filep
&& (*tail)->u.file.input_bfd == input_bfd
&& (*tail)->u.file.offset + (*tail)->size == (unsigned long) offset)
{
(*tail)->size += size;
if ((*tail)->size > ainfo->largest_file_shuffle)
ainfo->largest_file_shuffle = (*tail)->size;
return TRUE;
}
n = (struct shuffle *) objalloc_alloc (ainfo->memory,
sizeof (struct shuffle));
if (!n)
{
bfd_set_error (bfd_error_no_memory);
return FALSE;
}
n->next = NULL;
n->size = size;
n->filep = TRUE;
n->u.file.input_bfd = input_bfd;
n->u.file.offset = offset;
if (*head == (struct shuffle *) NULL)
*head = n;
if (*tail != (struct shuffle *) NULL)
(*tail)->next = n;
*tail = n;
if (size > ainfo->largest_file_shuffle)
ainfo->largest_file_shuffle = size;
return TRUE;
}
static bfd_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 (ainfo, head, tail, data, size)
struct accumulate *ainfo;
struct shuffle **head;
struct shuffle **tail;
bfd_byte *data;
unsigned long size;
{
struct shuffle *n;
n = (struct shuffle *) objalloc_alloc (ainfo->memory,
sizeof (struct shuffle));
if (!n)
{
bfd_set_error (bfd_error_no_memory);
return FALSE;
}
n->next = NULL;
n->size = size;
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;
}
PTR
bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info)
bfd *output_bfd ATTRIBUTE_UNUSED;
struct ecoff_debug_info *output_debug;
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 *) bfd_malloc (amt);
if (!ainfo)
return NULL;
if (! bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc,
1021))
return NULL;
ainfo->line = NULL;
ainfo->line_end = NULL;
ainfo->pdr = NULL;
ainfo->pdr_end = NULL;
ainfo->sym = NULL;
ainfo->sym_end = NULL;
ainfo->opt = NULL;
ainfo->opt_end = NULL;
ainfo->aux = NULL;
ainfo->aux_end = NULL;
ainfo->ss = NULL;
ainfo->ss_end = NULL;
ainfo->ss_hash = NULL;
ainfo->ss_hash_end = NULL;
ainfo->fdr = NULL;
ainfo->fdr_end = NULL;
ainfo->rfd = NULL;
ainfo->rfd_end = NULL;
ainfo->largest_file_shuffle = 0;
if (! info->relocatable)
{
if (! bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc))
return NULL;
output_debug->symbolic_header.issMax = 1;
}
ainfo->memory = objalloc_create ();
if (ainfo->memory == NULL)
{
bfd_set_error (bfd_error_no_memory);
return NULL;
}
return (PTR) ainfo;
}
void
bfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info)
PTR handle;
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->relocatable)
bfd_hash_table_free (&ainfo->str_hash.table);
objalloc_free (ainfo->memory);
free (ainfo);
}
bfd_boolean
bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
input_bfd, input_debug, input_swap,
info)
PTR handle;
bfd *output_bfd;
struct ecoff_debug_info *output_debug;
const struct ecoff_debug_swap *output_swap;
bfd *input_bfd;
struct ecoff_debug_info *input_debug;
const struct ecoff_debug_swap *input_swap;
struct bfd_link_info *info;
{
struct accumulate *ainfo = (struct accumulate *) handle;
void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
= input_swap->swap_sym_in;
void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *))
= input_swap->swap_rfd_in;
void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
= output_swap->swap_sym_out;
void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR))
= output_swap->swap_fdr_out;
void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR))
= output_swap->swap_rfd_out;
bfd_size_type external_pdr_size = output_swap->external_pdr_size;
bfd_size_type external_sym_size = output_swap->external_sym_size;
bfd_size_type external_opt_size = output_swap->external_opt_size;
bfd_size_type external_fdr_size = output_swap->external_fdr_size;
bfd_size_type external_rfd_size = output_swap->external_rfd_size;
HDRR * const output_symhdr = &output_debug->symbolic_header;
HDRR * const input_symhdr = &input_debug->symbolic_header;
bfd_vma section_adjust[scMax];
asection *sec;
bfd_byte *fdr_start;
bfd_byte *fdr_ptr;
bfd_byte *fdr_end;
bfd_size_type fdr_add;
unsigned int copied;
RFDT i;
unsigned long sz;
bfd_byte *rfd_out;
bfd_byte *rfd_in;
bfd_byte *rfd_end;
long newrfdbase = 0;
long oldrfdbase = 0;
bfd_byte *fdr_out;
bfd_size_type amt;
memset ((PTR) section_adjust, 0, sizeof section_adjust);
#define SET(name, indx) \
sec = bfd_get_section_by_name (input_bfd, name); \
if (sec != NULL) \
section_adjust[indx] = (sec->output_section->vma \
+ sec->output_offset \
- sec->vma);
SET (".text", scText);
SET (".data", scData);
SET (".bss", scBss);
SET (".sdata", scSData);
SET (".sbss", scSBss);
SET (".rdata", scRData);
SET (".rodata", scRData);
SET (".init", scInit);
SET (".fini", scFini);
SET (".rconst", scRConst);
#undef SET
if (input_debug->fdr != (FDR *) NULL)
{
fdr_start = (bfd_byte *) input_debug->fdr;
fdr_add = sizeof (FDR);
}
else
{
fdr_start = (bfd_byte *) input_debug->external_fdr;
fdr_add = input_swap->external_fdr_size;
}
fdr_end = fdr_start + input_symhdr->ifdMax * fdr_add;
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 *) objalloc_alloc (ainfo->memory, sz);
if (!input_debug->ifdmap || !rfd_out)
{
bfd_set_error (bfd_error_no_memory);
return FALSE;
}
if (!add_memory_shuffle (ainfo, &ainfo->rfd, &ainfo->rfd_end, rfd_out, sz))
return FALSE;
copied = 0;
for (fdr_ptr = fdr_start, i = 0;
fdr_ptr < fdr_end;
fdr_ptr += fdr_add, i++, rfd_out += external_rfd_size)
{
FDR fdr;
if (input_debug->fdr != (FDR *) NULL)
fdr = *(FDR *) fdr_ptr;
else
(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
if (fdr.cbLine == 0 && fdr.rss != -1 && fdr.fMerge)
{
const char *name;
char *lookup;
struct string_hash_entry *fh;
name = input_debug->ss + fdr.issBase + fdr.rss;
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;
if (fh->val != -1)
{
input_debug->ifdmap[i] = fh->val;
(*swap_rfd_out) (output_bfd, input_debug->ifdmap + i,
(PTR) rfd_out);
continue;
}
fh->val = output_symhdr->ifdMax + copied;
}
input_debug->ifdmap[i] = output_symhdr->ifdMax + copied;
(*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, (PTR) rfd_out);
++copied;
}
newrfdbase = output_symhdr->crfd;
output_symhdr->crfd += input_symhdr->ifdMax;
rfd_in = (bfd_byte *) input_debug->external_rfd;
rfd_end = rfd_in + input_symhdr->crfd * input_swap->external_rfd_size;
for (;
rfd_in < rfd_end;
rfd_in += input_swap->external_rfd_size)
{
RFDT rfd;
(*swap_rfd_in) (input_bfd, (PTR) rfd_in, &rfd);
BFD_ASSERT (rfd >= 0 && rfd < input_symhdr->ifdMax);
rfd = input_debug->ifdmap[rfd];
(*swap_rfd_out) (output_bfd, &rfd, (PTR) rfd_out);
rfd_out += external_rfd_size;
}
oldrfdbase = output_symhdr->crfd;
output_symhdr->crfd += input_symhdr->crfd;
sz = copied * external_fdr_size;
fdr_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
if (!fdr_out)
{
bfd_set_error (bfd_error_no_memory);
return FALSE;
}
if (!add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, fdr_out, sz))
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;
bfd_boolean fgotfilename;
if (input_debug->ifdmap[i] < output_symhdr->ifdMax)
{
continue;
}
if (input_debug->fdr != (FDR *) NULL)
fdr = *(FDR *) fdr_ptr;
else
(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
fdr_adr = fdr.adr;
fdr.adr += section_adjust[scText];
fgotfilename = FALSE;
sz = fdr.csym * external_sym_size;
sym_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
if (!sym_out)
{
bfd_set_error (bfd_error_no_memory);
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;
for (; lraw_src < lraw_end; lraw_src += input_swap->external_sym_size)
{
SYMR internal_sym;
(*swap_sym_in) (input_bfd, (PTR) lraw_src, &internal_sym);
BFD_ASSERT (internal_sym.sc != scCommon
&& internal_sym.sc != scSCommon);
switch (internal_sym.st)
{
case stNil:
if (ECOFF_IS_STAB (&internal_sym))
break;
case stGlobal:
case stStatic:
case stLabel:
case stProc:
case stStaticProc:
internal_sym.value += section_adjust[internal_sym.sc];
break;
default:
break;
}
if (! info->relocatable)
{
bfd_boolean ffilename;
const char *name;
if (! fgotfilename && internal_sym.iss == fdr.rss)
ffilename = TRUE;
else
ffilename = FALSE;
name = input_debug->ss + fdr.issBase + internal_sym.iss;
if (*name == '\0')
internal_sym.iss = 0;
else
{
struct string_hash_entry *sh;
sh = string_hash_lookup (&ainfo->str_hash, name, TRUE, TRUE);
if (sh == (struct string_hash_entry *) NULL)
return FALSE;
if (sh->val == -1)
{
sh->val = output_symhdr->issMax;
output_symhdr->issMax += strlen (name) + 1;
if (ainfo->ss_hash == (struct string_hash_entry *) NULL)
ainfo->ss_hash = sh;
if (ainfo->ss_hash_end
!= (struct string_hash_entry *) NULL)
ainfo->ss_hash_end->next = sh;
ainfo->ss_hash_end = sh;
}
internal_sym.iss = sh->val;
}
if (ffilename)
{
fdr.rss = internal_sym.iss;
fgotfilename = TRUE;
}
}
(*swap_sym_out) (output_bfd, &internal_sym, sym_out);
sym_out += external_sym_size;
}
fdr.isymBase = output_symhdr->isymMax;
output_symhdr->isymMax += fdr.csym;
if (fdr.cbLine > 0)
{
file_ptr pos = input_symhdr->cbLineOffset + fdr.cbLineOffset;
if (!add_file_shuffle (ainfo, &ainfo->line, &ainfo->line_end,
input_bfd, pos, (unsigned long) fdr.cbLine))
return FALSE;
fdr.ilineBase = output_symhdr->ilineMax;
fdr.cbLineOffset = output_symhdr->cbLine;
output_symhdr->ilineMax += fdr.cline;
output_symhdr->cbLine += fdr.cbLine;
}
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, pos,
fdr.caux * sizeof (union aux_ext)))
return FALSE;
fdr.iauxBase = output_symhdr->iauxMax;
output_symhdr->iauxMax += fdr.caux;
}
if (! info->relocatable)
{
fdr.issBase = 0;
fdr.cbSs = output_symhdr->issMax;
}
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, pos, (unsigned long) fdr.cbSs))
return FALSE;
fdr.issBase = output_symhdr->issMax;
output_symhdr->issMax += fdr.cbSs;
}
if (output_bfd->xvec->header_byteorder
== input_bfd->xvec->header_byteorder)
{
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, 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, pos, size))
return FALSE;
}
}
else
{
bfd_size_type outsz, insz;
bfd_byte *in;
bfd_byte *end;
bfd_byte *out;
outsz = external_pdr_size;
insz = input_swap->external_pdr_size;
in = ((bfd_byte *) input_debug->external_pdr
+ fdr.ipdFirst * insz);
end = in + fdr.cpd * insz;
sz = fdr.cpd * outsz;
out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
if (!out)
{
bfd_set_error (bfd_error_no_memory);
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;
(*input_swap->swap_pdr_in) (input_bfd, (PTR) in, &pdr);
(*output_swap->swap_pdr_out) (output_bfd, &pdr, (PTR) out);
}
outsz = external_opt_size;
insz = input_swap->external_opt_size;
in = ((bfd_byte *) input_debug->external_opt
+ fdr.ioptBase * insz);
end = in + fdr.copt * insz;
sz = fdr.copt * outsz;
out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz);
if (!out)
{
bfd_set_error (bfd_error_no_memory);
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;
(*input_swap->swap_opt_in) (input_bfd, (PTR) in, &opt);
(*output_swap->swap_opt_out) (output_bfd, &opt, (PTR) out);
}
}
fdr.ipdFirst = output_symhdr->ipdMax;
output_symhdr->ipdMax += fdr.cpd;
fdr.ioptBase = output_symhdr->ioptMax;
output_symhdr->ioptMax += fdr.copt;
if (fdr.crfd <= 0)
{
fdr.rfdBase = newrfdbase;
fdr.crfd = input_symhdr->ifdMax;
}
else
{
fdr.rfdBase += oldrfdbase;
}
(*swap_fdr_out) (output_bfd, &fdr, fdr_out);
fdr_out += external_fdr_size;
++output_symhdr->ifdMax;
}
return TRUE;
}
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)
struct accumulate *ainfo;
struct bfd_link_info *info;
struct ecoff_debug_info *debug;
FDR *fdr;
const char *string;
{
HDRR *symhdr;
size_t len;
bfd_size_type ret;
symhdr = &debug->symbolic_header;
len = strlen (string);
if (info->relocatable)
{
if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, (PTR) string,
len + 1))
return -1;
ret = symhdr->issMax;
symhdr->issMax += len + 1;
fdr->cbSs += len + 1;
}
else
{
struct string_hash_entry *sh;
sh = string_hash_lookup (&ainfo->str_hash, string, TRUE, TRUE);
if (sh == (struct string_hash_entry *) NULL)
return -1;
if (sh->val == -1)
{
sh->val = symhdr->issMax;
symhdr->issMax += len + 1;
if (ainfo->ss_hash == (struct string_hash_entry *) NULL)
ainfo->ss_hash = sh;
if (ainfo->ss_hash_end
!= (struct string_hash_entry *) NULL)
ainfo->ss_hash_end->next = sh;
ainfo->ss_hash_end = sh;
}
ret = sh->val;
}
return ret;
}
bfd_boolean
bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
output_swap, input_bfd, info)
PTR handle;
bfd *output_bfd;
struct ecoff_debug_info *output_debug;
const struct ecoff_debug_swap *output_swap;
bfd *input_bfd;
struct bfd_link_info *info;
{
struct accumulate *ainfo = (struct accumulate *) handle;
void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR))
= output_swap->swap_sym_out;
HDRR *output_symhdr = &output_debug->symbolic_header;
FDR fdr;
asection *sec;
asymbol **symbols;
asymbol **sym_ptr;
asymbol **sym_end;
long symsize;
long symcount;
PTR external_fdr;
memset ((PTR) &fdr, 0, sizeof fdr);
sec = bfd_get_section_by_name (input_bfd, ".text");
if (sec != NULL)
fdr.adr = sec->output_section->vma + sec->output_offset;
else
{
fdr.adr = 0;
}
fdr.issBase = output_symhdr->issMax;
fdr.cbSs = 0;
fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr,
input_bfd->filename);
if (fdr.rss == -1)
return FALSE;
fdr.isymBase = output_symhdr->isymMax;
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)
return FALSE;
symcount = bfd_canonicalize_symtab (input_bfd, symbols);
if (symcount < 0)
return FALSE;
sym_end = symbols + symcount;
fdr.csym = 0;
for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++)
{
SYMR internal_sym;
PTR external_sym;
if (((*sym_ptr)->flags & BSF_EXPORT) != 0)
continue;
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;
if (bfd_is_com_section ((*sym_ptr)->section)
|| bfd_is_und_section ((*sym_ptr)->section))
internal_sym.value = (*sym_ptr)->value;
else
internal_sym.value = ((*sym_ptr)->value
+ (*sym_ptr)->section->output_offset
+ (*sym_ptr)->section->output_section->vma);
internal_sym.st = stNil;
internal_sym.sc = scUndefined;
internal_sym.index = indexNil;
external_sym = (PTR) objalloc_alloc (ainfo->memory,
output_swap->external_sym_size);
if (!external_sym)
{
bfd_set_error (bfd_error_no_memory);
return FALSE;
}
(*swap_sym_out) (output_bfd, &internal_sym, external_sym);
add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end,
external_sym,
(unsigned long) output_swap->external_sym_size);
++fdr.csym;
++output_symhdr->isymMax;
}
bfd_release (output_bfd, (PTR) symbols);
external_fdr = (PTR) objalloc_alloc (ainfo->memory,
output_swap->external_fdr_size);
if (!external_fdr)
{
bfd_set_error (bfd_error_no_memory);
return FALSE;
}
(*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr);
add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end,
external_fdr,
(unsigned long) output_swap->external_fdr_size);
++output_symhdr->ifdMax;
return TRUE;
}
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;
bfd_boolean relocatable;
bfd_boolean (*get_extr) PARAMS ((asymbol *, EXTR *));
void (*set_index) PARAMS ((asymbol *, bfd_size_type));
{
HDRR * const symhdr = &debug->symbolic_header;
asymbol **sym_ptr_ptr;
size_t c;
sym_ptr_ptr = bfd_get_outsymbols (abfd);
if (sym_ptr_ptr == NULL)
return TRUE;
for (c = bfd_get_symcount (abfd); c > 0; c--, sym_ptr_ptr++)
{
asymbol *sym_ptr;
EXTR esym;
sym_ptr = *sym_ptr_ptr;
if (! (*get_extr) (sym_ptr, &esym))
continue;
if (! relocatable)
{
if (esym.asym.sc == scCommon)
esym.asym.sc = scBss;
else if (esym.asym.sc == scSCommon)
esym.asym.sc = scSBss;
}
if (bfd_is_com_section (sym_ptr->section)
|| bfd_is_und_section (sym_ptr->section)
|| sym_ptr->section->output_section == (asection *) NULL)
{
if (esym.asym.sc != scSUndefined
|| esym.asym.value == 0
|| sym_ptr->value != 0)
esym.asym.value = sym_ptr->value;
}
else
esym.asym.value = (sym_ptr->value
+ sym_ptr->section->output_offset
+ sym_ptr->section->output_section->vma);
if (set_index)
(*set_index) (sym_ptr, (bfd_size_type) symhdr->iextMax);
if (! bfd_ecoff_debug_one_external (abfd, debug, swap,
sym_ptr->name, &esym))
return FALSE;
}
return TRUE;
}
bfd_boolean
bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym)
bfd *abfd;
struct ecoff_debug_info *debug;
const struct ecoff_debug_swap *swap;
const char *name;
EXTR *esym;
{
const bfd_size_type external_ext_size = swap->external_ext_size;
void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR))
= swap->swap_ext_out;
HDRR * const symhdr = &debug->symbolic_header;
size_t namelen;
namelen = strlen (name);
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))
return FALSE;
}
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) * (size_t) external_ext_size))
return FALSE;
}
esym->asym.iss = symhdr->issExtMax;
(*swap_ext_out) (abfd, esym,
((char *) debug->external_ext
+ symhdr->iextMax * swap->external_ext_size));
++symhdr->iextMax;
strcpy (debug->ssext + symhdr->issExtMax, name);
symhdr->issExtMax += namelen + 1;
return TRUE;
}
static void
ecoff_align_debug (abfd, debug, swap)
bfd *abfd ATTRIBUTE_UNUSED;
struct ecoff_debug_info *debug;
const struct ecoff_debug_swap *swap;
{
HDRR * const symhdr = &debug->symbolic_header;
bfd_size_type debug_align, aux_align, rfd_align;
size_t add;
debug_align = swap->debug_align;
aux_align = debug_align / sizeof (union aux_ext);
rfd_align = debug_align / swap->external_rfd_size;
add = debug_align - (symhdr->cbLine & (debug_align - 1));
if (add != debug_align)
{
if (debug->line != (unsigned char *) NULL)
memset ((PTR) (debug->line + symhdr->cbLine), 0, add);
symhdr->cbLine += add;
}
add = debug_align - (symhdr->issMax & (debug_align - 1));
if (add != debug_align)
{
if (debug->ss != (char *) NULL)
memset ((PTR) (debug->ss + symhdr->issMax), 0, add);
symhdr->issMax += add;
}
add = debug_align - (symhdr->issExtMax & (debug_align - 1));
if (add != debug_align)
{
if (debug->ssext != (char *) NULL)
memset ((PTR) (debug->ssext + symhdr->issExtMax), 0, add);
symhdr->issExtMax += add;
}
add = aux_align - (symhdr->iauxMax & (aux_align - 1));
if (add != aux_align)
{
if (debug->external_aux != (union aux_ext *) NULL)
memset ((PTR) (debug->external_aux + symhdr->iauxMax), 0,
add * sizeof (union aux_ext));
symhdr->iauxMax += add;
}
add = rfd_align - (symhdr->crfd & (rfd_align - 1));
if (add != rfd_align)
{
if (debug->external_rfd != (PTR) NULL)
memset ((PTR) ((char *) debug->external_rfd
+ symhdr->crfd * swap->external_rfd_size),
0, (size_t) (add * swap->external_rfd_size));
symhdr->crfd += add;
}
}
bfd_size_type
bfd_ecoff_debug_size (abfd, debug, swap)
bfd *abfd;
struct ecoff_debug_info *debug;
const struct ecoff_debug_swap *swap;
{
bfd_size_type tot;
ecoff_align_debug (abfd, debug, swap);
tot = swap->external_hdr_size;
#define ADD(count, size) \
tot += debug->symbolic_header.count * size
ADD (cbLine, sizeof (unsigned char));
ADD (idnMax, swap->external_dnr_size);
ADD (ipdMax, swap->external_pdr_size);
ADD (isymMax, swap->external_sym_size);
ADD (ioptMax, swap->external_opt_size);
ADD (iauxMax, sizeof (union aux_ext));
ADD (issMax, sizeof (char));
ADD (issExtMax, sizeof (char));
ADD (ifdMax, swap->external_fdr_size);
ADD (crfd, swap->external_rfd_size);
ADD (iextMax, swap->external_ext_size);
#undef ADD
return tot;
}
static bfd_boolean
ecoff_write_symhdr (abfd, debug, swap, where)
bfd *abfd;
struct ecoff_debug_info *debug;
const struct ecoff_debug_swap *swap;
file_ptr where;
{
HDRR * const symhdr = &debug->symbolic_header;
char *buff = NULL;
ecoff_align_debug (abfd, debug, swap);
if (bfd_seek (abfd, where, SEEK_SET) != 0)
return FALSE;
where += swap->external_hdr_size;
symhdr->magic = swap->sym_magic;
#define SET(offset, count, size) \
if (symhdr->count == 0) \
symhdr->offset = 0; \
else \
{ \
symhdr->offset = where; \
where += symhdr->count * size; \
}
SET (cbLineOffset, cbLine, sizeof (unsigned char));
SET (cbDnOffset, idnMax, swap->external_dnr_size);
SET (cbPdOffset, ipdMax, swap->external_pdr_size);
SET (cbSymOffset, isymMax, swap->external_sym_size);
SET (cbOptOffset, ioptMax, swap->external_opt_size);
SET (cbAuxOffset, iauxMax, sizeof (union aux_ext));
SET (cbSsOffset, issMax, sizeof (char));
SET (cbSsExtOffset, issExtMax, sizeof (char));
SET (cbFdOffset, ifdMax, swap->external_fdr_size);
SET (cbRfdOffset, crfd, swap->external_rfd_size);
SET (cbExtOffset, iextMax, swap->external_ext_size);
#undef SET
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_bwrite (buff, swap->external_hdr_size, abfd)
!= swap->external_hdr_size)
goto error_return;
if (buff != NULL)
free (buff);
return TRUE;
error_return:
if (buff != NULL)
free (buff);
return FALSE;
}
bfd_boolean
bfd_ecoff_write_debug (abfd, debug, swap, where)
bfd *abfd;
struct ecoff_debug_info *debug;
const struct ecoff_debug_swap *swap;
file_ptr where;
{
HDRR * const symhdr = &debug->symbolic_header;
if (! ecoff_write_symhdr (abfd, debug, swap, where))
return FALSE;
#define WRITE(ptr, count, size, offset) \
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;
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, (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_rfd, crfd, swap->external_rfd_size, cbRfdOffset);
WRITE (external_ext, iextMax, swap->external_ext_size, cbExtOffset);
#undef WRITE
return TRUE;
}
static bfd_boolean ecoff_write_shuffle
PARAMS ((bfd *, const struct ecoff_debug_swap *, struct shuffle *,
PTR space));
static bfd_boolean
ecoff_write_shuffle (abfd, swap, shuffle, space)
bfd *abfd;
const struct ecoff_debug_swap *swap;
struct shuffle *shuffle;
PTR space;
{
register struct shuffle *l;
unsigned long total;
total = 0;
for (l = shuffle; l != (struct shuffle *) NULL; l = l->next)
{
if (! l->filep)
{
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_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)
{
unsigned int i;
bfd_byte *s;
i = swap->debug_align - (total & (swap->debug_align - 1));
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;
}
bfd_boolean
bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
PTR handle;
bfd *abfd;
struct ecoff_debug_info *debug;
const struct ecoff_debug_swap *swap;
struct bfd_link_info *info;
file_ptr where;
{
struct accumulate *ainfo = (struct accumulate *) handle;
PTR space = NULL;
bfd_size_type amt;
if (! ecoff_write_symhdr (abfd, debug, swap, where))
goto error_return;
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))
goto error_return;
if (info->relocatable)
{
BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL);
if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space))
goto error_return;
}
else
{
unsigned long total;
bfd_byte null;
struct string_hash_entry *sh;
BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
null = 0;
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;
sh != (struct string_hash_entry *) NULL;
sh = sh->next)
{
size_t len;
len = strlen (sh->root.string);
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)
{
unsigned int i;
bfd_byte *s;
i = swap->debug_align - (total & (swap->debug_align - 1));
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);
}
}
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)
{
unsigned int i;
bfd_byte *s;
i = (swap->debug_align
- (debug->symbolic_header.issExtMax & (swap->debug_align - 1)));
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))
goto error_return;
BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0
|| (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;
}
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;
}
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;
for (len = 0, fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
{
if (fdr_ptr->cpd == 0)
continue;
++len;
}
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;
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)
{
tab->base_addr = fdr_ptr->adr;
}
else
{
tab->base_addr = fdr_ptr->adr;
}
tab->fdr = fdr_ptr;
++tab;
}
qsort ((PTR) line_info->fdrtab, (size_t) len,
sizeof (struct ecoff_fdrtab_entry), cmp_fdrtab_entry);
return TRUE;
}
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;
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;
}
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;
offset = line_info->cache.start;
if (line_info->fdrtab == NULL
&& !mk_fdrtab (abfd, debug_info, debug_swap, line_info))
return FALSE;
tab = line_info->fdrtab;
i = fdrtab_lookup (line_info, offset);
if (i < 0)
return FALSE;
fdr_ptr = tab[i].fdr;
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;
external_pdr_size = debug_swap->external_pdr_size;
i = 0;
best_fdr = NULL;
do
{
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);
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 >= 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;
}
}
while (++i < line_info->fdrtab_len);
if (!best_fdr || !best_pdr)
return FALSE;
fdr_ptr = best_fdr;
pdr_ptr = best_pdr;
(*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
line_end = debug_info->line + fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
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 == -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;
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;
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;
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;
}
bfd_boolean
_bfd_ecoff_locate_line (abfd, section, offset, debug_info, debug_swap,
line_info, filename_ptr, functionname_ptr, retline_ptr)
bfd *abfd;
asection *section;
bfd_vma offset;
struct ecoff_debug_info * const debug_info;
const struct ecoff_debug_swap * const debug_swap;
struct ecoff_find_line *line_info;
const char **filename_ptr;
const char **functionname_ptr;
unsigned int *retline_ptr;
{
offset += section->vma;
if (line_info->cache.sect == NULL
|| line_info->cache.sect != section
|| offset < line_info->cache.start
|| offset >= line_info->cache.stop)
{
line_info->cache.sect = section;
line_info->cache.start = offset;
line_info->cache.stop = offset;
if (! lookup_line (abfd, debug_info, debug_swap, line_info))
{
line_info->cache.sect = NULL;
return FALSE;
}
}
*filename_ptr = line_info->cache.filename;
*functionname_ptr = line_info->cache.functionname;
*retline_ptr = line_info->cache.line_num;
return TRUE;
}
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;
}
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);
}
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);
}
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;
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;
}