gprofng: 30834 improve disassembly output for call and branch instructions
This patch makes the gprofng disassembler to emit, e.g.
call fprintf@plt [ 0x401060, .-0x49c]
instead of
call 0xfffffffffffffb64
I use bfd_get_synthetic_symtab() to get function names in the .plt section.
I have not yet modified Elf-reader in gprofng to remove parsing of .symtab or
.dynsym sections. But we plan to do it.
gprofng/ChangeLog
2023-09-20 Vladimir Mezentsev <vladimir.mezentsev@oracle.com>
PR gprofng/30834
* src/Disasm.cc: Show the function name in the call instruction
and the relative address in the branch instruction. Remove unused code.
* src/Disasm.h (map_PC_to_func, get_funcname_in_plt): New functions.
* src/Elf.cc: Get function names for the .plt section.
* src/Elf.h (get_funcname_in_plt, get_bfd_symbols): New functions.
* src/Stabs.cc: Add pltSym to SymLst. Remove the conversion to uint32_t.
This commit is contained in:
+58
-100
@@ -34,6 +34,7 @@
|
||||
#include "i18n.h"
|
||||
#include "util.h"
|
||||
#include "StringBuilder.h"
|
||||
#include "Function.h"
|
||||
|
||||
struct DisContext
|
||||
{
|
||||
@@ -126,7 +127,49 @@ read_memory_func (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
|
||||
static void
|
||||
print_address_func (bfd_vma addr, disassemble_info *info)
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, "0x%llx", (unsigned long long) addr);
|
||||
bfd_signed_vma off;
|
||||
unsigned long long ta;
|
||||
Disasm *dis;
|
||||
switch (info->insn_type)
|
||||
{
|
||||
case dis_branch:
|
||||
case dis_condbranch:
|
||||
off = (bfd_signed_vma) addr;
|
||||
dis = (Disasm *) info->stream;
|
||||
ta = dis->inst_addr + off;
|
||||
(*info->fprintf_func) (info->stream, ".%c0x%llx [ 0x%llx ]",
|
||||
off > 0 ? '+' : '-', (long long) (off > 0 ? off : -off), ta);
|
||||
return;
|
||||
case dis_jsr:
|
||||
off = (bfd_signed_vma) addr;
|
||||
dis = (Disasm *) info->stream;
|
||||
ta = dis->inst_addr + off;
|
||||
const char *nm = NULL;
|
||||
Function *f = dis->map_PC_to_func (ta);
|
||||
if (f)
|
||||
{
|
||||
if (dis->inst_addr >= f->img_offset
|
||||
&& dis->inst_addr < f->img_offset + f->size)
|
||||
{ // Same function
|
||||
(*info->fprintf_func) (info->stream, ".%c0x%llx [ 0x%llx ]",
|
||||
off > 0 ? '+' : '-', (long long) (off > 0 ? off : -off), ta);
|
||||
return;
|
||||
}
|
||||
if (f->flags & FUNC_FLAG_PLT)
|
||||
nm = dis->get_funcname_in_plt(ta);
|
||||
if (nm == NULL)
|
||||
nm = f->get_name ();
|
||||
}
|
||||
if (nm)
|
||||
(*info->fprintf_func) (info->stream, "%s [ 0x%llx, .%c0x%llx]",
|
||||
nm, ta, off > 0 ? '+' : '-', (long long) (off > 0 ? off : -off));
|
||||
else
|
||||
(*info->fprintf_func) (info->stream,
|
||||
".%c0x%llx [ 0x%llx ] // Unable to determine target symbol",
|
||||
off > 0 ? '+' : '-', (long long) (off > 0 ? off : -off), ta);
|
||||
return;
|
||||
}
|
||||
(*info->fprintf_func) (info->stream, "0x%llx", (long long) addr);
|
||||
}
|
||||
|
||||
static asymbol *
|
||||
@@ -247,35 +290,6 @@ Disasm::remove_disasm_hndl (void *hndl)
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
Disasm::get_instr_size (uint64_t vaddr, void *hndl)
|
||||
{
|
||||
DisContext *ctx = (DisContext *) hndl;
|
||||
if (ctx == NULL || vaddr < ctx->first_pc || vaddr >= ctx->last_pc)
|
||||
return -1;
|
||||
ctx->pc = vaddr;
|
||||
size_t sz = ctx->is_Intel ? sizeof (ctx->codeptr) : 4;
|
||||
if (sz > ctx->last_pc - vaddr)
|
||||
sz = (size_t) (ctx->last_pc - vaddr);
|
||||
if (ctx->elf->get_data (ctx->f_offset + (vaddr - ctx->first_pc),
|
||||
sz, ctx->codeptr) == NULL)
|
||||
return -1;
|
||||
|
||||
char buf[MAX_DISASM_STR];
|
||||
*buf = 0;
|
||||
uint64_t inst_vaddr = vaddr;
|
||||
#if MEZ_NEED_TO_FIX
|
||||
size_t instrs_cnt = 0;
|
||||
disasm_err_code_t status = disasm (handle, &inst_vaddr, ctx->last_pc, 1,
|
||||
ctx, buf, sizeof (buf), &instrs_cnt);
|
||||
if (instrs_cnt != 1 || status != disasm_err_ok)
|
||||
return -1;
|
||||
#endif
|
||||
return (int) (inst_vaddr - vaddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
Disasm::set_addr_end (uint64_t end_address)
|
||||
{
|
||||
@@ -312,6 +326,7 @@ Disasm::get_disasm (uint64_t inst_address, uint64_t end_address,
|
||||
printf ("ERROR: unsupported disassemble\n");
|
||||
return NULL;
|
||||
}
|
||||
inst_addr = inst_address;
|
||||
inst_size = disassemble (0, &dis_info);
|
||||
if (inst_size <= 0)
|
||||
{
|
||||
@@ -337,83 +352,26 @@ Disasm::get_disasm (uint64_t inst_address, uint64_t end_address,
|
||||
sb.appendf (fmt, bytes);
|
||||
}
|
||||
sb.append (dis_str);
|
||||
#if MEZ_NEED_TO_FIX
|
||||
// Write instruction
|
||||
if (ctx.is_Intel) // longest instruction length for Intel is 7
|
||||
sb.appendf (NTXT ("%-7s %s"), parts_array[1], parts_array[2]);
|
||||
else // longest instruction length for SPARC is 11
|
||||
sb.appendf (NTXT ("%-11s %s"), parts_array[1], parts_array[2]);
|
||||
if (strcmp (parts_array[1], NTXT ("call")) == 0)
|
||||
{
|
||||
if (strncmp (parts_array[2], NTXT ("0x"), 2) == 0)
|
||||
sb.append (GTXT ("\t! (Unable to determine target symbol)"));
|
||||
}
|
||||
#endif
|
||||
return sb.toString ();
|
||||
}
|
||||
|
||||
#if MEZ_NEED_TO_FIX
|
||||
void *
|
||||
Disasm::get_inst_ptr (disasm_handle_t, uint64_t vaddr, void *pass_through)
|
||||
Function *
|
||||
Disasm::map_PC_to_func (uint64_t pc)
|
||||
{
|
||||
// Actually it fetches only one instruction at a time for sparc,
|
||||
// and one byte at a time for intel.
|
||||
DisContext *ctx = (DisContext*) pass_through;
|
||||
size_t sz = ctx->is_Intel ? 1 : 4;
|
||||
if (vaddr + sz > ctx->last_pc)
|
||||
{
|
||||
ctx->codeptr[0] = -1;
|
||||
return ctx->codeptr;
|
||||
}
|
||||
if (ctx->elf->get_data (ctx->f_offset + (vaddr - ctx->first_pc), sz, ctx->codeptr) == NULL)
|
||||
{
|
||||
ctx->codeptr[0] = -1;
|
||||
return ctx->codeptr;
|
||||
}
|
||||
if (ctx->elf->need_swap_endian && !ctx->is_Intel)
|
||||
ctx->codeptr[0] = ctx->elf->decode (ctx->codeptr[0]);
|
||||
return ctx->codeptr;
|
||||
uint64_t low_pc = 0;
|
||||
if (stabs)
|
||||
return stabs->map_PC_to_func (pc, low_pc, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get a symbol name for an address
|
||||
disasm_err_code_t
|
||||
Disasm::get_sym_name (disasm_handle_t, // an open disassembler handle
|
||||
uint64_t target_address, // the target virtual address
|
||||
uint64_t inst_address, // virtual address of instruction
|
||||
// being disassembled
|
||||
int use_relocation, // flag to use relocation information
|
||||
char *buffer, // places the symbol here
|
||||
size_t buffer_size, // limit on symbol length
|
||||
int *, // sys/elf_{SPARC.386}.h
|
||||
uint64_t *offset, // from the symbol to the address
|
||||
void *pass_through) // disassembler context
|
||||
const char *
|
||||
Disasm::get_funcname_in_plt (uint64_t pc)
|
||||
{
|
||||
char buf[MAXPATHLEN];
|
||||
if (!use_relocation)
|
||||
return disasm_err_symbol;
|
||||
|
||||
DisContext *ctxp = (DisContext*) pass_through;
|
||||
char *name = NULL;
|
||||
if (ctxp->stabs)
|
||||
if (stabs)
|
||||
{
|
||||
uint64_t addr = ctxp->f_offset + (inst_address - ctxp->first_pc);
|
||||
name = ctxp->stabs->sym_name (target_address, addr, use_relocation);
|
||||
Elf *elf = stabs->openElf (true);
|
||||
if (elf)
|
||||
return elf->get_funcname_in_plt (pc);
|
||||
}
|
||||
if (name == NULL)
|
||||
return disasm_err_symbol;
|
||||
|
||||
char *s = NULL;
|
||||
if (*name == '_')
|
||||
s = cplus_demangle (name, DMGL_PARAMS);
|
||||
if (s)
|
||||
{
|
||||
snprintf (buffer, buffer_size, NTXT ("%s"), s);
|
||||
free (s);
|
||||
}
|
||||
else
|
||||
snprintf (buffer, buffer_size, NTXT ("%s"), name);
|
||||
|
||||
*offset = 0;
|
||||
return disasm_err_ok;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -48,7 +48,10 @@ public:
|
||||
char *get_disasm (uint64_t inst_address, uint64_t end_address,
|
||||
uint64_t start_address, uint64_t f_offset, int64_t &inst_size);
|
||||
void set_img_name (char *fname); // Only for dynfunc
|
||||
Function *map_PC_to_func(uint64_t pc);
|
||||
const char *get_funcname_in_plt (uint64_t pc);
|
||||
|
||||
uint64_t inst_addr; // address of current instruction
|
||||
StringBuilder *dis_str;
|
||||
|
||||
private:
|
||||
|
||||
@@ -151,6 +151,14 @@ Elf::Elf (char *filename) : DbeMessages (), Data_window (filename)
|
||||
gnu_debug_file = NULL;
|
||||
dbeFile = NULL;
|
||||
abfd = NULL;
|
||||
bfd_symcnt = -1;
|
||||
bfd_dynsymcnt = -1;
|
||||
bfd_synthcnt = -1;
|
||||
bfd_sym = NULL;
|
||||
bfd_dynsym = NULL;
|
||||
bfd_synthsym = NULL;
|
||||
synthsym = NULL;
|
||||
|
||||
if (bfd_status != BFD_INIT_MAGIC)
|
||||
{
|
||||
status = ELF_ERR_CANT_OPEN_FILE;
|
||||
@@ -162,6 +170,7 @@ Elf::Elf (char *filename) : DbeMessages (), Data_window (filename)
|
||||
status = ELF_ERR_CANT_OPEN_FILE;
|
||||
return;
|
||||
}
|
||||
abfd->flags |= BFD_DECOMPRESS;
|
||||
if (!bfd_check_format (abfd, bfd_object))
|
||||
{
|
||||
bfd_close (abfd);
|
||||
@@ -270,6 +279,10 @@ Elf::~Elf ()
|
||||
delete elfSymbols;
|
||||
delete gnu_debug_file;
|
||||
delete dbeFile;
|
||||
delete synthsym;
|
||||
free (bfd_sym);
|
||||
free (bfd_dynsym);
|
||||
free (bfd_synthsym);
|
||||
if (abfd)
|
||||
bfd_close (abfd);
|
||||
}
|
||||
@@ -722,6 +735,87 @@ Elf::find_ancillary_files (char *lo_name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
Elf::get_bfd_symbols()
|
||||
{
|
||||
if (bfd_symcnt < 0)
|
||||
{
|
||||
if ((bfd_get_file_flags (abfd) & HAS_SYMS) != 0)
|
||||
bfd_symcnt = bfd_get_symtab_upper_bound (abfd);
|
||||
if (bfd_symcnt > 0)
|
||||
{
|
||||
bfd_sym = (asymbol **) malloc (bfd_symcnt);
|
||||
bfd_symcnt = bfd_canonicalize_symtab (abfd, bfd_sym);
|
||||
if (bfd_symcnt < 0)
|
||||
{
|
||||
free (bfd_sym);
|
||||
bfd_sym = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
bfd_symcnt = 0;
|
||||
}
|
||||
|
||||
if (bfd_dynsymcnt < 0)
|
||||
{
|
||||
bfd_dynsymcnt = bfd_get_dynamic_symtab_upper_bound (abfd);
|
||||
if (bfd_dynsymcnt > 0)
|
||||
{
|
||||
bfd_dynsym = (asymbol **) malloc (bfd_dynsymcnt);
|
||||
bfd_dynsymcnt = bfd_canonicalize_dynamic_symtab (abfd, bfd_dynsym);
|
||||
if (bfd_dynsymcnt < 0)
|
||||
{
|
||||
free (bfd_dynsym);
|
||||
bfd_dynsym = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
bfd_dynsymcnt = 0;
|
||||
}
|
||||
if (bfd_synthcnt < 0)
|
||||
{
|
||||
bfd_synthcnt = bfd_get_synthetic_symtab (abfd, bfd_symcnt, bfd_sym,
|
||||
bfd_dynsymcnt, bfd_dynsym, &bfd_synthsym);
|
||||
if (bfd_synthcnt < 0)
|
||||
bfd_synthcnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cmp_sym_addr (const void *a, const void *b)
|
||||
{
|
||||
asymbol *sym1 = *((asymbol **) a);
|
||||
asymbol *sym2 = *((asymbol **) b);
|
||||
uint64_t a1 = sym1->value;
|
||||
uint64_t a2 = sym2->value;
|
||||
if (sym1->section)
|
||||
a1 += sym1->section->vma;
|
||||
if (sym2->section)
|
||||
a2 += sym2->section->vma;
|
||||
return a1 < a2 ? -1 : (a1 == a2 ? 0 : 1);
|
||||
}
|
||||
|
||||
const char *
|
||||
Elf::get_funcname_in_plt (uint64_t pc)
|
||||
{
|
||||
if (synthsym == NULL)
|
||||
{
|
||||
get_bfd_symbols();
|
||||
synthsym = new Vector<asymbol *> (bfd_synthcnt + 1);
|
||||
for (long i = 0; i < bfd_synthcnt; i++)
|
||||
synthsym->append (bfd_synthsym + i);
|
||||
synthsym->sort (cmp_sym_addr);
|
||||
}
|
||||
|
||||
asymbol sym, *symp = &sym;
|
||||
sym.section = NULL;
|
||||
sym.value = pc;
|
||||
long ind = synthsym->bisearch (0, -1, &symp, cmp_sym_addr);
|
||||
if (ind >= 0)
|
||||
return synthsym->get (ind)->name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char*
|
||||
Elf::get_location ()
|
||||
{
|
||||
|
||||
@@ -96,6 +96,7 @@ public:
|
||||
Elf_Internal_Rela *elf_getrela (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst);
|
||||
Elf64_Ancillary *elf_getancillary (Elf_Data *edta, unsigned int ndx, Elf64_Ancillary *dst);
|
||||
Elf *find_ancillary_files (char *lo_name); // read the .gnu_debuglink and .SUNW_ancillary seections
|
||||
const char *get_funcname_in_plt (uint64_t pc);
|
||||
char *get_location ();
|
||||
char *dump ();
|
||||
void dump_elf_sec ();
|
||||
@@ -135,12 +136,20 @@ public:
|
||||
|
||||
protected:
|
||||
Elf *get_related_file (const char *lo_name, const char *nm);
|
||||
void get_bfd_symbols();
|
||||
int elf_class;
|
||||
int elf_datatype;
|
||||
Elf_Internal_Ehdr *ehdrp;
|
||||
Elf_Data **data;
|
||||
bfd *abfd;
|
||||
static int bfd_status;
|
||||
long bfd_symcnt;
|
||||
long bfd_dynsymcnt;
|
||||
long bfd_synthcnt;
|
||||
asymbol **bfd_sym;
|
||||
asymbol **bfd_dynsym;
|
||||
asymbol *bfd_synthsym;
|
||||
Vector <asymbol *> *synthsym;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+21
-21
@@ -305,7 +305,6 @@ Stabs::Stabs (char *_path, char *_lo_name)
|
||||
|
||||
Stabs::~Stabs ()
|
||||
{
|
||||
delete pltSym;
|
||||
delete SymLstByName;
|
||||
Destroy (SymLst);
|
||||
Destroy (RelLst);
|
||||
@@ -1618,9 +1617,9 @@ Stabs::createFunction (LoadObject *lo, Module *module, Symbol *sym)
|
||||
Function *func = dbeSession->createFunction ();
|
||||
func->module = module;
|
||||
func->img_fname = path;
|
||||
func->img_offset = (off_t) sym->img_offset;
|
||||
func->img_offset = sym->img_offset;
|
||||
func->save_addr = sym->save;
|
||||
func->size = (uint32_t) sym->size;
|
||||
func->size = sym->size;
|
||||
func->set_name (sym->name);
|
||||
func->elfSym = sym;
|
||||
module->functions->append (func);
|
||||
@@ -1691,12 +1690,12 @@ Stabs::check_Symtab ()
|
||||
Elf *elf = openElf (true);
|
||||
if (elf == NULL)
|
||||
return;
|
||||
if (elfDis->plt != 0)
|
||||
if (elf->plt != 0)
|
||||
{
|
||||
Elf_Internal_Shdr *shdr = elfDis->get_shdr (elfDis->plt);
|
||||
Elf_Internal_Shdr *shdr = elf->get_shdr (elf->plt);
|
||||
if (shdr)
|
||||
{
|
||||
pltSym = new Symbol ();
|
||||
pltSym = new Symbol (SymLst);
|
||||
pltSym->value = shdr->sh_addr;
|
||||
pltSym->size = shdr->sh_size;
|
||||
pltSym->img_offset = shdr->sh_offset;
|
||||
@@ -1744,7 +1743,8 @@ Stabs::readSymSec (unsigned int sec, Elf *elf)
|
||||
switch (GELF_ST_TYPE (Sym.st_info))
|
||||
{
|
||||
case STT_FUNC:
|
||||
// Skip UNDEF symbols (bug 4817083)
|
||||
if (Sym.st_size == 0)
|
||||
break;
|
||||
if (Sym.st_shndx == 0)
|
||||
{
|
||||
if (Sym.st_value == 0)
|
||||
@@ -1752,8 +1752,8 @@ Stabs::readSymSec (unsigned int sec, Elf *elf)
|
||||
sitem = new Symbol (SymLst);
|
||||
sitem->flags |= SYM_UNDEF;
|
||||
if (pltSym)
|
||||
sitem->img_offset = (uint32_t) (pltSym->img_offset +
|
||||
Sym.st_value - pltSym->value);
|
||||
sitem->img_offset = pltSym->img_offset +
|
||||
Sym.st_value - pltSym->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1761,8 +1761,8 @@ Stabs::readSymSec (unsigned int sec, Elf *elf)
|
||||
if (shdrp == NULL)
|
||||
break;
|
||||
sitem = new Symbol (SymLst);
|
||||
sitem->img_offset = (uint32_t) (shdrp->sh_offset +
|
||||
Sym.st_value - shdrp->sh_addr);
|
||||
sitem->img_offset = shdrp->sh_offset +
|
||||
Sym.st_value - shdrp->sh_addr;
|
||||
}
|
||||
sitem->size = Sym.st_size;
|
||||
sitem->name = dbe_strdup (st_name);
|
||||
@@ -1882,7 +1882,7 @@ Stabs::check_Relocs ()
|
||||
if (shdr_txt == NULL)
|
||||
continue;
|
||||
if (!(shdr_txt->sh_flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
continue;
|
||||
|
||||
// Get corresponding symbol table section
|
||||
Elf_Internal_Shdr *shdr_sym = elf->get_shdr (shdr->sh_link);
|
||||
@@ -2305,9 +2305,9 @@ Stabs::append_local_funcs (Module *module, int first_ind)
|
||||
Function *func = dbeSession->createFunction ();
|
||||
sitem->func = func;
|
||||
func->img_fname = path;
|
||||
func->img_offset = (off_t) sitem->img_offset;
|
||||
func->save_addr = (uint32_t) sitem->save;
|
||||
func->size = (uint32_t) sitem->size;
|
||||
func->img_offset = sitem->img_offset;
|
||||
func->save_addr = sitem->save;
|
||||
func->size = sitem->size;
|
||||
func->module = module;
|
||||
func->set_name (sitem->name);
|
||||
module->functions->append (func);
|
||||
@@ -2381,9 +2381,9 @@ Stabs::append_Function (Module *module, char *fname)
|
||||
return sitem->func;
|
||||
sitem->func = func = dbeSession->createFunction ();
|
||||
func->img_fname = path;
|
||||
func->img_offset = (off_t) sitem->img_offset;
|
||||
func->save_addr = (uint32_t) sitem->save;
|
||||
func->size = (uint32_t) sitem->size;
|
||||
func->img_offset = sitem->img_offset;
|
||||
func->save_addr = sitem->save;
|
||||
func->size = sitem->size;
|
||||
}
|
||||
else
|
||||
func = dbeSession->createFunction ();
|
||||
@@ -2436,9 +2436,9 @@ Stabs::append_Function (Module *module, char *linkerName, uint64_t pc)
|
||||
|
||||
sitem->func = func = dbeSession->createFunction ();
|
||||
func->img_fname = path;
|
||||
func->img_offset = (off_t) sitem->img_offset;
|
||||
func->save_addr = (uint32_t) sitem->save;
|
||||
func->size = (uint32_t) sitem->size;
|
||||
func->img_offset = sitem->img_offset;
|
||||
func->save_addr = sitem->save;
|
||||
func->size = sitem->size;
|
||||
func->module = module;
|
||||
func->set_name (sitem->name); //XXXX ?? Now call it to set obj->name
|
||||
module->functions->append (func);
|
||||
|
||||
Reference in New Issue
Block a user