|
From: <sv...@va...> - 2006-01-13 23:12:57
|
Author: sewardj
Date: 2006-01-13 23:12:49 +0000 (Fri, 13 Jan 2006)
New Revision: 5527
Log:
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.
Modified:
trunk/coregrind/m_debuginfo/symtab.c
Modified: trunk/coregrind/m_debuginfo/symtab.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_debuginfo/symtab.c 2006-01-13 13:04:03 UTC (rev 552=
6)
+++ trunk/coregrind/m_debuginfo/symtab.c 2006-01-13 23:12:49 UTC (rev 552=
7)
@@ -47,6 +47,7 @@
#include "pub_core_options.h"
#include "pub_core_redir.h" // VG_(redir_notify_{new,delete}_SegIn=
fo)
#include "pub_core_tooliface.h" // VG_(needs).data_syms
+#include "pub_core_oset.h" // for ppc64-linux elf symbol reading
=20
#include "pub_core_aspacemgr.h"
=20
@@ -285,8 +286,7 @@
}
=20
/* 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 @@
=20
=20
/*------------------------------------------------------------*/
-/*--- Read info from a .so/exe file. ---*/
+/*--- ---*/
+/*--- Read symbol table and line info from ELF files. ---*/
+/*--- ---*/
/*------------------------------------------------------------*/
=20
+/* Identify an ELF object file. */
+
static Bool is_elf_object_file(const void *buf)
{
- {
- ElfXX_Ehdr *ehdr =3D (ElfXX_Ehdr *)buf;
- Int ok =3D 1;
+ ElfXX_Ehdr *ehdr =3D (ElfXX_Ehdr *)buf;
+ Int ok =3D 1;
=20
- ok &=3D (ehdr->e_ident[EI_MAG0] =3D=3D 0x7F
- && ehdr->e_ident[EI_MAG1] =3D=3D 'E'
- && ehdr->e_ident[EI_MAG2] =3D=3D 'L'
- && ehdr->e_ident[EI_MAG3] =3D=3D 'F');
- ok &=3D (ehdr->e_ident[EI_CLASS] =3D=3D VG_ELF_CLASS
- && ehdr->e_ident[EI_DATA] =3D=3D VG_ELF_DATA2XXX
- && ehdr->e_ident[EI_VERSION] =3D=3D EV_CURRENT);
- ok &=3D (ehdr->e_type =3D=3D ET_EXEC || ehdr->e_type =3D=3D ET_DYN=
);
- ok &=3D (ehdr->e_machine =3D=3D VG_ELF_MACHINE);
- ok &=3D (ehdr->e_version =3D=3D EV_CURRENT);
- ok &=3D (ehdr->e_shstrndx !=3D SHN_UNDEF);
- ok &=3D (ehdr->e_shoff !=3D 0 && ehdr->e_shnum !=3D 0);
- ok &=3D (ehdr->e_phoff !=3D 0 && ehdr->e_phnum !=3D 0);
+ ok &=3D (ehdr->e_ident[EI_MAG0] =3D=3D 0x7F
+ && ehdr->e_ident[EI_MAG1] =3D=3D 'E'
+ && ehdr->e_ident[EI_MAG2] =3D=3D 'L'
+ && ehdr->e_ident[EI_MAG3] =3D=3D 'F');
+ ok &=3D (ehdr->e_ident[EI_CLASS] =3D=3D VG_ELF_CLASS
+ && ehdr->e_ident[EI_DATA] =3D=3D VG_ELF_DATA2XXX
+ && ehdr->e_ident[EI_VERSION] =3D=3D EV_CURRENT);
+ ok &=3D (ehdr->e_type =3D=3D ET_EXEC || ehdr->e_type =3D=3D ET_DYN);
+ ok &=3D (ehdr->e_machine =3D=3D VG_ELF_MACHINE);
+ ok &=3D (ehdr->e_version =3D=3D EV_CURRENT);
+ ok &=3D (ehdr->e_shstrndx !=3D SHN_UNDEF);
+ ok &=3D (ehdr->e_shoff !=3D 0 && ehdr->e_shnum !=3D 0);
+ ok &=3D (ehdr->e_phoff !=3D 0 && ehdr->e_phnum !=3D 0);
=20
- if (ok)
- return True;
+ if (ok)
+ return True;
+ else
+ return False;
+}
+
+
+/* Show a raw ELF symbol, given its in-image address and name. */
+
+static
+void show_raw_elf_symbol ( Int i,=20
+ 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" ) );=20
+} =20
=20
- /* other file formats here? */
=20
- return False;
-}
+/* 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.
=20
-/* 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. */
+ 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.
=20
-static Bool is_interesting_symbol( SegInfo* si,=20
- ElfXX_Sym* sym,=20
- Char* sym_name,=20
- Addr sym_addr,
- UChar* opd_filea, /* oimage addr =
of .opd sec
- (ppc64-linux=
only) */
- /*OUT*/Addr* sym_addr_really )
+ 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=20
+Bool get_elf_symbol_info (=20
+ /* 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? */=20
+ )
{
- Bool plausible;
+ Bool plausible, is_in_opd;
=20
- /* Set default real address for the symbol. */
- *sym_addr_really =3D sym_addr;
+ /* Set defaults */
+ *sym_name_out =3D sym_name;
+ *sym_addr_out =3D sym_addr;
+ *sym_size_out =3D (Int)sym->st_size;
+ *sym_tocptr_out =3D 0; /* unknown/inapplicable */
+ *did_opd_deref_out =3D False;
=20
/* Figure out if we're interested in the symbol. Firstly, is it of
the right flavour? */
@@ -1140,28 +1202,13 @@
if (!plausible)
return False;
=20
- /* 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 !=3D 0
- && sym_addr >=3D si->got_start_vma=20
- && 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 !=3D 0
- && sym_addr >=3D 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 =3D=3D (ElfXX_Word)NULL
|| /* VG_(strlen)(sym_name) =3D=3D 0 */
/* equivalent but cheaper ... */
sym_name[0] =3D=3D 0
|| sym->st_size =3D=3D 0) {
- TRACE_SYMTAB("ignore -- size=3D0: %s\n", sym_name);
+ TRACE_SYMTAB(" ignore -- size=3D0: %s\n", sym_name);
return False;
}
=20
@@ -1169,22 +1216,40 @@
symbols, and particularly reduces the number of
overlapping address ranges. Don't ask me why ... */
if ((Int)sym->st_value =3D=3D 0) {
- TRACE_SYMTAB( "ignore -- valu=3D0: %s\n", sym_name);
+ TRACE_SYMTAB( " ignore -- valu=3D0: %s\n", sym_name);
return False;
}
=20
- /* 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 !=3D 0
+ && sym_addr >=3D si->got_start_vma=20
+ && 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 !=3D 0
+ && sym_addr >=3D si->plt_start_vma
+ && sym_addr < si->plt_start_vma + si->plt_size) {
+ TRACE_SYMTAB(" ignore -- in PLT: %s\n", sym_name);
+ return False;
+ }
=20
+ /* 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 =3D False;
+
if (si->opd_start_vma !=3D 0
&& sym_addr >=3D 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 @@
if (0) VG_(printf)("opdXXX: si->offset %p, sym_addr %p\n",=20
(void*)(si->offset), (void*)sym_addr);
=20
- 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;
+ }
=20
/* 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. */
=20
offset_in_opd =3D (Addr)sym_addr - (Addr)(si->opd_start_vma);
- if (offset_in_opd < 0 || offset_in_opd >=3D si->opd_size)
+ if (offset_in_opd < 0 || offset_in_opd >=3D si->opd_size) {
+ TRACE_SYMTAB(" ignore -- invalid OPD offset: %s\n", sym_name=
);
return False;
+ }
=20
/* 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 @@
=20
fn_descr =3D (ULong*)(opd_filea + offset_in_opd);
=20
- 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",=20
+ offset_in_opd, fn_descr);
if (0) VG_(printf)("opdXXZ: *fn_descr %p\n", (void*)(fn_descr[0]))=
;
=20
sym_addr =3D fn_descr[0];
@@ -1224,7 +1294,9 @@
sym_addr to get the real vma. */
=20
sym_addr +=3D si->offset;
- *sym_addr_really =3D sym_addr;
+ *sym_addr_out =3D sym_addr;
+ *did_opd_deref_out =3D True;
+ is_in_opd =3D True;
=20
/* 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 @@
# endif /* ppc64-linux nasty hack */
}
=20
+ /* 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 !=3D 0
+ && !is_in_opd
+ && sym_name[0] =3D=3D '.') {
+ vg_assert(!(*did_opd_deref_out));
+ *sym_name_out =3D &sym_name[1];
+ }
+# endif
+
/* If no part of the symbol falls within the mapped range,
ignore it. */
- if (sym_addr+sym->st_size <=3D si->start
- || sym_addr >=3D si->start+si->size) {
- TRACE_SYMTAB( "ignore -- outside mapped range\n" );
+ if (*sym_addr_out + *sym_size_out <=3D si->start
+ || *sym_addr_out >=3D si->start+si->size) {
+ TRACE_SYMTAB( " ignore -- outside mapped range\n" );
return False;
}
=20
- // 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 !=3D 0) {
+ vg_assert(*sym_addr_out + *sym_size_out <=3D si->opd_start_vma
+ || *sym_addr_out >=3D si->opd_start_vma + si->opd_size);
+ }
+# endif
+
+ /* Acquire! */
return True;
}
=20
-/* 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(=20
+ 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 */=20
+ )
{
- 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;
=20
if (o_strtab =3D=3D NULL || o_symtab =3D=3D NULL) {
Char buf[80];
@@ -1268,7 +1369,7 @@
return;
}
=20
- TRACE_SYMTAB("Reading %s (%d entries)\n", tab_name,=20
+ TRACE_SYMTAB("Reading (ELF, standard) %s (%d entries)\n", tab_name,=20
o_symtab_sz/sizeof(ElfXX_Sym) );
=20
/* Perhaps should start at i =3D 1; ELF docs suggest that entry
@@ -1278,74 +1379,212 @@
sym_name =3D (Char*)(o_strtab + sym->st_name);
sym_addr =3D si->offset + sym->st_value;
=20
- 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" ) );=20
- } =20
+ if (VG_(clo_trace_symtab))
+ show_raw_elf_symbol(i, sym, sym_name, sym_addr);
=20
- // Record interesting symbols in our symtab.
- if ( is_interesting_symbol(si, sym, sym_name, sym_addr,=20
- opd_filea, &sym_addr_really) ) {
- vg_assert(sym->st_name !=3D 0);
- vg_assert(sym_name[0] !=3D 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 <=3D si->opd_start_vma
- || sym_addr_really >=3D si->opd_start_vma + si->opd_s=
ize);
-# 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 =3D=3D sym_addr && sym_name[0] =3D=3D '.')
- sym_name++;
-# endif
+ if (get_elf_symbol_info(si, sym, sym_name, sym_addr, opd_filea,
+ &sym_name_really,=20
+ &sym_addr_really,
+ &sym_size,
+ &sym_tocptr,
+ &did_opd_deref)) {
=20
- name =3D ML_(addStr) ( si, sym_name, -1 );
- vg_assert(name !=3D NULL);
-
- risym.addr =3D sym_addr_really;
- risym.size =3D sym->st_size;
- risym.name =3D name;
+ risym.addr =3D sym_addr_really;
+ risym.size =3D sym_size;
+ risym.name =3D ML_(addStr) ( si, sym_name_really, -1 );
+ vg_assert(risym.name !=3D NULL);
addSym ( si, &risym );
=20
- 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,=20
(HChar*)risym.name
);
+ }
=20
}
}
}
=20
+
+/* Read an ELF symbol table (normal or dynamic). This one is for
+ ppc64-linux, which requires special treatment. */
+
+typedef
+ struct {=20
+ Addr addr;=20
+ Char* name;=20
+ }
+ 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 ) {=20
+ 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(=20
+ 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 */=20
+ )
+{
+ 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 =3D=3D NULL || o_symtab =3D=3D 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=
,=20
+ o_symtab_sz/sizeof(ElfXX_Sym) );
+
+ oset =3D VG_(OSet_Create)( offsetof(TempSym,key),=20
+ (OSetCmp_t)cmp_TempSymKey,=20
+ oset_malloc, oset_free );
+ vg_assert(oset);
+
+ /* Perhaps should start at i =3D 1; ELF docs suggest that entry
+ 0 always denotes 'unknown symbol'. */
+ for (i =3D 1; i < (Int)(o_symtab_sz/sizeof(ElfXX_Sym)); i++) {
+ sym =3D & o_symtab[i];
+ sym_name =3D (Char*)(o_strtab + sym->st_name);
+ sym_addr =3D 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,=20
+ &sym_addr_really,
+ &sym_size,
+ &sym_tocptr,
+ &from_opd)) {
+
+ /* Check if we've seen this (name,addr) key before. */
+ key.addr =3D sym_addr_really;
+ key.name =3D sym_name_really;
+ prev =3D VG_(OSet_Lookup)( oset, &key );
+
+ if (prev) {
+
+ /* Seen it before. Fold in whatever new info we can. */
+ modify =3D False;
+ old_size =3D 0;
+
+ if (prev->from_opd && !from_opd=20
+ && (prev->size =3D=3D 24 || prev->size =3D=3D 16)
+ && sym_size !=3D 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 =3D True;
+ old_size =3D prev->size;
+ prev->size =3D sym_size;
+ }
+ else
+ if (!prev->from_opd && from_opd
+ && (sym_size =3D=3D 24 || sym_size =3D=3D 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,=20
+ (HChar*)prev->key.name
+ );
+ }
+
+ } else {
+
+ /* A new (name,addr) key. Add and continue. */
+ elem =3D VG_(OSet_AllocNode)(oset, sizeof(TempSym));
+ vg_assert(elem);
+ elem->key =3D key;
+ elem->tocptr =3D sym_tocptr;
+ elem->size =3D sym_size;
+ elem->from_opd =3D 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,=20
+ (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 =3D 0;
+ VG_(OSet_ResetIter)( oset );
+
+ while ( (elem =3D VG_(OSet_Next)(oset)) ) {
+ risym.addr =3D elem->key.addr;
+ risym.size =3D elem->size;
+ risym.name =3D ML_(addStr) ( si, elem->key.name, -1 );
+ vg_assert(risym.name !=3D 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,=20
+ (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 @@
return addr;
}
=20
-/* 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 @@
}
=20
/* 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 =3D read_elf_symtab__ppc64_linux;
+# else
+ read_elf_symtab =3D read_elf_symtab__normal;
+# endif
+ read_elf_symtab(si, "symbol table",
+ o_symtab, o_symtab_sz,
+ o_strtab, o_strtab_sz, opd_filea);
=20
- 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);
+ }
=20
/* Read .eh_frame (call-frame-info) if any */
if (ehframe) {
@@ -1944,7 +2197,7 @@
{
SegInfo* si =3D alloc_SegInfo(seg_addr, seg_len, seg_offset, seg_file=
name);
=20
- if (!read_lib_symbols ( si )) {
+ if (!read_elf_debug_info ( si )) {
// Something went wrong (eg. bad ELF file).
freeSegInfo( si );
si =3D NULL;
|