diff options
author | Ian Lance Taylor <ian@airs.com> | 1996-01-26 23:42:58 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 1996-01-26 23:42:58 +0000 |
commit | 86aac8eabe837aed915022d188da157ba5736c09 (patch) | |
tree | 7f6c7fad1c561070c8977aaee8c7a7c587ecc9f5 /bfd/syms.c | |
parent | a77bf669dce7d953f2c32b162ccec49ed844f962 (diff) | |
download | gdb-86aac8eabe837aed915022d188da157ba5736c09.zip gdb-86aac8eabe837aed915022d188da157ba5736c09.tar.gz gdb-86aac8eabe837aed915022d188da157ba5736c09.tar.bz2 |
* 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.
Diffstat (limited to 'bfd/syms.c')
-rw-r--r-- | bfd/syms.c | 430 |
1 files changed, 413 insertions, 17 deletions
@@ -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; +} |