X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/5e2e79f859325ef28cbc98c6704a72de847e5711..2b63dbfefd03e2c69b3592f807fa5793b1243a7f:/gdb/elfread.c diff --git a/gdb/elfread.c b/gdb/elfread.c index ada668dc40..4e1afe9bd8 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -1,5 +1,5 @@ /* Read ELF (Executable and Linking Format) object files for GDB. - Copyright (C) 1991 Free Software Foundation, Inc. + Copyright 1991, 1992 Free Software Foundation, Inc. Written by Fred Fish at Cygnus Support. This file is part of GDB. @@ -24,7 +24,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ * * * This file is still under construction. When it is complete, this * * notice will be removed. Until then, direct any questions or changes * - * to Fred Fish at Cygnus Support (fnf@cygint) * + * to Fred Fish at Cygnus Support (fnf@cygnus.com) * * * * FIXME Still needs support for shared libraries. * * FIXME Still needs support for core files. * @@ -33,23 +33,45 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ************************************************************************/ #include "defs.h" -#include "elf/common.h" -#include "elf/external.h" -#include "elf/internal.h" #include "bfd.h" +#include "libbfd.h" /* For bfd_elf_find_section */ +#include "libelf.h" #include "symtab.h" #include "symfile.h" #include "objfiles.h" +#include "buildsym.h" +#include "gdb-stabs.h" +#include "complaints.h" +#include +#include "demangle.h" -#define STREQ(a,b) (strcmp((a),(b))==0) +/* The struct elfinfo is available only during ELF symbol table and + psymtab reading. It is destroyed at the complation of psymtab-reading. + It's local to elf_symfile_read. */ struct elfinfo { - unsigned int dboffset; /* Offset to dwarf debug section */ + file_ptr dboffset; /* Offset to dwarf debug section */ unsigned int dbsize; /* Size of dwarf debug section */ - unsigned int lnoffset; /* Offset to dwarf line number section */ + file_ptr lnoffset; /* Offset to dwarf line number section */ unsigned int lnsize; /* Size of dwarf line number section */ + asection *stabsect; /* Section pointer for .stab section */ + asection *stabindexsect; /* Section pointer for .stab.index section */ }; +/* Various things we might complain about... */ + +struct complaint section_info_complaint = + {"elf/stab section information %s without a preceding file symbol", 0, 0}; + +struct complaint section_info_dup_complaint = + {"duplicated elf/stab section information for %s", 0, 0}; + +struct complaint stab_info_mismatch_complaint = + {"elf/stab section information missing for %s", 0, 0}; + +struct complaint stab_info_questionable_complaint = + {"elf/stab section information questionable for %s", 0, 0}; + static void elf_symfile_init PARAMS ((struct objfile *)); @@ -57,17 +79,24 @@ static void elf_new_init PARAMS ((struct objfile *)); static void -elf_symfile_read PARAMS ((struct objfile *, CORE_ADDR, int)); +elf_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int)); static void elf_symfile_finish PARAMS ((struct objfile *)); static void -elf_symtab_read PARAMS ((bfd *, CORE_ADDR, int, struct objfile *)); +elf_symtab_read PARAMS ((bfd *, CORE_ADDR, struct objfile *)); static void -record_minimal_symbol PARAMS ((char *, CORE_ADDR, enum minimal_symbol_type, - struct objfile *)); +free_elfinfo PARAMS ((PTR)); + +static struct section_offsets * +elf_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR)); + +static void +record_minimal_symbol_and_info PARAMS ((char *, CORE_ADDR, + enum minimal_symbol_type, char *, + struct objfile *)); static void elf_locate_sections PARAMS ((bfd *, asection *, PTR)); @@ -83,11 +112,14 @@ elf_locate_sections PARAMS ((bfd *, asection *, PTR)); knowledge of DWARF (by design, so any debugging format can be used). + We also recognize the ".stab" sections used by the Sun compilers + released with Solaris 2. + FIXME: The section names should not be hardwired strings. */ static void -elf_locate_sections (abfd, sectp, eip) - bfd *abfd; +elf_locate_sections (ignore_abfd, sectp, eip) + bfd *ignore_abfd; asection *sectp; PTR eip; { @@ -104,6 +136,14 @@ elf_locate_sections (abfd, sectp, eip) ei -> lnoffset = sectp -> filepos; ei -> lnsize = bfd_get_section_size_before_reloc (sectp); } + else if (STREQ (sectp -> name, ".stab")) + { + ei -> stabsect = sectp; + } + else if (STREQ (sectp -> name, ".stab.index")) + { + ei -> stabindexsect = sectp; + } } #if 0 /* Currently unused */ @@ -136,33 +176,16 @@ elf_interpreter (abfd) #endif -/* - -LOCAL FUNCTION - - record_minimal_symbol -- add entry to minimal symbol table - -SYNOPSIS - - static void record_minimal_symbol (char *name, CORE_ADDR address) - -DESCRIPTION - - Given a pointer to the name of a symbol that should be added to the - minimal symbol table and the address associated with that symbol, records - this information for later use in building the minimal symbol table. - - */ - static void -record_minimal_symbol (name, address, ms_type, objfile) +record_minimal_symbol_and_info (name, address, ms_type, info, objfile) char *name; CORE_ADDR address; enum minimal_symbol_type ms_type; + char *info; /* FIXME, is this really char *? */ struct objfile *objfile; { name = obsavestring (name, strlen (name), &objfile -> symbol_obstack); - prim_record_minimal_symbol (name, address, ms_type); + prim_record_minimal_symbol_and_info (name, address, ms_type, info, -1); } /* @@ -173,7 +196,7 @@ LOCAL FUNCTION SYNOPSIS - void elf_symtab_read (bfd *abfd, CORE_ADDR addr, int mainline, + void elf_symtab_read (bfd *abfd, CORE_ADDR addr, struct objfile *objfile) DESCRIPTION @@ -183,13 +206,18 @@ DESCRIPTION or not (may be shared library for example), add all the global function and data symbols to the minimal symbol table. + In stabs-in-ELF, as implemented by Sun, there are some local symbols + defined in the ELF symbol table, which can be used to locate + the beginnings of sections from each ".o" file that was linked to + form the executable objfile. We gather any such info and record it + in data structures hung off the objfile's private data. + */ static void -elf_symtab_read (abfd, addr, mainline, objfile) +elf_symtab_read (abfd, addr, objfile) bfd *abfd; CORE_ADDR addr; - int mainline; struct objfile *objfile; { unsigned int storage_needed; @@ -197,35 +225,42 @@ elf_symtab_read (abfd, addr, mainline, objfile) asymbol **symbol_table; unsigned int number_of_symbols; unsigned int i; + int index; struct cleanup *back_to; CORE_ADDR symaddr; enum minimal_symbol_type ms_type; + /* If sectinfo is nonzero, it contains section info that should end up + filed in the objfile. */ + struct stab_section_info *sectinfo = 0; + /* If filesym is nonzero, it points to a file symbol, but we haven't + seen any section info for it yet. */ + asymbol *filesym = 0; + struct dbx_symfile_info *dbx = (struct dbx_symfile_info *) + objfile->sym_private; storage_needed = get_symtab_upper_bound (abfd); if (storage_needed > 0) { - symbol_table = (asymbol **) bfd_xmalloc (storage_needed); + symbol_table = (asymbol **) xmalloc (storage_needed); back_to = make_cleanup (free, symbol_table); number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); for (i = 0; i < number_of_symbols; i++) { - sym = *symbol_table++; + sym = symbol_table[i]; /* Select global/weak symbols that are defined in a specific section. Note that bfd now puts abs symbols in their own section, so all symbols we are interested in will have a section. */ if ((sym -> flags & (BSF_GLOBAL | BSF_WEAK)) && (sym -> section != NULL)) { - symaddr = sym -> value; - /* Relocate all non-absolute symbols by base address. - FIXME: Can we eliminate the check for mainline now, - since shouldn't addr be 0 in this case? */ - if (!mainline && (sym -> section != &bfd_abs_section)) - { - symaddr += addr; - } + /* Bfd symbols are section relative. */ + symaddr = sym -> value + sym -> section -> vma; + /* Relocate all non-absolute symbols by base address. */ + if (sym -> section != &bfd_abs_section) + symaddr += addr; + /* For non-absolute symbols, use the type of the section they are relative to, to intuit text/data. Bfd provides no way of figuring this out for absolute symbols. */ @@ -239,9 +274,83 @@ elf_symtab_read (abfd, addr, mainline, objfile) } else { - ms_type = mst_unknown; + /* FIXME: Solaris2 shared libraries include lots of + odd "absolute" and "undefined" symbols, that play + hob with actions like finding what function the PC + is in. Ignore them if they aren't text or data. */ + /* ms_type = mst_unknown; */ + continue; /* Skip this symbol. */ + } + /* Pass symbol size field in via BFD. FIXME!!! */ + { + elf32_symbol_type *esym = (elf32_symbol_type *) sym; + unsigned long size = esym->internal_elf_sym.st_size; + record_minimal_symbol_and_info ((char *) sym -> name, symaddr, + ms_type, (PTR) size, objfile); + } + } + + /* See if this is a debugging symbol that helps Solaris + stabs-in-elf debugging. */ + + else if (sym->flags & BSF_FILE) + { + /* Chain any old one onto the objfile; remember new sym. */ + if (sectinfo) + { + sectinfo->next = dbx->stab_section_info; + dbx->stab_section_info = sectinfo; + sectinfo = 0; + } + filesym = sym; + } + else if ((sym->flags & BSF_LOCAL) && + (sym->section) && + (sym->section->flags & SEC_DATA) && + (sym->name)) + { + /* Named Local variable in a Data section. Check its name. */ + index = -1; + switch (sym->name[1]) + { + case 'b': + if (STREQ ("Bbss.bss", sym->name)) + index = SECT_OFF_BSS; + break; + case 'd': + if (STREQ ("Ddata.data", sym->name)) + index = SECT_OFF_DATA; + break; + case 'r': + if (STREQ ("Drodata.rodata", sym->name)) + index = SECT_OFF_RODATA; + break; + } + if (index > 0) + { + /* We have some new info. Allocate a sectinfo, if + needed, and fill it in. */ + if (!sectinfo) + { + sectinfo = (struct stab_section_info *) + xmmalloc (objfile -> md, + sizeof (*sectinfo)); + memset ((PTR) sectinfo, 0, sizeof (*sectinfo)); + if (!filesym) + complain (§ion_info_complaint, sym->name); + else + sectinfo->filename = (char *)filesym->name; + } + if (sectinfo->sections[index]) + complain (§ion_info_dup_complaint, sectinfo->filename); + + /* Bfd symbols are section relative. */ + symaddr = sym -> value + sym -> section -> vma; + /* Relocate all non-absolute symbols by base address. */ + if (sym -> section != &bfd_abs_section) + symaddr += addr; + sectinfo->sections[index] = symaddr; } - record_minimal_symbol ((char *) sym -> name, symaddr, ms_type, objfile); } } do_cleanups (back_to); @@ -252,8 +361,9 @@ elf_symtab_read (abfd, addr, mainline, objfile) We have been initialized by a call to elf_symfile_init, which currently does nothing. - ADDR is the address relative to which the symbols in it are (e.g. - the base address of the text segment). + SECTION_OFFSETS is a set of offsets to apply to relocate the symbols + in each section. We simplify it down to a single offset for all + symbols. FIXME. MAINLINE is true if we are reading the main symbol table (as opposed to a shared lib or dynamically loaded file). @@ -264,45 +374,83 @@ elf_symtab_read (abfd, addr, mainline, objfile) symbol tables. When more extensive information is requested of a file, the corresponding partial symbol table is mutated into a full fledged symbol table by going back and reading the symbols - for real. The function dwarf_psymtab_to_symtab() is the function that - does this for DWARF symbols. + for real. + + We look for sections with specific names, to tell us what debug + format to look for: FIXME!!! + + dwarf_build_psymtabs() builds psymtabs for DWARF symbols; + elfstab_build_psymtabs() handles STABS symbols. Note that ELF files have a "minimal" symbol table, which looks a lot like a COFF symbol table, but has only the minimal information necessary - for linking. We process this also, and just use the information to - add to gdb's minimal symbol table. This gives us some minimal debugging - capability even for files compiled without -g. - */ + for linking. We process this also, and use the information to + build gdb's minimal symbol table. This gives us some minimal debugging + capability even for files compiled without -g. */ static void -elf_symfile_read (objfile, addr, mainline) +elf_symfile_read (objfile, section_offsets, mainline) struct objfile *objfile; - CORE_ADDR addr; + struct section_offsets *section_offsets; int mainline; { bfd *abfd = objfile->obfd; struct elfinfo ei; struct cleanup *back_to; + CORE_ADDR offset; init_minimal_symbol_collection (); back_to = make_cleanup (discard_minimal_symbols, 0); - /* Process the normal ELF symbol table first. */ + memset ((char *) &ei, 0, sizeof (ei)); - elf_symtab_read (abfd, addr, mainline, objfile); + /* Allocate struct to keep track of the symfile */ + objfile->sym_private = (PTR) + xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info)); + memset ((char *) objfile->sym_private, 0, sizeof (struct dbx_symfile_info)); + make_cleanup (free_elfinfo, (PTR) objfile); - /* Now process the DWARF debugging information, which is contained in + /* Process the normal ELF symbol table first. This may write some + chain of info into the dbx_symfile_info in objfile->sym_private, + which can later be used by elfstab_offset_sections. */ + + /* FIXME, should take a section_offsets param, not just an offset. */ + offset = ANOFFSET (section_offsets, 0); + elf_symtab_read (abfd, offset, objfile); + + /* Now process debugging information, which is contained in special ELF sections. We first have to find them... */ - (void) memset ((char *) &ei, 0, sizeof (ei)); bfd_map_over_sections (abfd, elf_locate_sections, (PTR) &ei); if (ei.dboffset && ei.lnoffset) { - dwarf_build_psymtabs (fileno ((FILE *)(abfd -> iostream)), - bfd_get_filename (abfd), - addr, mainline, + /* DWARF sections */ + dwarf_build_psymtabs (objfile, + section_offsets, mainline, ei.dboffset, ei.dbsize, - ei.lnoffset, ei.lnsize, objfile); + ei.lnoffset, ei.lnsize); + } + if (ei.stabsect) + { + /* STABS sections */ + + /* FIXME: Sun didn't really know how to implement this well. + They made .stab sections that don't point to the .stabstr + section with the sh_link field. BFD doesn't make string table + sections visible to the caller. So we have to search the + ELF section table, not the BFD section table, for the string + table. */ + struct elf32_internal_shdr *elf_sect; + + elf_sect = bfd_elf32_find_section (abfd, ".stabstr"); + if (elf_sect) + elfstab_build_psymtabs (objfile, + section_offsets, + mainline, + ei.stabsect->filepos, /* .stab offset */ + bfd_get_section_size_before_reloc (ei.stabsect),/* .stab size */ + (file_ptr) elf_sect->sh_offset, /* .stabstr offset */ + elf_sect->sh_size); /* .stabstr size */ } if (!have_partial_symbols ()) @@ -320,17 +468,41 @@ elf_symfile_read (objfile, addr, mainline) do_cleanups (back_to); } +/* This cleans up the objfile's sym_private pointer, and the chain of + stab_section_info's, that might be dangling from it. */ + +static void +free_elfinfo (objp) + PTR objp; +{ + struct objfile *objfile = (struct objfile *)objp; + struct dbx_symfile_info *dbxinfo = (struct dbx_symfile_info *) + objfile->sym_private; + struct stab_section_info *ssi, *nssi; + + ssi = dbxinfo->stab_section_info; + while (ssi) + { + nssi = ssi->next; + mfree (objfile->md, ssi); + ssi = nssi; + } + + dbxinfo->stab_section_info = 0; /* Just say No mo info about this. */ +} + + /* Initialize anything that needs initializing when a completely new symbol file is specified (not just adding some symbols from another file, e.g. a shared library). - For now at least, we have nothing in particular to do, so this function is - just a stub. */ + We reinitialize buildsym, since we may be reading stabs from an ELF file. */ static void -elf_new_init (objfile) - struct objfile *objfile; +elf_new_init (ignore) + struct objfile *ignore; { + stabsread_new_init (); buildsym_new_init (); } @@ -359,11 +531,101 @@ elf_symfile_finish (objfile) just a stub. */ static void -elf_symfile_init (objfile) +elf_symfile_init (ignore) + struct objfile *ignore; +{ +} + +/* ELF specific parsing routine for section offsets. + + Plain and simple for now. */ + +static +struct section_offsets * +elf_symfile_offsets (objfile, addr) struct objfile *objfile; + CORE_ADDR addr; { + struct section_offsets *section_offsets; + int i; + + section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (section_offsets, i) = addr; + + return section_offsets; } + +/* When handling an ELF file that contains Sun STABS debug info, + some of the debug info is relative to the particular chunk of the + section that was generated in its individual .o file. E.g. + offsets to static variables are relative to the start of the data + segment *for that module before linking*. This information is + painfully squirreled away in the ELF symbol table as local symbols + with wierd names. Go get 'em when needed. */ +void +elfstab_offset_sections (objfile, pst) + struct objfile *objfile; + struct partial_symtab *pst; +{ + char *filename = pst->filename; + struct dbx_symfile_info *dbx = (struct dbx_symfile_info *) + objfile->sym_private; + struct stab_section_info *maybe = dbx->stab_section_info; + struct stab_section_info *questionable = 0; + int i; + char *p; + + /* The ELF symbol info doesn't include path names, so strip the path + (if any) from the psymtab filename. */ + while (0 != (p = strchr (filename, '/'))) + filename = p+1; + + /* FIXME: This linear search could speed up significantly + if it was chained in the right order to match how we search it, + and if we unchained when we found a match. */ + for (; maybe; maybe = maybe->next) + { + if (filename[0] == maybe->filename[0] + && STREQ (filename, maybe->filename)) + { + /* We found a match. But there might be several source files + (from different directories) with the same name. */ + if (0 == maybe->found) + break; + questionable = maybe; /* Might use it later. */ + } + } + + if (maybe == 0 && questionable != 0) + { + complain (&stab_info_questionable_complaint, filename); + maybe = questionable; + } + + if (maybe) + { + /* Found it! Allocate a new psymtab struct, and fill it in. */ + maybe->found++; + pst->section_offsets = (struct section_offsets *) + obstack_alloc (&objfile -> psymbol_obstack, + sizeof (struct section_offsets) + + sizeof (pst->section_offsets->offsets) * (SECT_OFF_MAX-1)); + + for (i = 0; i < SECT_OFF_MAX; i++) + ANOFFSET (pst->section_offsets, i) = maybe->sections[i]; + return; + } + + /* We were unable to find any offsets for this file. Complain. */ + if (dbx->stab_section_info) /* If there *is* any info, */ + complain (&stab_info_mismatch_complaint, filename); +} /* Register that we are able to handle ELF object file formats and DWARF debugging formats. @@ -389,6 +651,7 @@ static struct sym_fns elf_sym_fns = elf_symfile_init, /* sym_init: read initial info, setup for sym_read() */ elf_symfile_read, /* sym_read: read a symbol file into symtab */ elf_symfile_finish, /* sym_finish: finished with file, cleanup */ + elf_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */ NULL /* next: pointer to next struct sym_fns */ };