[llvm] r263952 - [llvm-readobj] Impl GNU style symbols printing

Hemant Kulkarni via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 21 10:18:23 PDT 2016


Author: khemant
Date: Mon Mar 21 12:18:23 2016
New Revision: 263952

URL: http://llvm.org/viewvc/llvm-project?rev=263952&view=rev
Log:
[llvm-readobj] Impl GNU style symbols printing

Implements "readelf -sW and readelf -DsW"

Differential Revision: http://reviews.llvm.org/D18224

Added:
    llvm/trunk/test/tools/llvm-readobj/Inputs/symbols-proc-specific.elf-hexagon
    llvm/trunk/test/tools/llvm-readobj/gnu-symbols.test
Modified:
    llvm/trunk/tools/llvm-readobj/ELFDumper.cpp

Added: llvm/trunk/test/tools/llvm-readobj/Inputs/symbols-proc-specific.elf-hexagon
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/Inputs/symbols-proc-specific.elf-hexagon?rev=263952&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/llvm-readobj/Inputs/symbols-proc-specific.elf-hexagon (added) and llvm/trunk/test/tools/llvm-readobj/Inputs/symbols-proc-specific.elf-hexagon Mon Mar 21 12:18:23 2016 differ

Added: 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=263952&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/gnu-symbols.test (added)
+++ llvm/trunk/test/tools/llvm-readobj/gnu-symbols.test Mon Mar 21 12:18:23 2016
@@ -0,0 +1,46 @@
+RUN: llvm-readobj -symbols %p/Inputs/symbols-proc-specific.elf-hexagon \
+RUN:  --elf-output-style=GNU | FileCheck %s -check-prefix ELF32
+RUN: llvm-readobj -symbols %p/Inputs/relocs.obj.elf-x86_64 --elf-output-style=GNU \
+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
+
+ELF32: Symbol table '.symtab' contains 5 entries:
+ELF32-NEXT:    Num:    Value  Size Type    Bind   Vis      Ndx Name
+ELF32-NEXT:      0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
+ELF32-NEXT:      1: 00000000     0 FILE    LOCAL  DEFAULT  ABS a.c
+ELF32-NEXT:      2: 00000000    20 FUNC    GLOBAL DEFAULT    2 main
+ELF32-NEXT:      3: 00000004     4 OBJECT  GLOBAL DEFAULT PRC[0xff03] x
+ELF32-NEXT:      4: 00000000     4 OBJECT  GLOBAL DEFAULT    3 y
+
+ELF64: Symbol table '.symtab' contains 6 entries:
+ELF64-NEXT:   Num:    Value          Size Type    Bind   Vis      Ndx Name
+ELF64-NEXT:     0:  0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
+ELF64-NEXT:     1:  0000000000000000     0 SECTION LOCAL  DEFAULT    1
+ELF64-NEXT:     2:  0000000000000000     0 SECTION LOCAL  DEFAULT    3
+ELF64-NEXT:     3:  0000000000000000     0 SECTION LOCAL  DEFAULT    4
+ELF64-NEXT:     4:  0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
+ELF64-NEXT:     5:  0000000000000000     0 TLS     GLOBAL DEFAULT  UND sym
+
+DYN:Symbol table '.dynsym' contains 5 entries:
+DYN-NEXT:   Num:    Value          Size Type    Bind   Vis      Ndx Name
+DYN-NEXT:     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
+DYN-NEXT:     1: 00000000000001b8     0 NOTYPE  GLOBAL DEFAULT    4 foo
+DYN-NEXT:     2: 0000000000200268     0 NOTYPE  GLOBAL DEFAULT    5 _edata
+DYN-NEXT:     3: 0000000000200268     0 NOTYPE  GLOBAL DEFAULT    5 _end
+DYN-NEXT:     4: 0000000000200268     0 NOTYPE  GLOBAL DEFAULT    5 __bss_start
+
+DYN: Symbol table '.symtab' contains 12 entries:
+DYN-NEXT:   Num:    Value          Size Type    Bind   Vis      Ndx Name
+DYN-NEXT:     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
+DYN-NEXT:     1: 00000000000000e8     0 SECTION LOCAL  DEFAULT    1
+DYN-NEXT:     2: 0000000000000120     0 SECTION LOCAL  DEFAULT    2
+DYN-NEXT:     3: 0000000000000198     0 SECTION LOCAL  DEFAULT    3
+DYN-NEXT:     4: 00000000000001b8     0 SECTION LOCAL  DEFAULT    4
+DYN-NEXT:     5: 00000000002001b8     0 SECTION LOCAL  DEFAULT    5
+DYN-NEXT:     6: 00000000002001b8     0 OBJECT  LOCAL  DEFAULT    5 _DYNAMIC
+DYN-NEXT:     7: 0000000000200268     0 OBJECT  LOCAL  DEFAULT    5 _GLOBAL_OFFSET_TABLE_
+DYN-NEXT:     8: 0000000000200268     0 NOTYPE  GLOBAL DEFAULT    5 __bss_start
+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

Modified: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ELFDumper.cpp?rev=263952&r1=263951&r2=263952&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp Mon Mar 21 12:18:23 2016
@@ -159,9 +159,6 @@ private:
 
   void parseDynamicTable(ArrayRef<const Elf_Phdr *> LoadSegments);
 
-  void printSymbol(const Elf_Sym *Symbol, const Elf_Sym *FirstSym,
-                   StringRef StrTable, bool IsDynamic);
-
   void printValue(uint64_t Type, uint64_t Value);
 
   StringRef getDynamicString(uint64_t Offset) const;
@@ -182,6 +179,7 @@ private:
   const Elf_Hash *HashTable = nullptr;
   const Elf_GnuHash *GnuHashTable = nullptr;
   const Elf_Shdr *DotSymtabSec = nullptr;
+  StringRef DynSymtabName;
   ArrayRef<Elf_Word> ShndxTable;
 
   const Elf_Shdr *dot_gnu_version_sec = nullptr;   // .gnu.version
@@ -224,6 +222,8 @@ public:
   Elf_Rela_Range dyn_relas() const;
   std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,
                                 bool IsDynamic) const;
+
+  void printSymbolsHelper(bool IsDynamic) const;
   const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; }
   ArrayRef<Elf_Word> getShndxTable() const { return ShndxTable; }
   StringRef getDynamicStringTable() const { return DynamicStringTable; }
@@ -232,19 +232,54 @@ public:
   const DynRegionInfo &getDynPLTRelRegion() const { return DynPLTRelRegion; }
 };
 
+template <class ELFT>
+void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
+  StringRef StrTable, SymtabName;
+  size_t Entries = 0;
+  Elf_Sym_Range Syms(nullptr, nullptr);
+  if (IsDynamic) {
+    StrTable = DynamicStringTable;
+    Syms = dynamic_symbols();
+    SymtabName = DynSymtabName;
+    if (DynSymRegion.Addr)
+      Entries = DynSymRegion.Size / DynSymRegion.EntSize;
+  } else {
+    if (!DotSymtabSec)
+      return;
+    StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec));
+    Syms = Obj->symbols(DotSymtabSec);
+    SymtabName = unwrapOrError(Obj->getSectionName(DotSymtabSec));
+    Entries = DotSymtabSec->getEntityCount();
+  }
+  if (Syms.begin() == Syms.end())
+    return;
+  ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries);
+  for (const auto &Sym : Syms)
+    ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic);
+}
+
 template <typename ELFT> class DumpStyle {
 public:
-  virtual void printFileHeaders(const ELFFile<ELFT> *Obj) = 0;
-  virtual ~DumpStyle() { }
+  using Elf_Shdr = typename ELFFile<ELFT>::Elf_Shdr;
+  using Elf_Sym =  typename ELFFile<ELFT>::Elf_Sym;
+
   DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {}
+  virtual ~DumpStyle() {}
+  virtual void printFileHeaders(const ELFFile<ELFT> *Obj) = 0;
   virtual void printGroupSections(const ELFFile<ELFT> *Obj) = 0;
   virtual void printRelocations(const ELFFile<ELFT> *Obj) = 0;
   virtual void printSections(const ELFFile<ELFT> *Obj) = 0;
   virtual void printSymbols(const ELFFile<ELFT> *Obj) = 0;
   virtual void printDynamicSymbols(const ELFFile<ELFT> *Obj) = 0;
   virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0;
+  virtual void printSymtabMessage(const ELFFile<ELFT> *obj, StringRef Name,
+                                  size_t Offset) {
+    return;
+  }
+  virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol,
+                           const Elf_Sym *FirstSym, StringRef StrTable,
+                           bool IsDynamic) = 0;
   const ELFDumper<ELFT> *dumper() const { return Dumper; }
-
 private:
   const ELFDumper<ELFT> *Dumper;
 };
@@ -262,6 +297,8 @@ public:
   void printSymbols(const ELFO *Obj) override;
   void printDynamicSymbols(const ELFO *Obj) override;
   void printDynamicRelocations(const ELFO *Obj) override;
+  virtual void printSymtabMessage(const ELFO *Obj, StringRef Name,
+                                  size_t Offset) override;
 
 private:
   struct Field {
@@ -278,6 +315,7 @@ private:
         return EnumItem.AltName;
     return to_hexString(Value, false);
   }
+
   formatted_raw_ostream &printField(struct Field F) {
     if (F.Column != 0)
       OS.PadToColumn(F.Column);
@@ -287,6 +325,10 @@ private:
   }
   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,
+                   StringRef StrTable, bool IsDynamic) override;
+  std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol,
+                                  const Elf_Sym *FirstSym);
 };
 
 template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> {
@@ -300,17 +342,15 @@ public:
   void printRelocations(const ELFO *Obj) override;
   void printRelocations(const Elf_Shdr *Sec, const ELFO *Obj);
   void printSections(const ELFO *Obj) override;
-  void printSymbolsHelper(const ELFO *Obj, bool IsDynamic);
   void printSymbols(const ELFO *Obj) override;
   void printDynamicSymbols(const ELFO *Obj) override;
   void printDynamicRelocations(const ELFO *Obj) override;
 
 private:
   void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
-  void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
-                   StringRef StrTable, bool IsDynamic);
   void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel);
-
+  void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
+                   StringRef StrTable, bool IsDynamic) override;
   StreamWriter &W;
 };
 
@@ -840,15 +880,21 @@ static const EnumEntry<unsigned> ElfSymb
     {"Weak",   "WEAK",   ELF::STB_WEAK},
     {"Unique", "UNIQUE", ELF::STB_GNU_UNIQUE}};
 
+static const EnumEntry<unsigned> ElfSymbolVisibilities[] = {
+    {"DEFAULT",   "DEFAULT",   ELF::STV_DEFAULT},
+    {"INTERNAL",  "INTERNAL",  ELF::STV_INTERNAL},
+    {"HIDDEN",    "HIDDEN",    ELF::STV_HIDDEN},
+    {"PROTECTED", "PROTECTED", ELF::STV_PROTECTED}};
+
 static const EnumEntry<unsigned> ElfSymbolTypes[] = {
-    {"None",      "NOTYPE",   ELF::STT_NOTYPE},
-    {"Object",    "OBJECT",   ELF::STT_OBJECT},
-    {"Function",  "FUNCTION", ELF::STT_FUNC},
-    {"Section",   "SECTION",  ELF::STT_SECTION},
-    {"File",      "FILE",     ELF::STT_FILE},
-    {"Common",    "COMMON",   ELF::STT_COMMON},
-    {"TLS",       "TLS",      ELF::STT_TLS},
-    {"GNU_IFunc", "IFUNC",    ELF::STT_GNU_IFUNC}};
+    {"None",      "NOTYPE",  ELF::STT_NOTYPE},
+    {"Object",    "OBJECT",  ELF::STT_OBJECT},
+    {"Function",  "FUNC",    ELF::STT_FUNC},
+    {"Section",   "SECTION", ELF::STT_SECTION},
+    {"File",      "FILE",    ELF::STT_FILE},
+    {"Common",    "COMMON",  ELF::STT_COMMON},
+    {"TLS",       "TLS",     ELF::STT_TLS},
+    {"GNU_IFunc", "IFUNC",   ELF::STT_GNU_IFUNC}};
 
 static const EnumEntry<unsigned> AMDGPUSymbolTypes[] = {
   { "AMDGPU_HSA_KERNEL",            ELF::STT_AMDGPU_HSA_KERNEL },
@@ -1108,6 +1154,8 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile
       if (DynSymRegion.Size)
         reportError("Multilpe SHT_DYNSYM");
       DynSymRegion = createDRIFrom(&Sec);
+      // This is only used (if Elf_Shdr present)for naming section in GNU style
+      DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec));
       break;
     case ELF::SHT_SYMTAB_SHNDX:
       ShndxTable = unwrapOrError(Obj->getSHNDXTable(Sec));
@@ -2468,13 +2516,117 @@ template <class ELFT> void GNUStyle<ELFT
  p (processor specific)\n";
 }
 
+template <class ELFT>
+void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name,
+                                        size_t Entries) {
+  if (Name.size())
+    OS << "\nSymbol table '" << Name << "' contains " << Entries
+       << " entries:\n";
+  else
+    OS << "\n Symbol table for image:\n";
+
+  if (ELFT::Is64Bits)
+    OS << "   Num:    Value          Size Type    Bind   Vis      Ndx Name\n";
+  else
+    OS << "   Num:    Value  Size Type    Bind   Vis      Ndx Name\n";
+}
+
+template <class ELFT>
+std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj,
+                                                const Elf_Sym *Symbol,
+                                                const Elf_Sym *FirstSym) {
+  unsigned SectionIndex = Symbol->st_shndx;
+  switch (SectionIndex) {
+  case ELF::SHN_UNDEF:
+    return "UND";
+  case ELF::SHN_ABS:
+    return "ABS";
+  case ELF::SHN_COMMON:
+    return "COM";
+  case ELF::SHN_XINDEX:
+    SectionIndex = Obj->getExtendedSymbolTableIndex(
+        Symbol, FirstSym, this->dumper()->getShndxTable());
+  default:
+    // Find if:
+    // Processor specific
+    if (SectionIndex >= ELF::SHN_LOPROC && SectionIndex <= ELF::SHN_HIPROC)
+      return std::string("PRC[0x") +
+             to_string(format_hex_no_prefix(SectionIndex, 4)) + "]";
+    // OS specific
+    if (SectionIndex >= ELF::SHN_LOOS && SectionIndex <= ELF::SHN_HIOS)
+      return std::string("OS[0x") +
+             to_string(format_hex_no_prefix(SectionIndex, 4)) + "]";
+    // Architecture reserved:
+    if (SectionIndex >= ELF::SHN_LORESERVE &&
+        SectionIndex <= ELF::SHN_HIRESERVE)
+      return std::string("RSV[0x") +
+             to_string(format_hex_no_prefix(SectionIndex, 4)) + "]";
+    // A normal section with an index
+    return to_string(format_decimal(SectionIndex, 3));
+  }
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
+                                 const Elf_Sym *FirstSym, StringRef StrTable,
+                                 bool IsDynamic) {
+  static int Idx = 0;
+  static bool Dynamic = true;
+  size_t Width;
+
+  // If this function was called with a different value from IsDynamic
+  // from last call, happens when we move from dynamic to static symbol
+  // table, "Num" field should be reset.
+  if (!Dynamic != !IsDynamic) {
+    Idx = 0;
+    Dynamic = false;
+  }
+  std::string Num, Name, Value, Size, Binding, Type, Visibility, Section;
+  unsigned Bias = 0;
+  if (ELFT::Is64Bits) {
+    Bias = 8;
+    Width = 16;
+  } else {
+    Bias = 0;
+    Width = 8;
+  }
+  Field Fields[8] = {0,         8,         17 + Bias, 23 + Bias,
+                     31 + Bias, 38 + Bias, 47 + Bias, 51 + Bias};
+  Num = to_string(format_decimal(Idx++, 6)) + ":";
+  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, IsDynamic);
+  Fields[0].Str = Num;
+  Fields[1].Str = Value;
+  Fields[2].Str = Size;
+  Fields[3].Str = Type;
+  Fields[4].Str = Binding;
+  Fields[5].Str = Visibility;
+  Fields[6].Str = Section;
+  Fields[7].Str = Name;
+  for (auto &Entry : Fields)
+    printField(Entry);
+  OS << "\n";
+}
+
 template <class ELFT> void GNUStyle<ELFT>::printSymbols(const ELFO *Obj) {
-  OS << "GNU style symbols not implemented!\n";
+  this->dumper()->printSymbolsHelper(true);
+  this->dumper()->printSymbolsHelper(false);
 }
 
 template <class ELFT>
 void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
-  OS << "GNU style dynamic symbols not implemented!\n";
+  this->dumper()->printSymbolsHelper(true);
 }
 
 template <class ELFT>
@@ -2735,33 +2887,15 @@ void LLVMStyle<ELFT>::printSymbol(const
   W.printHex("Section", SectionName, SectionIndex);
 }
 
-template <class ELFT>
-void LLVMStyle<ELFT>::printSymbolsHelper(const ELFO *Obj, bool IsDynamic) {
-  StringRef StrTable;
-  typename ELFO::Elf_Sym_Range Syms(nullptr, nullptr);
-  if (IsDynamic) {
-    StrTable = this->dumper()->getDynamicStringTable();
-    Syms = this->dumper()->dynamic_symbols();
-  } else {
-    if (!this->dumper()->getDotSymtabSec())
-      return;
-    const auto DotSymtabSec = this->dumper()->getDotSymtabSec();
-    StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec));
-    Syms = Obj->symbols(DotSymtabSec);
-  }
-  for (const Elf_Sym &Sym : Syms)
-    printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic);
-}
-
 template <class ELFT> void LLVMStyle<ELFT>::printSymbols(const ELFO *Obj) {
   ListScope Group(W, "Symbols");
-  printSymbolsHelper(Obj, false);
+  this->dumper()->printSymbolsHelper(false);
 }
 
 template <class ELFT>
 void LLVMStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
   ListScope Group(W, "DynamicSymbols");
-  printSymbolsHelper(Obj, true);
+  this->dumper()->printSymbolsHelper(true);
 }
 
 template <class ELFT>




More information about the llvm-commits mailing list