public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] gprofng: 30834 improve disassembly output for call and branch instructions
@ 2023-09-21  3:13 vladimir.mezentsev
  0 siblings, 0 replies; only message in thread
From: vladimir.mezentsev @ 2023-09-21  3:13 UTC (permalink / raw)
  To: binutils; +Cc: Vladimir Mezentsev

From: Vladimir Mezentsev <vladimir.mezentsev@oracle.com>

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.
---
 gprofng/src/Disasm.cc | 158 ++++++++++++++++--------------------------
 gprofng/src/Disasm.h  |   3 +
 gprofng/src/Elf.cc    |  94 +++++++++++++++++++++++++
 gprofng/src/Elf.h     |   9 +++
 gprofng/src/Stabs.cc  |  42 +++++------
 5 files changed, 185 insertions(+), 121 deletions(-)

diff --git a/gprofng/src/Disasm.cc b/gprofng/src/Disasm.cc
index ef1ef7c9d9f..9c7e59a590b 100644
--- a/gprofng/src/Disasm.cc
+++ b/gprofng/src/Disasm.cc
@@ -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)
-    {
-      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
diff --git a/gprofng/src/Disasm.h b/gprofng/src/Disasm.h
index e82b1966b5d..4094c13a20e 100644
--- a/gprofng/src/Disasm.h
+++ b/gprofng/src/Disasm.h
@@ -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:
diff --git a/gprofng/src/Elf.cc b/gprofng/src/Elf.cc
index 469efe75988..9730b996a95 100644
--- a/gprofng/src/Elf.cc
+++ b/gprofng/src/Elf.cc
@@ -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 ()
 {
diff --git a/gprofng/src/Elf.h b/gprofng/src/Elf.h
index 85059bc613c..e5a4f68db69 100644
--- a/gprofng/src/Elf.h
+++ b/gprofng/src/Elf.h
@@ -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;
 };
 
 
diff --git a/gprofng/src/Stabs.cc b/gprofng/src/Stabs.cc
index ac2ff48f7e8..82d85efabeb 100644
--- a/gprofng/src/Stabs.cc
+++ b/gprofng/src/Stabs.cc
@@ -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);
-- 
2.31.1


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-09-21  3:14 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-21  3:13 [PATCH] gprofng: 30834 improve disassembly output for call and branch instructions vladimir.mezentsev

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).