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.
#include "i18n.h"
#include "util.h"
#include "StringBuilder.h"
+#include "Function.h"
struct DisContext
{
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 *
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)
{
printf ("ERROR: unsupported disassemble\n");
return NULL;
}
+ inst_addr = inst_address;
inst_size = disassemble (0, &dis_info);
if (inst_size <= 0)
{
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)
- {
- uint64_t addr = ctxp->f_offset + (inst_address - ctxp->first_pc);
- name = ctxp->stabs->sym_name (target_address, addr, use_relocation);
- }
- if (name == NULL)
- return disasm_err_symbol;
-
- char *s = NULL;
- if (*name == '_')
- s = cplus_demangle (name, DMGL_PARAMS);
- if (s)
+ if (stabs)
{
- snprintf (buffer, buffer_size, NTXT ("%s"), s);
- free (s);
+ Elf *elf = stabs->openElf (true);
+ if (elf)
+ return elf->get_funcname_in_plt (pc);
}
- else
- snprintf (buffer, buffer_size, NTXT ("%s"), name);
-
- *offset = 0;
- return disasm_err_ok;
+ return NULL;
}
-#endif
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:
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;
status = ELF_ERR_CANT_OPEN_FILE;
return;
}
+ abfd->flags |= BFD_DECOMPRESS;
if (!bfd_check_format (abfd, bfd_object))
{
bfd_close (abfd);
delete elfSymbols;
delete gnu_debug_file;
delete dbeFile;
+ delete synthsym;
+ free (bfd_sym);
+ free (bfd_dynsym);
+ free (bfd_synthsym);
if (abfd)
bfd_close (abfd);
}
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 ()
{
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 ();
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;
};
Stabs::~Stabs ()
{
- delete pltSym;
delete SymLstByName;
Destroy (SymLst);
Destroy (RelLst);
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);
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;
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)
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
{
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);
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);
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);
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 ();
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);