X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fecofflink.c;h=25b67fab2592a31ee5d6b6bb74dcb0cc31edeed6;hb=fd885f3a4d85dc33d794ca359ea91f31e3082717;hp=2ff5d1b2067dae84119dc5bb1ff62bc8c45f7869;hpb=b34976b65aea8f33690229600bbf4527ec3118e1;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/ecofflink.c b/bfd/ecofflink.c index 2ff5d1b206..25b67fab25 100644 --- a/bfd/ecofflink.c +++ b/bfd/ecofflink.c @@ -1,26 +1,27 @@ /* Routines to link ECOFF debugging information. - Copyright 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002 - Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support, . -This file is part of BFD, the Binary File Descriptor library. + 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 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 3 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. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + 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., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "libbfd.h" #include "objalloc.h" @@ -501,8 +502,8 @@ bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info) ainfo = (struct accumulate *) bfd_malloc (amt); if (!ainfo) return NULL; - if (! bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc, - 1021)) + if (!bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc, + sizeof (struct string_hash_entry), 1021)) return NULL; ainfo->line = NULL; @@ -526,9 +527,10 @@ bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info) ainfo->largest_file_shuffle = 0; - if (! info->relocateable) + if (! info->relocatable) { - if (! bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc)) + if (!bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc, + sizeof (struct string_hash_entry))) return NULL; /* The first entry in the string table is the empty string. */ @@ -559,7 +561,7 @@ bfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info) bfd_hash_table_free (&ainfo->fdr_hash.table); - if (! info->relocateable) + if (! info->relocatable) bfd_hash_table_free (&ainfo->str_hash.table); objalloc_free (ainfo->memory); @@ -716,7 +718,8 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, lookup = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 20); if (lookup == NULL) return FALSE; - sprintf (lookup, "%s %lx %lx", name, fdr.csym, fdr.caux); + sprintf (lookup, "%s %lx %lx", name, (unsigned long) fdr.csym, + (unsigned long) fdr.caux); fh = string_hash_lookup (&ainfo->fdr_hash, lookup, TRUE, TRUE); free (lookup); @@ -781,7 +784,6 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, fdr_ptr += fdr_add, i++) { FDR fdr; - bfd_vma fdr_adr; bfd_byte *sym_out; bfd_byte *lraw_src; bfd_byte *lraw_end; @@ -798,22 +800,6 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, else (*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr); - fdr_adr = fdr.adr; - - /* Adjust the FDR address for any changes that may have been - made by relaxing. */ - if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) - { - struct ecoff_value_adjust *adjust; - - for (adjust = input_debug->adjust; - adjust != (struct ecoff_value_adjust *) NULL; - adjust = adjust->next) - if (fdr_adr >= adjust->start - && fdr_adr < adjust->end) - fdr.adr += adjust->adjust; - } - /* FIXME: It is conceivable that this FDR points to the .init or .fini section, in which case this will not do the right thing. */ @@ -856,19 +842,6 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, case stLabel: case stProc: case stStaticProc: - if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) - { - bfd_vma value; - struct ecoff_value_adjust *adjust; - - value = internal_sym.value; - for (adjust = input_debug->adjust; - adjust != (struct ecoff_value_adjust *) NULL; - adjust = adjust->next) - if (value >= adjust->start - && value < adjust->end) - internal_sym.value += adjust->adjust; - } internal_sym.value += section_adjust[internal_sym.sc]; break; @@ -879,9 +852,9 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, /* 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 + this when performing a relocatable link because it would prevent us from easily merging different FDR's. */ - if (! info->relocateable) + if (! info->relocatable) { bfd_boolean ffilename; const char *name; @@ -958,7 +931,7 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, fdr.iauxBase = output_symhdr->iauxMax; output_symhdr->iauxMax += fdr.caux; } - if (! info->relocateable) + if (! info->relocatable) { /* When are are hashing strings, we lie about the number of @@ -978,9 +951,8 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, output_symhdr->issMax += fdr.cbSs; } - if ((output_bfd->xvec->header_byteorder - == input_bfd->xvec->header_byteorder) - && input_debug->adjust == (struct ecoff_value_adjust *) NULL) + if (output_bfd->xvec->header_byteorder + == input_bfd->xvec->header_byteorder) { /* The two BFD's have the same endianness, and we don't have to adjust the PDR addresses, so simply copying the @@ -1036,23 +1008,6 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, PDR pdr; (*input_swap->swap_pdr_in) (input_bfd, (PTR) in, &pdr); - - /* If we have been relaxing, we may have to adjust the - address. */ - if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) - { - bfd_vma adr; - struct ecoff_value_adjust *adjust; - - adr = fdr_adr + pdr.adr; - for (adjust = input_debug->adjust; - adjust != (struct ecoff_value_adjust *) NULL; - adjust = adjust->next) - if (adr >= adjust->start - && adr < adjust->end) - pdr.adr += adjust->adjust; - } - (*output_swap->swap_pdr_out) (output_bfd, &pdr, (PTR) out); } @@ -1127,10 +1082,10 @@ ecoff_add_string (ainfo, info, debug, fdr, string) symhdr = &debug->symbolic_header; len = strlen (string); - if (info->relocateable) + if (info->relocatable) { - if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, (PTR) string, - len + 1)) + if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, + (bfd_byte *) string, len + 1)) return -1; ret = symhdr->issMax; symhdr->issMax += len + 1; @@ -1199,7 +1154,7 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, fdr.issBase = output_symhdr->issMax; fdr.cbSs = 0; fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr, - bfd_archive_filename (input_bfd)); + input_bfd->filename); if (fdr.rss == -1) return FALSE; fdr.isymBase = output_symhdr->isymMax; @@ -1252,7 +1207,7 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, } (*swap_sym_out) (output_bfd, &internal_sym, external_sym); add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, - external_sym, + (bfd_byte *) external_sym, (unsigned long) output_swap->external_sym_size); ++fdr.csym; ++output_symhdr->isymMax; @@ -1273,7 +1228,7 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, } (*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr); add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, - external_fdr, + (bfd_byte *) external_fdr, (unsigned long) output_swap->external_fdr_size); ++output_symhdr->ifdMax; @@ -1287,12 +1242,12 @@ bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, this interface, so that must be changed to do something else. */ bfd_boolean -bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr, +bfd_ecoff_debug_externals (abfd, debug, swap, relocatable, get_extr, set_index) bfd *abfd; struct ecoff_debug_info *debug; const struct ecoff_debug_swap *swap; - bfd_boolean relocateable; + bfd_boolean relocatable; bfd_boolean (*get_extr) PARAMS ((asymbol *, EXTR *)); void (*set_index) PARAMS ((asymbol *, bfd_size_type)); { @@ -1317,7 +1272,7 @@ bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr, /* If we're producing an executable, move common symbols into bss. */ - if (! relocateable) + if (! relocatable) { if (esym.asym.sc == scCommon) esym.asym.sc = scBss; @@ -1383,10 +1338,14 @@ bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym) - (char *) debug->external_ext) < (symhdr->iextMax + 1) * external_ext_size) { - if (! ecoff_add_bytes ((char **) &debug->external_ext, - (char **) &debug->external_ext_end, + char *external_ext = (char *) debug->external_ext; + char *external_ext_end = (char *) debug->external_ext_end; + if (! ecoff_add_bytes ((char **) &external_ext, + (char **) &external_ext_end, (symhdr->iextMax + 1) * (size_t) external_ext_size)) return FALSE; + debug->external_ext = external_ext; + debug->external_ext_end = external_ext_end; } esym->asym.iss = symhdr->issExtMax; @@ -1544,7 +1503,7 @@ ecoff_write_symhdr (abfd, debug, swap, where) SET (cbExtOffset, iextMax, swap->external_ext_size); #undef SET - buff = (PTR) bfd_malloc (swap->external_hdr_size); + buff = (char *) bfd_malloc (swap->external_hdr_size); if (buff == NULL && swap->external_hdr_size != 0) goto error_return; @@ -1694,7 +1653,7 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) /* The string table is written out from the hash table if this is a final link. */ - if (info->relocateable) + if (info->relocatable) { BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL); if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space)) @@ -1836,16 +1795,15 @@ mk_fdrtab (abfd, debug_info, debug_swap, line_info) fdr_start = debug_info->fdr; fdr_end = fdr_start + debug_info->symbolic_header.ifdMax; - /* First, let's see how long the table needs to be: */ + /* First, let's see how long the table needs to be. */ for (len = 0, fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) { - if (fdr_ptr->cpd == 0) /* skip FDRs that have no PDRs */ + if (fdr_ptr->cpd == 0) /* Skip FDRs that have no PDRs. */ continue; ++len; } - /* Now, create and fill in the table: */ - + /* Now, create and fill in the table. */ amt = (bfd_size_type) len * sizeof (struct ecoff_fdrtab_entry); line_info->fdrtab = (struct ecoff_fdrtab_entry*) bfd_zalloc (abfd, amt); if (line_info->fdrtab == NULL) @@ -1868,7 +1826,7 @@ mk_fdrtab (abfd, debug_info, debug_swap, line_info) SYMR sym; sym_ptr = ((char *) debug_info->external_sym - + (fdr_ptr->isymBase + 1)*debug_swap->external_sym_size); + + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size); (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss, STABS_SYMBOL) == 0) @@ -1877,23 +1835,22 @@ mk_fdrtab (abfd, debug_info, debug_swap, line_info) if (!stabs) { - bfd_size_type external_pdr_size; - char *pdr_ptr; - PDR pdr; - - external_pdr_size = debug_swap->external_pdr_size; - - pdr_ptr = ((char *) debug_info->external_pdr - + fdr_ptr->ipdFirst * external_pdr_size); - (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + /* eraxxon: There are at least two problems with this computation: + 1) PDRs do *not* contain offsets but full vma's; and typically the + address of the first PDR is the address of the FDR, which will + make (most) of the results of the original computation 0! + 2) Once in a wacky while, the Compaq compiler generated PDR + addresses do not equal the FDR vma, but they (the PDR address) + are still vma's and not offsets. Cf. comments in + 'lookup_line'. */ /* The address of the first PDR is the offset of that procedure relative to the beginning of file FDR. */ - tab->base_addr = fdr_ptr->adr - pdr.adr; + tab->base_addr = fdr_ptr->adr; } else { /* XXX I don't know about stabs, so this is a guess - (davidm@cs.arizona.edu): */ + (davidm@cs.arizona.edu). */ tab->base_addr = fdr_ptr->adr; } tab->fdr = fdr_ptr; @@ -1937,14 +1894,22 @@ fdrtab_lookup (line_info, offset) else low = mid + 1; } + + /* eraxxon: at this point 'offset' is either lower than the lowest entry or + higher than the highest entry. In the former case high = low = mid = 0; + we want to return -1. In the latter case, low = high and mid = low - 1; + we want to return the index of the highest entry. Only in former case + will the following 'catch-all' test be true. */ ++mid; - /* last entry is catch-all for all higher addresses: */ + /* Last entry is catch-all for all higher addresses. */ if (offset < tab[mid].base_addr) return -1; find_min: + /* eraxxon: There may be multiple FDRs in the table with the + same base_addr; make sure that we are at the first one. */ while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr) --mid; @@ -1967,6 +1932,7 @@ lookup_line (abfd, debug_info, debug_swap, line_info) FDR *fdr_ptr; int i; + /* eraxxon: note that 'offset' is the full vma, not a section offset. */ offset = line_info->cache.start; /* Build FDR table (sorted by object file's base-address) if we @@ -1977,10 +1943,80 @@ lookup_line (abfd, debug_info, debug_swap, line_info) tab = line_info->fdrtab; - /* find first FDR for address OFFSET */ + /* Find first FDR for address OFFSET. */ i = fdrtab_lookup (line_info, offset); if (i < 0) return FALSE; /* no FDR, no fun... */ + + /* eraxxon: 'fdrtab_lookup' doesn't give what we want, at least for Compaq's + C++ compiler 6.2. Consider three FDRs with starting addresses of x, y, + and z, respectively, such that x < y < z. Assume further that + y < 'offset' < z. It is possible at times that the PDR for 'offset' is + associated with FDR x and *not* with FDR y. Erg!! + + From a binary dump of my C++ test case 'moo' using Compaq's coffobjanl + (output format has been edited for our purposes): + + FDR [2]: (main.C): First instruction: 0x12000207c + PDR [5] for File [2]: LoopTest__Xv <0x1200020a0> (a) + PDR [7] for File [2]: foo__Xv <0x120002168> + FDR [1]: (-1): First instruction: 0x1200020e8 + PDR [3] for File [1]: <0x120001ad0> (b) + FDR [6]: (-1): First instruction: 0x1200026f0 + + (a) In the case of PDR5, the vma is such that the first few instructions + of the procedure can be found. But since the size of this procedure is + 160b, the vma will soon cross into the 'address space' of FDR1 and no + debugging info will be found. How repugnant! + + (b) It is also possible for a PDR to have a *lower* vma than its associated + FDR; see FDR1 and PDR3. Gross! + + Since the FDRs that are causing so much havok (in this case) 1) do not + describe actual files (fdr.rss == -1), and 2) contain only compiler + generated routines, I thought a simple fix would be to exclude them from + the FDR table in 'mk_fdrtab'. But, besides not knowing for certain + whether this would be correct, it creates an additional problem. If we + happen to ask for source file info on a compiler generated (procedure) + symbol -- which is still in the symbol table -- the result can be + information from a real procedure! This is because compiler generated + procedures with vma's higher than the last FDR in the fdr table will be + associated with a PDR from this FDR, specifically the PDR with the + highest vma. This wasn't a problem before, because each procedure had a + PDR. (Yes, this problem could be eliminated if we kept the size of the + last PDR around, but things are already getting ugly). + + Probably, a better solution would be to have a sorted PDR table. Each + PDR would have a pointer to its FDR so file information could still be + obtained. A FDR table could still be constructed if necessary -- since + it only contains pointers, not much extra memory would be used -- but + the PDR table would be searched to locate debugging info. + + There is still at least one remaining issue. Sometimes a FDR can have a + bogus name, but contain PDRs that should belong to another FDR with a + real name. E.g: + + FDR [3]: 0000000120001b50 (/home/.../Array.H~alt~deccxx_5E5A62AD) + PDR [a] for File [3]: 0000000120001b50 + PDR [b] for File [3]: 0000000120001cf0 + PDR [c] for File [3]: 0000000120001dc8 + PDR [d] for File [3]: 0000000120001e40 + PDR [e] for File [3]: 0000000120001eb8 + PDR [f] for File [3]: 0000000120001f4c + FDR [4]: 0000000120001b50 (/home/.../Array.H) + + Here, FDR4 has the correct name, but should (seemingly) contain PDRa-f. + The symbol table for PDR4 does contain symbols for PDRa-f, but so does + the symbol table for FDR3. However the former is different; perhaps this + can be detected easily. (I'm not sure at this point.) This problem only + seems to be associated with files with templates. I am assuming the idea + is that there is a 'fake' FDR (with PDRs) for each differently typed set + of templates that must be generated. Currently, FDR4 is completely + excluded from the FDR table in 'mk_fdrtab' because it contains no PDRs. + + Since I don't have time to prepare a real fix for this right now, be + prepared for 'A Horrible Hack' to force the inspection of all non-stabs + FDRs. It's coming... */ fdr_ptr = tab[i].fdr; /* Check whether this file has stabs debugging information. In a @@ -2006,7 +2042,7 @@ lookup_line (abfd, debug_info, debug_swap, line_info) char *pdr_ptr; char *best_pdr = NULL; FDR *best_fdr; - bfd_vma best_dist = ~(bfd_vma) 0; + bfd_signed_vma best_dist = -1; PDR pdr; unsigned char *line_ptr; unsigned char *line_end; @@ -2068,14 +2104,24 @@ lookup_line (abfd, debug_info, debug_swap, line_info) considerably, which is undesirable. */ external_pdr_size = debug_swap->external_pdr_size; - /* Make offset relative to object file's start-address: */ - offset -= tab[i].base_addr; + /* eraxxon: The Horrible Hack: Because of the problems above, set 'i' + to 0 so we look through all FDRs. + + Because FDR's without any symbols are assumed to be non-stabs, + searching through all FDRs may cause the following code to try to + read stabs FDRs as ECOFF ones. However, I don't think this will + harm anything. */ + i = 0; + /* Search FDR list starting at tab[i] for the PDR that best matches OFFSET. Normally, the FDR list is only one entry long. */ best_fdr = NULL; do { - bfd_vma dist, min_dist = 0; + /* eraxxon: 'dist' and 'min_dist' can be negative now + because we iterate over every FDR rather than just ones + with a base address less than or equal to 'offset'. */ + bfd_signed_vma dist = -1, min_dist = -1; char *pdr_hold; char *pdr_end; @@ -2098,7 +2144,10 @@ lookup_line (abfd, debug_info, debug_swap, line_info) if (offset >= (pdr.adr - 0x10 * pdr.prof)) { dist = offset - (pdr.adr - 0x10 * pdr.prof); - if (!pdr_hold || dist < min_dist) + + /* eraxxon: 'dist' can be negative now. Note that + 'min_dist' can be negative if 'pdr_hold' below is NULL. */ + if (!pdr_hold || (dist >= 0 && dist < min_dist)) { min_dist = dist; pdr_hold = pdr_ptr; @@ -2106,21 +2155,22 @@ lookup_line (abfd, debug_info, debug_swap, line_info) } } - if (!best_pdr || min_dist < best_dist) + if (!best_pdr || (min_dist >= 0 && min_dist < best_dist)) { - best_dist = min_dist; + best_dist = (bfd_vma) min_dist; best_fdr = fdr_ptr; best_pdr = pdr_hold; } - /* continue looping until base_addr of next entry is different: */ + /* Continue looping until base_addr of next entry is different. */ } - while (++i < line_info->fdrtab_len - && tab[i].base_addr == tab[i - 1].base_addr); + /* eraxxon: We want to iterate over all FDRs. + See previous comment about 'fdrtab_lookup'. */ + while (++i < line_info->fdrtab_len); if (!best_fdr || !best_pdr) - return FALSE; /* shouldn't happen... */ + return FALSE; /* Shouldn't happen... */ - /* phew, finally we got something that we can hold onto: */ + /* Phew, finally we got something that we can hold onto. */ fdr_ptr = best_fdr; pdr_ptr = best_pdr; (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); @@ -2130,7 +2180,7 @@ lookup_line (abfd, debug_info, debug_swap, line_info) number entries. */ line_end = debug_info->line + fdr_ptr->cbLineOffset + fdr_ptr->cbLine; - /* Make offset relative to procedure entry: */ + /* Make offset relative to procedure entry. */ offset -= pdr.adr - 0x10 * pdr.prof; lineno = pdr.lnLow; line_ptr = debug_info->line + fdr_ptr->cbLineOffset + pdr.cbLineOffset;