mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 10:05:29 +00:00
Further refine ppc64-linux ELF symbol table reading to try to
establish the toc base value (R2) needed for any given symbol. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@5530
This commit is contained in:
parent
61c4ef43b3
commit
32b3ef00fc
@ -37,6 +37,7 @@ typedef
|
||||
Addr addr; /* lowest address of entity */
|
||||
UInt size; /* size in bytes */
|
||||
Char *name; /* name */
|
||||
Addr tocptr; /* ppc64-linux only: value that R2 should have */
|
||||
}
|
||||
RiSym;
|
||||
|
||||
|
||||
@ -1098,9 +1098,11 @@ static Bool is_elf_object_file(const void *buf)
|
||||
|
||||
static
|
||||
void show_raw_elf_symbol ( Int i,
|
||||
ElfXX_Sym* sym, Char* sym_name, Addr sym_addr)
|
||||
ElfXX_Sym* sym, Char* sym_name, Addr sym_addr,
|
||||
Bool ppc64_linux_format )
|
||||
{
|
||||
VG_(printf)("raw symbol [%3d]: ", i);
|
||||
HChar* space = ppc64_linux_format ? " " : "";
|
||||
VG_(printf)("raw symbol [%4d]: ", i);
|
||||
switch (ELFXX_ST_BIND(sym->st_info)) {
|
||||
case STB_LOCAL: VG_(printf)("LOC "); break;
|
||||
case STB_GLOBAL: VG_(printf)("GLO "); break;
|
||||
@ -1119,8 +1121,8 @@ void show_raw_elf_symbol ( Int i,
|
||||
case STT_HIPROC: VG_(printf)("hip "); break;
|
||||
default: VG_(printf)("??? "); break;
|
||||
}
|
||||
VG_(printf)(": val %08p, sz %4d %s\n",
|
||||
sym_addr, sym->st_size,
|
||||
VG_(printf)(": val %010p, %ssz %4d %s\n",
|
||||
sym_addr, space, sym->st_size,
|
||||
( sym->st_name ? sym_name : (Char*)"NONAME" ) );
|
||||
}
|
||||
|
||||
@ -1138,7 +1140,7 @@ void show_raw_elf_symbol ( Int i,
|
||||
|
||||
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
|
||||
starts with a dot, an .opd deference is not attempted, and no TOC
|
||||
pointer is calculated, but the the leading dot is removed from the
|
||||
name.
|
||||
|
||||
@ -1155,23 +1157,23 @@ Bool get_elf_symbol_info (
|
||||
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? */
|
||||
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* from_opd_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;
|
||||
*sym_name_out = sym_name;
|
||||
*sym_addr_out = sym_addr;
|
||||
*sym_size_out = (Int)sym->st_size;
|
||||
*sym_tocptr_out = 0; /* unknown/inapplicable */
|
||||
*from_opd_out = False;
|
||||
|
||||
/* Figure out if we're interested in the symbol. Firstly, is it of
|
||||
the right flavour? */
|
||||
@ -1294,8 +1296,9 @@ Bool get_elf_symbol_info (
|
||||
sym_addr to get the real vma. */
|
||||
|
||||
sym_addr += si->offset;
|
||||
*sym_addr_out = sym_addr;
|
||||
*did_opd_deref_out = True;
|
||||
*sym_addr_out = sym_addr;
|
||||
*sym_tocptr_out = fn_descr[1] + si->offset;
|
||||
*from_opd_out = True;
|
||||
is_in_opd = True;
|
||||
|
||||
/* Do a final sanity check: if the symbol falls outside the
|
||||
@ -1312,7 +1315,7 @@ Bool get_elf_symbol_info (
|
||||
if (si->opd_start_vma != 0
|
||||
&& !is_in_opd
|
||||
&& sym_name[0] == '.') {
|
||||
vg_assert(!(*did_opd_deref_out));
|
||||
vg_assert(!(*from_opd_out));
|
||||
*sym_name_out = &sym_name[1];
|
||||
}
|
||||
# endif
|
||||
@ -1357,7 +1360,7 @@ void read_elf_symtab__normal(
|
||||
Char *sym_name, *sym_name_really;
|
||||
Int sym_size;
|
||||
Addr sym_tocptr;
|
||||
Bool did_opd_deref;
|
||||
Bool from_opd;
|
||||
RiSym risym;
|
||||
ElfXX_Sym *sym;
|
||||
|
||||
@ -1369,7 +1372,7 @@ void read_elf_symtab__normal(
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE_SYMTAB("Reading (ELF, standard) %s (%d entries)\n", tab_name,
|
||||
TRACE_SYMTAB("\nReading (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
|
||||
@ -1380,24 +1383,26 @@ void read_elf_symtab__normal(
|
||||
sym_addr = si->offset + sym->st_value;
|
||||
|
||||
if (VG_(clo_trace_symtab))
|
||||
show_raw_elf_symbol(i, sym, sym_name, sym_addr);
|
||||
show_raw_elf_symbol(i, sym, sym_name, sym_addr, False);
|
||||
|
||||
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)) {
|
||||
&from_opd)) {
|
||||
|
||||
risym.addr = sym_addr_really;
|
||||
risym.size = sym_size;
|
||||
risym.name = ML_(addStr) ( si, sym_name_really, -1 );
|
||||
risym.addr = sym_addr_really;
|
||||
risym.size = sym_size;
|
||||
risym.name = ML_(addStr) ( si, sym_name_really, -1 );
|
||||
risym.tocptr = sym_tocptr;
|
||||
vg_assert(risym.name != NULL);
|
||||
vg_assert(risym.tocptr == 0); /* has no role except on ppc64-linux */
|
||||
addSym ( si, &risym );
|
||||
|
||||
if (VG_(clo_trace_symtab)) {
|
||||
VG_(printf)(" record [%3d]: "
|
||||
" val %8p, sz %4d %s\n",
|
||||
VG_(printf)(" record [%4d]: "
|
||||
" val %010p, sz %4d %s\n",
|
||||
i, (void*)risym.addr, (Int)risym.size,
|
||||
(HChar*)risym.name
|
||||
);
|
||||
@ -1452,8 +1457,8 @@ void read_elf_symtab__ppc64_linux(
|
||||
Addr sym_addr, sym_addr_really;
|
||||
Char *sym_name, *sym_name_really;
|
||||
Int sym_size;
|
||||
Addr sym_tocptr;
|
||||
Bool from_opd, modify;
|
||||
Addr sym_tocptr, old_tocptr;
|
||||
Bool from_opd, modify_size, modify_tocptr;
|
||||
RiSym risym;
|
||||
ElfXX_Sym *sym;
|
||||
OSet *oset;
|
||||
@ -1469,7 +1474,7 @@ void read_elf_symtab__ppc64_linux(
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE_SYMTAB("Reading (ELF, ppc64-linux) %s (%d entries)\n", tab_name,
|
||||
TRACE_SYMTAB("\nReading (ELF, ppc64-linux) %s (%d entries)\n", tab_name,
|
||||
o_symtab_sz/sizeof(ElfXX_Sym) );
|
||||
|
||||
oset = VG_(OSet_Create)( offsetof(TempSym,key),
|
||||
@ -1485,7 +1490,7 @@ void read_elf_symtab__ppc64_linux(
|
||||
sym_addr = si->offset + sym->st_value;
|
||||
|
||||
if (VG_(clo_trace_symtab))
|
||||
show_raw_elf_symbol(i, sym, sym_name, sym_addr);
|
||||
show_raw_elf_symbol(i, sym, sym_name, sym_addr, True);
|
||||
|
||||
if (get_elf_symbol_info(si, sym, sym_name, sym_addr, opd_filea,
|
||||
&sym_name_really,
|
||||
@ -1502,8 +1507,10 @@ void read_elf_symtab__ppc64_linux(
|
||||
if (prev) {
|
||||
|
||||
/* Seen it before. Fold in whatever new info we can. */
|
||||
modify = False;
|
||||
old_size = 0;
|
||||
modify_size = False;
|
||||
modify_tocptr = False;
|
||||
old_size = 0;
|
||||
old_tocptr = 0;
|
||||
|
||||
if (prev->from_opd && !from_opd
|
||||
&& (prev->size == 24 || prev->size == 16)
|
||||
@ -1511,27 +1518,45 @@ void read_elf_symtab__ppc64_linux(
|
||||
/* 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;
|
||||
modify_size = 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. */
|
||||
/* Existing one is non-opd, new one is opd. 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. */
|
||||
vg_assert(prev->tocptr == 0);
|
||||
modify_tocptr = True;
|
||||
old_tocptr = prev->tocptr;
|
||||
prev->tocptr = sym_tocptr;
|
||||
}
|
||||
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,
|
||||
/* Only one or the other is possible (I think) */
|
||||
vg_assert(!(modify_size && modify_tocptr));
|
||||
|
||||
if (modify_size && VG_(clo_trace_symtab)) {
|
||||
VG_(printf)(" modify (old sz %4d) "
|
||||
" val %010p, toc %010p, sz %4d %s\n",
|
||||
old_size,
|
||||
(void*) prev->key.addr,
|
||||
(void*) prev->tocptr,
|
||||
(Int) prev->size,
|
||||
(HChar*)prev->key.name
|
||||
);
|
||||
}
|
||||
if (modify_tocptr && VG_(clo_trace_symtab)) {
|
||||
VG_(printf)(" modify (upd tocptr) "
|
||||
" val %010p, toc %010p, sz %4d %s\n",
|
||||
(void*) prev->key.addr,
|
||||
(void*) prev->tocptr,
|
||||
(Int) prev->size,
|
||||
(HChar*)prev->key.name
|
||||
);
|
||||
}
|
||||
@ -1547,9 +1572,11 @@ void read_elf_symtab__ppc64_linux(
|
||||
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,
|
||||
VG_(printf)(" to-oset [%4d]: "
|
||||
" val %010p, toc %010p, sz %4d %s\n",
|
||||
i, (void*) elem->key.addr,
|
||||
(void*) elem->tocptr,
|
||||
(Int) elem->size,
|
||||
(HChar*)elem->key.name
|
||||
);
|
||||
}
|
||||
@ -1565,18 +1592,21 @@ void read_elf_symtab__ppc64_linux(
|
||||
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 );
|
||||
risym.addr = elem->key.addr;
|
||||
risym.size = elem->size;
|
||||
risym.name = ML_(addStr) ( si, elem->key.name, -1 );
|
||||
risym.tocptr = elem->tocptr;
|
||||
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,
|
||||
VG_(printf)(" record [%4d]: "
|
||||
" val %010p, toc %010p, sz %4d %s\n",
|
||||
i, (void*) risym.addr,
|
||||
(void*) risym.tocptr,
|
||||
(Int) risym.size,
|
||||
(HChar*)risym.name
|
||||
);
|
||||
);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@ -2474,6 +2504,21 @@ Bool get_fnname ( Bool demangle, Addr a, Char* buf, Int nbuf,
|
||||
return True;
|
||||
}
|
||||
|
||||
/* ppc64-linux only: find the TOC pointer (R2 value) that should be in
|
||||
force at the entry point address of the function containing
|
||||
guest_code_addr. Returns 0 if not known. */
|
||||
Addr VG_(get_tocptr) ( Addr guest_code_addr )
|
||||
{
|
||||
SegInfo* si;
|
||||
Int sno;
|
||||
search_all_symtabs ( guest_code_addr,
|
||||
&si, &sno, True/*match_anywhere_in_fun*/ );
|
||||
if (si == NULL)
|
||||
return 0;
|
||||
else
|
||||
return si->symtab[sno].tocptr;
|
||||
}
|
||||
|
||||
/* This is available to tools... always demangle C++ names,
|
||||
match anywhere in function, but don't show offsets. */
|
||||
Bool VG_(get_fnname) ( Addr a, Char* buf, Int nbuf )
|
||||
|
||||
@ -64,6 +64,10 @@ extern Bool VG_(use_CFI_info) ( /*MOD*/Addr* ipP,
|
||||
Addr min_accessible,
|
||||
Addr max_accessible );
|
||||
|
||||
/* ppc64-linux only: find the TOC pointer (R2 value) that should be in
|
||||
force at the entry point address of the function containing
|
||||
guest_code_addr. Returns 0 if not known. */
|
||||
extern Addr VG_(get_tocptr) ( Addr guest_code_addr );
|
||||
|
||||
#endif // __PUB_CORE_DEBUGINFO_H
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user