aboutsummaryrefslogtreecommitdiff
path: root/bfd/syms.c
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>1996-01-26 23:42:58 +0000
committerIan Lance Taylor <ian@airs.com>1996-01-26 23:42:58 +0000
commit86aac8eabe837aed915022d188da157ba5736c09 (patch)
tree7f6c7fad1c561070c8977aaee8c7a7c587ecc9f5 /bfd/syms.c
parenta77bf669dce7d953f2c32b162ccec49ed844f962 (diff)
downloadgdb-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.c430
1 files changed, 413 insertions, 17 deletions
diff --git a/bfd/syms.c b/bfd/syms.c
index 2365c24..8024a2b 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;
+}