gprofng: 30834 improve disassembly output for call and branch instructions
authorVladimir Mezentsev <vladimir.mezentsev@oracle.com>
Wed, 20 Sep 2023 20:22:12 +0000 (13:22 -0700)
committerVladimir Mezentsev <vladimir.mezentsev@oracle.com>
Fri, 22 Sep 2023 01:56:30 +0000 (18:56 -0700)
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
gprofng/src/Disasm.h
gprofng/src/Elf.cc
gprofng/src/Elf.h
gprofng/src/Stabs.cc

index ef1ef7c9d9f18f128574bf0f050e6481e4219772..9c7e59a590bf7c686dffca1b4a6cf3225416596e 100644 (file)
@@ -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
index e82b1966b5dcb58095d106e09a5e36038ae8fb18..4094c13a20e033a3de402f4d0d213b0655ebd381 100644 (file)
@@ -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:
index 469efe75988adeddfe758def4a8cab71d67ce84d..9730b996a95e080ff7b526e7153323df88220c30 100644 (file)
@@ -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 ()
 {
index 85059bc613cc8a84023d86116218f9a2d89efc62..e5a4f68db693a7769c0435d0261e900e5f096b88 100644 (file)
@@ -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;
 };
 
 
index ac2ff48f7e80e3775ac27d1d7d36b0e3f666380e..82d85efabeb49256cb5211ddbcdc6954666e935a 100644 (file)
@@ -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);