From: Julian Seward Date: Fri, 13 Jan 2006 23:12:49 +0000 (+0000) Subject: Tidy up ELF symbol table reading a bit. Make a completely new X-Git-Tag: svn/VALGRIND_3_2_0~384 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e626b54566d7705228b7684e166a3c46b4ce1bec;p=thirdparty%2Fvalgrind.git Tidy up ELF symbol table reading a bit. Make a completely new function for reading ELF symbol tables on ppc64-linux so as to avoid cluttering up the {x86,amd64,ppc32}-linux cases with convoluted hoop-jumping needed to handle both the dotful (older) and dotless (newer) ppc64-linux ABI variants. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@5527 --- diff --git a/coregrind/m_debuginfo/symtab.c b/coregrind/m_debuginfo/symtab.c index 074767a3db..99c756a01e 100644 --- a/coregrind/m_debuginfo/symtab.c +++ b/coregrind/m_debuginfo/symtab.c @@ -47,6 +47,7 @@ #include "pub_core_options.h" #include "pub_core_redir.h" // VG_(redir_notify_{new,delete}_SegInfo) #include "pub_core_tooliface.h" // VG_(needs).data_syms +#include "pub_core_oset.h" // for ppc64-linux elf symbol reading #include "pub_core_aspacemgr.h" @@ -285,8 +286,7 @@ Char* ML_(addStr) ( SegInfo* si, Char* str, Int len ) } /* Add a symbol to the symbol table. */ -static __inline__ -void addSym ( SegInfo* si, RiSym* sym ) +static void addSym ( SegInfo* si, RiSym* sym ) { UInt new_sz, i; RiSym* new_tab; @@ -1061,55 +1061,117 @@ void canonicaliseCfiSI ( SegInfo* si ) /*------------------------------------------------------------*/ -/*--- Read info from a .so/exe file. ---*/ +/*--- ---*/ +/*--- Read symbol table and line info from ELF files. ---*/ +/*--- ---*/ /*------------------------------------------------------------*/ +/* Identify an ELF object file. */ + static Bool is_elf_object_file(const void *buf) { - { - ElfXX_Ehdr *ehdr = (ElfXX_Ehdr *)buf; - Int ok = 1; - - ok &= (ehdr->e_ident[EI_MAG0] == 0x7F - && ehdr->e_ident[EI_MAG1] == 'E' - && ehdr->e_ident[EI_MAG2] == 'L' - && ehdr->e_ident[EI_MAG3] == 'F'); - ok &= (ehdr->e_ident[EI_CLASS] == VG_ELF_CLASS - && ehdr->e_ident[EI_DATA] == VG_ELF_DATA2XXX - && ehdr->e_ident[EI_VERSION] == EV_CURRENT); - ok &= (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN); - ok &= (ehdr->e_machine == VG_ELF_MACHINE); - ok &= (ehdr->e_version == EV_CURRENT); - ok &= (ehdr->e_shstrndx != SHN_UNDEF); - ok &= (ehdr->e_shoff != 0 && ehdr->e_shnum != 0); - ok &= (ehdr->e_phoff != 0 && ehdr->e_phnum != 0); + ElfXX_Ehdr *ehdr = (ElfXX_Ehdr *)buf; + Int ok = 1; + + ok &= (ehdr->e_ident[EI_MAG0] == 0x7F + && ehdr->e_ident[EI_MAG1] == 'E' + && ehdr->e_ident[EI_MAG2] == 'L' + && ehdr->e_ident[EI_MAG3] == 'F'); + ok &= (ehdr->e_ident[EI_CLASS] == VG_ELF_CLASS + && ehdr->e_ident[EI_DATA] == VG_ELF_DATA2XXX + && ehdr->e_ident[EI_VERSION] == EV_CURRENT); + ok &= (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN); + ok &= (ehdr->e_machine == VG_ELF_MACHINE); + ok &= (ehdr->e_version == EV_CURRENT); + ok &= (ehdr->e_shstrndx != SHN_UNDEF); + ok &= (ehdr->e_shoff != 0 && ehdr->e_shnum != 0); + ok &= (ehdr->e_phoff != 0 && ehdr->e_phnum != 0); - if (ok) - return True; - } - - /* other file formats here? */ - - return False; + if (ok) + return True; + else + return False; } -/* Decide whether SYM is something we should collect. It may also - decide to change the stated address of the symbol, in which case a - different value is assigned to *SYM_ADDR_REALLY; otherwise SYM is - copied to *SYM_ADDR_REALLY. */ -static Bool is_interesting_symbol( SegInfo* si, - ElfXX_Sym* sym, - Char* sym_name, - Addr sym_addr, - UChar* opd_filea, /* oimage addr of .opd sec - (ppc64-linux only) */ - /*OUT*/Addr* sym_addr_really ) -{ - Bool plausible; +/* Show a raw ELF symbol, given its in-image address and name. */ - /* Set default real address for the symbol. */ - *sym_addr_really = sym_addr; +static +void show_raw_elf_symbol ( Int i, + ElfXX_Sym* sym, Char* sym_name, Addr sym_addr) +{ + VG_(printf)("raw symbol [%3d]: ", i); + switch (ELFXX_ST_BIND(sym->st_info)) { + case STB_LOCAL: VG_(printf)("LOC "); break; + case STB_GLOBAL: VG_(printf)("GLO "); break; + case STB_WEAK: VG_(printf)("WEA "); break; + case STB_LOPROC: VG_(printf)("lop "); break; + case STB_HIPROC: VG_(printf)("hip "); break; + default: VG_(printf)("??? "); break; + } + switch (ELFXX_ST_TYPE(sym->st_info)) { + case STT_NOTYPE: VG_(printf)("NOT "); break; + case STT_OBJECT: VG_(printf)("OBJ "); break; + case STT_FUNC: VG_(printf)("FUN "); break; + case STT_SECTION: VG_(printf)("SEC "); break; + case STT_FILE: VG_(printf)("FIL "); break; + case STT_LOPROC: VG_(printf)("lop "); break; + case STT_HIPROC: VG_(printf)("hip "); break; + default: VG_(printf)("??? "); break; + } + VG_(printf)(": val %08p, sz %4d %s\n", + sym_addr, sym->st_size, + ( sym->st_name ? sym_name : (Char*)"NONAME" ) ); +} + + +/* Decide whether SYM is something we should collect, and if so, copy + relevant info to the _OUT arguments. For {x86,amd64,ppc32}-linux + this is straightforward - the name, address, size are copied out + unchanged. + + For ppc64-linux it's more complex. If the symbol is seen to be in + the .opd section, it is taken to be a function descriptor, and so + a dereference is attempted, in order to get hold of the real entry + point address. Also as part of the dereference, there is an attempt + to calculate the TOC pointer (R2 value) associated with the symbol. + + To support the ppc64-linux pre-"dotless" ABI (prior to gcc 4.0.0), + if the symbol is seen to be outside the .opd section and its name + starts with a dot, and .opd deference is not attempted, and no TOC + pointer is calculated, but the the leading dot is removed from the + name. + + As a result, on ppc64-linux, the caller of this function may have + to piece together the real size, address, name of the symbol from + multiple calls to this function. Ugly and confusing. +*/ +static +Bool get_elf_symbol_info ( + /* INPUTS */ + SegInfo* si, /* containing SegInfo */ + ElfXX_Sym* sym, /* ELF symbol */ + Char* sym_name, /* name */ + Addr sym_addr, /* declared address */ + UChar* opd_filea, /* oimage of .opd sec (ppc64-linux only) */ + /* OUTPUTS */ + Char** sym_name_out, /* name we should record */ + Addr* sym_addr_out, /* addr we should record */ + Int* sym_size_out, /* symbol size */ + Addr* sym_tocptr_out, /* ppc64-linux only: R2 value to be + used on entry */ + Bool* did_opd_deref_out /* ppc64-linux only: did we deref an + .opd entry? */ + ) +{ + Bool plausible, is_in_opd; + + /* Set defaults */ + *sym_name_out = sym_name; + *sym_addr_out = sym_addr; + *sym_size_out = (Int)sym->st_size; + *sym_tocptr_out = 0; /* unknown/inapplicable */ + *did_opd_deref_out = False; /* Figure out if we're interested in the symbol. Firstly, is it of the right flavour? */ @@ -1140,28 +1202,13 @@ static Bool is_interesting_symbol( SegInfo* si, if (!plausible) return False; - /* Secondly, if it's apparently in a GOT or PLT, it's really - a reference to a symbol defined elsewhere, so ignore it. */ - if (si->got_start_vma != 0 - && sym_addr >= si->got_start_vma - && sym_addr < si->got_start_vma + si->got_size) { - TRACE_SYMTAB("ignore -- in GOT: %s\n", sym_name); - return False; - } - if (si->plt_start_vma != 0 - && sym_addr >= si->plt_start_vma - && sym_addr < si->plt_start_vma + si->plt_size) { - TRACE_SYMTAB("ignore -- in PLT: %s\n", sym_name); - return False; - } - - /* Don't bother if nameless, or zero-sized. */ + /* Ignore if nameless, or zero-sized. */ if (sym->st_name == (ElfXX_Word)NULL || /* VG_(strlen)(sym_name) == 0 */ /* equivalent but cheaper ... */ sym_name[0] == 0 || sym->st_size == 0) { - TRACE_SYMTAB("ignore -- size=0: %s\n", sym_name); + TRACE_SYMTAB(" ignore -- size=0: %s\n", sym_name); return False; } @@ -1169,22 +1216,40 @@ static Bool is_interesting_symbol( SegInfo* si, symbols, and particularly reduces the number of overlapping address ranges. Don't ask me why ... */ if ((Int)sym->st_value == 0) { - TRACE_SYMTAB( "ignore -- valu=0: %s\n", sym_name); + TRACE_SYMTAB( " ignore -- valu=0: %s\n", sym_name); return False; } - /* ppc64-linux nasty hack: if the symbol is in a .opd section, then - really what we have is the address of a function descriptor. So - use the first word of that as the function's text. + /* If it's apparently in a GOT or PLT, it's really a reference to a + symbol defined elsewhere, so ignore it. */ + if (si->got_start_vma != 0 + && sym_addr >= si->got_start_vma + && sym_addr < si->got_start_vma + si->got_size) { + TRACE_SYMTAB(" ignore -- in GOT: %s\n", sym_name); + return False; + } + if (si->plt_start_vma != 0 + && sym_addr >= si->plt_start_vma + && sym_addr < si->plt_start_vma + si->plt_size) { + TRACE_SYMTAB(" ignore -- in PLT: %s\n", sym_name); + return False; + } + + /* ppc64-linux nasty hack: if the symbol is in an .opd section, + then really what we have is the address of a function + descriptor. So use the first word of that as the function's + text. See thread starting at http://gcc.gnu.org/ml/gcc-patches/2004-08/msg00557.html */ + is_in_opd = False; + if (si->opd_start_vma != 0 && sym_addr >= si->opd_start_vma && sym_addr < si->opd_start_vma + si->opd_size) { # if !defined(VGP_ppc64_linux) - TRACE_SYMTAB("ignore -- in OPD: %s\n", sym_name); + TRACE_SYMTAB(" ignore -- in OPD: %s\n", sym_name); return False; # else Int offset_in_opd; @@ -1193,16 +1258,20 @@ static Bool is_interesting_symbol( SegInfo* si, if (0) VG_(printf)("opdXXX: si->offset %p, sym_addr %p\n", (void*)(si->offset), (void*)sym_addr); - if (!VG_IS_8_ALIGNED(sym_addr)) + if (!VG_IS_8_ALIGNED(sym_addr)) { + TRACE_SYMTAB(" ignore -- not 8-aligned: %s\n", sym_name); return False; + } /* sym_addr is a vma pointing into the .opd section. We know the vma of the opd section start, so we can figure out how far into the opd section this is. */ offset_in_opd = (Addr)sym_addr - (Addr)(si->opd_start_vma); - if (offset_in_opd < 0 || offset_in_opd >= si->opd_size) + if (offset_in_opd < 0 || offset_in_opd >= si->opd_size) { + TRACE_SYMTAB(" ignore -- invalid OPD offset: %s\n", sym_name); return False; + } /* Now we want to know what's at that offset in the .opd section. We can't look in the running image since it won't @@ -1212,7 +1281,8 @@ static Bool is_interesting_symbol( SegInfo* si, fn_descr = (ULong*)(opd_filea + offset_in_opd); - if (0) VG_(printf)("opdXXY: offset %d, fn_descr %p\n", offset_in_opd, fn_descr); + if (0) VG_(printf)("opdXXY: offset %d, fn_descr %p\n", + offset_in_opd, fn_descr); if (0) VG_(printf)("opdXXZ: *fn_descr %p\n", (void*)(fn_descr[0])); sym_addr = fn_descr[0]; @@ -1224,7 +1294,9 @@ static Bool is_interesting_symbol( SegInfo* si, sym_addr to get the real vma. */ sym_addr += si->offset; - *sym_addr_really = sym_addr; + *sym_addr_out = sym_addr; + *did_opd_deref_out = True; + is_in_opd = True; /* Do a final sanity check: if the symbol falls outside the SegInfo's mapped range, ignore it. Since sym_addr has been @@ -1234,31 +1306,60 @@ static Bool is_interesting_symbol( SegInfo* si, # endif /* ppc64-linux nasty hack */ } + /* Here's yet another ppc64-linux hack. Get rid of leading dot if + the symbol is outside .opd. */ +# if defined(VGP_ppc64_linux) + if (si->opd_start_vma != 0 + && !is_in_opd + && sym_name[0] == '.') { + vg_assert(!(*did_opd_deref_out)); + *sym_name_out = &sym_name[1]; + } +# endif + /* If no part of the symbol falls within the mapped range, ignore it. */ - if (sym_addr+sym->st_size <= si->start - || sym_addr >= si->start+si->size) { - TRACE_SYMTAB( "ignore -- outside mapped range\n" ); + if (*sym_addr_out + *sym_size_out <= si->start + || *sym_addr_out >= si->start+si->size) { + TRACE_SYMTAB( " ignore -- outside mapped range\n" ); return False; } - // It is an interesting symbol! +# if defined(VGP_ppc64_linux) + /* It's crucial that we never add symbol addresses in the .opd + section. This would completely mess up function redirection and + intercepting. This assert ensures that any symbols that make it + into the symbol table on ppc64-linux don't point into .opd. */ + if (si->opd_start_vma != 0) { + vg_assert(*sym_addr_out + *sym_size_out <= si->opd_start_vma + || *sym_addr_out >= si->opd_start_vma + si->opd_size); + } +# endif + + /* Acquire! */ return True; } -/* Read a symbol table (normal or dynamic) */ + +/* Read an ELF symbol table (normal or dynamic). This one is for the + "normal" case ({x86,amd64,ppc32}-linux). */ static -void read_symtab( SegInfo* si, Char* tab_name, Bool do_intercepts, - ElfXX_Sym* o_symtab, UInt o_symtab_sz, - UChar* o_strtab, UInt o_strtab_sz, - UChar* opd_filea /* ppc64-linux only */ ) -{ - Int i; - Addr sym_addr, sym_addr_really; - Char* sym_name; - RiSym risym; - Char* name; - ElfXX_Sym* sym; +__attribute__((unused)) /* not referred to on all targets */ +void read_elf_symtab__normal( + SegInfo* si, Char* tab_name, + ElfXX_Sym* o_symtab, UInt o_symtab_sz, + UChar* o_strtab, UInt o_strtab_sz, + UChar* opd_filea /* ppc64-linux only */ + ) +{ + Int i; + Addr sym_addr, sym_addr_really; + Char *sym_name, *sym_name_really; + Int sym_size; + Addr sym_tocptr; + Bool did_opd_deref; + RiSym risym; + ElfXX_Sym *sym; if (o_strtab == NULL || o_symtab == NULL) { Char buf[80]; @@ -1268,7 +1369,7 @@ void read_symtab( SegInfo* si, Char* tab_name, Bool do_intercepts, return; } - TRACE_SYMTAB("Reading %s (%d entries)\n", tab_name, + TRACE_SYMTAB("Reading (ELF, standard) %s (%d entries)\n", tab_name, o_symtab_sz/sizeof(ElfXX_Sym) ); /* Perhaps should start at i = 1; ELF docs suggest that entry @@ -1278,74 +1379,212 @@ void read_symtab( SegInfo* si, Char* tab_name, Bool do_intercepts, sym_name = (Char*)(o_strtab + sym->st_name); sym_addr = si->offset + sym->st_value; - if (VG_(clo_trace_symtab)) { - VG_(printf)("raw symbol [%d]: ", i); - switch (ELFXX_ST_BIND(sym->st_info)) { - case STB_LOCAL: VG_(printf)("LOC "); break; - case STB_GLOBAL: VG_(printf)("GLO "); break; - case STB_WEAK: VG_(printf)("WEA "); break; - case STB_LOPROC: VG_(printf)("lop "); break; - case STB_HIPROC: VG_(printf)("hip "); break; - default: VG_(printf)("??? "); break; - } - switch (ELFXX_ST_TYPE(sym->st_info)) { - case STT_NOTYPE: VG_(printf)("NOT "); break; - case STT_OBJECT: VG_(printf)("OBJ "); break; - case STT_FUNC: VG_(printf)("FUN "); break; - case STT_SECTION: VG_(printf)("SEC "); break; - case STT_FILE: VG_(printf)("FIL "); break; - case STT_LOPROC: VG_(printf)("lop "); break; - case STT_HIPROC: VG_(printf)("hip "); break; - default: VG_(printf)("??? "); break; - } - VG_(printf)( - ": value %p, size %d, name %s\n", - sym_addr, sym->st_size, - ( sym->st_name ? sym_name : (Char*)"NONAME" ) ); - } - - // Record interesting symbols in our symtab. - if ( is_interesting_symbol(si, sym, sym_name, sym_addr, - opd_filea, &sym_addr_really) ) { - vg_assert(sym->st_name != 0); - vg_assert(sym_name[0] != 0); -# if defined(VGP_ppc64_linux) - /* It's crucial that we never add symbol addresses in the - .opd section. This would completely mess up function - redirection and intercepting. This assert ensures that - any symbols that make it into the symbol table on - ppc64-linux don't point into .opd. */ - vg_assert(sym_addr_really + sym->st_size <= si->opd_start_vma - || sym_addr_really >= si->opd_start_vma + si->opd_size); -# endif -# if defined(VGP_ppc64_linux) - /* Another ppc64-linux kludge, for the pre-"dotless" ABI - (prior to gcc 4.0.0). If the symbol to be added has a - leading dot and it wasn't derived via an indirect through - .opd, remove the dot before adding it. */ - if (sym_addr_really == sym_addr && sym_name[0] == '.') - sym_name++; -# endif + if (VG_(clo_trace_symtab)) + show_raw_elf_symbol(i, sym, sym_name, sym_addr); - name = ML_(addStr) ( si, sym_name, -1 ); - vg_assert(name != NULL); + if (get_elf_symbol_info(si, sym, sym_name, sym_addr, opd_filea, + &sym_name_really, + &sym_addr_really, + &sym_size, + &sym_tocptr, + &did_opd_deref)) { - risym.addr = sym_addr_really; - risym.size = sym->st_size; - risym.name = name; + risym.addr = sym_addr_really; + risym.size = sym_size; + risym.name = ML_(addStr) ( si, sym_name_really, -1 ); + vg_assert(risym.name != NULL); addSym ( si, &risym ); - if (VG_(clo_trace_symtab)) - VG_(printf)(" record [%d]: " - " value %p, size %d, name %s\n", + if (VG_(clo_trace_symtab)) { + VG_(printf)(" record [%3d]: " + " val %8p, sz %4d %s\n", i, (void*)risym.addr, (Int)risym.size, (HChar*)risym.name ); + } + + } + } +} + + +/* Read an ELF symbol table (normal or dynamic). This one is for + ppc64-linux, which requires special treatment. */ + +typedef + struct { + Addr addr; + Char* name; + } + TempSymKey; + +typedef + struct { + TempSymKey key; + Addr tocptr; + Int size; + Bool from_opd; + } + TempSym; + +static Word cmp_TempSymKey ( TempSymKey* key1, TempSym* elem2 ) { + if (key1->addr < elem2->key.addr) return -1; + if (key1->addr > elem2->key.addr) return 1; + return (Word)VG_(strcmp)(key1->name, elem2->key.name); +} +static void* oset_malloc ( SizeT szB ) { + return VG_(arena_malloc)(VG_AR_SYMTAB, szB); +} +static void oset_free ( void* p ) { + VG_(arena_free)(VG_AR_SYMTAB, p); +} + +static +__attribute__((unused)) /* not referred to on all targets */ +void read_elf_symtab__ppc64_linux( + SegInfo* si, Char* tab_name, + ElfXX_Sym* o_symtab, UInt o_symtab_sz, + UChar* o_strtab, UInt o_strtab_sz, + UChar* opd_filea /* ppc64-linux only */ + ) +{ + Int i, old_size; + Addr sym_addr, sym_addr_really; + Char *sym_name, *sym_name_really; + Int sym_size; + Addr sym_tocptr; + Bool from_opd, modify; + RiSym risym; + ElfXX_Sym *sym; + OSet *oset; + TempSymKey key; + TempSym *elem; + TempSym *prev; + if (o_strtab == NULL || o_symtab == NULL) { + Char buf[80]; + vg_assert(VG_(strlen)(tab_name) < 40); + VG_(sprintf)(buf, " object doesn't have a %s", tab_name); + ML_(symerr)(buf); + return; + } + + TRACE_SYMTAB("Reading (ELF, ppc64-linux) %s (%d entries)\n", tab_name, + o_symtab_sz/sizeof(ElfXX_Sym) ); + + oset = VG_(OSet_Create)( offsetof(TempSym,key), + (OSetCmp_t)cmp_TempSymKey, + oset_malloc, oset_free ); + vg_assert(oset); + + /* Perhaps should start at i = 1; ELF docs suggest that entry + 0 always denotes 'unknown symbol'. */ + for (i = 1; i < (Int)(o_symtab_sz/sizeof(ElfXX_Sym)); i++) { + sym = & o_symtab[i]; + sym_name = (Char*)(o_strtab + sym->st_name); + sym_addr = si->offset + sym->st_value; + + if (VG_(clo_trace_symtab)) + show_raw_elf_symbol(i, sym, sym_name, sym_addr); + + if (get_elf_symbol_info(si, sym, sym_name, sym_addr, opd_filea, + &sym_name_really, + &sym_addr_really, + &sym_size, + &sym_tocptr, + &from_opd)) { + + /* Check if we've seen this (name,addr) key before. */ + key.addr = sym_addr_really; + key.name = sym_name_really; + prev = VG_(OSet_Lookup)( oset, &key ); + + if (prev) { + + /* Seen it before. Fold in whatever new info we can. */ + modify = False; + old_size = 0; + + if (prev->from_opd && !from_opd + && (prev->size == 24 || prev->size == 16) + && sym_size != prev->size) { + /* Existing one is an opd-redirect, with a bogus size, + so the only useful new fact we have is the real size + of the symbol. */ + modify = True; + old_size = prev->size; + prev->size = sym_size; + } + else + if (!prev->from_opd && from_opd + && (sym_size == 24 || sym_size == 16)) { + /* Existing one is non-opd, new one is. What we can + acquire from the new one is the TOC ptr to be used. + Since the existing sym is non-toc, it shouldn't + currently have an known TOC ptr. */ + } + else { + /* ignore. can we do better here? */ + } + + if (modify && VG_(clo_trace_symtab)) { + VG_(printf)(" modify (old sz %4d) " + " val %8p, sz %4d %s\n", + old_size, + (void*)prev->key.addr, (Int)prev->size, + (HChar*)prev->key.name + ); + } + + } else { + + /* A new (name,addr) key. Add and continue. */ + elem = VG_(OSet_AllocNode)(oset, sizeof(TempSym)); + vg_assert(elem); + elem->key = key; + elem->tocptr = sym_tocptr; + elem->size = sym_size; + elem->from_opd = from_opd; + VG_(OSet_Insert)(oset, elem); + if (VG_(clo_trace_symtab)) { + VG_(printf)(" to-oset [%3d]: " + " val %8p, sz %4d %s\n", + i, (void*)elem->key.addr, (Int)elem->size, + (HChar*)elem->key.name + ); + } + + } } } + + /* All the syms that matter are in the oset. Now pull them out, + build a "standard" symbol table, and nuke the oset. */ + + i = 0; + VG_(OSet_ResetIter)( oset ); + + while ( (elem = VG_(OSet_Next)(oset)) ) { + risym.addr = elem->key.addr; + risym.size = elem->size; + risym.name = ML_(addStr) ( si, elem->key.name, -1 ); + vg_assert(risym.name != NULL); + + addSym ( si, &risym ); + if (VG_(clo_trace_symtab)) { + VG_(printf)(" record [%3d]: " + " val %8p, sz %4d %s\n", + i, (void*)risym.addr, (Int)risym.size, + (HChar*)risym.name + ); + } + i++; + } + + VG_(OSet_Destroy)( oset, NULL ); } + /* * This routine for calculating the CRC for a separate debug file * is GPLed code borrowed from binutils. @@ -1493,10 +1732,15 @@ Addr find_debug_file( Char* objpath, Char* debugname, UInt crc, UInt* size ) return addr; } -/* Read the symbols from the object/exe specified by the SegInfo into - the tables within the supplied SegInfo. */ + +/* The central function for reading ELF debug info. For the + object/exe specified by the SegInfo, find ELF sections, then read + the symbols, line number info, file name info, CFA (stack-unwind + info) and anything else we want, into the tables within the + supplied SegInfo. +*/ static -Bool read_lib_symbols ( SegInfo* si ) +Bool read_elf_debug_info ( SegInfo* si ) { Bool res; ElfXX_Ehdr* ehdr; /* The ELF header */ @@ -1846,13 +2090,22 @@ Bool read_lib_symbols ( SegInfo* si ) } /* Read symbols */ - read_symtab(si, "symbol table", False, - o_symtab, o_symtab_sz, - o_strtab, o_strtab_sz, opd_filea); + { + void (*read_elf_symtab)(SegInfo*,Char*,ElfXX_Sym*, + UInt,UChar*,UInt,UChar*); +# if defined(VGP_ppc64_linux) + read_elf_symtab = read_elf_symtab__ppc64_linux; +# else + read_elf_symtab = read_elf_symtab__normal; +# endif + read_elf_symtab(si, "symbol table", + o_symtab, o_symtab_sz, + o_strtab, o_strtab_sz, opd_filea); - read_symtab(si, "dynamic symbol table", True, - o_dynsym, o_dynsym_sz, - o_dynstr, o_dynstr_sz, opd_filea); + read_elf_symtab(si, "dynamic symbol table", + o_dynsym, o_dynsym_sz, + o_dynstr, o_dynstr_sz, opd_filea); + } /* Read .eh_frame (call-frame-info) if any */ if (ehframe) { @@ -1944,7 +2197,7 @@ SegInfo *VG_(read_seg_symbols) ( Addr seg_addr, SizeT seg_len, { SegInfo* si = alloc_SegInfo(seg_addr, seg_len, seg_offset, seg_filename); - if (!read_lib_symbols ( si )) { + if (!read_elf_debug_info ( si )) { // Something went wrong (eg. bad ELF file). freeSegInfo( si ); si = NULL;