From 71efdf833f230dfdda691157f65bd9de4eb57839 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 24 Nov 1993 07:18:44 +0000 Subject: [PATCH] New file to hold ECOFF linking routines used by both ECOFF and MIPS ELF. --- bfd/.Sanitize | 1 + bfd/ecofflink.c | 829 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 830 insertions(+) create mode 100644 bfd/ecofflink.c diff --git a/bfd/.Sanitize b/bfd/.Sanitize index 05520a9..2c17e64 100644 --- a/bfd/.Sanitize +++ b/bfd/.Sanitize @@ -100,6 +100,7 @@ demo64.c dep-in.sed doc ecoff.c +ecofflink.c ecoffswap.h elf.c elf32-gen.c diff --git a/bfd/ecofflink.c b/bfd/ecofflink.c new file mode 100644 index 0000000..8882bac --- /dev/null +++ b/bfd/ecofflink.c @@ -0,0 +1,829 @@ +/* Routines to link ECOFF debugging information. + Copyright 1993 Free Software Foundation, Inc. + Written by Ian Lance Taylor, 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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#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, + bfd_size_type need)); +static bfd_size_type ecoff_add_string PARAMS ((struct ecoff_debug_info *, + FDR *fdr, const char *string)); +static void ecoff_align_debug PARAMS ((bfd *abfd, + struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap)); + +/* 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; + bfd_size_type need; +{ + bfd_size_type have; + bfd_size_type want; + 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; +} + +/* 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 + INPUT_SWAP point to the swapping information needed. */ + +boolean +bfd_ecoff_debug_accumulate (output_bfd, output_debug, output_swap, + input_bfd, input_debug, input_swap, + relocateable) + 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; + boolean relocateable; +{ + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = input_swap->swap_sym_in; + void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) + = output_swap->swap_sym_out; + void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)) + = output_swap->swap_fdr_out; + void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR)) + = output_swap->swap_rfd_out; + HDRR *output_symhdr; + HDRR *input_symhdr; + bfd_vma section_adjust[scMax]; + asection *sec; + char *sym_out; + char *lraw_src; + char *lraw_end; + char *fdr_ptr; + char *fdr_end; + bfd_size_type fdr_add; + char *fdr_out; + + output_symhdr = &output_debug->symbolic_header; + input_symhdr = &input_debug->symbolic_header; + + /* Make sure the buffers are large enough. */ +#define CHECK(start, end, count, size) \ + if ((char *) output_debug->end - (char *) output_debug->start \ + < (output_symhdr->count + input_symhdr->count) * size) \ + { \ + if (! ecoff_add_bytes ((char **) &output_debug->start, \ + (char **) &output_debug->end, \ + ((output_symhdr->count \ + + input_symhdr->count) \ + * size))) \ + return false; \ + } + + CHECK (line, line_end, cbLine, sizeof (unsigned char)); +#if 0 + /* I don't think dense number information is needed. */ + CHECK (external_dnr, external_dnr_end, idnMax, + output_swap->external_dnr_size); +#endif + CHECK (external_pdr, external_pdr_end, ipdMax, + output_swap->external_pdr_size); + CHECK (external_sym, external_sym_end, isymMax, + output_swap->external_sym_size); + CHECK (external_opt, external_opt_end, ioptMax, + output_swap->external_opt_size); + CHECK (external_aux, external_aux_end, iauxMax, + sizeof (union aux_ext)); + CHECK (ss, ss_end, issMax, sizeof (char)); + CHECK (external_fdr, external_fdr_end, ifdMax, + output_swap->external_fdr_size); + + /* The RFD's are special, since we create them if needed. */ + { + bfd_size_type crfd; + + crfd = input_symhdr->crfd; + if (input_symhdr->crfd == 0) + input_symhdr->crfd = input_symhdr->ifdMax; + CHECK (external_rfd, external_rfd_end, crfd, + output_swap->external_rfd_size); + input_symhdr->crfd = crfd; + } + +#undef CHECK + + /* 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 + + /* Swap in the local symbols, adjust their values, and swap them out + again. The external symbols are handled separately. */ + sym_out = ((char *) output_debug->external_sym + + output_symhdr->isymMax * output_swap->external_sym_size); + lraw_src = (char *) input_debug->external_sym; + lraw_end = lraw_src + input_symhdr->isymMax * 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; + } + + (*swap_sym_out) (output_bfd, &internal_sym, sym_out); + sym_out += output_swap->external_sym_size; + } + + /* Copy the information that does not need swapping. */ + memcpy (output_debug->line + output_symhdr->cbLine, + input_debug->line, + input_symhdr->cbLine * sizeof (unsigned char)); + memcpy (output_debug->external_aux + output_symhdr->iauxMax, + input_debug->external_aux, + input_symhdr->iauxMax * sizeof (union aux_ext)); + memcpy (output_debug->ss + output_symhdr->issMax, + input_debug->ss, + input_symhdr->issMax * sizeof (char)); + + /* Some of the information may need to be swapped. */ + if (output_bfd->xvec->header_byteorder_big_p + == input_bfd->xvec->header_byteorder_big_p) + { + /* The two BFD's have the same endianness, so memcpy will + suffice. */ +#if 0 + /* I don't think dense number information is needed. */ + BFD_ASSERT (output_swap->external_dnr_size + == input_swap->external_dnr_size); + if (input_symhdr->idnMax > 0) + memcpy (((char *) output_debug->external_dnr + + output_symhdr->idnMax * output_swap->external_dnr_size), + input_debug->external_dnr, + input_symhdr->idnMax * output_swap->external_dnr_size); +#endif + BFD_ASSERT (output_swap->external_pdr_size + == input_swap->external_pdr_size); + if (input_symhdr->ipdMax > 0) + memcpy (((char *) output_debug->external_pdr + + output_symhdr->ipdMax * output_swap->external_pdr_size), + input_debug->external_pdr, + input_symhdr->ipdMax * output_swap->external_pdr_size); + BFD_ASSERT (output_swap->external_opt_size + == input_swap->external_opt_size); + if (input_symhdr->ioptMax > 0) + memcpy (((char *) output_debug->external_opt + + output_symhdr->ioptMax * output_swap->external_opt_size), + input_debug->external_opt, + input_symhdr->ioptMax * output_swap->external_opt_size); + } + else + { + bfd_size_type outsz, insz; + char *in; + char *end; + char *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 slow in the normal case. */ +#if 0 + /* I don't think dense number information is needed. */ + outsz = output_swap->external_dnr_size; + insz = input_swap->external_dnr_size; + in = (char *) input_debug->external_dnr; + end = in + input_symhdr->idnMax * insz; + out = ((char *) output_debug->external_dnr + + output_symhdr->idnMax * outsz); + for (; in < end; in += insz, out += outsz) + { + DNR dnr; + + (*input_swap->swap_dnr_in) (input_bfd, in, &dnr); + (*output_swap->swap_dnr_out) (output_bfd, &dnr, out); + } +#endif + + outsz = output_swap->external_pdr_size; + insz = input_swap->external_pdr_size; + in = (char *) input_debug->external_pdr; + end = in + input_symhdr->ipdMax * insz; + out = ((char *) output_debug->external_pdr + + output_symhdr->ipdMax * outsz); + for (; in < end; in += insz, out += outsz) + { + PDR pdr; + + (*input_swap->swap_pdr_in) (input_bfd, in, &pdr); + (*output_swap->swap_pdr_out) (output_bfd, &pdr, out); + } + + outsz = output_swap->external_opt_size; + insz = input_swap->external_opt_size; + in = (char *) input_debug->external_opt; + end = in + input_symhdr->ioptMax * insz; + out = ((char *) output_debug->external_opt + + output_symhdr->ioptMax * outsz); + for (; in < end; in += insz, out += outsz) + { + OPTR opt; + + (*input_swap->swap_opt_in) (input_bfd, in, &opt); + (*output_swap->swap_opt_out) (output_bfd, &opt, out); + } + } + + /* Set ifdbase so that the external symbols know how to adjust their + ifd values. */ + input_debug->ifdbase = output_symhdr->ifdMax; + + /* We need to handle the FDR's whether they are swapped or not. */ + if (input_debug->fdr != (FDR *) NULL) + { + fdr_ptr = (char *) input_debug->fdr; + fdr_add = sizeof (FDR); + } + else + { + fdr_ptr = (char *) input_debug->external_fdr; + fdr_add = input_swap->external_fdr_size; + } + fdr_end = fdr_ptr + input_symhdr->ifdMax * fdr_add; + fdr_out = ((char *) output_debug->external_fdr + + output_symhdr->ifdMax * output_swap->external_fdr_size); + for (; + fdr_ptr < fdr_end; + fdr_ptr += fdr_add, fdr_out += output_swap->external_fdr_size) + { + FDR fdr; + + if (input_debug->fdr != (FDR *) NULL) + fdr = *(FDR *) fdr_ptr; + else + (*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr); + + /* 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]; + + fdr.issBase += output_symhdr->issMax; + fdr.isymBase += output_symhdr->isymMax; + fdr.ilineBase += output_symhdr->ilineMax; + fdr.ioptBase += output_symhdr->ioptMax; + fdr.ipdFirst += output_symhdr->ipdMax; + fdr.iauxBase += output_symhdr->iauxMax; + fdr.rfdBase += output_symhdr->crfd; + + /* If there are no RFD's, we are going to add some. We don't + want to adjust crfd for this, so that all the FDR's can share + the RFD's. */ + if (input_symhdr->crfd == 0) + fdr.crfd = input_symhdr->ifdMax; + + if (fdr.cbLine != 0) + fdr.cbLineOffset += output_symhdr->cbLine; + + (*swap_fdr_out) (output_bfd, &fdr, fdr_out); + } + + if (input_symhdr->crfd > 0) + { + void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)) + = input_swap->swap_rfd_in; + bfd_size_type outsz, insz; + char *rfd_in; + char *rfd_end; + char *rfd_out; + + /* Swap and adjust the RFD's. RFD's are only created by the + linker, so this will only be necessary if one of the input + files is the result of a partial link. Presumably all + necessary RFD's are present. */ + outsz = output_swap->external_rfd_size; + insz = input_swap->external_rfd_size; + rfd_in = (char *) input_debug->external_rfd; + rfd_end = rfd_in + input_symhdr->crfd * insz; + rfd_out = ((char *) output_debug->external_rfd + + output_symhdr->crfd * outsz); + for (; + rfd_in < rfd_end; + rfd_in += insz, rfd_out += outsz) + { + RFDT rfd; + + (*swap_rfd_in) (input_bfd, rfd_in, &rfd); + rfd += output_symhdr->ifdMax; + (*swap_rfd_out) (output_bfd, &rfd, rfd_out); + } + output_symhdr->crfd += input_symhdr->crfd; + } + else + { + bfd_size_type outsz; + char *rfd_out; + char *rfd_end; + RFDT rfd; + + /* Create RFD's. Some of the debugging information includes + relative file indices. These indices are taken as indices to + the RFD table if there is one, or to the global table if + there is not. If we did not create RFD's, we would have to + parse and adjust all the debugging information which contains + file indices. */ + outsz = output_swap->external_rfd_size; + rfd = output_symhdr->ifdMax; + rfd_out = ((char *) output_debug->external_rfd + + output_symhdr->crfd * outsz); + rfd_end = (rfd_out + input_symhdr->ifdMax * outsz); + for (; rfd_out < rfd_end; rfd_out += outsz, rfd++) + (*swap_rfd_out) (output_bfd, &rfd, rfd_out); + output_symhdr->crfd += input_symhdr->ifdMax; + } + + /* Update the counts. */ + output_symhdr->ilineMax += input_symhdr->ilineMax; + output_symhdr->cbLine += input_symhdr->cbLine; +#if 0 + /* I don't think dense number information is needed. */ + output_symhdr->idnMax += input_symhdr->idnMax; +#endif + output_symhdr->ipdMax += input_symhdr->ipdMax; + output_symhdr->isymMax += input_symhdr->isymMax; + output_symhdr->ioptMax += input_symhdr->ioptMax; + output_symhdr->iauxMax += input_symhdr->iauxMax; + output_symhdr->issMax += input_symhdr->issMax; + output_symhdr->ifdMax += input_symhdr->ifdMax; + + return true; +} + +/* Add a string to the debugging information we are accumulating. + Return the offset from the fdr string base. */ + +static bfd_size_type +ecoff_add_string (output, fdr, string) + struct ecoff_debug_info *output; + FDR *fdr; + const char *string; +{ + HDRR *symhdr; + size_t len; + bfd_size_type ret; + + symhdr = &output->symbolic_header; + len = strlen (string); + if (output->ss_end - output->ss < symhdr->issMax + len + 1) + { + if (ecoff_add_bytes (&output->ss, &output->ss_end, + symhdr->issMax + len + 1) == false) + return -1; + } + memcpy (output->ss + symhdr->issMax, string, len + 1); + ret = fdr->cbSs; + symhdr->issMax += len + 1; + fdr->cbSs += len + 1; + return ret; +} + +/* Add debugging information from a non-ECOFF file. */ + +boolean +bfd_ecoff_debug_link_other (output_bfd, output_debug, output_swap, input_bfd) + bfd *output_bfd; + struct ecoff_debug_info *output_debug; + const struct ecoff_debug_swap *output_swap; + bfd *input_bfd; +{ + 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; + + 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; + fdr.rss = ecoff_add_string (output_debug, &fdr, + bfd_get_filename (input_bfd)); + 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; + + if (((*sym_ptr)->flags & BSF_EXPORT) != 0) + continue; + memset (&internal_sym, 0, sizeof internal_sym); + internal_sym.iss = ecoff_add_string (output_debug, &fdr, + (*sym_ptr)->name); + + 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; + + if (((char *) output_debug->external_sym_end + - (char *) output_debug->external_sym) + < (output_symhdr->isymMax + 1) * output_swap->external_sym_size) + { + if (! ecoff_add_bytes ((char **) &output_debug->external_sym, + (char **) &output_debug->external_sym_end, + ((output_symhdr->isymMax + 1) + * output_swap->external_sym_size))) + return false; + } + + (*swap_sym_out) (output_bfd, &internal_sym, + ((char *) output_debug->external_sym + + (output_symhdr->isymMax + * output_swap->external_sym_size))); + ++fdr.csym; + ++output_symhdr->isymMax; + } + + bfd_release (output_bfd, (PTR) symbols); + + if (((char *) output_debug->external_fdr_end + - (char *) output_debug->external_fdr) + < (output_symhdr->ifdMax + 1) * output_swap->external_fdr_size) + { + if (! ecoff_add_bytes ((char **) &output_debug->external_fdr, + (char **) &output_debug->external_fdr_end, + ((output_symhdr->ifdMax + 1) + * output_swap->external_fdr_size))) + return false; + } + + /* 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. */ + (*output_swap->swap_fdr_out) + (output_bfd, &fdr, + ((char *) output_debug->external_fdr + + output_symhdr->ifdMax * output_swap->external_fdr_size)); + ++output_symhdr->ifdMax; + return true; +} + +/* Set up ECOFF debugging information for the external symbols. */ + +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)); +{ + 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; + 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 (debug->ssext_end - debug->ssext + < symhdr->issExtMax + strlen (sym_ptr->name) + 1) + { + if (ecoff_add_bytes ((char **) &debug->ssext, + (char **) &debug->ssext_end, + symhdr->issExtMax + strlen (sym_ptr->name) + 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; + } + + esym.asym.iss = symhdr->issExtMax; + + if (bfd_is_com_section (sym_ptr->section) + || sym_ptr->section == &bfd_und_section) + esym.asym.value = sym_ptr->value; + else + esym.asym.value = (sym_ptr->value + + sym_ptr->section->output_offset + + sym_ptr->section->output_section->vma); + + (*swap_ext_out) (abfd, &esym, + ((char *) debug->external_ext + + symhdr->iextMax * swap->external_ext_size)); + + if (set_index) + (*set_index) (sym_ptr, symhdr->iextMax); + + ++symhdr->iextMax; + + strcpy (debug->ssext + symhdr->issExtMax, sym_ptr->name); + symhdr->issExtMax += strlen (sym_ptr->name) + 1; + } + + return true; +} + +/* Align the ECOFF debugging information. */ + +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; + bfd_size_type debug_align, aux_align, add; + + /* Adjust the counts so that structures are aligned. The alignment + of ALLOC_SIZE ensures that we do not have to worry about running + off the end of the memory block when doing the memset. */ + debug_align = swap->debug_align; + aux_align = debug_align / sizeof (union aux_ext); + + add = debug_align - (symhdr->cbLine & (debug_align - 1)); + if (add != debug_align) + { + memset (debug->line + symhdr->cbLine, 0, add); + symhdr->cbLine += add; + } + + add = debug_align - (symhdr->issMax & (debug_align - 1)); + if (add != debug_align) + { + memset (debug->ss + symhdr->issMax, 0, add); + symhdr->issMax += add; + } + + add = debug_align - (symhdr->issExtMax & (debug_align - 1)); + if (add != debug_align) + { + memset (debug->ssext + symhdr->issExtMax, 0, add); + symhdr->issExtMax += add; + } + + add = aux_align - (symhdr->iauxMax & (aux_align - 1)); + if (add != aux_align) + { + memset (debug->external_aux + symhdr->iauxMax, 0, + add * sizeof (union aux_ext)); + symhdr->iauxMax += add; + } +} + +/* 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; +} + +/* 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; + 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; + +#define WRITE(ptr, count, size, offset) \ + BFD_ASSERT (symhdr->offset == 0 || bfd_tell (abfd) == symhdr->offset); \ + if (bfd_write (debug->ptr, size, symhdr->count, abfd) \ + != size * symhdr->count) \ + return false; + + WRITE (line, cbLine, sizeof (unsigned char), cbLineOffset); + WRITE (external_dnr, idnMax, swap->external_dnr_size, cbDnOffset); + WRITE (external_pdr, ipdMax, swap->external_pdr_size, cbPdOffset); + WRITE (external_sym, isymMax, swap->external_sym_size, cbSymOffset); + WRITE (external_opt, ioptMax, swap->external_opt_size, cbOptOffset); + WRITE (external_aux, iauxMax, 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; +} -- 2.7.4