X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fsyms.c;h=1c4bf288a83ef0f524dce855c88892b68b161d30;hb=86fb1dece37497b267579ed4f062d280cd5760cd;hp=4154cbfd831c39e17a2402e225aeb7f42a4832a7;hpb=57a1867e6c8713e9e5e86f933e6b416688b43e34;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/syms.c b/bfd/syms.c index 4154cbfd83..1c4bf288a8 100644 --- a/bfd/syms.c +++ b/bfd/syms.c @@ -1,5 +1,7 @@ /* Generic symbol-table support for the BFD library. - Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002 + Free Software Foundation, Inc. Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -16,7 +18,7 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* SECTION @@ -48,6 +50,7 @@ SECTION @menu @* Reading Symbols:: @* Writing Symbols:: +@* Mini Symbols:: @* typedef asymbol:: @* symbol handling functions:: @end menu @@ -61,12 +64,15 @@ SUBSECTION allocating storage, and the actual reading process. This is an excerpt from an application which reads the symbol table: -| unsigned int storage_needed; +| long storage_needed; | asymbol **symbol_table; -| unsigned int number_of_symbols; -| unsigned int i; +| long number_of_symbols; +| long i; | -| storage_needed = get_symtab_upper_bound (abfd); +| storage_needed = bfd_get_symtab_upper_bound (abfd); +| +| if (storage_needed < 0) +| FAIL | | if (storage_needed == 0) { | return ; @@ -76,16 +82,18 @@ SUBSECTION | number_of_symbols = | bfd_canonicalize_symtab (abfd, symbol_table); | +| if (number_of_symbols < 0) +| FAIL +| | for (i = 0; i < number_of_symbols; i++) { | process_symbol (symbol_table[i]); | } - All storage for the symbols themselves is in an obstack + All storage for the symbols themselves is in an objalloc connected to the BFD; it is freed when the BFD is closed. - INODE -Writing Symbols, typedef asymbol, Reading Symbols, Symbols +Writing Symbols, Mini Symbols, Reading Symbols, Symbols SUBSECTION Writing symbols @@ -131,14 +139,34 @@ SUBSECTION which is not one of <<.text>>, <<.data>> or <<.bss>> cannot be described. -*/ +INODE +Mini Symbols, typedef asymbol, Writing Symbols, Symbols +SUBSECTION + Mini Symbols + Mini symbols provide read-only access to the symbol table. + They use less memory space, but require more time to access. + They can be useful for tools like nm or objdump, which may + have to handle symbol tables of extremely large executables. + The <> function will read the symbols + into memory in an internal form. It will return a <> + pointer to a block of memory, a symbol count, and the size of + each symbol. The pointer is allocated using <>, and + should be freed by the caller when it is no longer needed. + + The function <> will take a pointer + to a minisymbol, and a pointer to a structure returned by + <>, and return a <> structure. + The return value may or may not be the same as the value from + <> which was passed in. + +*/ /* DOCDD INODE -typedef asymbol, symbol handling functions, Writing Symbols, Symbols +typedef asymbol, symbol handling functions, Mini Symbols, Symbols */ /* @@ -155,123 +183,140 @@ CODE_FRAGMENT . .typedef struct symbol_cache_entry .{ -. {* A pointer to the BFD which owns the symbol. This information -. is necessary so that a back end can work out what additional -. information (invisible to the application writer) is carried -. with the symbol. +. {* A pointer to the BFD which owns the symbol. This information +. is necessary so that a back end can work out what additional +. information (invisible to the application writer) is carried +. with the symbol. . -. This field is *almost* redundant, since you can use section->owner -. instead, except that some symbols point to the global sections -. bfd_{abs,com,und}_section. This could be fixed by making -. these globals be per-bfd (or per-target-flavor). FIXME. *} +. This field is *almost* redundant, since you can use section->owner +. instead, except that some symbols point to the global sections +. bfd_{abs,com,und}_section. This could be fixed by making +. these globals be per-bfd (or per-target-flavor). FIXME. *} +. struct _bfd *the_bfd; {* Use bfd_asymbol_bfd(sym) to access this field. *} . -. struct _bfd *the_bfd; {* Use bfd_asymbol_bfd(sym) to access this field. *} +. {* The text of the symbol. The name is left alone, and not copied; the +. application may not alter it. *} +. const char *name; . -. {* The text of the symbol. The name is left alone, and not copied; the -. application may not alter it. *} -. CONST char *name; -. -. {* The value of the symbol. This really should be a union of a -. numeric value with a pointer, since some flags indicate that -. a pointer to another symbol is stored here. *} +. {* The value of the symbol. This really should be a union of a +. numeric value with a pointer, since some flags indicate that +. a pointer to another symbol is stored here. *} . symvalue value; . -. {* Attributes of a symbol: *} -. +. {* Attributes of a symbol. *} .#define BSF_NO_FLAGS 0x00 . -. {* The symbol has local scope; <> in <>. The value -. is the offset into the section of the data. *} +. {* The symbol has local scope; <> in <>. The value +. is the offset into the section of the data. *} .#define BSF_LOCAL 0x01 . -. {* The symbol has global scope; initialized data in <>. The -. value is the offset into the section of the data. *} +. {* The symbol has global scope; initialized data in <>. The +. value is the offset into the section of the data. *} .#define BSF_GLOBAL 0x02 . -. {* The symbol has global scope and is exported. The value is -. the offset into the section of the data. *} -.#define BSF_EXPORT BSF_GLOBAL {* no real difference *} +. {* The symbol has global scope and is exported. The value is +. the offset into the section of the data. *} +.#define BSF_EXPORT BSF_GLOBAL {* No real difference. *} . -. {* A normal C symbol would be one of: -. <>, <>, <> or -. <> *} +. {* A normal C symbol would be one of: +. <>, <>, <> or +. <>. *} . -. {* The symbol is a debugging record. The value has an arbitary -. meaning. *} +. {* The symbol is a debugging record. The value has an arbitary +. meaning, unless BSF_DEBUGGING_RELOC is also set. *} .#define BSF_DEBUGGING 0x08 . -. {* The symbol denotes a function entry point. Used in ELF, -. perhaps others someday. *} +. {* The symbol denotes a function entry point. Used in ELF, +. perhaps others someday. *} .#define BSF_FUNCTION 0x10 . -. {* Used by the linker. *} +. {* Used by the linker. *} .#define BSF_KEEP 0x20 .#define BSF_KEEP_G 0x40 . -. {* A weak global symbol, overridable without warnings by -. a regular global symbol of the same name. *} +. {* A weak global symbol, overridable without warnings by +. a regular global symbol of the same name. *} .#define BSF_WEAK 0x80 . -. {* This symbol was created to point to a section, e.g. ELF's -. STT_SECTION symbols. *} +. {* This symbol was created to point to a section, e.g. ELF's +. STT_SECTION symbols. *} .#define BSF_SECTION_SYM 0x100 . -. {* The symbol used to be a common symbol, but now it is -. allocated. *} +. {* The symbol used to be a common symbol, but now it is +. allocated. *} .#define BSF_OLD_COMMON 0x200 . -. {* The default value for common data. *} +. {* The default value for common data. *} .#define BFD_FORT_COMM_DEFAULT_VALUE 0 . -. {* In some files the type of a symbol sometimes alters its -. location in an output file - ie in coff a <> symbol -. which is also <> symbol appears where it was -. declared and not at the end of a section. This bit is set -. by the target BFD part to convey this information. *} -. +. {* In some files the type of a symbol sometimes alters its +. location in an output file - ie in coff a <> symbol +. which is also <> symbol appears where it was +. declared and not at the end of a section. This bit is set +. by the target BFD part to convey this information. *} .#define BSF_NOT_AT_END 0x400 . -. {* Signal that the symbol is the label of constructor section. *} +. {* 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 -. for ELF STT_FILE symbols. *} +. {* BSF_FILE marks symbols that contain a file name. This is used +. for ELF STT_FILE symbols. *} .#define BSF_FILE 0x4000 . -. {* Symbol is from dynamic linking information. *} +. {* Symbol is from dynamic linking information. *} .#define BSF_DYNAMIC 0x8000 . +. {* The symbol denotes a data object. Used in ELF, and perhaps +. others someday. *} +.#define BSF_OBJECT 0x10000 +. +. {* This symbol is a debugging symbol. The value is the offset +. into the section of the data. BSF_DEBUGGING should be set +. as well. *} +.#define BSF_DEBUGGING_RELOC 0x20000 +. +. {* This symbol is thread local. Used in ELF. *} +.#define BSF_THREAD_LOCAL 0x40000 +. . flagword flags; . -. {* A pointer to the section to which this symbol is -. relative. This will always be non NULL, there are special -. sections for undefined and absolute symbols *} +. {* A pointer to the section to which this symbol is +. relative. This will always be non NULL, there are special +. sections for undefined and absolute symbols. *} . struct sec *section; . -. {* Back end special data. This is being phased out in favour -. of making this a union. *} -. PTR udata; +. {* Back end special data. *} +. union +. { +. PTR p; +. bfd_vma i; +. } +. udata; +.} +.asymbol; . -.} asymbol; */ #include "bfd.h" #include "sysdep.h" - #include "libbfd.h" +#include "safe-ctype.h" +#include "bfdlink.h" #include "aout/stab_gnu.h" +static char coff_section_type PARAMS ((const char *)); +static int cmpindexentry PARAMS ((const PTR, const PTR)); + /* DOCDD INODE @@ -282,17 +327,62 @@ SUBSECTION /* FUNCTION - get_symtab_upper_bound + bfd_get_symtab_upper_bound DESCRIPTION Return the number of bytes required to store a vector of pointers to <> for all the symbols in the BFD @var{abfd}, including a terminal NULL pointer. If there are no symbols in - the BFD, then return 0. + the BFD, then return 0. If an error occurs, return -1. + +.#define bfd_get_symtab_upper_bound(abfd) \ +. BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) +. +*/ + +/* +FUNCTION + bfd_is_local_label -.#define get_symtab_upper_bound(abfd) \ -. BFD_SEND (abfd, _get_symtab_upper_bound, (abfd)) +SYNOPSIS + boolean bfd_is_local_label(bfd *abfd, asymbol *sym); +DESCRIPTION + Return true if the given symbol @var{sym} in the BFD @var{abfd} is + a compiler generated local label, else return false. +*/ + +boolean +bfd_is_local_label (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + /* The BSF_SECTION_SYM check is needed for IA-64, where every label that + starts with '.' is local. This would accidentally catch section names + if we didn't reject them here. */ + if ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_SECTION_SYM)) != 0) + return false; + if (sym->name == NULL) + return false; + return bfd_is_local_label_name (abfd, sym->name); +} + +/* +FUNCTION + bfd_is_local_label_name + +SYNOPSIS + boolean bfd_is_local_label_name(bfd *abfd, const char *name); + +DESCRIPTION + Return true if a symbol with the name @var{name} in the BFD + @var{abfd} is a compiler generated local label, else return + false. This just checks whether the name has the form of a + local label. + +.#define bfd_is_local_label_name(abfd, name) \ +. BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) +. */ /* @@ -306,14 +396,12 @@ DESCRIPTION Return the actual number of symbol pointers, not including the NULL. - .#define bfd_canonicalize_symtab(abfd, location) \ . BFD_SEND (abfd, _bfd_canonicalize_symtab,\ . (abfd, location)) - +. */ - /* FUNCTION bfd_set_symtab @@ -349,14 +437,15 @@ FUNCTION bfd_print_symbol_vandf SYNOPSIS - void bfd_print_symbol_vandf(PTR file, asymbol *symbol); + void bfd_print_symbol_vandf(bfd *abfd, PTR file, asymbol *symbol); DESCRIPTION Print the value and flags of the @var{symbol} supplied to the stream @var{file}. */ void -bfd_print_symbol_vandf (arg, symbol) +bfd_print_symbol_vandf (abfd, arg, symbol) + bfd *abfd; PTR arg; asymbol *symbol; { @@ -364,27 +453,33 @@ bfd_print_symbol_vandf (arg, symbol) flagword type = symbol->flags; if (symbol->section != (asection *) NULL) { - fprintf_vma (file, symbol->value + symbol->section->vma); + bfd_fprintf_vma (abfd, file, + symbol->value + symbol->section->vma); } else { - fprintf_vma (file, symbol->value); + bfd_fprintf_vma (abfd, file, symbol->value); } /* This presumes that a symbol can not be both BSF_DEBUGGING and - BSF_DYNAMIC. */ + BSF_DYNAMIC, nor more than one of BSF_FUNCTION, BSF_FILE, and + BSF_OBJECT. */ fprintf (file, " %c%c%c%c%c%c%c", - (type & BSF_LOCAL) ? 'l' : ' ', - (type & BSF_GLOBAL) ? 'g' : ' ', + ((type & BSF_LOCAL) + ? (type & BSF_GLOBAL) ? '!' : 'l' + : (type & BSF_GLOBAL) ? 'g' : ' '), (type & BSF_WEAK) ? 'w' : ' ', (type & BSF_CONSTRUCTOR) ? 'C' : ' ', (type & BSF_WARNING) ? 'W' : ' ', (type & BSF_INDIRECT) ? 'I' : ' ', - (type & BSF_DEBUGGING) ? 'd' - : (type & BSF_DYNAMIC) ? 'D' : ' '); + (type & BSF_DEBUGGING) ? 'd' : (type & BSF_DYNAMIC) ? 'D' : ' ', + ((type & BSF_FUNCTION) + ? 'F' + : ((type & BSF_FILE) + ? 'f' + : ((type & BSF_OBJECT) ? 'O' : ' ')))); } - /* FUNCTION bfd_make_empty_symbol @@ -400,8 +495,34 @@ DESCRIPTION .#define bfd_make_empty_symbol(abfd) \ . BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) +. */ +/* +FUNCTION + _bfd_generic_make_empty_symbol + +SYNOPSIS + asymbol *_bfd_generic_make_empty_symbol (bfd *); + +DESCRIPTION + Create a new <> structure for the BFD @var{abfd} + and return a pointer to it. Used by core file routines, + binary back-end and anywhere else where no private info + is needed. +*/ + +asymbol * +_bfd_generic_make_empty_symbol (abfd) + bfd *abfd; +{ + bfd_size_type amt = sizeof (asymbol); + asymbol *new = (asymbol *) bfd_zalloc (abfd, amt); + if (new) + new->the_bfd = abfd; + return new; +} + /* FUNCTION bfd_make_debug_symbol @@ -413,51 +534,61 @@ DESCRIPTION .#define bfd_make_debug_symbol(abfd,ptr,size) \ . BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) +. */ struct section_to_type { - CONST char *section; + const char *section; char type; }; /* Map section names to POSIX/BSD single-character symbol types. This table is probably incomplete. It is sorted for convenience of adding entries. Since it is so short, a linear search is used. */ -static CONST struct section_to_type stt[] = +static const struct section_to_type stt[] = { - {"*DEBUG*", 'N'}, {".bss", 'b'}, + {"code", 't'}, /* MRI .text */ {".data", 'd'}, - {".sbss", 's'}, /* Small BSS (uninitialized data) */ - {".scommon", 'c'}, /* Small common */ - {".sdata", 'g'}, /* Small initialized data */ + {"*DEBUG*", 'N'}, + {".debug", 'N'}, /* MSVC's .debug (non-standard debug syms) */ + {".drectve", 'i'}, /* MSVC's .drective section */ + {".edata", 'e'}, /* MSVC's .edata (export) section */ + {".fini", 't'}, /* ELF fini section */ + {".idata", 'i'}, /* MSVC's .idata (import) section */ + {".init", 't'}, /* ELF init section */ + {".pdata", 'p'}, /* MSVC's .pdata (stack unwind) section */ + {".rdata", 'r'}, /* Read only data. */ + {".rodata", 'r'}, /* Read only data. */ + {".sbss", 's'}, /* Small BSS (uninitialized data). */ + {".scommon", 'c'}, /* Small common. */ + {".sdata", 'g'}, /* Small initialized data. */ {".text", 't'}, + {"vars", 'd'}, /* MRI .data */ + {"zerovars", 'b'}, /* MRI .bss */ {0, 0} }; /* Return the single-character symbol type corresponding to - section S, or '?' for an unknown COFF section. */ + section S, or '?' for an unknown COFF section. + + Check for any leading string which matches, so .text5 returns + 't' as well as .text */ static char coff_section_type (s) - char *s; + const char *s; { - CONST struct section_to_type *t; + const struct section_to_type *t; for (t = &stt[0]; t->section; t++) - if (!strcmp (s, t->section)) + if (!strncmp (s, t->section, strlen (t->section))) return t->type; + return '?'; } -#ifndef islower -#define islower(c) ((c) >= 'a' && (c) <= 'z') -#endif -#ifndef toupper -#define toupper(c) (islower(c) ? ((c) & ~0x20) : (c)) -#endif - /* FUNCTION bfd_decode_symclass @@ -477,21 +608,42 @@ bfd_decode_symclass (symbol) if (bfd_is_com_section (symbol->section)) return 'C'; - if (symbol->section == &bfd_und_section) - return 'U'; - if (symbol->section == &bfd_ind_section) + if (bfd_is_und_section (symbol->section)) + { + if (symbol->flags & BSF_WEAK) + { + /* If weak, determine if it's specifically an object + or non-object weak. */ + if (symbol->flags & BSF_OBJECT) + return 'v'; + else + return 'w'; + } + else + return 'U'; + } + if (bfd_is_ind_section (symbol->section)) return 'I'; + if (symbol->flags & BSF_WEAK) + { + /* If weak, determine if it's specifically an object + or non-object weak. */ + if (symbol->flags & BSF_OBJECT) + return 'V'; + else + return 'W'; + } if (!(symbol->flags & (BSF_GLOBAL | BSF_LOCAL))) return '?'; - if (symbol->section == &bfd_abs_section) + if (bfd_is_abs_section (symbol->section)) c = 'a'; else if (symbol->section) c = coff_section_type (symbol->section->name); else return '?'; if (symbol->flags & BSF_GLOBAL) - c = toupper (c); + c = TOUPPER (c); return c; /* We don't have to handle these cases just yet, but we will soon: @@ -504,6 +656,26 @@ bfd_decode_symclass (symbol) */ } +/* +FUNCTION + bfd_is_undefined_symclass + +DESCRIPTION + Returns non-zero if the class symbol returned by + bfd_decode_symclass represents an undefined symbol. + Returns zero otherwise. + +SYNOPSIS + boolean bfd_is_undefined_symclass (int symclass); +*/ + +boolean +bfd_is_undefined_symclass (symclass) + int symclass; +{ + return symclass == 'U' || symclass == 'w' || symclass == 'v'; +} + /* FUNCTION bfd_symbol_info @@ -523,15 +695,651 @@ bfd_symbol_info (symbol, ret) symbol_info *ret; { ret->type = bfd_decode_symclass (symbol); - if (ret->type != 'U') - ret->value = symbol->value + symbol->section->vma; - else + + if (bfd_is_undefined_symclass (ret->type)) ret->value = 0; + else + ret->value = symbol->value + symbol->section->vma; + ret->name = symbol->name; } -void -bfd_symbol_is_absolute () +/* +FUNCTION + bfd_copy_private_symbol_data + +SYNOPSIS + boolean bfd_copy_private_symbol_data(bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym); + +DESCRIPTION + Copy private symbol information from @var{isym} in the BFD + @var{ibfd} to the symbol @var{osym} in the BFD @var{obfd}. + Return <> on success, <> on error. Possible error + returns are: + + o <> - + Not enough memory exists to create private data for @var{osec}. + +.#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ +. BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ +. (ibfd, isymbol, obfd, osymbol)) +. +*/ + +/* The generic version of the function which returns mini symbols. + This is used when the backend does not provide a more efficient + version. It just uses BFD asymbol structures as mini symbols. */ + +long +_bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep) + bfd *abfd; + boolean dynamic; + PTR *minisymsp; + unsigned int *sizep; +{ + long storage; + asymbol **syms = NULL; + long symcount; + + if (dynamic) + storage = bfd_get_dynamic_symtab_upper_bound (abfd); + else + storage = bfd_get_symtab_upper_bound (abfd); + if (storage < 0) + goto error_return; + if (storage == 0) + return 0; + + syms = (asymbol **) bfd_malloc ((bfd_size_type) storage); + if (syms == NULL) + goto error_return; + + if (dynamic) + symcount = bfd_canonicalize_dynamic_symtab (abfd, syms); + else + symcount = bfd_canonicalize_symtab (abfd, syms); + if (symcount < 0) + goto error_return; + + *minisymsp = (PTR) syms; + *sizep = sizeof (asymbol *); + return symcount; + + error_return: + if (syms != NULL) + free (syms); + return -1; +} + +/* The generic version of the function which converts a minisymbol to + an asymbol. We don't worry about the sym argument we are passed; + we just return the asymbol the minisymbol points to. */ + +/*ARGSUSED*/ +asymbol * +_bfd_generic_minisymbol_to_symbol (abfd, dynamic, minisym, sym) + bfd *abfd ATTRIBUTE_UNUSED; + boolean dynamic ATTRIBUTE_UNUSED; + const PTR minisym; + asymbol *sym ATTRIBUTE_UNUSED; +{ + 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. */ + +/* We use a cache by default. */ + +#define ENABLE_CACHING + +/* We keep an array of indexentry structures to record where in the + stabs section we should look to find line number information for a + particular address. */ + +struct indexentry +{ + bfd_vma val; + bfd_byte *stab; + bfd_byte *str; + char *directory_name; + char *file_name; + char *function_name; +}; + +/* Compare two indexentry structures. This is called via qsort. */ + +static int +cmpindexentry (a, b) + const PTR a; + const PTR b; +{ + const struct indexentry *contestantA = (const struct indexentry *) a; + const struct indexentry *contestantB = (const struct indexentry *) b; + + if (contestantA->val < contestantB->val) + return -1; + else if (contestantA->val > contestantB->val) + return 1; + else + return 0; +} + +/* A pointer to this structure is stored in *pinfo. */ + +struct stab_find_info { - abort (); + /* 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; + + /* A table that indexes stabs by memory address. */ + struct indexentry *indextable; + /* The number of entries in indextable. */ + int indextablesize; + +#ifdef ENABLE_CACHING + /* Cached values to restart quickly. */ + struct indexentry *cached_indexentry; + bfd_vma cached_offset; + bfd_byte *cached_stab; + char *cached_file_name; +#endif + + /* Saved ptr to malloc'ed filename. */ + char *filename; +}; + +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, *str; + bfd_byte *last_stab = NULL; + bfd_size_type stroff; + struct indexentry *indexentry; + char *file_name; + char *directory_name; + int saw_fun; + boolean saw_line, saw_func; + + *pfound = false; + *pfilename = bfd_get_filename (abfd); + *pfnname = NULL; + *pline = 0; + + /* 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) + + 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; + int i; + char *name; + char *function_name; + bfd_size_type amt = sizeof *info; + + info = (struct stab_find_info *) bfd_zalloc (abfd, amt); + 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 = (PTR) 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, + (bfd_vma) 0, stabsize) + || ! bfd_get_section_contents (abfd, info->strsec, info->strs, + (bfd_vma) 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 ((bfd_size_type) 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, (bfd_vma) val, info->stabs + r->address); + } + } + + if (reloc_vector != NULL) + free (reloc_vector); + + /* First time through this function, build a table matching + function VM addresses to stabs, then sort based on starting + VM address. Do this in two passes: once to count how many + table entries we'll need, and a second to actually build the + table. */ + + info->indextablesize = 0; + saw_fun = 1; + for (stab = info->stabs; stab < info->stabs + stabsize; stab += STABSIZE) + { + if (stab[TYPEOFF] == N_SO) + { + /* N_SO with null name indicates EOF */ + if (bfd_get_32 (abfd, stab + STRDXOFF) == 0) + continue; + + /* if we did not see a function def, leave space for one. */ + if (saw_fun == 0) + ++info->indextablesize; + + saw_fun = 0; + + /* two N_SO's in a row is a filename and directory. Skip */ + if (stab + STABSIZE < info->stabs + stabsize + && *(stab + STABSIZE + TYPEOFF) == N_SO) + { + stab += STABSIZE; + } + } + else if (stab[TYPEOFF] == N_FUN) + { + saw_fun = 1; + ++info->indextablesize; + } + } + + if (saw_fun == 0) + ++info->indextablesize; + + if (info->indextablesize == 0) + return true; + ++info->indextablesize; + + amt = info->indextablesize; + amt *= sizeof (struct indexentry); + info->indextable = (struct indexentry *) bfd_alloc (abfd, amt); + if (info->indextable == NULL) + return false; + + file_name = NULL; + directory_name = NULL; + saw_fun = 1; + + for (i = 0, stroff = 0, stab = info->stabs, str = info->strs; + i < info->indextablesize && stab < info->stabs + stabsize; + stab += STABSIZE) + { + switch (stab[TYPEOFF]) + { + case 0: + /* This is the first entry in a compilation unit. */ + if ((bfd_size_type) ((info->strs + strsize) - str) < stroff) + break; + str += stroff; + stroff = bfd_get_32 (abfd, stab + VALOFF); + break; + + case N_SO: + /* The main file name. */ + + /* The following code creates a new indextable entry with + a NULL function name if there were no N_FUNs in a file. + Note that a N_SO without a file name is an EOF and + there could be 2 N_SO following it with the new filename + and directory. */ + if (saw_fun == 0) + { + info->indextable[i].val = bfd_get_32 (abfd, last_stab + VALOFF); + info->indextable[i].stab = last_stab; + info->indextable[i].str = str; + info->indextable[i].directory_name = directory_name; + info->indextable[i].file_name = file_name; + info->indextable[i].function_name = NULL; + ++i; + } + saw_fun = 0; + + file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); + if (*file_name == '\0') + { + directory_name = NULL; + file_name = NULL; + saw_fun = 1; + } + else + { + last_stab = stab; + if (stab + STABSIZE >= info->stabs + stabsize + || *(stab + STABSIZE + TYPEOFF) != N_SO) + { + directory_name = NULL; + } + else + { + /* Two consecutive N_SOs are a directory and a + file name. */ + stab += STABSIZE; + directory_name = file_name; + file_name = ((char *) str + + bfd_get_32 (abfd, stab + STRDXOFF)); + } + } + break; + + case N_SOL: + /* The name of an include file. */ + file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); + break; + + case N_FUN: + /* A function name. */ + saw_fun = 1; + name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); + + if (*name == '\0') + name = NULL; + + function_name = name; + + if (name == NULL) + continue; + + info->indextable[i].val = bfd_get_32 (abfd, stab + VALOFF); + info->indextable[i].stab = stab; + info->indextable[i].str = str; + info->indextable[i].directory_name = directory_name; + info->indextable[i].file_name = file_name; + info->indextable[i].function_name = function_name; + ++i; + break; + } + } + + if (saw_fun == 0) + { + info->indextable[i].val = bfd_get_32 (abfd, last_stab + VALOFF); + info->indextable[i].stab = last_stab; + info->indextable[i].str = str; + info->indextable[i].directory_name = directory_name; + info->indextable[i].file_name = file_name; + info->indextable[i].function_name = NULL; + ++i; + } + + info->indextable[i].val = (bfd_vma) -1; + info->indextable[i].stab = info->stabs + stabsize; + info->indextable[i].str = str; + info->indextable[i].directory_name = NULL; + info->indextable[i].file_name = NULL; + info->indextable[i].function_name = NULL; + ++i; + + info->indextablesize = i; + qsort (info->indextable, (size_t) i, sizeof (struct indexentry), + cmpindexentry); + + *pinfo = (PTR) info; + } + + /* We are passed a section relative offset. The offsets in the + stabs information are absolute. */ + offset += bfd_get_section_vma (abfd, section); + +#ifdef ENABLE_CACHING + if (info->cached_indexentry != NULL + && offset >= info->cached_offset + && offset < (info->cached_indexentry + 1)->val) + { + stab = info->cached_stab; + indexentry = info->cached_indexentry; + file_name = info->cached_file_name; + } + else +#endif + { + /* Cache non-existant or invalid. Do binary search on + indextable. */ + + long low, high; + long mid = -1; + + indexentry = NULL; + + low = 0; + high = info->indextablesize - 1; + while (low != high) + { + mid = (high + low) / 2; + if (offset >= info->indextable[mid].val + && offset < info->indextable[mid + 1].val) + { + indexentry = &info->indextable[mid]; + break; + } + + if (info->indextable[mid].val > offset) + high = mid; + else + low = mid + 1; + } + + if (indexentry == NULL) + return true; + + stab = indexentry->stab + STABSIZE; + file_name = indexentry->file_name; + } + + directory_name = indexentry->directory_name; + str = indexentry->str; + + saw_line = false; + saw_func = false; + for (; stab < (indexentry+1)->stab; stab += STABSIZE) + { + boolean done; + bfd_vma val; + + done = false; + + switch (stab[TYPEOFF]) + { + case N_SOL: + /* The name of an include file. */ + val = bfd_get_32 (abfd, stab + VALOFF); + if (val <= offset) + { + file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); + *pline = 0; + } + 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 = indexentry->val + bfd_get_32 (abfd, stab + VALOFF); + /* If this line starts before our desired offset, or if it's + the first line we've been able to find, use it. The + !saw_line check works around a bug in GCC 2.95.3, which emits + the first N_SLINE late. */ + if (!saw_line || val <= offset) + { + *pline = bfd_get_16 (abfd, stab + DESCOFF); + +#ifdef ENABLE_CACHING + info->cached_stab = stab; + info->cached_offset = val; + info->cached_file_name = file_name; + info->cached_indexentry = indexentry; +#endif + } + if (val > offset) + done = true; + saw_line = true; + break; + + case N_FUN: + case N_SO: + if (saw_func || saw_line) + done = true; + saw_func = true; + break; + } + + if (done) + break; + } + + *pfound = true; + + if (file_name == NULL || IS_ABSOLUTE_PATH (file_name) + || directory_name == NULL) + *pfilename = 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, file_name) != 0) + { + if (info->filename != NULL) + free (info->filename); + info->filename = (char *) bfd_malloc ((bfd_size_type) dirlen + + strlen (file_name) + 1); + if (info->filename == NULL) + return false; + strcpy (info->filename, directory_name); + strcpy (info->filename + dirlen, file_name); + } + + *pfilename = info->filename; + } + + if (indexentry->function_name != 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 (indexentry->function_name, ':'); + if (s != NULL) + *s = '\0'; + + *pfnname = indexentry->function_name; + } + + return true; }