[llvm] [llvm-readelf] Add --extra-sym-info (PR #65580)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 7 01:14:46 PDT 2023


https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/65580:

GNU readelf introduced --extra-sym-info/-X to display the section name
for --syms (https://sourceware.org/PR30684). Port the feature, which is
currently llvm-readelf only.

For STO_AARCH64_VARIANT_PCS/STO_RISCV_VARIANT_PCS, the Ndx and Name
columns may not be aligned.


>From 88fc82f3b1abee925acc31350e6606d91082e863 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Wed, 6 Sep 2023 23:20:09 -0700
Subject: [PATCH] [llvm-readelf] Add --extra-sym-info

GNU readelf introduced --extra-sym-info/-X to display the section name
for --syms (https://sourceware.org/PR30684). Port the feature, which is
currently llvm-readelf only.

For STO_AARCH64_VARIANT_PCS/STO_RISCV_VARIANT_PCS, the Ndx and Name
columns may not be aligned.
---
 llvm/docs/CommandGuide/llvm-readelf.rst       |   4 +
 .../ELF/aarch64-symbols-stother.test          |  10 ++
 llvm/test/tools/llvm-readobj/ELF/symbols.test |  59 ++++++++--
 .../tools/llvm-readobj/ELF/symtab-shndx.test  |  12 ++
 llvm/tools/llvm-readobj/COFFDumper.cpp        |   4 +-
 llvm/tools/llvm-readobj/ELFDumper.cpp         | 109 ++++++++++++------
 llvm/tools/llvm-readobj/MachODumper.cpp       |   6 +-
 llvm/tools/llvm-readobj/ObjDumper.h           |  10 +-
 llvm/tools/llvm-readobj/Opts.td               |   2 +
 llvm/tools/llvm-readobj/WasmDumper.cpp        |   4 +-
 llvm/tools/llvm-readobj/XCOFFDumper.cpp       |   4 +-
 llvm/tools/llvm-readobj/llvm-readobj.cpp      |   5 +-
 12 files changed, 169 insertions(+), 60 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-readelf.rst b/llvm/docs/CommandGuide/llvm-readelf.rst
index 2ad217cec7ace1c..6ee4a5dfb15917a 100644
--- a/llvm/docs/CommandGuide/llvm-readelf.rst
+++ b/llvm/docs/CommandGuide/llvm-readelf.rst
@@ -77,6 +77,10 @@ OPTIONS
  ``GNU`` (the default) output mimics the equivalent GNU :program:`readelf`
  output. ``JSON`` is JSON formatted output intended for machine consumption.
 
+.. option:: --extra-sym-info
+
+ Display extra information (section name) when showing symbols.
+
 .. option:: --section-groups, -g
 
  Display section groups.
diff --git a/llvm/test/tools/llvm-readobj/ELF/aarch64-symbols-stother.test b/llvm/test/tools/llvm-readobj/ELF/aarch64-symbols-stother.test
index a223c519c819ef7..63cd116556d43d3 100644
--- a/llvm/test/tools/llvm-readobj/ELF/aarch64-symbols-stother.test
+++ b/llvm/test/tools/llvm-readobj/ELF/aarch64-symbols-stother.test
@@ -4,6 +4,7 @@
 # RUN: llvm-readobj --symbols %t.o | FileCheck %s --check-prefix=LLVM
 # RUN: llvm-readobj --symbols %t.o --elf-output-style=JSON --pretty-print | FileCheck %s --check-prefix=JSON
 # RUN: llvm-readelf --symbols %t.o | FileCheck %s --check-prefix=GNU
+# RUN: llvm-readelf --symbols --extra-sym-info %t.o | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=GNUX
 
 # LLVM:      Name: foo1
 # LLVM:      Other [ (0x80)
@@ -29,6 +30,15 @@
 # GNU-NEXT: 3: 0000000000000000 0 NOTYPE LOCAL PROTECTED [VARIANT_PCS]      UND foo3
 # GNU-NEXT: 4: 0000000000000000 0 NOTYPE LOCAL PROTECTED                    UND foo4
 
+#      GNUX:Symbol table '.symtab' contains 5 entries:
+# GNUX-NEXT:   Num:    Value          Size Type    Bind   Vis+Other              Ndx(SecName) Name [+ Version Info]
+# GNUX-NEXT:     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT                UND 
+# GNUX-NEXT:     1: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT [VARIANT_PCS]  UND foo1
+# GNUX-NEXT:     2: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT [VARIANT_PCS | 40] UND foo2
+# GNUX-NEXT:     3: 0000000000000000     0 NOTYPE  LOCAL  PROTECTED [VARIANT_PCS] UND foo3
+# GNUX-NEXT:     4: 0000000000000000     0 NOTYPE  LOCAL  PROTECTED              UND foo4
+
+
 # JSON:     "Name": "foo1",
 # JSON:     "Other": {
 # JSON-NEXT:  "Value": 128,
diff --git a/llvm/test/tools/llvm-readobj/ELF/symbols.test b/llvm/test/tools/llvm-readobj/ELF/symbols.test
index fd4c07c5cceb7b0..74ca4e577772d0e 100644
--- a/llvm/test/tools/llvm-readobj/ELF/symbols.test
+++ b/llvm/test/tools/llvm-readobj/ELF/symbols.test
@@ -13,9 +13,11 @@
 # RUN: yaml2obj %s -DBITS=64 -DTYPE=ET_REL -o %t64
 # RUN: llvm-readobj --symbols %t64 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=SYMBOLS-LLVM
 # RUN: llvm-readelf --symbols %t64 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=SYMBOLS-GNU64
+# RUN: llvm-readelf -s --extra-sym-info %t64 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=SYMBOLS-GNU64X
 # RUN: yaml2obj %s -DBITS=32 -DTYPE=ET_REL -o %t32
 # RUN: llvm-readobj --symbols %t32 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=SYMBOLS-LLVM
 # RUN: llvm-readelf --symbols %t32 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=SYMBOLS-GNU32
+# RUN: llvm-readelf -s -X %t32 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=SYMBOLS-GNU32X
 ## b) Check dynamic objects.
 # RUN: yaml2obj %s -DBITS=64 -DTYPE=ET_DYN -o %t64.so
 # RUN: llvm-readobj --symbols %t64.so | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=SYMBOLS-LLVM
@@ -41,7 +43,7 @@
 # SYMBOLS-LLVM-NEXT:    Binding: Local (0x0)
 # SYMBOLS-LLVM-NEXT:    Type: None (0x0)
 # SYMBOLS-LLVM-NEXT:    Other: 0
-# SYMBOLS-LLVM-NEXT:    Section: Undefined (0x0)
+# SYMBOLS-LLVM-NEXT:    Section: .text (0x1)
 # SYMBOLS-LLVM-NEXT:  }
 # SYMBOLS-LLVM-NEXT:  Symbol {
 # SYMBOLS-LLVM-NEXT:    Name: bar (1)
@@ -52,19 +54,44 @@
 # SYMBOLS-LLVM-NEXT:    Other: 0
 # SYMBOLS-LLVM-NEXT:    Section: Undefined (0x0)
 # SYMBOLS-LLVM-NEXT:  }
+# SYMBOLS-LLVM-NEXT:  Symbol {
+# SYMBOLS-LLVM-NEXT:    Name: data (9)
+# SYMBOLS-LLVM-NEXT:    Value: 0x3
+# SYMBOLS-LLVM-NEXT:    Size: 0
+# SYMBOLS-LLVM-NEXT:    Binding: Global (0x1)
+# SYMBOLS-LLVM-NEXT:    Type: None (0x0)
+# SYMBOLS-LLVM-NEXT:    Other: 0
+# SYMBOLS-LLVM-NEXT:    Section: .data (0x2)
+# SYMBOLS-LLVM-NEXT:  }
 # SYMBOLS-LLVM-NEXT:]
 
-#      SYMBOLS-GNU64:Symbol table '.symtab' contains 3 entries:
+#      SYMBOLS-GNU64:Symbol table '.symtab' contains 4 entries:
 # SYMBOLS-GNU64-NEXT:   Num:    Value          Size Type    Bind   Vis       Ndx Name
 # SYMBOLS-GNU64-NEXT:     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   UND 
-# SYMBOLS-GNU64-NEXT:     1: 0000000000000001     0 NOTYPE  LOCAL  DEFAULT   UND foo
+# SYMBOLS-GNU64-NEXT:     1: 0000000000000001     0 NOTYPE  LOCAL  DEFAULT     1 foo
 # SYMBOLS-GNU64-NEXT:     2: 0000000000000002     0 NOTYPE  LOCAL  DEFAULT   UND bar
+# SYMBOLS-GNU64-NEXT:     3: 0000000000000003     0 NOTYPE  GLOBAL DEFAULT     2 data
 
-#      SYMBOLS-GNU32:Symbol table '.symtab' contains 3 entries:
+#     SYMBOLS-GNU64X:Symbol table '.symtab' contains 4 entries:
+#SYMBOLS-GNU64X-NEXT:   Num:    Value          Size Type    Bind   Vis+Other Ndx(SecName) Name [+ Version Info]
+#SYMBOLS-GNU64X-NEXT:     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   UND          
+#SYMBOLS-GNU64X-NEXT:     1: 0000000000000001     0 NOTYPE  LOCAL  DEFAULT     1 (.text)  foo
+#SYMBOLS-GNU64X-NEXT:     2: 0000000000000002     0 NOTYPE  LOCAL  DEFAULT   UND          bar
+#SYMBOLS-GNU64X-NEXT:     3: 0000000000000003     0 NOTYPE  GLOBAL DEFAULT     2 (.data)  data
+
+#      SYMBOLS-GNU32:Symbol table '.symtab' contains 4 entries:
 # SYMBOLS-GNU32-NEXT:   Num:    Value  Size Type    Bind   Vis       Ndx Name
 # SYMBOLS-GNU32-NEXT:     0: 00000000     0 NOTYPE  LOCAL  DEFAULT   UND 
-# SYMBOLS-GNU32-NEXT:     1: 00000001     0 NOTYPE  LOCAL  DEFAULT   UND foo
+# SYMBOLS-GNU32-NEXT:     1: 00000001     0 NOTYPE  LOCAL  DEFAULT     1 foo
 # SYMBOLS-GNU32-NEXT:     2: 00000002     0 NOTYPE  LOCAL  DEFAULT   UND bar
+# SYMBOLS-GNU32-NEXT:     3: 00000003     0 NOTYPE  GLOBAL DEFAULT     2 data
+
+#     SYMBOLS-GNU32X:Symbol table '.symtab' contains 4 entries:
+#SYMBOLS-GNU32X-NEXT:   Num:    Value  Size Type    Bind   Vis+Other Ndx(SecName) Name [+ Version Info]
+#SYMBOLS-GNU32X-NEXT:     0: 00000000     0 NOTYPE  LOCAL  DEFAULT   UND          
+#SYMBOLS-GNU32X-NEXT:     1: 00000001     0 NOTYPE  LOCAL  DEFAULT     1 (.text)  foo
+#SYMBOLS-GNU32X-NEXT:     2: 00000002     0 NOTYPE  LOCAL  DEFAULT   UND          bar
+#SYMBOLS-GNU32X-NEXT:     3: 00000003     0 NOTYPE  GLOBAL DEFAULT     2 (.data)  data
 
 ## Case 2: Check flag aliases produce identical output
 # RUN: llvm-readobj --symbols %t64 > %t.symbols
@@ -100,10 +127,10 @@
 ## Case 6: Test that the Num index starts from zero at every new symbol table.
 # RUN: llvm-readelf --symbols %t64 %t64 | FileCheck %s --check-prefix=NUM-INDEX
 
-# NUM-INDEX:      Symbol table '.symtab' contains 3 entries:
+# NUM-INDEX:      Symbol table '.symtab' contains 4 entries:
 # NUM-INDEX-NEXT:    Num: {{.*}}
 # NUM-INDEX-NEXT:      0: {{.*}}
-# NUM-INDEX:      Symbol table '.symtab' contains 3 entries:
+# NUM-INDEX:      Symbol table '.symtab' contains 4 entries:
 # NUM-INDEX-NEXT:    Num: {{.*}}
 # NUM-INDEX-NEXT:      0: {{.*}}
 
@@ -112,11 +139,21 @@ FileHeader:
   Class: ELFCLASS[[BITS]]
   Data:  ELFDATA2LSB
   Type:  [[TYPE]]
+Sections:
+  - Name:  .text
+    Type: SHT_PROGBITS
+  - Name:  .data
+    Type: SHT_PROGBITS
 Symbols:
-  - Name:  foo
-    Value: 0x1
-  - Name:  bar
-    Value: 0x2
+  - Name:    foo
+    Value:   0x1
+    Section: .text
+  - Name:    bar
+    Value:   0x2
+  - Name:    data
+    Value:   0x3
+    Binding: STB_GLOBAL
+    Section: .data
 DynamicSymbols:
   - Name:  zed
 
diff --git a/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test b/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test
index 493222adc302065..b632048371847bf 100644
--- a/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test
+++ b/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test
@@ -7,6 +7,7 @@
 
 # RUN: yaml2obj --docnum=1 %s -o %t1
 # RUN: llvm-readelf --symbols --dyn-syms %t1 2>&1 | FileCheck %s --check-prefix=GNU
+# RUN: llvm-readelf --symbols --dyn-syms --extra-sym-info %t1 2>&1 | FileCheck %s --check-prefix=GNUX
 # RUN: llvm-readobj --symbols --dyn-syms %t1 2>&1 | FileCheck %s --check-prefix=LLVM
 
 # GNU:      Symbol table '.dynsym' contains 3 entries:
@@ -20,6 +21,17 @@
 # GNU-NEXT:      1: 00000000     0 NOTYPE  LOCAL  DEFAULT     2 sym1
 # GNU-NEXT:      2: 00000000     0 NOTYPE  LOCAL  DEFAULT     1 sym2
 
+# GNUX:      Symbol table '.dynsym' contains 3 entries:
+# GNUX-NEXT:    Num:    Value  Size Type    Bind   Vis+Other Ndx(SecName) Name [+ Version Info]
+# GNUX-NEXT:      0: 00000000     0 NOTYPE  LOCAL  DEFAULT   UND
+# GNUX-NEXT:      1: 00000000     0 NOTYPE  LOCAL  DEFAULT     3 (.section3) dynsym1
+# GNUX-NEXT:      2: 00000000     0 NOTYPE  LOCAL  DEFAULT     2 (.section2) dynsym2
+# GNUX:      Symbol table '.symtab' contains 3 entries:
+# GNUX-NEXT:    Num:    Value  Size Type    Bind   Vis+Other Ndx(SecName) Name [+ Version Info]
+# GNUX-NEXT:      0: 00000000     0 NOTYPE  LOCAL  DEFAULT   UND
+# GNUX-NEXT:      1: 00000000     0 NOTYPE  LOCAL  DEFAULT     2 (.section2) sym1
+# GNUX-NEXT:      2: 00000000     0 NOTYPE  LOCAL  DEFAULT     1 (.section1) sym2
+
 # LLVM:      Symbols [
 # LLVM-NEXT:   Symbol {
 # LLVM-NEXT:     Name:  (0)
diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index 2c8b6e00a1455be..6e32a7eeb9d7d79 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -110,7 +110,7 @@ class COFFDumper : public ObjDumper {
 
 private:
   StringRef getSymbolName(uint32_t Index);
-  void printSymbols() override;
+  void printSymbols(bool ExtraSymInfo) override;
   void printDynamicSymbols() override;
   void printSymbol(const SymbolRef &Sym);
   void printRelocation(const SectionRef &Section, const RelocationRef &Reloc,
@@ -1609,7 +1609,7 @@ void COFFDumper::printRelocation(const SectionRef &Section,
   }
 }
 
-void COFFDumper::printSymbols() {
+void COFFDumper::printSymbols(bool /*ExtraSymInfo*/) {
   ListScope Group(W, "Symbols");
 
   for (const SymbolRef &Symbol : Obj->symbols())
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 4872d055766248b..e3387d02bc8f966 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -298,11 +298,13 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
       llvm::function_ref<void(const Elf_Relr &)> RelrFn);
 
   virtual void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset,
-                                  bool NonVisibilityBitsUsed) const {};
+                                  bool NonVisibilityBitsUsed,
+                                  bool ExtraSymInfo) const {};
   virtual void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
                            DataRegion<Elf_Word> ShndxTable,
                            std::optional<StringRef> StrTable, bool IsDynamic,
-                           bool NonVisibilityBitsUsed) const = 0;
+                           bool NonVisibilityBitsUsed,
+                           bool ExtraSymInfo) const = 0;
 
   virtual void printMipsABIFlags() = 0;
   virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
@@ -406,7 +408,7 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
   std::string getStaticSymbolName(uint32_t Index) const;
   StringRef getDynamicString(uint64_t Value) const;
 
-  void printSymbolsHelper(bool IsDynamic) const;
+  void printSymbolsHelper(bool IsDynamic, bool ExtraSymInfo) const;
   std::string getDynamicEntry(uint64_t Type, uint64_t Value) const;
 
   Expected<RelSymbol<ELFT>> getRelocationTarget(const Relocation<ELFT> &R,
@@ -508,7 +510,8 @@ ELFDumper<ELFT>::getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab,
 }
 
 template <class ELFT>
-void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
+void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic,
+                                         bool ExtraSymInfo) const {
   std::optional<StringRef> StrTable;
   size_t Entries = 0;
   Elf_Sym_Range Syms(nullptr, nullptr);
@@ -549,10 +552,10 @@ void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
                       this->getElfObject().getELFFile().end())
                 : DataRegion<Elf_Word>(this->getShndxTable(SymtabSec));
 
-  printSymtabMessage(SymtabSec, Entries, NonVisibilityBitsUsed);
+  printSymtabMessage(SymtabSec, Entries, NonVisibilityBitsUsed, ExtraSymInfo);
   for (const Elf_Sym &Sym : Syms)
     printSymbol(Sym, &Sym - Syms.begin(), ShndxTable, StrTable, IsDynamic,
-                NonVisibilityBitsUsed);
+                NonVisibilityBitsUsed, ExtraSymInfo);
 }
 
 template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> {
@@ -574,14 +577,16 @@ template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> {
   void printGroupSections() override;
   void printRelocations() override;
   void printSectionHeaders() override;
-  void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override;
+  void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols,
+                    bool ExtraSymInfo) override;
   void printHashSymbols() override;
   void printSectionDetails() override;
   void printDependentLibs() override;
   void printDynamicTable() override;
   void printDynamicRelocations() override;
   void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset,
-                          bool NonVisibilityBitsUsed) const override;
+                          bool NonVisibilityBitsUsed,
+                          bool ExtraSymInfo) const override;
   void printProgramHeaders(bool PrintProgramHeaders,
                            cl::boolOrDefault PrintSectionMapping) override;
   void printVersionSymbolSection(const Elf_Shdr *Sec) override;
@@ -656,12 +661,14 @@ template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> {
   void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
                    DataRegion<Elf_Word> ShndxTable,
                    std::optional<StringRef> StrTable, bool IsDynamic,
-                   bool NonVisibilityBitsUsed) const override;
+                   bool NonVisibilityBitsUsed,
+                   bool ExtraSymInfo) const override;
   void printDynamicRelocHeader(unsigned Type, StringRef Name,
                                const DynRegionInfo &Reg) override;
 
   std::string getSymbolSectionNdx(const Elf_Sym &Symbol, unsigned SymIndex,
-                                  DataRegion<Elf_Word> ShndxTable) const;
+                                  DataRegion<Elf_Word> ShndxTable,
+                                  bool ExtraSymInfo = false) const;
   void printProgramHeaders() override;
   void printSectionMapping() override;
   void printGNUVersionSectionProlog(const typename ELFT::Shdr &Sec,
@@ -686,7 +693,8 @@ template <typename ELFT> class LLVMELFDumper : public ELFDumper<ELFT> {
   void printGroupSections() override;
   void printRelocations() override;
   void printSectionHeaders() override;
-  void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override;
+  void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols,
+                    bool ExtraSymInfo) override;
   void printDependentLibs() override;
   void printDynamicTable() override;
   void printDynamicRelocations() override;
@@ -719,7 +727,8 @@ template <typename ELFT> class LLVMELFDumper : public ELFDumper<ELFT> {
   void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
                    DataRegion<Elf_Word> ShndxTable,
                    std::optional<StringRef> StrTable, bool IsDynamic,
-                   bool /*NonVisibilityBitsUsed*/) const override;
+                   bool /*NonVisibilityBitsUsed*/,
+                   bool /*ExtraSymInfo*/) const override;
   void printProgramHeaders() override;
   void printSectionMapping() override {}
   void printStackSizeEntry(uint64_t Size,
@@ -3998,7 +4007,8 @@ template <class ELFT> void GNUELFDumper<ELFT>::printSectionHeaders() {
 template <class ELFT>
 void GNUELFDumper<ELFT>::printSymtabMessage(const Elf_Shdr *Symtab,
                                             size_t Entries,
-                                            bool NonVisibilityBitsUsed) const {
+                                            bool NonVisibilityBitsUsed,
+                                            bool ExtraSymInfo) const {
   StringRef Name;
   if (Symtab)
     Name = this->getPrintableSectionName(*Symtab);
@@ -4008,21 +4018,27 @@ void GNUELFDumper<ELFT>::printSymtabMessage(const Elf_Shdr *Symtab,
     OS << "\nSymbol table for image";
   OS << " contains " << Entries << " entries:\n";
 
-  if (ELFT::Is64Bits)
+  if (ELFT::Is64Bits) {
     OS << "   Num:    Value          Size Type    Bind   Vis";
-  else
+    if (ExtraSymInfo)
+      OS << "+Other";
+  } else {
     OS << "   Num:    Value  Size Type    Bind   Vis";
+    if (ExtraSymInfo)
+      OS << "+Other";
+  }
 
-  if (NonVisibilityBitsUsed)
-    OS << "             ";
-  OS << "       Ndx Name\n";
+  OS.PadToColumn((ELFT::Is64Bits ? 56 : 48) + (NonVisibilityBitsUsed ? 13 : 0));
+  if (ExtraSymInfo)
+    OS << "Ndx(SecName) Name [+ Version Info]\n";
+  else
+    OS << "Ndx Name\n";
 }
 
 template <class ELFT>
-std::string
-GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
-                                        unsigned SymIndex,
-                                        DataRegion<Elf_Word> ShndxTable) const {
+std::string GNUELFDumper<ELFT>::getSymbolSectionNdx(
+    const Elf_Sym &Symbol, unsigned SymIndex, DataRegion<Elf_Word> ShndxTable,
+    bool ExtraSymInfo) const {
   unsigned SectionIndex = Symbol.st_shndx;
   switch (SectionIndex) {
   case ELF::SHN_UNDEF:
@@ -4041,7 +4057,8 @@ GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
       this->reportUniqueWarning(IndexOrErr.takeError());
       return "RSV[0xffff]";
     }
-    return to_string(format_decimal(*IndexOrErr, 3));
+    SectionIndex = *IndexOrErr;
+    break;
   }
   default:
     // Find if:
@@ -4058,17 +4075,31 @@ GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
         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));
+    break;
   }
+
+  std::string Extra;
+  if (ExtraSymInfo) {
+    auto Sec = this->Obj.getSection(SectionIndex);
+    if (!Sec) {
+      this->reportUniqueWarning(Sec.takeError());
+    } else {
+      auto SecName = this->Obj.getSectionName(**Sec);
+      if (!SecName)
+        this->reportUniqueWarning(SecName.takeError());
+      else
+        Extra = Twine(" (" + *SecName + ")").str();
+    }
+  }
+  return to_string(format_decimal(SectionIndex, 3)) + Extra;
 }
 
 template <class ELFT>
 void GNUELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
                                      DataRegion<Elf_Word> ShndxTable,
                                      std::optional<StringRef> StrTable,
-                                     bool IsDynamic,
-                                     bool NonVisibilityBitsUsed) const {
+                                     bool IsDynamic, bool NonVisibilityBitsUsed,
+                                     bool ExtraSymInfo) const {
   unsigned Bias = ELFT::Is64Bits ? 8 : 0;
   Field Fields[8] = {0,         8,         17 + Bias, 23 + Bias,
                      31 + Bias, 38 + Bias, 48 + Bias, 51 + Bias};
@@ -4115,8 +4146,10 @@ void GNUELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
   }
 
   Fields[6].Column += NonVisibilityBitsUsed ? 13 : 0;
-  Fields[6].Str = getSymbolSectionNdx(Symbol, SymIndex, ShndxTable);
+  Fields[6].Str =
+      getSymbolSectionNdx(Symbol, SymIndex, ShndxTable, ExtraSymInfo);
 
+  Fields[7].Column += ExtraSymInfo ? 10 : 0;
   Fields[7].Str = this->getFullSymbolName(Symbol, SymIndex, ShndxTable,
                                           StrTable, IsDynamic);
   for (const Field &Entry : Fields)
@@ -4162,13 +4195,14 @@ void GNUELFDumper<ELFT>::printHashedSymbol(const Elf_Sym *Symbol,
 
 template <class ELFT>
 void GNUELFDumper<ELFT>::printSymbols(bool PrintSymbols,
-                                      bool PrintDynamicSymbols) {
+                                      bool PrintDynamicSymbols,
+                                      bool ExtraSymInfo) {
   if (!PrintSymbols && !PrintDynamicSymbols)
     return;
   // GNU readelf prints both the .dynsym and .symtab with --symbols.
-  this->printSymbolsHelper(true);
+  this->printSymbolsHelper(true, ExtraSymInfo);
   if (PrintSymbols)
-    this->printSymbolsHelper(false);
+    this->printSymbolsHelper(false, ExtraSymInfo);
 }
 
 template <class ELFT>
@@ -7011,7 +7045,8 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printSectionHeaders() {
               this->Obj.getSection(Sym, this->DotSymtabSec, ShndxTable));
           if (SymSec == &Sec)
             printSymbol(Sym, &Sym - &Symbols[0], ShndxTable, StrTable, false,
-                        false);
+                        /*NonVisibilityBitsUsed=*/false,
+                        /*ExtraSymInfo=*/false);
         }
       }
     }
@@ -7098,7 +7133,8 @@ void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
                                       DataRegion<Elf_Word> ShndxTable,
                                       std::optional<StringRef> StrTable,
                                       bool IsDynamic,
-                                      bool /*NonVisibilityBitsUsed*/) const {
+                                      bool /*NonVisibilityBitsUsed*/,
+                                      bool /*ExtraSymInfo*/) const {
   std::string FullSymbolName = this->getFullSymbolName(
       Symbol, SymIndex, ShndxTable, StrTable, IsDynamic);
   unsigned char SymbolType = Symbol.getType();
@@ -7122,14 +7158,15 @@ void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
 
 template <class ELFT>
 void LLVMELFDumper<ELFT>::printSymbols(bool PrintSymbols,
-                                       bool PrintDynamicSymbols) {
+                                       bool PrintDynamicSymbols,
+                                       bool ExtraSymInfo) {
   if (PrintSymbols) {
     ListScope Group(W, "Symbols");
-    this->printSymbolsHelper(false);
+    this->printSymbolsHelper(false, ExtraSymInfo);
   }
   if (PrintDynamicSymbols) {
     ListScope Group(W, "DynamicSymbols");
-    this->printSymbolsHelper(true);
+    this->printSymbolsHelper(true, ExtraSymInfo);
   }
 }
 
diff --git a/llvm/tools/llvm-readobj/MachODumper.cpp b/llvm/tools/llvm-readobj/MachODumper.cpp
index 5b385019486ca65..ce5ba46695d86b9 100644
--- a/llvm/tools/llvm-readobj/MachODumper.cpp
+++ b/llvm/tools/llvm-readobj/MachODumper.cpp
@@ -59,7 +59,7 @@ class MachODumper : public ObjDumper {
   StringRef getSymbolName(const SymbolRef &Symbol) const;
   uint8_t getSymbolType(const SymbolRef &Symbol) const;
 
-  void printSymbols() override;
+  void printSymbols(bool ExtraSymInfo) override;
   void printSymbols(std::optional<SymbolComparator> SymComp) override;
   void printDynamicSymbols() override;
   void printDynamicSymbols(std::optional<SymbolComparator> SymComp) override;
@@ -632,7 +632,9 @@ bool MachODumper::compareSymbolsByType(SymbolRef LHS, SymbolRef RHS) const {
   return getSymbolType(LHS) < getSymbolType(RHS);
 }
 
-void MachODumper::printSymbols() { printSymbols(std::nullopt); }
+void MachODumper::printSymbols(bool /*ExtraSymInfo*/) {
+  printSymbols(std::nullopt);
+}
 
 void MachODumper::printSymbols(std::optional<SymbolComparator> SymComp) {
   ListScope Group(W, "Symbols");
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index 921792f886d0e26..a44fa42b85c9b0e 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -77,13 +77,15 @@ class ObjDumper {
   virtual void printFileHeaders() = 0;
   virtual void printSectionHeaders() = 0;
   virtual void printRelocations() = 0;
-  virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) {
+  virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols,
+                            bool ExtraSymInfo) {
     if (PrintSymbols)
-      printSymbols();
+      printSymbols(ExtraSymInfo);
     if (PrintDynamicSymbols)
       printDynamicSymbols();
   }
   virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols,
+                            bool ExtraSymInfo,
                             std::optional<SymbolComparator> SymComp) {
     if (SymComp) {
       if (PrintSymbols)
@@ -91,7 +93,7 @@ class ObjDumper {
       if (PrintDynamicSymbols)
         printDynamicSymbols(SymComp);
     } else {
-      printSymbols(PrintSymbols, PrintDynamicSymbols);
+      printSymbols(PrintSymbols, PrintDynamicSymbols, ExtraSymInfo);
     }
   }
   virtual void printProgramHeaders(bool PrintProgramHeaders,
@@ -187,7 +189,7 @@ class ObjDumper {
   ScopedPrinter &W;
 
 private:
-  virtual void printSymbols() {}
+  virtual void printSymbols(bool ExtraSymInfo) {}
   virtual void printSymbols(std::optional<SymbolComparator> Comp) {}
   virtual void printDynamicSymbols() {}
   virtual void printDynamicSymbols(std::optional<SymbolComparator> Comp) {}
diff --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td
index fec0adb5e6a6b38..e2d93c6ec229e9f 100644
--- a/llvm/tools/llvm-readobj/Opts.td
+++ b/llvm/tools/llvm-readobj/Opts.td
@@ -25,6 +25,7 @@ def dependent_libraries : FF<"dependent-libraries", "Display the dependent libra
 def dyn_relocations : FF<"dyn-relocations", "Display the dynamic relocation entries in the file">;
 def dyn_syms : FF<"dyn-syms", "Display the dynamic symbol table">;
 def expand_relocs : FF<"expand-relocs", "Expand each shown relocation to multiple lines">;
+def extra_sym_info : FF<"extra-sym-info", "Display extra information when showing symbols">;
 def file_header : FF<"file-header", "Display file header">;
 def headers : FF<"headers", "Equivalent to setting: --file-header, --program-headers, --section-headers">;
 defm hex_dump : Eq<"hex-dump", "Display the specified section(s) as hexadecimal bytes">, MetaVarName<"<name or index>">;
@@ -135,5 +136,6 @@ def : F<"S", "Alias for --section-headers">, Alias<section_headers>;
 def : F<"s", "Alias for --symbols">, Alias<symbols>;
 def : F<"t", "Alias for --section-details">, Alias<section_details>;
 def : F<"u", "Alias for --unwind">, Alias<unwind>;
+def : F<"X", "Alias for --extra-sym-info">, Alias<extra_sym_info>, Group<grp_elf>;
 def : F<"V", "Alias for --version-info">, Alias<version_info>, Group<grp_elf>;
 def : JoinedOrSeparate<["-"], "x">, Alias<hex_dump_EQ>, HelpText<"Alias for --hex-dump">, MetaVarName<"<name or index>">;
diff --git a/llvm/tools/llvm-readobj/WasmDumper.cpp b/llvm/tools/llvm-readobj/WasmDumper.cpp
index e6f0ac7ba762799..5d7639b0b70fd0f 100644
--- a/llvm/tools/llvm-readobj/WasmDumper.cpp
+++ b/llvm/tools/llvm-readobj/WasmDumper.cpp
@@ -70,7 +70,7 @@ class WasmDumper : public ObjDumper {
   void printRelocation(const SectionRef &Section, const RelocationRef &Reloc);
 
 private:
-  void printSymbols() override;
+  void printSymbols(bool ExtraSymInfo) override;
   void printDynamicSymbols() override { llvm_unreachable("unimplemented"); }
 
   const WasmObjectFile *Obj;
@@ -144,7 +144,7 @@ void WasmDumper::printRelocations() {
   }
 }
 
-void WasmDumper::printSymbols() {
+void WasmDumper::printSymbols(bool /*ExtraSymInfo*/) {
   ListScope Group(W, "Symbols");
 
   for (const SymbolRef &Symbol : Obj->symbols())
diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp
index 74ebcc4ec7d85c6..8ebd670d5d56afd 100644
--- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp
@@ -33,7 +33,7 @@ class XCOFFDumper : public ObjDumper {
   void printAuxiliaryHeader() override;
   void printSectionHeaders() override;
   void printRelocations() override;
-  void printSymbols() override;
+  void printSymbols(bool ExtraSymInfo) override;
   void printDynamicSymbols() override;
   void printUnwindInfo() override;
   void printStackMap() const override;
@@ -903,7 +903,7 @@ void XCOFFDumper::printSymbol(const SymbolRef &S) {
   }
 }
 
-void XCOFFDumper::printSymbols() {
+void XCOFFDumper::printSymbols(bool /*ExtraSymInfo*/) {
   ListScope Group(W, "Symbols");
   for (const SymbolRef &S : Obj.symbols())
     printSymbol(S);
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 8a10df4beb13f54..ca633ceff90800e 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -102,6 +102,7 @@ bool Demangle;
 static bool DependentLibraries;
 static bool DynRelocs;
 static bool DynamicSymbols;
+static bool ExtraSymInfo;
 static bool FileHeaders;
 static bool Headers;
 static std::vector<std::string> HexDump;
@@ -217,6 +218,7 @@ static void parseOptions(const opt::InputArgList &Args) {
   opts::DynRelocs = Args.hasArg(OPT_dyn_relocations);
   opts::DynamicSymbols = Args.hasArg(OPT_dyn_syms);
   opts::ExpandRelocs = Args.hasArg(OPT_expand_relocs);
+  opts::ExtraSymInfo = Args.hasArg(OPT_extra_sym_info);
   opts::FileHeaders = Args.hasArg(OPT_file_header);
   opts::Headers = Args.hasArg(OPT_headers);
   opts::HexDump = Args.getAllArgValues(OPT_hex_dump_EQ);
@@ -435,7 +437,8 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
   if (opts::UnwindInfo)
     Dumper->printUnwindInfo();
   if (opts::Symbols || opts::DynamicSymbols)
-    Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols, SymComp);
+    Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols,
+                         opts::ExtraSymInfo, SymComp);
   if (!opts::StringDump.empty())
     Dumper->printSectionsAsString(Obj, opts::StringDump);
   if (!opts::HexDump.empty())



More information about the llvm-commits mailing list