diff options
Diffstat (limited to 'bfd/coffgen.c')
-rw-r--r-- | bfd/coffgen.c | 1501 |
1 files changed, 1501 insertions, 0 deletions
diff --git a/bfd/coffgen.c b/bfd/coffgen.c new file mode 100644 index 0000000..4bd0161 --- /dev/null +++ b/bfd/coffgen.c @@ -0,0 +1,1501 @@ +/* Support for the generic parts of COFF, for BFD. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Written by Cygnus Support. + +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. */ + +/* Most of this hacked by Steve Chamberlain, sac@cygnus.com. + Split out of coffcode.h by Ian Taylor, ian@cygnus.com. */ + +/* This file contains COFF code that is not dependent on any + particular COFF target. There is only one version of this file in + libbfd.a, so no target specific code may be put in here. Or, to + put it another way, + + ********** DO NOT PUT TARGET SPECIFIC CODE IN THIS FILE ********** + + If you need to add some target specific behaviour, add a new hook + function to bfd_coff_backend_data. + + Some of these functions are also called by the ECOFF routines. + Those functions may not use any COFF specific information, such as + coff_data (abfd). */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "libcoff.h" + +static asection bfd_debug_section = { "*DEBUG*" }; + +/* Take a section header read from a coff file (in HOST byte order), + and make a BFD "section" out of it. This is used by ECOFF. */ +static boolean +DEFUN(make_a_section_from_file,(abfd, hdr, target_index), + bfd *abfd AND + struct internal_scnhdr *hdr AND + unsigned int target_index) +{ + asection *return_section; + char *name; + + /* Assorted wastage to null-terminate the name, thanks AT&T! */ + name = bfd_alloc(abfd, sizeof (hdr->s_name)+1); + if (name == NULL) { + bfd_error = no_memory; + return false; + } + strncpy(name, (char *) &hdr->s_name[0], sizeof (hdr->s_name)); + name[sizeof (hdr->s_name)] = 0; + + return_section = bfd_make_section(abfd, name); + if (return_section == NULL) + return_section = bfd_coff_make_section_hook (abfd, name); + if (return_section == NULL) + return false; + + /* s_paddr is presumed to be = to s_vaddr */ + + return_section->vma = hdr->s_vaddr; + return_section->_raw_size = hdr->s_size; + return_section->filepos = hdr->s_scnptr; + return_section->rel_filepos = hdr->s_relptr; + return_section->reloc_count = hdr->s_nreloc; + + bfd_coff_set_alignment_hook (abfd, return_section, hdr); + + return_section->line_filepos = hdr->s_lnnoptr; + + return_section->lineno_count = hdr->s_nlnno; + return_section->userdata = NULL; + return_section->next = (asection *) NULL; + return_section->flags = bfd_coff_styp_to_sec_flags_hook (abfd, hdr); + + return_section->target_index = target_index; + + if (hdr->s_nreloc != 0) + return_section->flags |= SEC_RELOC; + /* FIXME: should this check 'hdr->s_size > 0' */ + if (hdr->s_scnptr != 0) + return_section->flags |= SEC_HAS_CONTENTS; + return true; +} + +/* Read in a COFF object and make it into a BFD. This is used by + ECOFF as well. */ + +static +bfd_target * +DEFUN(coff_real_object_p,(abfd, nscns, internal_f, internal_a), + bfd *abfd AND + unsigned nscns AND + struct internal_filehdr *internal_f AND + struct internal_aouthdr *internal_a) +{ + PTR tdata; + size_t readsize; /* length of file_info */ + unsigned int scnhsz; + char *external_sections; + + /* Build a play area */ + tdata = bfd_coff_mkobject_hook (abfd, (PTR) internal_f); + if (tdata == NULL) + return 0; + + scnhsz = bfd_coff_scnhsz (abfd); + readsize = nscns * scnhsz; + external_sections = (char *)bfd_alloc(abfd, readsize); + + if (bfd_read((PTR)external_sections, 1, readsize, abfd) != readsize) { + goto fail; + } + + /* Now copy data as required; construct all asections etc */ + if (nscns != 0) { + unsigned int i; + for (i = 0; i < nscns; i++) { + struct internal_scnhdr tmp; + bfd_coff_swap_scnhdr_in(abfd, (PTR) (external_sections + i * scnhsz), + (PTR) &tmp); + make_a_section_from_file(abfd,&tmp, i+1); + } + } + +/* make_abs_section(abfd);*/ + + if (bfd_coff_set_arch_mach_hook (abfd, (PTR) internal_f) == false) + goto fail; + + if (!(internal_f->f_flags & F_RELFLG)) + abfd->flags |= HAS_RELOC; + if ((internal_f->f_flags & F_EXEC)) + abfd->flags |= EXEC_P; + if (!(internal_f->f_flags & F_LNNO)) + abfd->flags |= HAS_LINENO; + if (!(internal_f->f_flags & F_LSYMS)) + abfd->flags |= HAS_LOCALS; + + + bfd_get_symcount(abfd) = internal_f->f_nsyms; + if (internal_f->f_nsyms) + abfd->flags |= HAS_SYMS; + + bfd_get_start_address(abfd) = internal_f->f_opthdr ? internal_a->entry : 0; + + return abfd->xvec; + fail: + bfd_release(abfd, tdata); + return (bfd_target *)NULL; +} + +/* Turn a COFF file into a BFD, but fail with wrong_format if it is + not a COFF file. This is also used by ECOFF. */ + +bfd_target * +DEFUN(coff_object_p,(abfd), + bfd *abfd) +{ + unsigned int filhsz; + unsigned int aoutsz; + int nscns; + PTR filehdr; + struct internal_filehdr internal_f; + struct internal_aouthdr internal_a; + + bfd_error = system_call_error; + + /* figure out how much to read */ + filhsz = bfd_coff_filhsz (abfd); + aoutsz = bfd_coff_aoutsz (abfd); + + filehdr = bfd_alloc (abfd, filhsz); + if (filehdr == NULL) + return 0; + if (bfd_read(filehdr, 1, filhsz, abfd) != filhsz) + return 0; + bfd_coff_swap_filehdr_in(abfd, filehdr, &internal_f); + bfd_release (abfd, filehdr); + + if (bfd_coff_bad_format_hook (abfd, &internal_f) == false) { + bfd_error = wrong_format; + return 0; + } + nscns =internal_f.f_nscns; + + if (internal_f.f_opthdr) { + PTR opthdr; + + opthdr = bfd_alloc (abfd, aoutsz); + if (opthdr == NULL) + return 0;; + if (bfd_read(opthdr, 1,aoutsz, abfd) != aoutsz) { + return 0; + } + bfd_coff_swap_aouthdr_in(abfd, opthdr, (PTR)&internal_a); + } + + /* Seek past the opt hdr stuff */ + bfd_seek(abfd, (file_ptr) (internal_f.f_opthdr + filhsz), SEEK_SET); + + return coff_real_object_p(abfd, nscns, &internal_f, &internal_a); +} + +/* Get the BFD section from a COFF symbol section number. */ + +struct sec * +DEFUN(coff_section_from_bfd_index,(abfd, index), + bfd *abfd AND + int index) +{ + struct sec *answer = abfd->sections; + + if (index == N_ABS) + { + return &bfd_abs_section; + } + if (index == N_UNDEF) + { + return &bfd_und_section; + } + if(index == N_DEBUG) + { + return &bfd_debug_section; + + } + + while (answer) { + if (answer->target_index == index) + return answer; + answer = answer->next; + } + BFD_ASSERT(0); + return &bfd_und_section; /* For gcc -W and lint. Never executed. */ +} + +/* Get the upper bound of a COFF symbol table. */ + +unsigned int +coff_get_symtab_upper_bound(abfd) +bfd *abfd; +{ + if (!bfd_coff_slurp_symbol_table(abfd)) + return 0; + + return (bfd_get_symcount(abfd) + 1) * (sizeof(coff_symbol_type *)); +} + + +/* Canonicalize a COFF symbol table. */ + +unsigned int +DEFUN(coff_get_symtab, (abfd, alocation), + bfd *abfd AND + asymbol **alocation) +{ + unsigned int counter = 0; + coff_symbol_type *symbase; + coff_symbol_type **location = (coff_symbol_type **) (alocation); + if (!bfd_coff_slurp_symbol_table(abfd)) + return 0; + + symbase = obj_symbols(abfd); + while (counter < bfd_get_symcount(abfd)) + { + /* This nasty code looks at the symbol to decide whether or + not it is descibes a constructor/destructor entry point. It + is structured this way to (hopefully) speed non matches */ +#if 0 + if (0 && symbase->symbol.name[9] == '$') + { + bfd_constructor_entry(abfd, + (asymbol **)location, + symbase->symbol.name[10] == 'I' ? + "CTOR" : "DTOR"); + } +#endif + *(location++) = symbase++; + counter++; + } + *location++ = 0; + return bfd_get_symcount(abfd); +} + +/* Set lineno_count for the output sections of a COFF file. */ + +void +DEFUN(coff_count_linenumbers,(abfd), + bfd *abfd) +{ + unsigned int limit = bfd_get_symcount(abfd); + unsigned int i; + asymbol **p; + { + asection *s = abfd->sections->output_section; + while (s) { + BFD_ASSERT(s->lineno_count == 0); + s = s->next; + } + } + + + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) { + asymbol *q_maybe = *p; + if (bfd_asymbol_flavour(q_maybe) == bfd_target_coff_flavour) { + coff_symbol_type *q = coffsymbol(q_maybe); + if (q->lineno) { + /* + This symbol has a linenumber, increment the owning + section's linenumber count + */ + alent *l = q->lineno; + q->symbol.section->output_section->lineno_count++; + l++; + while (l->line_number) { + q->symbol.section->output_section->lineno_count++; + l++; + } + } + } + } +} + +/* Takes a bfd and a symbol, returns a pointer to the coff specific + area of the symbol if there is one. */ + +coff_symbol_type * +DEFUN(coff_symbol_from,(ignore_abfd, symbol), + bfd *ignore_abfd AND + asymbol *symbol) +{ + if (bfd_asymbol_flavour(symbol) != bfd_target_coff_flavour) + return (coff_symbol_type *)NULL; + + if (bfd_asymbol_bfd(symbol)->tdata.coff_obj_data == (coff_data_type*)NULL) + return (coff_symbol_type *)NULL; + + return (coff_symbol_type *) symbol; +} + +static void +DEFUN(fixup_symbol_value,(coff_symbol_ptr, syment), +coff_symbol_type *coff_symbol_ptr AND +struct internal_syment *syment) +{ + + /* Normalize the symbol flags */ + if (coff_symbol_ptr->symbol.section == &bfd_com_section) { + /* a common symbol is undefined with a value */ + syment->n_scnum = N_UNDEF; + syment->n_value = coff_symbol_ptr->symbol.value; + } + else if (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING) { + syment->n_value = coff_symbol_ptr->symbol.value; + } + else if (coff_symbol_ptr->symbol.section == & bfd_und_section) { + syment->n_scnum = N_UNDEF; + syment->n_value = 0; + } + else { + if (coff_symbol_ptr->symbol.section) { + syment->n_scnum = + coff_symbol_ptr->symbol.section->output_section->target_index; + + syment->n_value = + coff_symbol_ptr->symbol.value + + coff_symbol_ptr->symbol.section->output_offset + + coff_symbol_ptr->symbol.section->output_section->vma; + } + else { + BFD_ASSERT(0); + /* This can happen, but I don't know why yet (steve@cygnus.com) */ + syment->n_scnum = N_ABS; + syment->n_value = coff_symbol_ptr->symbol.value; + } + } +} + +/* run through all the symbols in the symbol table and work out what + their indexes into the symbol table will be when output + + Coff requires that each C_FILE symbol points to the next one in the + chain, and that the last one points to the first external symbol. We + do that here too. + +*/ +void +DEFUN(coff_renumber_symbols,(bfd_ptr), + bfd *bfd_ptr) +{ + unsigned int symbol_count = bfd_get_symcount(bfd_ptr); + asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; + unsigned int native_index = 0; + struct internal_syment *last_file = (struct internal_syment *)NULL; + unsigned int symbol_index; + + /* COFF demands that undefined symbols come after all other symbols. + Since we don't need to impose this extra knowledge on all our client + programs, deal with that here. Sort the symbol table; just move the + undefined symbols to the end, leaving the rest alone. */ + /* @@ Do we have some condition we could test for, so we don't always + have to do this? I don't think relocatability is quite right, but + I'm not certain. [raeburn:19920508.1711EST] */ + { + asymbol **newsyms; + int i; + + newsyms = (asymbol **) bfd_alloc_by_size_t (bfd_ptr, + sizeof (asymbol *) + * (symbol_count + 1)); + bfd_ptr->outsymbols = newsyms; + for (i = 0; i < symbol_count; i++) + if (symbol_ptr_ptr[i]->section != &bfd_und_section) + *newsyms++ = symbol_ptr_ptr[i]; + for (i = 0; i < symbol_count; i++) + if (symbol_ptr_ptr[i]->section == &bfd_und_section) + *newsyms++ = symbol_ptr_ptr[i]; + *newsyms = (asymbol *) NULL; + symbol_ptr_ptr = bfd_ptr->outsymbols; + } + + for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) + { + coff_symbol_type *coff_symbol_ptr = coff_symbol_from(bfd_ptr, symbol_ptr_ptr[symbol_index]); + if (coff_symbol_ptr && coff_symbol_ptr->native) { + combined_entry_type *s = coff_symbol_ptr->native; + int i; + + if (s->u.syment.n_sclass == C_FILE) + { + if (last_file != (struct internal_syment *)NULL) { + last_file->n_value = native_index; + } + last_file = &(s->u.syment); + } + else { + + /* Modify the symbol values according to their section and + type */ + + fixup_symbol_value(coff_symbol_ptr, &(s->u.syment)); + } + for (i = 0; i < s->u.syment.n_numaux + 1; i++) { + s[i].offset = native_index ++; + } + } + else { + native_index++; + } + } + obj_conv_table_size (bfd_ptr) = native_index; +} + +/* + Run thorough the symbol table again, and fix it so that all pointers to + entries are changed to the entries' index in the output symbol table. + +*/ +void +DEFUN(coff_mangle_symbols,(bfd_ptr), + bfd *bfd_ptr) +{ + unsigned int symbol_count = bfd_get_symcount(bfd_ptr); + asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; + unsigned int symbol_index; + + for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) + { + coff_symbol_type *coff_symbol_ptr = + coff_symbol_from(bfd_ptr, symbol_ptr_ptr[symbol_index]); + + if (coff_symbol_ptr && coff_symbol_ptr->native) { + int i; + combined_entry_type *s = coff_symbol_ptr->native; + + for (i = 0; i < s->u.syment.n_numaux ; i++) { + combined_entry_type *a = s + i + 1; + if (a->fix_tag) { + a->u.auxent.x_sym.x_tagndx.l = + a->u.auxent.x_sym.x_tagndx.p->offset; + a->fix_tag = 0; + } + if (a->fix_end) { + a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l = + a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p->offset; + a->fix_end = 0; + + } + + } + } + } +} + +static int string_size; + +static void +DEFUN(coff_fix_symbol_name,(abfd, symbol, native), + bfd *abfd AND + asymbol *symbol AND + combined_entry_type *native) +{ + unsigned int name_length; + union internal_auxent *auxent; + char * name = ( char *)(symbol->name); + + if (name == (char *) NULL) { + /* coff symbols always have names, so we'll make one up */ + symbol->name = "strange"; + name = (char *)symbol->name; + } + name_length = strlen(name); + + if (native->u.syment.n_sclass == C_FILE) { + strncpy(native->u.syment._n._n_name, ".file", SYMNMLEN); + auxent = &(native+1)->u.auxent; + + if (bfd_coff_long_filenames (abfd)) { + if (name_length <= FILNMLEN) { + strncpy(auxent->x_file.x_fname, name, FILNMLEN); + } + else { + auxent->x_file.x_n.x_offset = string_size + 4; + auxent->x_file.x_n.x_zeroes = 0; + string_size += name_length + 1; + } + } + else { + strncpy(auxent->x_file.x_fname, name, FILNMLEN); + if (name_length > FILNMLEN) { + name[FILNMLEN] = '\0'; + } + } + } + else + { /* NOT A C_FILE SYMBOL */ + if (name_length <= SYMNMLEN) { + /* This name will fit into the symbol neatly */ + strncpy(native->u.syment._n._n_name, symbol->name, SYMNMLEN); + } + else { + native->u.syment._n._n_n._n_offset = string_size + 4; + native->u.syment._n._n_n._n_zeroes = 0; + string_size += name_length + 1; + } + } +} + +#define set_index(symbol, idx) ((symbol)->udata =(PTR) (idx)) + +static unsigned int +DEFUN(coff_write_symbol,(abfd, symbol, native, written), +bfd *abfd AND +asymbol *symbol AND +combined_entry_type *native AND +unsigned int written) +{ + unsigned int numaux = native->u.syment.n_numaux; + int type = native->u.syment.n_type; + int class = native->u.syment.n_sclass; + PTR buf; + bfd_size_type symesz; + + /* @@ bfd_debug_section isn't accessible outside this file, but we know + that C_FILE symbols belong there. So move them. */ + if (native->u.syment.n_sclass == C_FILE) + symbol->section = &bfd_debug_section; + + if (symbol->section == &bfd_abs_section) + { + native->u.syment.n_scnum = N_ABS; + } + else if (symbol->section == &bfd_debug_section) + { + native->u.syment.n_scnum = N_DEBUG; + } + else if (symbol->section == &bfd_und_section) + { + native->u.syment.n_scnum = N_UNDEF; + } + else + { + native->u.syment.n_scnum = + symbol->section->output_section->target_index; + } + + + coff_fix_symbol_name(abfd, symbol, native); + + symesz = bfd_coff_symesz (abfd); + buf = bfd_alloc (abfd, symesz); + bfd_coff_swap_sym_out(abfd, &native->u.syment, buf); + bfd_write(buf, 1, symesz, abfd); + bfd_release (abfd, buf); + + if (native->u.syment.n_numaux > 0) + { + bfd_size_type auxesz; + unsigned int j; + + auxesz = bfd_coff_auxesz (abfd); + buf = bfd_alloc (abfd, auxesz); + for (j = 0; j < native->u.syment.n_numaux; j++) + { + bfd_coff_swap_aux_out(abfd, + &((native + j + 1)->u.auxent), + type, + class, + buf); + bfd_write(buf, 1, auxesz, abfd); + } + bfd_release (abfd, buf); + } + /* + Reuse somewhere in the symbol to keep the index + */ + set_index(symbol, written); + return written + 1 + numaux; +} + + +static unsigned int +DEFUN(coff_write_alien_symbol,(abfd, symbol, written), + bfd *abfd AND + asymbol *symbol AND + unsigned int written) +{ + /* + This symbol has been created by the loader, or come from a non + coff format. It has no native element to inherit, make our + own + */ + combined_entry_type *native; + combined_entry_type dummy; + native = &dummy; + native->u.syment.n_type = T_NULL; + native->u.syment.n_flags = 0; + if (symbol->section == &bfd_und_section) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + } + else if (symbol->section == &bfd_com_section) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + + } + + else if (symbol->flags & BSF_DEBUGGING) { + /* + remove name so it doesn't take up any space + */ + symbol->name = ""; + } + else { + native->u.syment.n_scnum = symbol->section->output_section->target_index; + native->u.syment.n_value = symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset; + /* Copy the any flags from the the file hdr into the symbol */ + { + coff_symbol_type *c = coff_symbol_from(abfd, symbol); + if (c != (coff_symbol_type *)NULL) { + native->u.syment.n_flags = bfd_asymbol_bfd(&c->symbol)->flags; + } + } + } + + native->u.syment.n_type = 0; + if (symbol->flags & BSF_LOCAL) + native->u.syment.n_sclass = C_STAT; + else + native->u.syment.n_sclass = C_EXT; + native->u.syment.n_numaux = 0; + + return coff_write_symbol(abfd, symbol, native, written); +} + +static unsigned int +DEFUN(coff_write_native_symbol,(abfd, symbol, written), +bfd *abfd AND +coff_symbol_type *symbol AND +unsigned int written) +{ + /* + Does this symbol have an ascociated line number - if so then + make it remember this symbol index. Also tag the auxent of + this symbol to point to the right place in the lineno table + */ + combined_entry_type *native = symbol->native; + + alent *lineno = symbol->lineno; + + if (lineno && !symbol->done_lineno) { + unsigned int count = 0; + lineno[count].u.offset = written; + if (native->u.syment.n_numaux) { + union internal_auxent *a = &((native+1)->u.auxent); + + a->x_sym.x_fcnary.x_fcn.x_lnnoptr = + symbol->symbol.section->output_section->moving_line_filepos; + } + /* + And count and relocate all other linenumbers + */ + + count++; + while (lineno[count].line_number) { +#if 0 +/* 13 april 92. sac +I've been told this, but still need proof: +> The second bug is also in `bfd/coffcode.h'. This bug causes the linker to screw +> up the pc-relocations for all the line numbers in COFF code. This bug isn't +> only specific to A29K implementations, but affects all systems using COFF +> format binaries. Note that in COFF object files, the line number core offsets +> output by the assembler are relative to the start of each procedure, not +> to the start of the .text section. This patch relocates the line numbers +> relative to the `native->u.syment.n_value' instead of the section virtual +> address. modular!olson@cs.arizona.edu (Jon Olson) +*/ + lineno[count].u.offset += native->u.syment.n_value; + +#else + lineno[count].u.offset += + symbol->symbol.section->output_section->vma + + symbol->symbol.section->output_offset; +#endif + count++; + } + symbol->done_lineno = true; + + symbol->symbol.section->output_section->moving_line_filepos += + count * bfd_coff_linesz (abfd); + } + return coff_write_symbol(abfd, &( symbol->symbol), native,written); +} + +void +DEFUN(coff_write_symbols,(abfd), + bfd *abfd) +{ + unsigned int i; + unsigned int limit = bfd_get_symcount(abfd); + unsigned int written = 0; + + asymbol **p; + + string_size = 0; + + + /* Seek to the right place */ + bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET); + + /* Output all the symbols we have */ + + written = 0; + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) + { + asymbol *symbol = *p; + coff_symbol_type *c_symbol = coff_symbol_from(abfd, symbol); + + if (c_symbol == (coff_symbol_type *) NULL || + c_symbol->native == (combined_entry_type *)NULL) + { + written = coff_write_alien_symbol(abfd, symbol, written); + } + else + { + written = coff_write_native_symbol(abfd, c_symbol, written); + } + + } + + bfd_get_symcount(abfd) = written; + + /* Now write out strings */ + + if (string_size != 0) + { + unsigned int size = string_size + 4; + bfd_byte buffer[4]; + + bfd_h_put_32(abfd, size, buffer); + bfd_write((PTR) buffer, 1, sizeof(buffer), abfd); + for (p = abfd->outsymbols, i = 0; + i < limit; + i++, p++) + { + asymbol *q = *p; + size_t name_length = strlen(q->name); + int maxlen; + coff_symbol_type* c_symbol = coff_symbol_from(abfd, q); + maxlen = ((c_symbol != NULL && c_symbol->native != NULL) && + (c_symbol->native->u.syment.n_sclass == C_FILE)) ? + FILNMLEN : SYMNMLEN; + + if (name_length > maxlen) { + bfd_write((PTR) (q->name), 1, name_length + 1, abfd); + } + } + } + else { + /* We would normally not write anything here, but we'll write + out 4 so that any stupid coff reader which tries to read + the string table even when there isn't one won't croak. + */ + + uint32e_type size = 4; + size = size; + bfd_write((PTR)&size, 1, sizeof(size), abfd); + + } +} + +void +DEFUN(coff_write_linenumbers,(abfd), + bfd *abfd) +{ + asection *s; + bfd_size_type linesz; + PTR buff; + + linesz = bfd_coff_linesz (abfd); + buff = bfd_alloc (abfd, linesz); + for (s = abfd->sections; s != (asection *) NULL; s = s->next) { + if (s->lineno_count) { + asymbol **q = abfd->outsymbols; + bfd_seek(abfd, s->line_filepos, SEEK_SET); + /* Find all the linenumbers in this section */ + while (*q) { + asymbol *p = *q; + alent *l = + BFD_SEND(bfd_asymbol_bfd(p), _get_lineno, (bfd_asymbol_bfd(p), p)); + if (l) { + /* Found a linenumber entry, output */ + struct internal_lineno out; + memset( (PTR)&out, 0, sizeof(out)); + out.l_lnno = 0; + out.l_addr.l_symndx = l->u.offset; + bfd_coff_swap_lineno_out(abfd, &out, buff); + bfd_write(buff, 1, linesz, abfd); + l++; + while (l->line_number) { + out.l_lnno = l->line_number; + out.l_addr.l_symndx = l->u.offset; + bfd_coff_swap_lineno_out(abfd, &out, buff); + bfd_write(buff, 1, linesz, abfd); + l++; + } + } + q++; + } + } + } + bfd_release (abfd, buff); +} + +alent * +DEFUN(coff_get_lineno,(ignore_abfd, symbol), + bfd *ignore_abfd AND + asymbol *symbol) +{ + return coffsymbol(symbol)->lineno; +} + +asymbol * +coff_section_symbol (abfd, name) + bfd *abfd; + char *name; +{ + asection *sec = bfd_make_section_old_way (abfd, name); + asymbol *sym; + combined_entry_type *csym; + + sym = sec->symbol; + if (coff_symbol_from (abfd, sym)) + csym = coff_symbol_from (abfd, sym)->native; + else + csym = 0; + /* Make sure back-end COFF stuff is there. */ + if (csym == 0) + { + struct foo { + coff_symbol_type sym; + /* @@FIXME This shouldn't use a fixed size!! */ + combined_entry_type e[10]; + }; + struct foo *f; + f = (struct foo *) bfd_alloc_by_size_t (abfd, sizeof (*f)); + memset ((char *) f, 0, sizeof (*f)); + coff_symbol_from (abfd, sym)->native = csym = f->e; + } + csym[0].u.syment.n_sclass = C_STAT; + csym[0].u.syment.n_numaux = 1; +/* SF_SET_STATICS (sym); @@ ??? */ + if (sec) + { + csym[1].u.auxent.x_scn.x_scnlen = sec->_raw_size; + csym[1].u.auxent.x_scn.x_nreloc = sec->reloc_count; + csym[1].u.auxent.x_scn.x_nlinno = sec->lineno_count; + } + else + { + csym[1].u.auxent.x_scn.x_scnlen = 0; + csym[1].u.auxent.x_scn.x_nreloc = 0; + csym[1].u.auxent.x_scn.x_nlinno = 0; + } + return sym; +} + +/* This function transforms the offsets into the symbol table into + pointers to syments. */ + +static void +DEFUN(coff_pointerize_aux,(abfd, table_base, type, class, auxent), +bfd *abfd AND +combined_entry_type *table_base AND +int type AND +int class AND +combined_entry_type *auxent) +{ + /* Don't bother if this is a file or a section */ + if (class == C_STAT && type == T_NULL) return; + if (class == C_FILE) return; + + /* Otherwise patch up */ +#define N_TMASK coff_data (abfd)->local_n_tmask +#define N_BTSHFT coff_data (abfd)->local_n_btshft + if (ISFCN(type) || ISTAG(class) || class == C_BLOCK) { + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = table_base + + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l; + auxent->fix_end = 1; + } + /* A negative tagndx is meaningless, but the SCO 3.2v4 cc can + generate one, so we must be careful to ignore it. */ + if (auxent->u.auxent.x_sym.x_tagndx.l > 0) { + auxent->u.auxent.x_sym.x_tagndx.p = + table_base + auxent->u.auxent.x_sym.x_tagndx.l; + auxent->fix_tag = 1; + } +} + +static char * +DEFUN(build_string_table,(abfd), +bfd *abfd) +{ + char string_table_size_buffer[4]; + unsigned int string_table_size; + char *string_table; + + /* At this point we should be "seek"'d to the end of the + symbols === the symbol table size. */ + if (bfd_read((char *) string_table_size_buffer, + sizeof(string_table_size_buffer), + 1, abfd) != sizeof(string_table_size)) { + bfd_error = system_call_error; + return (NULL); + } /* on error */ + + string_table_size = bfd_h_get_32(abfd, (bfd_byte *) string_table_size_buffer); + + if ((string_table = (PTR) bfd_alloc(abfd, string_table_size -= 4)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on mallocation error */ + if (bfd_read(string_table, string_table_size, 1, abfd) != string_table_size) { + bfd_error = system_call_error; + return (NULL); + } + return string_table; +} + +/* Allocate space for the ".debug" section, and read it. + We did not read the debug section until now, because + we didn't want to go to the trouble until someone needed it. */ + +static char * +DEFUN(build_debug_section,(abfd), + bfd *abfd) +{ + char *debug_section; + long position; + + asection *sect = bfd_get_section_by_name (abfd, ".debug"); + + if (!sect) { + bfd_error = no_debug_section; + return NULL; + } + + debug_section = (PTR) bfd_alloc (abfd, + bfd_get_section_size_before_reloc (sect)); + if (debug_section == NULL) { + bfd_error = no_memory; + return NULL; + } + + /* Seek to the beginning of the `.debug' section and read it. + Save the current position first; it is needed by our caller. + Then read debug section and reset the file pointer. */ + + position = bfd_tell (abfd); + bfd_seek (abfd, sect->filepos, SEEK_SET); + if (bfd_read (debug_section, + bfd_get_section_size_before_reloc (sect), 1, abfd) + != bfd_get_section_size_before_reloc(sect)) { + bfd_error = system_call_error; + return NULL; + } + bfd_seek (abfd, position, SEEK_SET); + return debug_section; +} + + +/* Return a pointer to a malloc'd copy of 'name'. 'name' may not be + \0-terminated, but will not exceed 'maxlen' characters. The copy *will* + be \0-terminated. */ +static char * +DEFUN(copy_name,(abfd, name, maxlen), + bfd *abfd AND + char *name AND + int maxlen) +{ + int len; + char *newname; + + for (len = 0; len < maxlen; ++len) { + if (name[len] == '\0') { + break; + } + } + + if ((newname = (PTR) bfd_alloc(abfd, len+1)) == NULL) { + bfd_error = no_memory; + return (NULL); + } + strncpy(newname, name, len); + newname[len] = '\0'; + return newname; +} + +/* Read a symbol table into freshly bfd_allocated memory, swap it, and + knit the symbol names into a normalized form. By normalized here I + mean that all symbols have an n_offset pointer that points to a null- + terminated string. */ + +combined_entry_type * +DEFUN(coff_get_normalized_symtab,(abfd), +bfd *abfd) +{ + combined_entry_type *internal; + combined_entry_type *internal_ptr; + combined_entry_type *symbol_ptr; + combined_entry_type *internal_end; + bfd_size_type symesz; + PTR raw; + char *raw_src; + char *raw_end; + char *string_table = NULL; + char *debug_section = NULL; + unsigned long size; + + unsigned int raw_size; + if (obj_raw_syments(abfd) != (combined_entry_type *)NULL) { + return obj_raw_syments(abfd); + } + if ((size = bfd_get_symcount(abfd) * sizeof(combined_entry_type)) == 0) { + bfd_error = no_symbols; + return (NULL); + } + + internal = (combined_entry_type *)bfd_alloc(abfd, size); + internal_end = internal + bfd_get_symcount(abfd); + + symesz = bfd_coff_symesz (abfd); + raw_size = bfd_get_symcount(abfd) * symesz; + raw = bfd_alloc(abfd,raw_size); + + if (bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET) == -1 + || bfd_read(raw, raw_size, 1, abfd) != raw_size) { + bfd_error = system_call_error; + return (NULL); + } + /* mark the end of the symbols */ + raw_end = (char *) raw + bfd_get_symcount(abfd) * symesz; + /* + FIXME SOMEDAY. A string table size of zero is very weird, but + probably possible. If one shows up, it will probably kill us. + */ + + /* Swap all the raw entries */ + for (raw_src = (char *) raw, internal_ptr = internal; + raw_src < raw_end; + raw_src += symesz, internal_ptr++) { + + unsigned int i; + bfd_coff_swap_sym_in(abfd, (PTR)raw_src, (PTR)&internal_ptr->u.syment); + internal_ptr->fix_tag = 0; + internal_ptr->fix_end = 0; + symbol_ptr = internal_ptr; + + for (i = 0; + i < symbol_ptr->u.syment.n_numaux; + i++) + { + internal_ptr++; + raw_src += symesz; + + internal_ptr->fix_tag = 0; + internal_ptr->fix_end = 0; + bfd_coff_swap_aux_in(abfd, (PTR) raw_src, + symbol_ptr->u.syment.n_type, + symbol_ptr->u.syment.n_sclass, + &(internal_ptr->u.auxent)); + /* Remember that bal entries arn't pointerized */ + if (i != 1 || symbol_ptr->u.syment.n_sclass != C_LEAFPROC) + { + + coff_pointerize_aux(abfd, + internal, + symbol_ptr->u.syment.n_type, + symbol_ptr->u.syment.n_sclass, + internal_ptr); + } + + } + } + + /* Free all the raw stuff */ + bfd_release(abfd, raw); + + for (internal_ptr = internal; internal_ptr < internal_end; + internal_ptr ++) + { + if (internal_ptr->u.syment.n_sclass == C_FILE) { + /* make a file symbol point to the name in the auxent, since + the text ".file" is redundant */ + if ((internal_ptr+1)->u.auxent.x_file.x_n.x_zeroes == 0) { + /* the filename is a long one, point into the string table */ + if (string_table == NULL) { + string_table = build_string_table(abfd); + } + + internal_ptr->u.syment._n._n_n._n_offset = + (int) (string_table - 4 + + (internal_ptr+1)->u.auxent.x_file.x_n.x_offset); + } + else { + /* ordinary short filename, put into memory anyway */ + internal_ptr->u.syment._n._n_n._n_offset = (int) + copy_name(abfd, (internal_ptr+1)->u.auxent.x_file.x_fname, + FILNMLEN); + } + } + else { + if (internal_ptr->u.syment._n._n_n._n_zeroes != 0) { + /* This is a "short" name. Make it long. */ + unsigned long i = 0; + char *newstring = NULL; + + /* find the length of this string without walking into memory + that isn't ours. */ + for (i = 0; i < 8; ++i) { + if (internal_ptr->u.syment._n._n_name[i] == '\0') { + break; + } /* if end of string */ + } /* possible lengths of this string. */ + + if ((newstring = (PTR) bfd_alloc(abfd, ++i)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + memset(newstring, 0, i); + strncpy(newstring, internal_ptr->u.syment._n._n_name, i-1); + internal_ptr->u.syment._n._n_n._n_offset = (int) newstring; + internal_ptr->u.syment._n._n_n._n_zeroes = 0; + } + else if (!bfd_coff_symname_in_debug(abfd, &internal_ptr->u.syment)) { + /* Long name already. Point symbol at the string in the table. */ + if (string_table == NULL) { + string_table = build_string_table(abfd); + } + internal_ptr->u.syment._n._n_n._n_offset = (int) + (string_table - 4 + internal_ptr->u.syment._n._n_n._n_offset); + } + else { + /* Long name in debug section. Very similar. */ + if (debug_section == NULL) { + debug_section = build_debug_section(abfd); + } + internal_ptr->u.syment._n._n_n._n_offset = (int) + (debug_section + internal_ptr->u.syment._n._n_n._n_offset); + } + } + internal_ptr += internal_ptr->u.syment.n_numaux; + } + + obj_raw_syments(abfd) = internal; + + return (internal); +} /* coff_get_normalized_symtab() */ + +unsigned int +DEFUN (coff_get_reloc_upper_bound, (abfd, asect), + bfd *abfd AND + sec_ptr asect) +{ + if (bfd_get_format(abfd) != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + return (asect->reloc_count + 1) * sizeof(arelent *); +} + +asymbol * +DEFUN (coff_make_empty_symbol, (abfd), + bfd *abfd) +{ + coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type)); + if (new == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + new->symbol.section = 0; + new->native = 0; + new->lineno = (alent *) NULL; + new->done_lineno = false; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +asymbol * +DEFUN (coff_make_debug_symbol, (abfd, ptr, sz), + bfd *abfd AND + PTR ptr AND + unsigned long sz) +{ + coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type)); + if (new == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + /* @@ This shouldn't be using a constant multiplier. */ + new->native = (combined_entry_type *) bfd_zalloc (abfd, sizeof (combined_entry_type) * 10); + new->symbol.section = &bfd_debug_section; + new->lineno = (alent *) NULL; + new->done_lineno = false; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +void +DEFUN(coff_print_symbol,(abfd, filep, symbol, how), + bfd *abfd AND + PTR filep AND + asymbol *symbol AND + bfd_print_symbol_type how) +{ + FILE *file = (FILE *)filep; + switch (how) { + case bfd_print_symbol_name: + fprintf(file, "%s", symbol->name); + break; + case bfd_print_symbol_more: + fprintf(file, "coff %lx %lx", (unsigned long) coffsymbol(symbol)->native, + (unsigned long) coffsymbol(symbol)->lineno); + break; + case bfd_print_symbol_nm: + + { + CONST char *section_name = symbol->section->name; + bfd_print_symbol_vandf((PTR) file, symbol); + + + fprintf(file, " %-5s %s %s %s", + section_name, + coffsymbol(symbol)->native ? "n" : "g", + coffsymbol(symbol)->lineno ? "l" : " ", + symbol->name); + } + + + break; + case bfd_print_symbol_all: + /* Print out the symbols in a reasonable way */ + { + CONST char *section_name = symbol->section->name; + + + if (coffsymbol(symbol)->native) + { + unsigned int aux; + combined_entry_type *combined = coffsymbol(symbol)->native; + combined_entry_type *root = obj_raw_syments(abfd); + + fprintf(file,"[%3d]", + combined - root); + + + fprintf(file, "(sc %2d)(fl%4x)(ty%3x)(sc%3d) nx(%d) %08x %s", + combined->u.syment.n_scnum, + combined->u.syment.n_flags, + combined->u.syment.n_type, + combined->u.syment.n_sclass, + combined->u.syment.n_numaux, + combined->u.syment.n_value, + symbol->name + ); + for (aux = 0; aux < combined->u.syment.n_numaux; aux++) + { + fprintf(file,"\n"); + switch (combined->u.syment.n_sclass) { + case C_FILE: + fprintf(file, "File "); + break; + default: + fprintf(file, "AUX lnno %x size %x tagndx %x", + combined[aux+1].u.auxent.x_sym.x_misc.x_lnsz.x_lnno, + combined[aux+1].u.auxent.x_sym.x_misc.x_lnsz.x_size, + combined[aux+1].u.auxent.x_sym.x_tagndx.l); + break; + + } + + } + + { + struct lineno_cache_entry *l = coffsymbol(symbol)->lineno; + if (l) + { + printf("\n%s :", l->u.sym->name); + l++; + while (l->line_number) + { + printf("\n%4d : %x", + l->line_number, + l->u.offset); + l++; + + } + } + } + + + + } + + else { + bfd_print_symbol_vandf((PTR) file, symbol); + fprintf(file, " %-5s %s %s %s", + section_name, + coffsymbol(symbol)->native ? "n" : "g", + coffsymbol(symbol)->lineno ? "l" : " ", + symbol->name); + } + + } + + } +} + +/* Provided a BFD, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. */ + +boolean +DEFUN(coff_find_nearest_line,(abfd, + section, + ignore_symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr), + bfd *abfd AND + asection *section AND + asymbol **ignore_symbols AND + bfd_vma offset AND + CONST char **filename_ptr AND + CONST char **functionname_ptr AND + unsigned int *line_ptr) +{ + static bfd *cache_abfd; + static asection *cache_section; + static bfd_vma cache_offset; + static unsigned int cache_i; + static alent *cache_l; + + unsigned int i = 0; + coff_data_type *cof = coff_data(abfd); + /* Run through the raw syments if available */ + combined_entry_type *p; + alent *l; + unsigned int line_base = 0; + + + *filename_ptr = 0; + *functionname_ptr = 0; + *line_ptr = 0; + + /* Don't try and find line numbers in a non coff file */ + if (abfd->xvec->flavour != bfd_target_coff_flavour) + return false; + + if (cof == NULL) + return false; + + p = cof->raw_syments; + + for (i = 0; i < cof->raw_syment_count; i++) { + if (p->u.syment.n_sclass == C_FILE) { + /* File name has been moved into symbol */ + *filename_ptr = (char *) p->u.syment._n._n_n._n_offset; + break; + } + p += 1 + p->u.syment.n_numaux; + } + /* Now wander though the raw linenumbers of the section */ + /* + If this is the same BFD as we were previously called with and this is + the same section, and the offset we want is further down then we can + prime the lookup loop + */ + if (abfd == cache_abfd && + section == cache_section && + offset >= cache_offset) { + i = cache_i; + l = cache_l; + } + else { + i = 0; + l = section->lineno; + } + + for (; i < section->lineno_count; i++) { + if (l->line_number == 0) { + /* Get the symbol this line number points at */ + coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym); + *functionname_ptr = coff->symbol.name; + if (coff->native) { + combined_entry_type *s = coff->native; + s = s + 1 + s->u.syment.n_numaux; + /* + S should now point to the .bf of the function + */ + if (s->u.syment.n_numaux) { + /* + The linenumber is stored in the auxent + */ + union internal_auxent *a = &((s + 1)->u.auxent); + line_base = a->x_sym.x_misc.x_lnsz.x_lnno; + } + } + } + else { + if (l->u.offset > offset) + break; + *line_ptr = l->line_number + line_base + 1; + } + l++; + } + + cache_abfd = abfd; + cache_section = section; + cache_offset = offset; + cache_i = i; + cache_l = l; + + return true; +} + +int +DEFUN(coff_sizeof_headers,(abfd, reloc), + bfd *abfd AND + boolean reloc) +{ + size_t size; + + if (reloc == false) { + size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); + } + else { + size = bfd_coff_filhsz (abfd); + } + + size += abfd->section_count * bfd_coff_scnhsz (abfd); + return size; +} |