1993-11-24 07:18:44 +00:00
|
|
|
|
/* Routines to link ECOFF debugging information.
|
|
|
|
|
Copyright 1993 Free Software Foundation, Inc.
|
|
|
|
|
Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
|
|
|
|
|
|
|
|
|
|
This file is part of BFD, the Binary File Descriptor library.
|
|
|
|
|
|
|
|
|
|
This 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
|
|
|
|
|
|
#include "bfd.h"
|
|
|
|
|
#include "sysdep.h"
|
1994-01-11 16:23:41 +00:00
|
|
|
|
#include "bfdlink.h"
|
1993-11-24 07:18:44 +00:00
|
|
|
|
#include "libbfd.h"
|
1994-01-11 16:23:41 +00:00
|
|
|
|
#include "obstack.h"
|
1993-11-24 07:18:44 +00:00
|
|
|
|
#include "coff/internal.h"
|
|
|
|
|
#include "coff/sym.h"
|
|
|
|
|
#include "coff/symconst.h"
|
|
|
|
|
#include "coff/ecoff.h"
|
|
|
|
|
|
|
|
|
|
static boolean ecoff_add_bytes PARAMS ((char **buf, char **bufend,
|
1994-01-06 20:04:43 +00:00
|
|
|
|
size_t need));
|
1994-01-11 16:23:41 +00:00
|
|
|
|
static struct bfd_hash_entry *string_hash_newfunc
|
|
|
|
|
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
|
|
|
|
|
const char *));
|
1993-11-24 07:18:44 +00:00
|
|
|
|
static void ecoff_align_debug PARAMS ((bfd *abfd,
|
|
|
|
|
struct ecoff_debug_info *debug,
|
|
|
|
|
const struct ecoff_debug_swap *swap));
|
1994-01-11 16:23:41 +00:00
|
|
|
|
static boolean ecoff_write_symhdr PARAMS ((bfd *, struct ecoff_debug_info *,
|
|
|
|
|
const struct ecoff_debug_swap *,
|
|
|
|
|
file_ptr where));
|
|
|
|
|
|
|
|
|
|
/* Obstack allocation and deallocation routines. */
|
1994-02-05 03:02:32 +00:00
|
|
|
|
#define obstack_chunk_alloc bfd_xmalloc_by_size_t
|
1994-01-11 16:23:41 +00:00
|
|
|
|
#define obstack_chunk_free free
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
|
|
|
|
/* The minimum amount of data to allocate. */
|
|
|
|
|
#define ALLOC_SIZE (4064)
|
|
|
|
|
|
|
|
|
|
/* Add bytes to a buffer. Return success. */
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
ecoff_add_bytes (buf, bufend, need)
|
|
|
|
|
char **buf;
|
|
|
|
|
char **bufend;
|
1994-01-06 20:04:43 +00:00
|
|
|
|
size_t need;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
{
|
1994-01-06 20:04:43 +00:00
|
|
|
|
size_t have;
|
|
|
|
|
size_t want;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
char *newbuf;
|
|
|
|
|
|
|
|
|
|
have = *bufend - *buf;
|
|
|
|
|
if (have > need)
|
|
|
|
|
want = ALLOC_SIZE;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
want = need - have;
|
|
|
|
|
if (want < ALLOC_SIZE)
|
|
|
|
|
want = ALLOC_SIZE;
|
|
|
|
|
}
|
|
|
|
|
if (*buf == NULL)
|
|
|
|
|
newbuf = (char *) malloc (have + want);
|
|
|
|
|
else
|
|
|
|
|
newbuf = (char *) realloc (*buf, have + want);
|
|
|
|
|
if (newbuf == NULL)
|
|
|
|
|
{
|
|
|
|
|
bfd_error = no_memory;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*buf = newbuf;
|
|
|
|
|
*bufend = *buf + have + want;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
/* We keep a hash table which maps strings to numbers. We use it to
|
|
|
|
|
map FDR names to indices in the output file, and to map local
|
|
|
|
|
strings when combining stabs debugging information. */
|
|
|
|
|
|
|
|
|
|
struct string_hash_entry
|
|
|
|
|
{
|
|
|
|
|
struct bfd_hash_entry root;
|
|
|
|
|
/* FDR index or string table offset. */
|
|
|
|
|
long val;
|
|
|
|
|
/* Next entry in string table. */
|
|
|
|
|
struct string_hash_entry *next;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct string_hash_table
|
|
|
|
|
{
|
|
|
|
|
struct bfd_hash_table table;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Routine to create an entry in a string hash 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;
|
|
|
|
|
|
|
|
|
|
/* Allocate the structure if it has not already been allocated by a
|
|
|
|
|
subclass. */
|
|
|
|
|
if (ret == (struct string_hash_entry *) NULL)
|
|
|
|
|
ret = ((struct string_hash_entry *)
|
|
|
|
|
bfd_hash_allocate (table, sizeof (struct string_hash_entry)));
|
|
|
|
|
|
|
|
|
|
/* Call the allocation method of the superclass. */
|
|
|
|
|
ret = ((struct string_hash_entry *)
|
|
|
|
|
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
|
|
|
|
|
|
|
|
|
|
/* Initialize the local fields. */
|
|
|
|
|
ret->val = -1;
|
|
|
|
|
ret->next = NULL;
|
|
|
|
|
|
|
|
|
|
return (struct bfd_hash_entry *) ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Look up an entry in an string hash table. */
|
|
|
|
|
|
|
|
|
|
#define string_hash_lookup(t, string, create, copy) \
|
|
|
|
|
((struct string_hash_entry *) \
|
|
|
|
|
bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
|
|
|
|
|
|
|
|
|
|
/* We can't afford to read in all the debugging information when we do
|
|
|
|
|
a link. Instead, we build a list of these structures to show how
|
|
|
|
|
different parts of the input file map to the output file. */
|
|
|
|
|
|
|
|
|
|
struct shuffle
|
|
|
|
|
{
|
|
|
|
|
/* The next entry in this linked list. */
|
|
|
|
|
struct shuffle *next;
|
|
|
|
|
/* The length of the information. */
|
|
|
|
|
unsigned long size;
|
|
|
|
|
/* Whether this information comes from a file or not. */
|
|
|
|
|
boolean filep;
|
|
|
|
|
union
|
|
|
|
|
{
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
/* The BFD the data comes from. */
|
|
|
|
|
bfd *input_bfd;
|
|
|
|
|
/* The offset within input_bfd. */
|
|
|
|
|
file_ptr offset;
|
|
|
|
|
} file;
|
|
|
|
|
/* The data to be written out. */
|
|
|
|
|
PTR memory;
|
|
|
|
|
} u;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* This structure holds information across calls to
|
|
|
|
|
bfd_ecoff_debug_accumulate. */
|
|
|
|
|
|
|
|
|
|
struct accumulate
|
|
|
|
|
{
|
|
|
|
|
/* The FDR hash table. */
|
|
|
|
|
struct string_hash_table fdr_hash;
|
|
|
|
|
/* The strings hash table. */
|
|
|
|
|
struct string_hash_table str_hash;
|
|
|
|
|
/* Linked lists describing how to shuffle the input debug
|
|
|
|
|
information into the output file. We keep a pointer to both the
|
|
|
|
|
head and the tail. */
|
|
|
|
|
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;
|
|
|
|
|
/* The size of the largest file shuffle. */
|
|
|
|
|
unsigned long largest_file_shuffle;
|
|
|
|
|
/* An obstack for debugging information. */
|
|
|
|
|
struct obstack memory;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Add a file entry to a shuffle list. */
|
|
|
|
|
|
|
|
|
|
static void add_file_shuffle PARAMS ((struct accumulate *,
|
|
|
|
|
struct shuffle **,
|
|
|
|
|
struct shuffle **, bfd *, file_ptr,
|
|
|
|
|
unsigned long));
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
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 == offset)
|
|
|
|
|
{
|
|
|
|
|
/* Just merge this entry onto the existing one. */
|
|
|
|
|
(*tail)->size += size;
|
|
|
|
|
if ((*tail)->size > ainfo->largest_file_shuffle)
|
|
|
|
|
ainfo->largest_file_shuffle = (*tail)->size;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = (struct shuffle *) obstack_alloc (&ainfo->memory,
|
|
|
|
|
sizeof (struct shuffle));
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add a memory entry to a shuffle list. */
|
|
|
|
|
|
|
|
|
|
static void add_memory_shuffle PARAMS ((struct accumulate *,
|
|
|
|
|
struct shuffle **head,
|
|
|
|
|
struct shuffle **tail,
|
|
|
|
|
bfd_byte *data, unsigned long size));
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
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 *) obstack_alloc (&ainfo->memory,
|
|
|
|
|
sizeof (struct shuffle));
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialize the FDR hash table. This returns a handle which is then
|
|
|
|
|
passed in to bfd_ecoff_debug_accumulate, et. al. */
|
|
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
|
PTR
|
|
|
|
|
bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info)
|
|
|
|
|
bfd *output_bfd;
|
|
|
|
|
struct ecoff_debug_info *output_debug;
|
|
|
|
|
const struct ecoff_debug_swap *output_swap;
|
|
|
|
|
struct bfd_link_info *info;
|
|
|
|
|
{
|
|
|
|
|
struct accumulate *ainfo;
|
|
|
|
|
|
|
|
|
|
ainfo = (struct accumulate *) bfd_xmalloc (sizeof (struct accumulate));
|
|
|
|
|
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->relocateable)
|
|
|
|
|
{
|
|
|
|
|
if (! bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* The first entry in the string table is the empty string. */
|
|
|
|
|
output_debug->symbolic_header.issMax = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obstack_begin (&ainfo->memory, 4050);
|
|
|
|
|
|
|
|
|
|
return (PTR) ainfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free the accumulated debugging information. */
|
|
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
|
void
|
|
|
|
|
bfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info)
|
|
|
|
|
PTR handle;
|
|
|
|
|
bfd *output_bfd;
|
|
|
|
|
struct ecoff_debug_info *output_debug;
|
|
|
|
|
const struct ecoff_debug_swap *output_swap;
|
|
|
|
|
struct bfd_link_info *info;
|
|
|
|
|
{
|
|
|
|
|
struct accumulate *ainfo = (struct accumulate *) handle;
|
|
|
|
|
|
|
|
|
|
bfd_hash_table_free (&ainfo->fdr_hash.table);
|
|
|
|
|
|
|
|
|
|
if (! info->relocateable)
|
|
|
|
|
bfd_hash_table_free (&ainfo->str_hash.table);
|
|
|
|
|
|
|
|
|
|
obstack_free (&ainfo->memory, (PTR) NULL);
|
|
|
|
|
|
|
|
|
|
free (ainfo);
|
|
|
|
|
}
|
|
|
|
|
|
1993-11-24 07:18:44 +00:00
|
|
|
|
/* Accumulate the debugging information from INPUT_BFD into
|
|
|
|
|
OUTPUT_BFD. The INPUT_DEBUG argument points to some ECOFF
|
|
|
|
|
debugging information which we want to link into the information
|
|
|
|
|
pointed to by the OUTPUT_DEBUG argument. OUTPUT_SWAP and
|
1994-01-11 16:23:41 +00:00
|
|
|
|
INPUT_SWAP point to the swapping information needed. INFO is the
|
|
|
|
|
linker information structure. HANDLE is returned by
|
|
|
|
|
bfd_ecoff_debug_init. */
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-06 20:04:43 +00:00
|
|
|
|
/*ARGSUSED*/
|
1993-11-24 07:18:44 +00:00
|
|
|
|
boolean
|
1994-01-11 16:23:41 +00:00
|
|
|
|
bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
|
1993-11-24 07:18:44 +00:00
|
|
|
|
input_bfd, input_debug, input_swap,
|
1994-01-11 16:23:41 +00:00
|
|
|
|
info)
|
|
|
|
|
PTR handle;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
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;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
struct bfd_link_info *info;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
struct accumulate *ainfo = (struct accumulate *) handle;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
|
|
|
|
|
= input_swap->swap_sym_in;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *))
|
|
|
|
|
= input_swap->swap_rfd_in;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
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;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
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;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
bfd_vma section_adjust[scMax];
|
|
|
|
|
asection *sec;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
bfd_byte *fdr_start;
|
|
|
|
|
bfd_byte *fdr_ptr;
|
|
|
|
|
bfd_byte *fdr_end;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
bfd_size_type fdr_add;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
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;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
|
|
|
|
/* Use section_adjust to hold the value to add to a symbol in a
|
|
|
|
|
particular section. */
|
|
|
|
|
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);
|
|
|
|
|
/* scRdata section may be either .rdata or .rodata. */
|
|
|
|
|
SET (".rdata", scRData);
|
|
|
|
|
SET (".rodata", scRData);
|
|
|
|
|
SET (".init", scInit);
|
|
|
|
|
SET (".fini", scFini);
|
|
|
|
|
|
|
|
|
|
#undef SET
|
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
/* Find all the debugging information based on the FDR's. We need
|
|
|
|
|
to handle them whether they are swapped or not. */
|
|
|
|
|
if (input_debug->fdr != (FDR *) NULL)
|
1993-11-24 07:18:44 +00:00
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
fdr_start = (bfd_byte *) input_debug->fdr;
|
|
|
|
|
fdr_add = sizeof (FDR);
|
1993-11-24 07:18:44 +00:00
|
|
|
|
}
|
1994-01-11 16:23:41 +00:00
|
|
|
|
else
|
1993-11-24 07:18:44 +00:00
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
fdr_start = (bfd_byte *) input_debug->external_fdr;
|
|
|
|
|
fdr_add = input_swap->external_fdr_size;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
}
|
1994-01-11 16:23:41 +00:00
|
|
|
|
fdr_end = fdr_start + input_symhdr->ifdMax * fdr_add;
|
|
|
|
|
|
|
|
|
|
input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd,
|
|
|
|
|
(input_symhdr->ifdMax
|
|
|
|
|
* sizeof (RFDT)));
|
|
|
|
|
|
|
|
|
|
sz = (input_symhdr->crfd + input_symhdr->ifdMax) * external_rfd_size;
|
|
|
|
|
rfd_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
|
|
|
|
|
add_memory_shuffle (ainfo, &ainfo->rfd, &ainfo->rfd_end, rfd_out, sz);
|
|
|
|
|
|
|
|
|
|
copied = 0;
|
|
|
|
|
|
|
|
|
|
/* Look through the FDR's to see which ones we are going to include
|
|
|
|
|
in the final output. We do not want duplicate FDR information
|
|
|
|
|
for header files, because ECOFF debugging is often very large.
|
|
|
|
|
When we find an FDR with no line information which can be merged,
|
|
|
|
|
we look it up in a hash table to ensure that we only include it
|
|
|
|
|
once. We keep a table mapping FDR numbers to the final number
|
|
|
|
|
they get with the BFD, so that we can refer to it when we write
|
|
|
|
|
out the external symbols. */
|
|
|
|
|
for (fdr_ptr = fdr_start, i = 0;
|
|
|
|
|
fdr_ptr < fdr_end;
|
|
|
|
|
fdr_ptr += fdr_add, i++, rfd_out += external_rfd_size)
|
1993-11-24 07:18:44 +00:00
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
FDR fdr;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
if (input_debug->fdr != (FDR *) NULL)
|
|
|
|
|
fdr = *(FDR *) fdr_ptr;
|
|
|
|
|
else
|
|
|
|
|
(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
|
|
|
|
|
|
|
|
|
|
/* See if this FDR can be merged with an existing one. */
|
|
|
|
|
if (fdr.cbLine == 0 && fdr.rss != -1 && fdr.fMerge)
|
1993-11-24 07:18:44 +00:00
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
const char *name;
|
|
|
|
|
char *lookup;
|
|
|
|
|
struct string_hash_entry *fh;
|
|
|
|
|
|
|
|
|
|
/* We look up a string formed from the file name and the
|
|
|
|
|
number of symbols. Sometimes an include file will
|
|
|
|
|
conditionally define a typedef or something based on the
|
|
|
|
|
order of include files. Using the number of symbols as a
|
|
|
|
|
hash reduces the chance that we will merge symbol
|
|
|
|
|
information that should not be merged. */
|
|
|
|
|
name = input_debug->ss + fdr.issBase + fdr.rss;
|
|
|
|
|
lookup = (char *) alloca (strlen (name) + 20);
|
|
|
|
|
sprintf (lookup, "%s %lx", name, fdr.csym);
|
|
|
|
|
|
|
|
|
|
fh = string_hash_lookup (&ainfo->fdr_hash, lookup, true, true);
|
|
|
|
|
if (fh == (struct string_hash_entry *) NULL)
|
|
|
|
|
return false;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
if (fh->val != -1)
|
|
|
|
|
{
|
|
|
|
|
input_debug->ifdmap[i] = fh->val;
|
|
|
|
|
(*swap_rfd_out) (output_bfd, input_debug->ifdmap + i,
|
|
|
|
|
(PTR) rfd_out);
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
/* Don't copy this FDR. */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
fh->val = output_symhdr->ifdMax + copied;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
}
|
1994-01-11 16:23:41 +00:00
|
|
|
|
|
|
|
|
|
input_debug->ifdmap[i] = output_symhdr->ifdMax + copied;
|
|
|
|
|
(*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, (PTR) rfd_out);
|
|
|
|
|
++copied;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
newrfdbase = output_symhdr->crfd;
|
|
|
|
|
output_symhdr->crfd += input_symhdr->ifdMax;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
/* Copy over any existing RFD's. RFD's are only created by the
|
|
|
|
|
linker, so this will only happen for input files which are the
|
|
|
|
|
result of a partial link. */
|
|
|
|
|
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)
|
1993-11-24 07:18:44 +00:00
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
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;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
}
|
1994-01-11 16:23:41 +00:00
|
|
|
|
|
|
|
|
|
oldrfdbase = output_symhdr->crfd;
|
|
|
|
|
output_symhdr->crfd += input_symhdr->crfd;
|
|
|
|
|
|
|
|
|
|
/* Look through the FDR's and copy over all associated debugging
|
|
|
|
|
information. */
|
|
|
|
|
sz = copied * external_fdr_size;
|
|
|
|
|
fdr_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
|
|
|
|
|
add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, fdr_out, sz);
|
|
|
|
|
for (fdr_ptr = fdr_start, i = 0;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
fdr_ptr < fdr_end;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
fdr_ptr += fdr_add, i++)
|
1993-11-24 07:18:44 +00:00
|
|
|
|
{
|
|
|
|
|
FDR fdr;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
bfd_byte *sym_out;
|
|
|
|
|
bfd_byte *lraw_src;
|
|
|
|
|
bfd_byte *lraw_end;
|
|
|
|
|
boolean fgotfilename;
|
|
|
|
|
|
|
|
|
|
if (input_debug->ifdmap[i] < output_symhdr->ifdMax)
|
|
|
|
|
{
|
|
|
|
|
/* We are not copying this FDR. */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
|
|
|
|
if (input_debug->fdr != (FDR *) NULL)
|
|
|
|
|
fdr = *(FDR *) fdr_ptr;
|
|
|
|
|
else
|
|
|
|
|
(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
|
|
|
|
|
|
|
|
|
|
/* FIXME: It is conceivable that this FDR points to the .init or
|
|
|
|
|
.fini section, in which case this will not do the right
|
|
|
|
|
thing. */
|
|
|
|
|
fdr.adr += section_adjust[scText];
|
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
/* Swap in the local symbols, adjust their values, and swap them
|
|
|
|
|
out again. */
|
|
|
|
|
fgotfilename = false;
|
|
|
|
|
sz = fdr.csym * external_sym_size;
|
|
|
|
|
sym_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz);
|
|
|
|
|
add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out, sz);
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
/* Adjust the symbol value if appropriate. */
|
|
|
|
|
switch (internal_sym.st)
|
|
|
|
|
{
|
|
|
|
|
case stNil:
|
|
|
|
|
if (ECOFF_IS_STAB (&internal_sym))
|
|
|
|
|
break;
|
|
|
|
|
/* Fall through. */
|
|
|
|
|
case stGlobal:
|
|
|
|
|
case stStatic:
|
|
|
|
|
case stLabel:
|
|
|
|
|
case stProc:
|
|
|
|
|
case stStaticProc:
|
|
|
|
|
internal_sym.value += section_adjust[internal_sym.sc];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we are doing a final link, we hash all the strings in
|
|
|
|
|
the local symbol table together. This reduces the amount
|
|
|
|
|
of space required by debugging information. We don't do
|
|
|
|
|
this when performing a relocateable link because it would
|
|
|
|
|
prevent us from easily merging different FDR's. */
|
|
|
|
|
if (! info->relocateable)
|
|
|
|
|
{
|
|
|
|
|
boolean ffilename;
|
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
|
|
if (! fgotfilename && internal_sym.iss == fdr.rss)
|
|
|
|
|
ffilename = true;
|
|
|
|
|
else
|
|
|
|
|
ffilename = false;
|
|
|
|
|
|
|
|
|
|
/* Hash the name into the string table. */
|
|
|
|
|
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;
|
|
|
|
|
}
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
fdr.isymBase = output_symhdr->isymMax;
|
|
|
|
|
output_symhdr->isymMax += fdr.csym;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
/* Copy the information that does not need swapping. */
|
|
|
|
|
if (fdr.cbLine > 0)
|
|
|
|
|
{
|
|
|
|
|
add_file_shuffle (ainfo, &ainfo->line, &ainfo->line_end,
|
|
|
|
|
input_bfd,
|
|
|
|
|
input_symhdr->cbLineOffset + fdr.cbLineOffset,
|
|
|
|
|
fdr.cbLine);
|
|
|
|
|
fdr.ilineBase = output_symhdr->ilineMax;
|
|
|
|
|
fdr.cbLineOffset = output_symhdr->cbLine;
|
|
|
|
|
output_symhdr->ilineMax += fdr.cline;
|
|
|
|
|
output_symhdr->cbLine += fdr.cbLine;
|
|
|
|
|
}
|
|
|
|
|
if (fdr.caux > 0)
|
|
|
|
|
{
|
|
|
|
|
add_file_shuffle (ainfo, &ainfo->aux, &ainfo->aux_end,
|
|
|
|
|
input_bfd,
|
|
|
|
|
(input_symhdr->cbAuxOffset
|
|
|
|
|
+ fdr.iauxBase * sizeof (union aux_ext)),
|
|
|
|
|
fdr.caux * sizeof (union aux_ext));
|
|
|
|
|
fdr.iauxBase = output_symhdr->iauxMax;
|
|
|
|
|
output_symhdr->iauxMax += fdr.caux;
|
|
|
|
|
}
|
|
|
|
|
if (! info->relocateable)
|
|
|
|
|
{
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
/* When are are hashing strings, we lie about the number of
|
|
|
|
|
strings attached to each FDR. We need to set cbSs
|
|
|
|
|
because some versions of dbx apparently use it to decide
|
|
|
|
|
how much of the string table to read in. */
|
|
|
|
|
fdr.issBase = 0;
|
|
|
|
|
fdr.cbSs = output_symhdr->issMax;
|
|
|
|
|
}
|
|
|
|
|
else if (fdr.cbSs > 0)
|
|
|
|
|
{
|
|
|
|
|
add_file_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end,
|
|
|
|
|
input_bfd,
|
|
|
|
|
input_symhdr->cbSsOffset + fdr.issBase,
|
|
|
|
|
fdr.cbSs);
|
|
|
|
|
fdr.issBase = output_symhdr->issMax;
|
|
|
|
|
output_symhdr->issMax += fdr.cbSs;
|
|
|
|
|
}
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
if (output_bfd->xvec->header_byteorder_big_p
|
|
|
|
|
== input_bfd->xvec->header_byteorder_big_p)
|
1993-11-24 07:18:44 +00:00
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
/* The two BFD's have the same endianness, so simply copying
|
|
|
|
|
the information will suffice. */
|
|
|
|
|
BFD_ASSERT (external_pdr_size == input_swap->external_pdr_size);
|
|
|
|
|
if (fdr.cpd > 0)
|
|
|
|
|
add_file_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end,
|
|
|
|
|
input_bfd,
|
|
|
|
|
(input_symhdr->cbPdOffset
|
|
|
|
|
+ fdr.ipdFirst * external_pdr_size),
|
|
|
|
|
fdr.cpd * external_pdr_size);
|
|
|
|
|
BFD_ASSERT (external_opt_size == input_swap->external_opt_size);
|
|
|
|
|
if (fdr.copt > 0)
|
|
|
|
|
add_file_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end,
|
|
|
|
|
input_bfd,
|
|
|
|
|
(input_symhdr->cbOptOffset
|
|
|
|
|
+ fdr.ioptBase * external_opt_size),
|
|
|
|
|
fdr.copt * external_opt_size);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bfd_size_type outsz, insz;
|
|
|
|
|
bfd_byte *in;
|
|
|
|
|
bfd_byte *end;
|
|
|
|
|
bfd_byte *out;
|
|
|
|
|
|
|
|
|
|
/* The two BFD's have different endianness, so we must swap
|
|
|
|
|
everything in and out. This code would always work, but
|
|
|
|
|
it would be unnecessarily slow in the normal case. */
|
|
|
|
|
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 *) obstack_alloc (&ainfo->memory, sz);
|
|
|
|
|
add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out, sz);
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Swap over the optimization information. */
|
|
|
|
|
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 *) obstack_alloc (&ainfo->memory, sz);
|
|
|
|
|
add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out, sz);
|
|
|
|
|
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;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
if (fdr.crfd <= 0)
|
|
|
|
|
{
|
|
|
|
|
/* Point this FDR at the table of RFD's we created. */
|
|
|
|
|
fdr.rfdBase = newrfdbase;
|
|
|
|
|
fdr.crfd = input_symhdr->ifdMax;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Point this FDR at the remapped RFD's. */
|
|
|
|
|
fdr.rfdBase += oldrfdbase;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
(*swap_fdr_out) (output_bfd, &fdr, fdr_out);
|
|
|
|
|
fdr_out += external_fdr_size;
|
|
|
|
|
++output_symhdr->ifdMax;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add a string to the debugging information we are accumulating.
|
|
|
|
|
Return the offset from the fdr string base. */
|
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
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;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
FDR *fdr;
|
|
|
|
|
const char *string;
|
|
|
|
|
{
|
|
|
|
|
HDRR *symhdr;
|
|
|
|
|
size_t len;
|
|
|
|
|
bfd_size_type ret;
|
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
symhdr = &debug->symbolic_header;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
len = strlen (string);
|
1994-01-11 16:23:41 +00:00
|
|
|
|
if (info->relocateable)
|
|
|
|
|
{
|
|
|
|
|
add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, (PTR) string,
|
|
|
|
|
len + 1);
|
|
|
|
|
ret = symhdr->issMax;
|
|
|
|
|
symhdr->issMax += len + 1;
|
|
|
|
|
fdr->cbSs += len + 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
1993-11-24 07:18:44 +00:00
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
struct string_hash_entry *sh;
|
|
|
|
|
|
|
|
|
|
sh = string_hash_lookup (&ainfo->str_hash, string, true, true);
|
|
|
|
|
if (sh == (struct string_hash_entry *) NULL)
|
1994-01-06 20:04:43 +00:00
|
|
|
|
return (bfd_size_type) -1;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
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;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
}
|
1994-01-11 16:23:41 +00:00
|
|
|
|
|
1993-11-24 07:18:44 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add debugging information from a non-ECOFF file. */
|
|
|
|
|
|
|
|
|
|
boolean
|
1994-01-11 16:23:41 +00:00
|
|
|
|
bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug,
|
|
|
|
|
output_swap, input_bfd, info)
|
|
|
|
|
PTR handle;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
bfd *output_bfd;
|
|
|
|
|
struct ecoff_debug_info *output_debug;
|
|
|
|
|
const struct ecoff_debug_swap *output_swap;
|
|
|
|
|
bfd *input_bfd;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
struct bfd_link_info *info;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
struct accumulate *ainfo = (struct accumulate *) handle;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
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;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
PTR external_fdr;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
|
|
|
|
memset (&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
|
|
|
|
|
{
|
|
|
|
|
/* FIXME: What about .init or .fini? */
|
|
|
|
|
fdr.adr = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fdr.issBase = output_symhdr->issMax;
|
|
|
|
|
fdr.cbSs = 0;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr,
|
1993-11-24 07:18:44 +00:00
|
|
|
|
bfd_get_filename (input_bfd));
|
1994-01-06 20:04:43 +00:00
|
|
|
|
if (fdr.rss == -1)
|
|
|
|
|
return false;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
fdr.isymBase = output_symhdr->isymMax;
|
|
|
|
|
|
|
|
|
|
/* Get the local symbols from the input BFD. */
|
|
|
|
|
symbols = (asymbol **) bfd_alloc (output_bfd,
|
|
|
|
|
get_symtab_upper_bound (input_bfd));
|
|
|
|
|
if (symbols == (asymbol **) NULL)
|
|
|
|
|
{
|
|
|
|
|
bfd_error = no_memory;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols);
|
|
|
|
|
|
|
|
|
|
/* Handle the local symbols. Any external symbols are handled
|
|
|
|
|
separately. */
|
|
|
|
|
fdr.csym = 0;
|
|
|
|
|
for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++)
|
|
|
|
|
{
|
|
|
|
|
SYMR internal_sym;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
PTR external_sym;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
|
|
|
|
if (((*sym_ptr)->flags & BSF_EXPORT) != 0)
|
|
|
|
|
continue;
|
|
|
|
|
memset (&internal_sym, 0, sizeof internal_sym);
|
1994-01-11 16:23:41 +00:00
|
|
|
|
internal_sym.iss = ecoff_add_string (ainfo, info, output_debug, &fdr,
|
1993-11-24 07:18:44 +00:00
|
|
|
|
(*sym_ptr)->name);
|
|
|
|
|
|
1994-01-06 20:04:43 +00:00
|
|
|
|
if (internal_sym.iss == -1)
|
|
|
|
|
return false;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
if (bfd_is_com_section ((*sym_ptr)->section)
|
|
|
|
|
|| (*sym_ptr)->section == &bfd_und_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;
|
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
external_sym = (PTR) obstack_alloc (&ainfo->memory,
|
|
|
|
|
output_swap->external_sym_size);
|
|
|
|
|
(*swap_sym_out) (output_bfd, &internal_sym, external_sym);
|
|
|
|
|
add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end,
|
|
|
|
|
external_sym, output_swap->external_sym_size);
|
1993-11-24 07:18:44 +00:00
|
|
|
|
++fdr.csym;
|
|
|
|
|
++output_symhdr->isymMax;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bfd_release (output_bfd, (PTR) symbols);
|
|
|
|
|
|
|
|
|
|
/* Leave everything else in the FDR zeroed out. This will cause
|
|
|
|
|
the lang field to be langC. The fBigendian field will
|
|
|
|
|
indicate little endian format, but it doesn't matter because
|
|
|
|
|
it only applies to aux fields and there are none. */
|
1994-01-11 16:23:41 +00:00
|
|
|
|
external_fdr = (PTR) obstack_alloc (&ainfo->memory,
|
|
|
|
|
output_swap->external_fdr_size);
|
|
|
|
|
(*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr);
|
|
|
|
|
add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end,
|
|
|
|
|
external_fdr, output_swap->external_fdr_size);
|
|
|
|
|
|
1993-11-24 07:18:44 +00:00
|
|
|
|
++output_symhdr->ifdMax;
|
1994-01-11 16:23:41 +00:00
|
|
|
|
|
1993-11-24 07:18:44 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
/* Set up ECOFF debugging information for the external symbols.
|
|
|
|
|
FIXME: This is done using a memory buffer, but it should be
|
|
|
|
|
probably be changed to use a shuffle structure. The assembler uses
|
|
|
|
|
this interface, so that must be changed to do something else. */
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr,
|
|
|
|
|
set_index)
|
|
|
|
|
bfd *abfd;
|
|
|
|
|
struct ecoff_debug_info *debug;
|
|
|
|
|
const struct ecoff_debug_swap *swap;
|
|
|
|
|
boolean relocateable;
|
|
|
|
|
boolean (*get_extr) PARAMS ((asymbol *, EXTR *));
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
/* Get the external symbol information. */
|
|
|
|
|
if ((*get_extr) (sym_ptr, &esym) == false)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* If we're producing an executable, move common symbols into
|
|
|
|
|
bss. */
|
|
|
|
|
if (relocateable == false)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
|| sym_ptr->section == &bfd_und_section)
|
1994-02-04 04:18:28 +00:00
|
|
|
|
{
|
|
|
|
|
/* FIXME: gas does not keep the value of a small undefined
|
|
|
|
|
symbol in the symbol itself, because of relocation
|
|
|
|
|
problems. */
|
|
|
|
|
if (esym.asym.sc != scSUndefined
|
|
|
|
|
|| esym.asym.value == 0
|
|
|
|
|
|| sym_ptr->value != 0)
|
|
|
|
|
esym.asym.value = sym_ptr->value;
|
|
|
|
|
}
|
1993-11-24 07:18:44 +00:00
|
|
|
|
else
|
|
|
|
|
esym.asym.value = (sym_ptr->value
|
|
|
|
|
+ sym_ptr->section->output_offset
|
|
|
|
|
+ sym_ptr->section->output_section->vma);
|
|
|
|
|
|
|
|
|
|
if (set_index)
|
1994-01-06 20:04:43 +00:00
|
|
|
|
(*set_index) (sym_ptr, (bfd_size_type) symhdr->iextMax);
|
|
|
|
|
|
|
|
|
|
if (! bfd_ecoff_debug_one_external (abfd, debug, swap,
|
|
|
|
|
sym_ptr->name, &esym))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-06 20:04:43 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-06 20:04:43 +00:00
|
|
|
|
/* Add a single external symbol to the debugging information. */
|
|
|
|
|
|
|
|
|
|
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 (debug->ssext_end - debug->ssext
|
|
|
|
|
< symhdr->issExtMax + namelen + 1)
|
|
|
|
|
{
|
|
|
|
|
if (ecoff_add_bytes ((char **) &debug->ssext,
|
|
|
|
|
(char **) &debug->ssext_end,
|
|
|
|
|
symhdr->issExtMax + namelen + 1)
|
|
|
|
|
== false)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if ((char *) debug->external_ext_end - (char *) debug->external_ext
|
|
|
|
|
< (symhdr->iextMax + 1) * external_ext_size)
|
|
|
|
|
{
|
|
|
|
|
if (ecoff_add_bytes ((char **) &debug->external_ext,
|
|
|
|
|
(char **) &debug->external_ext_end,
|
|
|
|
|
(symhdr->iextMax + 1) * external_ext_size)
|
|
|
|
|
== false)
|
|
|
|
|
return false;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
1994-01-06 20:04:43 +00:00
|
|
|
|
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;
|
|
|
|
|
|
1993-11-24 07:18:44 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Align the ECOFF debugging information. */
|
|
|
|
|
|
1994-01-06 20:04:43 +00:00
|
|
|
|
/*ARGSUSED*/
|
1993-11-24 07:18:44 +00:00
|
|
|
|
static void
|
|
|
|
|
ecoff_align_debug (abfd, debug, swap)
|
|
|
|
|
bfd *abfd;
|
|
|
|
|
struct ecoff_debug_info *debug;
|
|
|
|
|
const struct ecoff_debug_swap *swap;
|
|
|
|
|
{
|
|
|
|
|
HDRR * const symhdr = &debug->symbolic_header;
|
1994-01-25 01:50:46 +00:00
|
|
|
|
bfd_size_type debug_align, aux_align, rfd_align;
|
1994-01-06 20:04:43 +00:00
|
|
|
|
size_t add;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
/* Adjust the counts so that structures are aligned. */
|
1993-11-24 07:18:44 +00:00
|
|
|
|
debug_align = swap->debug_align;
|
|
|
|
|
aux_align = debug_align / sizeof (union aux_ext);
|
1994-01-25 01:50:46 +00:00
|
|
|
|
rfd_align = debug_align / swap->external_rfd_size;
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
|
|
|
|
add = debug_align - (symhdr->cbLine & (debug_align - 1));
|
|
|
|
|
if (add != debug_align)
|
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
if (debug->line != (unsigned char *) NULL)
|
|
|
|
|
memset (debug->line + symhdr->cbLine, 0, add);
|
1993-11-24 07:18:44 +00:00
|
|
|
|
symhdr->cbLine += add;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add = debug_align - (symhdr->issMax & (debug_align - 1));
|
|
|
|
|
if (add != debug_align)
|
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
if (debug->ss != (char *) NULL)
|
|
|
|
|
memset (debug->ss + symhdr->issMax, 0, add);
|
1993-11-24 07:18:44 +00:00
|
|
|
|
symhdr->issMax += add;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add = debug_align - (symhdr->issExtMax & (debug_align - 1));
|
|
|
|
|
if (add != debug_align)
|
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
if (debug->ssext != (char *) NULL)
|
|
|
|
|
memset (debug->ssext + symhdr->issExtMax, 0, add);
|
1993-11-24 07:18:44 +00:00
|
|
|
|
symhdr->issExtMax += add;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add = aux_align - (symhdr->iauxMax & (aux_align - 1));
|
|
|
|
|
if (add != aux_align)
|
|
|
|
|
{
|
1994-01-11 16:23:41 +00:00
|
|
|
|
if (debug->external_aux != (union aux_ext *) NULL)
|
|
|
|
|
memset (debug->external_aux + symhdr->iauxMax, 0,
|
|
|
|
|
add * sizeof (union aux_ext));
|
1993-11-24 07:18:44 +00:00
|
|
|
|
symhdr->iauxMax += add;
|
|
|
|
|
}
|
1994-01-25 01:50:46 +00:00
|
|
|
|
|
|
|
|
|
add = rfd_align - (symhdr->crfd & (rfd_align - 1));
|
|
|
|
|
if (add != rfd_align)
|
|
|
|
|
{
|
|
|
|
|
if (debug->external_rfd != (PTR) NULL)
|
|
|
|
|
memset (((char *) debug->external_rfd
|
|
|
|
|
+ symhdr->crfd * swap->external_rfd_size),
|
|
|
|
|
0, add * swap->external_rfd_size);
|
|
|
|
|
symhdr->crfd += add;
|
|
|
|
|
}
|
1993-11-24 07:18:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the size required by the ECOFF debugging information. */
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
/* Write out the ECOFF symbolic header, given the file position it is
|
|
|
|
|
going to be placed at. This assumes that the counts are set
|
|
|
|
|
correctly. */
|
1993-11-24 07:18:44 +00:00
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
static boolean
|
|
|
|
|
ecoff_write_symhdr (abfd, debug, swap, where)
|
1993-11-24 07:18:44 +00:00
|
|
|
|
bfd *abfd;
|
|
|
|
|
struct ecoff_debug_info *debug;
|
|
|
|
|
const struct ecoff_debug_swap *swap;
|
|
|
|
|
file_ptr where;
|
|
|
|
|
{
|
|
|
|
|
HDRR * const symhdr = &debug->symbolic_header;
|
|
|
|
|
char *buff;
|
|
|
|
|
|
|
|
|
|
ecoff_align_debug (abfd, debug, swap);
|
|
|
|
|
|
|
|
|
|
/* Go to the right location in the file. */
|
|
|
|
|
if (bfd_seek (abfd, where, SEEK_SET) != 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
where += swap->external_hdr_size;
|
|
|
|
|
|
|
|
|
|
/* Fill in the file offsets. */
|
|
|
|
|
#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) alloca (swap->external_hdr_size);
|
|
|
|
|
(*swap->swap_hdr_out) (abfd, symhdr, buff);
|
|
|
|
|
if (bfd_write (buff, 1, swap->external_hdr_size, abfd)
|
|
|
|
|
!= swap->external_hdr_size)
|
|
|
|
|
return false;
|
|
|
|
|
|
1994-01-11 16:23:41 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out the ECOFF debugging information. This function assumes
|
|
|
|
|
that the information (the pointers and counts) in *DEBUG have been
|
|
|
|
|
set correctly. WHERE is the position in the file to write the
|
|
|
|
|
information to. This function fills in the file offsets in the
|
|
|
|
|
symbolic header. */
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
1993-11-24 07:18:44 +00:00
|
|
|
|
#define WRITE(ptr, count, size, offset) \
|
|
|
|
|
BFD_ASSERT (symhdr->offset == 0 || bfd_tell (abfd) == symhdr->offset); \
|
1994-01-06 20:04:43 +00:00
|
|
|
|
if (bfd_write ((PTR) debug->ptr, size, symhdr->count, abfd) \
|
1993-11-24 07:18:44 +00:00
|
|
|
|
!= 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, 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;
|
|
|
|
|
}
|
1994-01-11 16:23:41 +00:00
|
|
|
|
|
|
|
|
|
/* Write out a shuffle list. */
|
|
|
|
|
|
|
|
|
|
static boolean ecoff_write_shuffle PARAMS ((bfd *,
|
|
|
|
|
const struct ecoff_debug_swap *,
|
|
|
|
|
struct shuffle *, PTR space));
|
|
|
|
|
|
|
|
|
|
static 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_write (l->u.memory, 1, l->size, abfd) != l->size)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0
|
|
|
|
|
|| bfd_read (space, 1, l->size, l->u.file.input_bfd) != l->size
|
|
|
|
|
|| bfd_write (space, 1, l->size, abfd) != l->size)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
total += l->size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((total & (swap->debug_align - 1)) != 0)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
bfd_byte *s;
|
|
|
|
|
|
|
|
|
|
i = swap->debug_align - (total & (swap->debug_align - 1));
|
|
|
|
|
s = (bfd_byte *) alloca (i);
|
|
|
|
|
memset (s, 0, i);
|
|
|
|
|
if (bfd_write ((PTR) s, 1, i, abfd) != i)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out debugging information using accumulated linker
|
|
|
|
|
information. */
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if (! ecoff_write_symhdr (abfd, debug, swap, where))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
space = (PTR) alloca (ainfo->largest_file_shuffle);
|
|
|
|
|
|
|
|
|
|
if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space)
|
|
|
|
|
|| ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space)
|
|
|
|
|
|| ! ecoff_write_shuffle (abfd, swap, ainfo->sym, space)
|
|
|
|
|
|| ! ecoff_write_shuffle (abfd, swap, ainfo->opt, space)
|
|
|
|
|
|| ! ecoff_write_shuffle (abfd, swap, ainfo->aux, space))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/* The string table is written out from the hash table if this is a
|
|
|
|
|
final link. */
|
|
|
|
|
if (info->relocateable)
|
|
|
|
|
{
|
|
|
|
|
BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL);
|
|
|
|
|
if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned long total;
|
|
|
|
|
bfd_byte null;
|
|
|
|
|
struct string_hash_entry *sh;
|
|
|
|
|
|
|
|
|
|
BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
|
|
|
|
|
null = 0;
|
|
|
|
|
if (bfd_write ((PTR) &null, 1, 1, abfd) != 1)
|
|
|
|
|
return false;
|
|
|
|
|
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);
|
|
|
|
|
if (bfd_write ((PTR) sh->root.string, 1, len + 1, abfd) != len + 1)
|
|
|
|
|
return false;
|
|
|
|
|
total += len + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((total & (swap->debug_align - 1)) != 0)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
bfd_byte *s;
|
|
|
|
|
|
|
|
|
|
i = swap->debug_align - (total & (swap->debug_align - 1));
|
|
|
|
|
s = (bfd_byte *) alloca (i);
|
|
|
|
|
memset (s, 0, i);
|
|
|
|
|
if (bfd_write ((PTR) s, 1, i, abfd) != i)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The external strings and symbol are not converted over to using
|
|
|
|
|
shuffles. FIXME: They probably should be. */
|
|
|
|
|
if (bfd_write (debug->ssext, 1, debug->symbolic_header.issExtMax, abfd)
|
|
|
|
|
!= debug->symbolic_header.issExtMax)
|
|
|
|
|
return false;
|
|
|
|
|
if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
bfd_byte *s;
|
|
|
|
|
|
|
|
|
|
i = (swap->debug_align
|
|
|
|
|
- (debug->symbolic_header.issExtMax & (swap->debug_align - 1)));
|
|
|
|
|
s = (bfd_byte *) alloca (i);
|
|
|
|
|
memset (s, 0, i);
|
|
|
|
|
if (bfd_write ((PTR) s, 1, i, abfd) != i)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! ecoff_write_shuffle (abfd, swap, ainfo->fdr, space)
|
|
|
|
|
|| ! ecoff_write_shuffle (abfd, swap, ainfo->rfd, space))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0
|
|
|
|
|
|| debug->symbolic_header.cbExtOffset == bfd_tell (abfd));
|
|
|
|
|
|
|
|
|
|
if (bfd_write (debug->external_ext, swap->external_ext_size,
|
|
|
|
|
debug->symbolic_header.iextMax, abfd)
|
|
|
|
|
!= debug->symbolic_header.iextMax * swap->external_ext_size)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|