[llvm] r287786 - llvm-readobj: Use hash tables to print dynamic symbols.

Hemant Kulkarni via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 23 10:04:23 PST 2016


Author: khemant
Date: Wed Nov 23 12:04:23 2016
New Revision: 287786

URL: http://llvm.org/viewvc/llvm-project?rev=287786&view=rev
Log:
llvm-readobj: Use hash tables to print dynamic symbols.

-symbols prints both .symtab and .dynsym symbols for GNU style in ELF.
-dyn-symbols prints symbols looking up through hash tables. This helps validate hash tables.

Modified:
    llvm/trunk/test/tools/llvm-readobj/gnu-symbols.test
    llvm/trunk/tools/llvm-readobj/ELFDumper.cpp

Modified: llvm/trunk/test/tools/llvm-readobj/gnu-symbols.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/gnu-symbols.test?rev=287786&r1=287785&r2=287786&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/gnu-symbols.test (original)
+++ llvm/trunk/test/tools/llvm-readobj/gnu-symbols.test Wed Nov 23 12:04:23 2016
@@ -4,6 +4,8 @@ RUN: llvm-readobj -symbols %p/Inputs/rel
 RUN:   | FileCheck %s -check-prefix ELF64
 RUN: llvm-readobj -symbols %p/Inputs/gnuhash.so.elf-x86_64 --elf-output-style=GNU \
 RUN:   | FileCheck %s -check-prefix DYN
+RUN: llvm-readobj -dyn-symbols %p/Inputs/dynamic-table-exe.x86 --elf-output-style=GNU \
+RUN:   | FileCheck %s -check-prefix HASH
 
 ELF32: Symbol table '.symtab' contains 5 entries:
 ELF32-NEXT:    Num:    Value  Size Type    Bind   Vis      Ndx Name
@@ -44,3 +46,29 @@ DYN-NEXT:     8: 0000000000200268     0
 DYN-NEXT:     9: 00000000000001b8     0 NOTYPE  GLOBAL DEFAULT    4 foo
 DYN-NEXT:    10: 0000000000200268     0 NOTYPE  GLOBAL DEFAULT    5 _edata
 DYN-NEXT:    11: 0000000000200268     0 NOTYPE  GLOBAL DEFAULT    5 _end
+
+HASH:     Symbol table of .hash for image:
+HASH-NEXT:   Num Buc:    Value  Size   Type   Bind Vis      Ndx Name
+HASH-NEXT:     9   0: 00000000     0 FUNC    GLOBAL DEFAULT UND __gxx_personality_v0 at CXXABI_1.3
+HASH-NEXT:    13   0: 00001b64     0 NOTYPE  GLOBAL DEFAULT ABS _edata@
+HASH-NEXT:     7   0: 00000000     0 FUNC    GLOBAL DEFAULT UND _ZNSt14basic_ifstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode at GLIBCXX_3.4
+HASH-NEXT:     2   0: 00000000     0 NOTYPE  WEAK   DEFAULT UND _Jv_RegisterClasses@
+HASH-NEXT:     1   0: 00000000     0 NOTYPE  WEAK   DEFAULT UND __gmon_start__@
+HASH-NEXT:    16   1: 00000850    81 FUNC    GLOBAL DEFAULT  14 main@
+HASH-NEXT:    10   1: 00000000     0 FUNC    GLOBAL DEFAULT UND _Unwind_Resume at GCC_3.0
+HASH-NEXT:     8   1: 00000000     0 FUNC    GLOBAL DEFAULT UND puts at GLIBC_2.0
+HASH-NEXT:    12   1: 00001b68     0 NOTYPE  GLOBAL DEFAULT ABS _end@
+HASH-NEXT:     6   1: 00000000     0 FUNC    GLOBAL DEFAULT UND _ZNSt14basic_ifstreamIcSt11char_traitsIcEED1Ev at GLIBCXX_3.4
+HASH-NEXT:     5   1: 00000000     0 NOTYPE  WEAK   DEFAULT UND _ITM_registerTMCloneTable@
+HASH-NEXT:     4   1: 00000000     0 NOTYPE  WEAK   DEFAULT UND _ITM_deregisterTMCloneTable@
+HASH-NEXT:     3   1: 00000000     0 FUNC    GLOBAL DEFAULT UND __libc_start_main at GLIBC_2.0
+HASH-NEXT:    11   2: 00000000     0 FUNC    WEAK   DEFAULT UND __cxa_finalize at GLIBC_2.1.3
+HASH-NEXT:    15   2: 00001b64     0 NOTYPE  GLOBAL DEFAULT ABS __bss_start@
+HASH-NEXT:    14   2: 0000093c     4 OBJECT  GLOBAL DEFAULT  16 _IO_stdin_used@
+HASH:     Symbol table of .gnu.hash for image:
+HASH-NEXT:   Num Buc:    Value  Size   Type   Bind Vis      Ndx Name
+HASH-NEXT:    12   0: 00001b68     0 NOTYPE  GLOBAL DEFAULT ABS _end@
+HASH-NEXT:    13   0: 00001b64     0 NOTYPE  GLOBAL DEFAULT ABS _edata@
+HASH-NEXT:    14   1: 0000093c     4 OBJECT  GLOBAL DEFAULT  16 _IO_stdin_used@
+HASH-NEXT:    15   1: 00001b64     0 NOTYPE  GLOBAL DEFAULT ABS __bss_start@
+HASH-NEXT:    16   1: 00000850    81 FUNC    GLOBAL DEFAULT  14 main@

Modified: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ELFDumper.cpp?rev=287786&r1=287785&r2=287786&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp Wed Nov 23 12:04:23 2016
@@ -328,6 +328,8 @@ private:
     OS.flush();
     return OS;
   }
+  void printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym, uint32_t Sym,
+                         StringRef StrTable, uint32_t Bucket);
   void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
                        const Elf_Rela &R, bool IsRela);
   void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
@@ -2812,15 +2814,120 @@ void GNUStyle<ELFT>::printSymbol(const E
     printField(Entry);
   OS << "\n";
 }
+template <class ELFT>
+void GNUStyle<ELFT>::printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym,
+                                       uint32_t Sym, StringRef StrTable,
+                                       uint32_t Bucket) {
+  std::string Num, Buc, Name, Value, Size, Binding, Type, Visibility, Section;
+  unsigned Width, Bias = 0;
+  if (ELFT::Is64Bits) {
+    Bias = 8;
+    Width = 16;
+  } else {
+    Bias = 0;
+    Width = 8;
+  }
+  Field Fields[9] = {0,         6,         11,        20 + Bias, 25 + Bias,
+                     34 + Bias, 41 + Bias, 49 + Bias, 53 + Bias};
+  Num = to_string(format_decimal(Sym, 5));
+  Buc = to_string(format_decimal(Bucket, 3)) + ":";
+
+  const auto Symbol = FirstSym + Sym;
+  Value = to_string(format_hex_no_prefix(Symbol->st_value, Width));
+  Size = to_string(format_decimal(Symbol->st_size, 5));
+  unsigned char SymbolType = Symbol->getType();
+  if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU &&
+      SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS)
+    Type = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
+  else
+    Type = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes));
+  unsigned Vis = Symbol->getVisibility();
+  Binding = printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
+  Visibility = printEnum(Vis, makeArrayRef(ElfSymbolVisibilities));
+  Section = getSymbolSectionNdx(Obj, Symbol, FirstSym);
+  Name = this->dumper()->getFullSymbolName(Symbol, StrTable, true);
+  Fields[0].Str = Num;
+  Fields[1].Str = Buc;
+  Fields[2].Str = Value;
+  Fields[3].Str = Size;
+  Fields[4].Str = Type;
+  Fields[5].Str = Binding;
+  Fields[6].Str = Visibility;
+  Fields[7].Str = Section;
+  Fields[8].Str = Name;
+  for (auto &Entry : Fields)
+    printField(Entry);
+  OS << "\n";
+}
 
 template <class ELFT> void GNUStyle<ELFT>::printSymbols(const ELFO *Obj) {
+  if (opts::DynamicSymbols)
+    return;
   this->dumper()->printSymbolsHelper(true);
   this->dumper()->printSymbolsHelper(false);
 }
 
 template <class ELFT>
 void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
-  this->dumper()->printSymbolsHelper(true);
+  if (this->dumper()->getDynamicStringTable().size() == 0)
+    return;
+  auto StringTable = this->dumper()->getDynamicStringTable();
+  auto DynSyms = this->dumper()->dynamic_symbols();
+  auto GnuHash = this->dumper()->getGnuHashTable();
+  auto SysVHash = this->dumper()->getHashTable();
+
+  // If no hash or .gnu.hash found, try using symbol table
+  if (GnuHash == nullptr && SysVHash == nullptr)
+    this->dumper()->printSymbolsHelper(true);
+
+  // Try printing .hash
+  if (this->dumper()->getHashTable()) {
+    OS << "\n Symbol table of .hash for image:\n";
+    if (ELFT::Is64Bits)
+      OS << "  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name";
+    else
+      OS << "  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name";
+    OS << "\n";
+
+    uint32_t NBuckets = SysVHash->nbucket;
+    uint32_t NChains = SysVHash->nchain;
+    auto Buckets = SysVHash->buckets();
+    auto Chains = SysVHash->chains();
+    for (uint32_t Buc = 0; Buc < NBuckets; Buc++) {
+      if (Buckets[Buc] == ELF::STN_UNDEF)
+        continue;
+      for (uint32_t Ch = Buckets[Buc]; Ch < NChains; Ch = Chains[Ch]) {
+        if (Ch == ELF::STN_UNDEF)
+          break;
+        printHashedSymbol(Obj, &DynSyms[0], Ch, StringTable, Buc);
+      }
+    }
+  }
+
+  // Try printing .gnu.hash
+  if (GnuHash) {
+    OS << "\n Symbol table of .gnu.hash for image:\n";
+    if (ELFT::Is64Bits)
+      OS << "  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name";
+    else
+      OS << "  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name";
+    OS << "\n";
+    uint32_t NBuckets = GnuHash->nbuckets;
+    auto Buckets = GnuHash->buckets();
+    for (uint32_t Buc = 0; Buc < NBuckets; Buc++) {
+      if (Buckets[Buc] == ELF::STN_UNDEF)
+        continue;
+      uint32_t Index = Buckets[Buc];
+      uint32_t GnuHashable = Index - GnuHash->symndx;
+      // Print whole chain
+      while (true) {
+        printHashedSymbol(Obj, &DynSyms[0], Index++, StringTable, Buc);
+        // Chain ends at symbol with stopper bit
+        if ((GnuHash->values(DynSyms.size())[GnuHashable++] & 1) == 1)
+          break;
+      }
+    }
+  }
 }
 
 static inline std::string printPhdrFlags(unsigned Flag) {




More information about the llvm-commits mailing list