From 86aac8eabe837aed915022d188da157ba5736c09 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 26 Jan 1996 23:42:58 +0000 Subject: [PATCH] * syms.c: Include "bfdlink.h". (struct stab_find_info): Define. (_bfd_stab_section_find_nearest_line): New function. * libbfd-in.h (_bfd_stab_section_find_nearest_line): Declare. * libbfd.h: Rebuild. * elf-bfd.h (struct elf_obj_tdata): Add line_info field. * elf.c (_bfd_elf_find_nearest_line): Try calling _bfd_stab_section_find_nearest_line before searching the ELF symbol table. Find the closest STT_FUNC symbol, not the last one. * libcoff-in.h (coff_data_type): Add line_info field. * libcoff.h: Rebuild. * coffgen.c (coff_find_nearest_line): Try calling _bfd_stab_section_find_nearest_line before searching the COFF symbol table. * Makefile.in: Rebuild dependencies. --- bfd/ChangeLog | 24 +++ bfd/Makefile.in | 15 +- bfd/elf-bfd.h | 123 +++++++++++++- bfd/elf.c | 22 ++- bfd/libcoff-in.h | 16 +- bfd/libcoff.h | 16 +- bfd/syms.c | 430 +++++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 596 insertions(+), 50 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 494f705585f..b076c001fd8 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,27 @@ +Fri Jan 26 18:33:35 1996 Ian Lance Taylor + + * syms.c: Include "bfdlink.h". + (struct stab_find_info): Define. + (_bfd_stab_section_find_nearest_line): New function. + * libbfd-in.h (_bfd_stab_section_find_nearest_line): Declare. + * libbfd.h: Rebuild. + * elf-bfd.h (struct elf_obj_tdata): Add line_info field. + * elf.c (_bfd_elf_find_nearest_line): Try calling + _bfd_stab_section_find_nearest_line before searching the ELF + symbol table. Find the closest STT_FUNC symbol, not the last one. + * libcoff-in.h (coff_data_type): Add line_info field. + * libcoff.h: Rebuild. + * coffgen.c (coff_find_nearest_line): Try calling + _bfd_stab_section_find_nearest_line before searching the COFF + symbol table. + * Makefile.in: Rebuild dependencies. + +Fri Jan 26 16:11:19 1996 Michael Meissner + + * elf32-ppc.c (R_PPC_EMB_SDA21 relocations): Make relocation size + 4 bytes, so we get the correct value when updating the register + field in little endian mode. + Thu Jan 25 12:14:16 1996 Ian Lance Taylor * libcoff-in.h (struct xcoff_tdata): Remove toc_section and diff --git a/bfd/Makefile.in b/bfd/Makefile.in index 46a70958fe3..6af061ceed5 100644 --- a/bfd/Makefile.in +++ b/bfd/Makefile.in @@ -1,5 +1,6 @@ # Makefile template for Configure for the BFD library. -# Copyright (C) 1990, 91, 92, 93, 94, 1995 Free Software Foundation, Inc. +# Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 +# Free Software Foundation, Inc. # Written by Cygnus Support. # # This file is part of BFD, the Binary File Descriptor library. @@ -713,7 +714,8 @@ libbfd.o: libbfd.c opncls.o: opncls.c reloc.o: reloc.c $(INCDIR)/bfdlink.h section.o: section.c -syms.o: syms.c $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def +syms.o: syms.c $(INCDIR)/bfdlink.h $(INCDIR)/aout/stab_gnu.h \ + $(INCDIR)/aout/stab.def targets.o: targets.c hash.o: hash.c linker.o: linker.c $(INCDIR)/bfdlink.h genlink.h @@ -852,7 +854,7 @@ elf32-ppc.o: elf32-ppc.c $(INCDIR)/bfdlink.h elf-bfd.h \ $(INCDIR)/elf/ppc.h elf32-target.h elf32-sparc.o: elf32-sparc.c $(INCDIR)/bfdlink.h elf-bfd.h \ $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ - elf32-target.h + $(INCDIR)/elf/sparc.h elf32-target.h elf32.o: elf32.c elfcode.h $(INCDIR)/bfdlink.h elf-bfd.h \ $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ elfcore.h elflink.h @@ -962,8 +964,8 @@ aout64.o: aout64.c aoutx.h $(INCDIR)/bfdlink.h libaout.h \ $(INCDIR)/aout/ar.h coff-alpha.o: coff-alpha.c $(INCDIR)/bfdlink.h $(INCDIR)/coff/internal.h \ $(INCDIR)/coff/sym.h $(INCDIR)/coff/symconst.h $(INCDIR)/coff/ecoff.h \ - $(INCDIR)/coff/alpha.h libcoff.h libecoff.h coffswap.h \ - ecoffswap.h + $(INCDIR)/coff/alpha.h $(INCDIR)/aout/ar.h libcoff.h \ + libecoff.h coffswap.h ecoffswap.h demo64.o: demo64.c aoutf1.h $(INCDIR)/aout/sun4.h libaout.h \ $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \ $(INCDIR)/aout/stab.def $(INCDIR)/aout/ar.h aout-target.h @@ -987,8 +989,7 @@ hpux-core.o: hpux-core.c irix-core.o: irix-core.c lynx-core.o: lynx-core.c osf-core.o: osf-core.c -trad-core.o: trad-core.c libaout.h $(INCDIR)/bfdlink.h \ - hosts/i386bsd.h +trad-core.o: trad-core.c libaout.h $(INCDIR)/bfdlink.h cisco-core.o: cisco-core.c i386dynix.o: i386dynix.c $(INCDIR)/aout/dynix3.h aoutx.h \ $(INCDIR)/bfdlink.h libaout.h $(INCDIR)/aout/aout64.h \ diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 10c30c6e0ad..b6060634eb5 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -102,6 +102,11 @@ struct elf_link_hash_entry require an entry in the procedure linkage table. */ bfd_vma plt_offset; + /* If this symbol is used in the linker created sections, the processor + specific backend uses this field to map the field into the offset + from the beginning of the section. */ + struct elf_linker_section_pointers *linker_section_pointer; + /* Symbol type (STT_NOTYPE, STT_OBJECT, etc.). */ char type; @@ -482,6 +487,52 @@ struct bfd_elf_section_data #define get_elf_backend_data(abfd) \ ((struct elf_backend_data *) (abfd)->xvec->backend_data) +/* Enumeration to specify the special section. */ +typedef enum elf_linker_section_enum +{ + LINKER_SECTION_UNKNOWN, /* not used */ + LINKER_SECTION_GOT, /* .got section for global offset pointers */ + LINKER_SECTION_PLT, /* .plt section for generated procedure stubs */ + LINKER_SECTION_SDATA, /* .sdata/.sbss section for PowerPC */ + LINKER_SECTION_SDATA2, /* .sdata2/.sbss2 section for PowerPC */ + LINKER_SECTION_MAX /* # of linker sections */ +} elf_linker_section_enum_t; + +/* Sections created by the linker. */ + +typedef struct elf_linker_section +{ + char *name; /* name of the section */ + char *rel_name; /* name of the associated .rel{,a}. section */ + char *bss_name; /* name of a related .bss section */ + char *sym_name; /* name of symbol to reference this section */ + asection *section; /* pointer to the section */ + asection *bss_section; /* pointer to the bss section associated with this */ + asection *rel_section; /* pointer to the relocations needed for this section */ + struct elf_link_hash_entry *sym_hash; /* pointer to the created symbol hash value */ + bfd_vma initial_size; /* initial size before any linker generated allocations */ + bfd_vma sym_offset; /* offset of symbol from beginning of section */ + bfd_vma hole_size; /* size of reserved address hole in allocation */ + bfd_vma hole_offset; /* current offset for the hole */ + bfd_vma max_hole_offset; /* maximum offset for the hole */ + elf_linker_section_enum_t which; /* which section this is */ + boolean hole_written_p; /* whether the hole has been initialized */ + int alignment; /* alignment for the section */ + flagword flags; /* flags to use to create the section */ +} elf_linker_section_t; + +/* Linked list of allocated pointer entries. This hangs off of the symbol lists, and + provides allows us to return different pointers, based on different addend's. */ + +typedef struct elf_linker_section_pointers +{ + struct elf_linker_section_pointers *next; /* next allocated pointer for this symbol */ + bfd_vma offset; /* offset of pointer from beginning of section */ + bfd_signed_vma addend; /* addend used */ + elf_linker_section_enum_t which; /* which linker section this is */ + boolean written_address_p; /* whether address was written yet */ +} elf_linker_section_pointers_t; + /* Some private data is stashed away for future use using the tdata pointer in the bfd structure. */ @@ -494,7 +545,7 @@ struct elf_obj_tdata struct bfd_strtab_hash *strtab_ptr; int num_locals; int num_globals; - asymbol **section_syms; /* STT_SECTION symbols for each section */ + asymbol **section_syms; /* STT_SECTION symbols for each section */ Elf_Internal_Shdr symtab_hdr; Elf_Internal_Shdr shstrtab_hdr; Elf_Internal_Shdr strtab_hdr; @@ -503,10 +554,10 @@ struct elf_obj_tdata unsigned int symtab_section, shstrtab_section; unsigned int strtab_section, dynsymtab_section; file_ptr next_file_pos; - void *prstatus; /* The raw /proc prstatus structure */ - void *prpsinfo; /* The raw /proc prpsinfo structure */ - bfd_vma gp; /* The gp value (MIPS only, for now) */ - unsigned int gp_size; /* The gp size (MIPS only, for now) */ + void *prstatus; /* The raw /proc prstatus structure */ + void *prpsinfo; /* The raw /proc prpsinfo structure */ + bfd_vma gp; /* The gp value (MIPS only, for now) */ + unsigned int gp_size; /* The gp size (MIPS only, for now) */ /* This is set to true if the object was created by the backend linker. */ @@ -521,6 +572,10 @@ struct elf_obj_tdata table, used when linking. This is indexed by the symbol index. */ bfd_vma *local_got_offsets; + /* A mapping from local symbols to offsets into the various linker + sections added. This is index by the symbol index. */ + elf_linker_section_pointers_t **linker_section_pointers; + /* The linker ELF emulation code needs to let the backend ELF linker know what filename should be used for a dynamic object if the dynamic object is found using a search. This field is used to @@ -537,6 +592,9 @@ struct elf_obj_tdata /* Records the result of `get_program_header_size'. */ bfd_size_type program_header_size; + /* Used by find_nearest_line entry point. */ + PTR line_info; + /* Used by MIPS ELF find_nearest_line entry point. The structure could be included directly in this one, but there's no point to wasting the memory just for the infrequently called @@ -545,6 +603,9 @@ struct elf_obj_tdata /* Used to determine if the e_flags field has been initialized */ boolean flags_init; + + /* Linker sections that we are interested in. */ + struct elf_linker_section *linker_section[ (int)LINKER_SECTION_MAX ]; }; #define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data) @@ -562,9 +623,11 @@ struct elf_obj_tdata #define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size) #define elf_sym_hashes(bfd) (elf_tdata(bfd) -> sym_hashes) #define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got_offsets) +#define elf_local_ptr_offsets(bfd) (elf_tdata(bfd) -> linker_section_pointers) #define elf_dt_needed_name(bfd) (elf_tdata(bfd) -> dt_needed_name) #define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) #define elf_flags_init(bfd) (elf_tdata(bfd) -> flags_init) +#define elf_linker_section(bfd,n) (elf_tdata(bfd) -> linker_section[(int)n]) extern int _bfd_elf_section_from_bfd_section PARAMS ((bfd *, asection *)); extern char *bfd_elf_string_from_elf_section @@ -661,6 +724,56 @@ boolean _bfd_elf_create_dynamic_sections PARAMS ((bfd *, boolean _bfd_elf_create_got_section PARAMS ((bfd *, struct bfd_link_info *)); +elf_linker_section_t *_bfd_elf_create_linker_section + PARAMS ((bfd *abfd, + struct bfd_link_info *info, + enum elf_linker_section_enum, + elf_linker_section_t *defaults)); + +elf_linker_section_pointers_t *_bfd_elf_find_pointer_linker_section + PARAMS ((elf_linker_section_pointers_t *linker_pointers, + bfd_signed_vma addend, + elf_linker_section_enum_t which)); + +boolean bfd_elf32_create_pointer_linker_section + PARAMS ((bfd *abfd, + struct bfd_link_info *info, + elf_linker_section_t *lsect, + struct elf_link_hash_entry *h, + const Elf32_Internal_Rela *rel)); + +bfd_vma bfd_elf32_finish_pointer_linker_section + PARAMS ((bfd *output_abfd, + bfd *input_bfd, + struct bfd_link_info *info, + elf_linker_section_t *lsect, + struct elf_link_hash_entry *h, + bfd_vma relocation, + const Elf32_Internal_Rela *rel, + int relative_reloc)); + +boolean bfd_elf64_create_pointer_linker_section + PARAMS ((bfd *abfd, + struct bfd_link_info *info, + elf_linker_section_t *lsect, + struct elf_link_hash_entry *h, + const Elf64_Internal_Rela *rel)); + +bfd_vma bfd_elf64_finish_pointer_linker_section + PARAMS ((bfd *output_abfd, + bfd *input_bfd, + struct bfd_link_info *info, + elf_linker_section_t *lsect, + struct elf_link_hash_entry *h, + bfd_vma relocation, + const Elf64_Internal_Rela *rel, + int relative_reloc)); + +boolean _bfd_elf_make_linker_section_rela + PARAMS ((bfd *dynobj, + elf_linker_section_t *lsect, + int alignment)); + extern const bfd_target *bfd_elf32_object_p PARAMS ((bfd *)); extern const bfd_target *bfd_elf32_core_file_p PARAMS ((bfd *)); extern char *bfd_elf32_core_file_failing_command PARAMS ((bfd *)); diff --git a/bfd/elf.c b/bfd/elf.c index e12a885c5ee..95181c6f57c 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -554,6 +554,7 @@ _bfd_elf_link_hash_newfunc (entry, table, string) ret->weakdef = NULL; ret->got_offset = (bfd_vma) -1; ret->plt_offset = (bfd_vma) -1; + ret->linker_section_pointer = (elf_linker_section_pointers_t *)0; ret->type = STT_NOTYPE; ret->elf_link_hash_flags = 0; } @@ -3142,15 +3143,26 @@ _bfd_elf_find_nearest_line (abfd, CONST char **functionname_ptr; unsigned int *line_ptr; { + boolean found; const char *filename; asymbol *func; + bfd_vma low_func; asymbol **p; + if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, + &found, filename_ptr, + functionname_ptr, line_ptr, + &elf_tdata (abfd)->line_info)) + return false; + if (found) + return true; + if (symbols == NULL) return false; filename = NULL; func = NULL; + low_func = 0; for (p = symbols; *p != NULL; p++) { @@ -3169,9 +3181,13 @@ _bfd_elf_find_nearest_line (abfd, filename = bfd_asymbol_name (&q->symbol); break; case STT_FUNC: - if (func == NULL - || q->symbol.value <= offset) - func = (asymbol *) q; + if (q->symbol.section == section + && q->symbol.value >= low_func + && q->symbol.value <= offset) + { + func = (asymbol *) q; + low_func = q->symbol.value; + } break; } } diff --git a/bfd/libcoff-in.h b/bfd/libcoff-in.h index 820a75d58a2..ce993b27459 100644 --- a/bfd/libcoff-in.h +++ b/bfd/libcoff-in.h @@ -89,6 +89,9 @@ typedef struct coff_tdata int *local_toc_sym_map; struct bfd_link_info *link_info; + + /* Used by coff_find_nearest_line. */ + PTR line_info; } coff_data_type; /* Tdata for pe image files. */ @@ -117,11 +120,11 @@ struct xcoff_tdata /* TOC value. */ bfd_vma toc; - /* Section holding TOC. */ - asection *toc_section; + /* Index of section holding TOC. */ + int sntoc; - /* Section holding entry point. */ - asection *entry_section; + /* Index of section holding entry point. */ + int snentry; /* .text alignment from optional header. */ int text_align_power; @@ -223,11 +226,6 @@ struct coff_link_hash_entry /* Pointer to array of auxiliary entries, if any. */ union internal_auxent *aux; - - /* If this symbol requires an entry in the table of contents, the - processor specific backend uses this field to hold the offset - into the .toc section. */ - bfd_vma toc_offset; }; /* COFF linker hash table. */ diff --git a/bfd/libcoff.h b/bfd/libcoff.h index b9fe260153a..6cb948ad0d7 100644 --- a/bfd/libcoff.h +++ b/bfd/libcoff.h @@ -89,6 +89,9 @@ typedef struct coff_tdata int *local_toc_sym_map; struct bfd_link_info *link_info; + + /* Used by coff_find_nearest_line. */ + PTR line_info; } coff_data_type; /* Tdata for pe image files. */ @@ -117,11 +120,11 @@ struct xcoff_tdata /* TOC value. */ bfd_vma toc; - /* Section holding TOC. */ - asection *toc_section; + /* Index of section holding TOC. */ + int sntoc; - /* Section holding entry point. */ - asection *entry_section; + /* Index of section holding entry point. */ + int snentry; /* .text alignment from optional header. */ int text_align_power; @@ -223,11 +226,6 @@ struct coff_link_hash_entry /* Pointer to array of auxiliary entries, if any. */ union internal_auxent *aux; - - /* If this symbol requires an entry in the table of contents, the - processor specific backend uses this field to hold the offset - into the .toc section. */ - bfd_vma toc_offset; }; /* COFF linker hash table. */ diff --git a/bfd/syms.c b/bfd/syms.c index 2365c24e2e2..8024a2bc5fc 100644 --- a/bfd/syms.c +++ b/bfd/syms.c @@ -48,6 +48,7 @@ SECTION @menu @* Reading Symbols:: @* Writing Symbols:: +@* Mini Symbols:: @* typedef asymbol:: @* symbol handling functions:: @end menu @@ -91,7 +92,7 @@ SUBSECTION INODE -Writing Symbols, Mini symbols, Reading Symbols, Symbols +Writing Symbols, Mini Symbols, Reading Symbols, Symbols SUBSECTION Writing symbols @@ -138,9 +139,9 @@ SUBSECTION be described. INODE -Mini symbols, typedef asymbol, Writing Symbols, Symbols +Mini Symbols, typedef asymbol, Writing Symbols, Symbols SUBSECTION - Mini symbols + Mini Symbols Mini symbols provide read-only access to the symbol table. They use less memory space, but require more time to access. @@ -166,7 +167,7 @@ SUBSECTION /* DOCDD INODE -typedef asymbol, symbol handling functions, Mini symbols, Symbols +typedef asymbol, symbol handling functions, Mini Symbols, Symbols */ /* @@ -262,15 +263,14 @@ CODE_FRAGMENT . {* Signal that the symbol is the label of constructor section. *} .#define BSF_CONSTRUCTOR 0x800 . -. {* Signal that the symbol is a warning symbol. If the symbol -. is a warning symbol, then the value field (I know this is -. tacky) will point to the asymbol which when referenced will -. cause the warning. *} +. {* Signal that the symbol is a warning symbol. The name is a +. warning. The name of the next symbol is the one to warn about; +. if a reference is made to a symbol with the same name as the next +. symbol, a warning is issued by the linker. *} .#define BSF_WARNING 0x1000 . -. {* Signal that the symbol is indirect. The value of the symbol -. is a pointer to an undefined asymbol which contains the -. name to use instead. *} +. {* Signal that the symbol is indirect. This symbol is an indirect +. pointer to the symbol with the same name as the next symbol. *} .#define BSF_INDIRECT 0x2000 . . {* BSF_FILE marks symbols that contain a file name. This is used @@ -299,8 +299,8 @@ CODE_FRAGMENT #include "bfd.h" #include "sysdep.h" - #include "libbfd.h" +#include "bfdlink.h" #include "aout/stab_gnu.h" /* @@ -634,12 +634,9 @@ _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep) if (storage < 0) goto error_return; - syms = (asymbol **) malloc ((size_t) storage); + syms = (asymbol **) bfd_malloc ((size_t) storage); if (syms == NULL) - { - bfd_set_error (bfd_error_no_memory); - goto error_return; - } + goto error_return; if (dynamic) symcount = bfd_canonicalize_dynamic_symtab (abfd, syms); @@ -672,3 +669,402 @@ _bfd_generic_minisymbol_to_symbol (abfd, dynamic, minisym, sym) { return *(asymbol **) minisym; } + +/* Look through stabs debugging information in .stab and .stabstr + sections to find the source file and line closest to a desired + location. This is used by COFF and ELF targets. It sets *pfound + to true if it finds some information. The *pinfo field is used to + pass cached information in and out of this routine; this first time + the routine is called for a BFD, *pinfo should be NULL. The value + placed in *pinfo should be saved with the BFD, and passed back each + time this function is called. */ + +/* A pointer to this structure is stored in *pinfo. */ + +struct stab_find_info +{ + /* The .stab section. */ + asection *stabsec; + /* The .stabstr section. */ + asection *strsec; + /* The contents of the .stab section. */ + bfd_byte *stabs; + /* The contents of the .stabstr section. */ + bfd_byte *strs; + /* An malloc buffer to hold the file name. */ + char *filename; + /* Cached values to restart quickly. */ + bfd_vma cached_offset; + bfd_byte *cached_stab; + bfd_byte *cached_str; + bfd_size_type cached_stroff; +}; + +boolean +_bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, pfound, + pfilename, pfnname, pline, pinfo) + bfd *abfd; + asymbol **symbols; + asection *section; + bfd_vma offset; + boolean *pfound; + const char **pfilename; + const char **pfnname; + unsigned int *pline; + PTR *pinfo; +{ + struct stab_find_info *info; + bfd_size_type stabsize, strsize; + bfd_byte *stab, *stabend, *str; + bfd_size_type stroff; + bfd_vma fnaddr; + char *directory_name, *main_file_name, *current_file_name, *line_file_name; + char *fnname; + bfd_vma low_func_vma, low_line_vma; + + *pfound = false; + *pfilename = bfd_get_filename (abfd); + *pfnname = NULL; + *pline = 0; + + info = (struct stab_find_info *) *pinfo; + if (info != NULL) + { + if (info->stabsec == NULL || info->strsec == NULL) + { + /* No stabs debugging information. */ + return true; + } + + stabsize = info->stabsec->_raw_size; + strsize = info->strsec->_raw_size; + } + else + { + long reloc_size, reloc_count; + arelent **reloc_vector; + + info = (struct stab_find_info *) bfd_zalloc (abfd, sizeof *info); + if (info == NULL) + return false; + + /* FIXME: When using the linker --split-by-file or + --split-by-reloc options, it is possible for the .stab and + .stabstr sections to be split. We should handle that. */ + + info->stabsec = bfd_get_section_by_name (abfd, ".stab"); + info->strsec = bfd_get_section_by_name (abfd, ".stabstr"); + + if (info->stabsec == NULL || info->strsec == NULL) + { + /* No stabs debugging information. Set *pinfo so that we + can return quickly in the info != NULL case above. */ + *pinfo = info; + return true; + } + + stabsize = info->stabsec->_raw_size; + strsize = info->strsec->_raw_size; + + info->stabs = (bfd_byte *) bfd_alloc (abfd, stabsize); + info->strs = (bfd_byte *) bfd_alloc (abfd, strsize); + if (info->stabs == NULL || info->strs == NULL) + return false; + + if (! bfd_get_section_contents (abfd, info->stabsec, info->stabs, 0, + stabsize) + || ! bfd_get_section_contents (abfd, info->strsec, info->strs, 0, + strsize)) + return false; + + /* If this is a relocateable object file, we have to relocate + the entries in .stab. This should always be simple 32 bit + relocations against symbols defined in this object file, so + this should be no big deal. */ + reloc_size = bfd_get_reloc_upper_bound (abfd, info->stabsec); + if (reloc_size < 0) + return false; + reloc_vector = (arelent **) bfd_malloc (reloc_size); + if (reloc_vector == NULL && reloc_size != 0) + return false; + reloc_count = bfd_canonicalize_reloc (abfd, info->stabsec, reloc_vector, + symbols); + if (reloc_count < 0) + { + if (reloc_vector != NULL) + free (reloc_vector); + return false; + } + if (reloc_count > 0) + { + arelent **pr; + + for (pr = reloc_vector; *pr != NULL; pr++) + { + arelent *r; + unsigned long val; + asymbol *sym; + + r = *pr; + if (r->howto->rightshift != 0 + || r->howto->size != 2 + || r->howto->bitsize != 32 + || r->howto->pc_relative + || r->howto->bitpos != 0 + || r->howto->dst_mask != 0xffffffff) + { + (*_bfd_error_handler) + ("Unsupported .stab relocation"); + bfd_set_error (bfd_error_invalid_operation); + if (reloc_vector != NULL) + free (reloc_vector); + return false; + } + + val = bfd_get_32 (abfd, info->stabs + r->address); + val &= r->howto->src_mask; + sym = *r->sym_ptr_ptr; + val += sym->value + sym->section->vma + r->addend; + bfd_put_32 (abfd, val, info->stabs + r->address); + } + } + + if (reloc_vector != NULL) + free (reloc_vector); + + *pinfo = info; + } + + /* We are passed a section relative offset. The offsets in the + stabs information are absolute. */ + offset += bfd_get_section_vma (abfd, section); + + /* Stabs entries use a 12 byte format: + 4 byte string table index + 1 byte stab type + 1 byte stab other field + 2 byte stab desc field + 4 byte stab value + FIXME: This will have to change for a 64 bit object format. + + The stabs symbols are divided into compilation units. For the + first entry in each unit, the type of 0, the value is the length + of the string table for this unit, and the desc field is the + number of stabs symbols for this unit. */ + +#define STRDXOFF (0) +#define TYPEOFF (4) +#define OTHEROFF (5) +#define DESCOFF (6) +#define VALOFF (8) +#define STABSIZE (12) + + /* It would be nice if we could skip ahead to the stabs symbols for + the next compilation unit to quickly scan through the compilation + units. Unfortunately, since each line number gets a separate + stabs entry, it is entirely plausible that a large source file + will overflow the 16 bit count of stabs entries. */ + fnaddr = 0; + directory_name = NULL; + main_file_name = NULL; + current_file_name = NULL; + line_file_name = NULL; + fnname = NULL; + low_func_vma = 0; + low_line_vma = 0; + + stabend = info->stabs + stabsize; + + if (info->cached_stab == NULL || offset < info->cached_offset) + { + stab = info->stabs; + str = info->strs; + stroff = 0; + } + else + { + stab = info->cached_stab; + str = info->cached_str; + stroff = info->cached_stroff; + } + + info->cached_offset = offset; + + for (; stab < stabend; stab += STABSIZE) + { + boolean done; + bfd_vma val; + char *name; + + done = false; + + switch (stab[TYPEOFF]) + { + case 0: + /* This is the first entry in a compilation unit. */ + if ((bfd_size_type) ((info->strs + strsize) - str) < stroff) + { + done = true; + break; + } + str += stroff; + stroff = bfd_get_32 (abfd, stab + VALOFF); + break; + + case N_SO: + /* The main file name. */ + + val = bfd_get_32 (abfd, stab + VALOFF); + if (val > offset) + { + done = true; + break; + } + + name = str + bfd_get_32 (abfd, stab + STRDXOFF); + + /* An empty string indicates the end of the compilation + unit. */ + if (*name == '\0') + { + /* If there are functions in different sections, they + may have addresses larger than val, but we don't want + to forget the file name. When there are functions in + different cases, there is supposed to be an N_FUN at + the end of the function indicating where it ends. */ + if (low_func_vma < val || fnname == NULL) + main_file_name = NULL; + break; + } + + /* We know that we have to get to at least this point in the + stabs entries for this offset. */ + info->cached_stab = stab; + info->cached_str = str; + info->cached_stroff = stroff; + + current_file_name = name; + + /* Look ahead to the next symbol. Two consecutive N_SO + symbols are a directory and a file name. */ + if (stab + STABSIZE >= stabend + || *(stab + STABSIZE + TYPEOFF) != N_SO) + directory_name = NULL; + else + { + stab += STABSIZE; + directory_name = current_file_name; + current_file_name = str + bfd_get_32 (abfd, stab + STRDXOFF); + } + + main_file_name = current_file_name; + + break; + + case N_SOL: + /* The name of an include file. */ + current_file_name = str + bfd_get_32 (abfd, stab + STRDXOFF); + break; + + case N_SLINE: + case N_DSLINE: + case N_BSLINE: + /* A line number. The value is relative to the start of the + current function. */ + val = fnaddr + bfd_get_32 (abfd, stab + VALOFF); + if (val >= low_line_vma && val <= offset) + { + *pline = bfd_get_16 (abfd, stab + DESCOFF); + low_line_vma = val; + line_file_name = current_file_name; + } + break; + + case N_FUN: + /* A function name. */ + val = bfd_get_32 (abfd, stab + VALOFF); + name = str + bfd_get_32 (abfd, stab + STRDXOFF); + + /* An empty string here indicates the end of a function, and + the value is relative to fnaddr. */ + + if (*name == '\0') + { + val += fnaddr; + if (val >= low_func_vma && val < offset) + fnname = NULL; + } + else + { + if (val >= low_func_vma && val <= offset) + { + fnname = name; + low_func_vma = val; + } + + fnaddr = val; + } + + break; + } + + if (done) + break; + } + + if (main_file_name == NULL) + { + /* No information found. */ + return true; + } + + *pfound = true; + + if (*pline != 0) + main_file_name = line_file_name; + + if (main_file_name != NULL) + { + if (main_file_name[0] == '/' || directory_name == NULL) + *pfilename = main_file_name; + else + { + size_t dirlen; + + dirlen = strlen (directory_name); + if (info->filename == NULL + || strncmp (info->filename, directory_name, dirlen) != 0 + || strcmp (info->filename + dirlen, main_file_name) != 0) + { + if (info->filename != NULL) + free (info->filename); + info->filename = (char *) bfd_malloc (dirlen + + strlen (main_file_name) + + 1); + if (info->filename == NULL) + return false; + strcpy (info->filename, directory_name); + strcpy (info->filename + dirlen, main_file_name); + } + + *pfilename = info->filename; + } + } + + if (fnname != NULL) + { + char *s; + + /* This will typically be something like main:F(0,1), so we want + to clobber the colon. It's OK to change the name, since the + string is in our own local storage anyhow. */ + + s = strchr (fnname, ':'); + if (s != NULL) + *s = '\0'; + + *pfnname = fnname; + } + + return true; +} -- 2.30.2