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
This commit is contained in:
Julian Seward 2006-01-13 23:12:49 +00:00
parent 171ac07602
commit e626b54566

View File

@ -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;
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);
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 )
/* Show a raw ELF symbol, given its in-image address and name. */
static
void show_raw_elf_symbol ( Int i,
ElfXX_Sym* sym, Char* sym_name, Addr sym_addr)
{
Bool plausible;
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" ) );
}
/* Set default real address for the symbol. */
*sym_addr_really = sym_addr;
/* 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 */ )
__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;
RiSym risym;
Char* name;
ElfXX_Sym* sym;
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" ) );
}
if (VG_(clo_trace_symtab))
show_raw_elf_symbol(i, sym, sym_name, sym_addr);
// 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 (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)) {
name = ML_(addStr) ( si, sym_name, -1 );
vg_assert(name != NULL);
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;