[llvm] r371201 - [llvm-readelf] - Print unknown st_other value if present in GNU output.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 6 06:05:35 PDT 2019


Author: grimar
Date: Fri Sep  6 06:05:34 2019
New Revision: 371201

URL: http://llvm.org/viewvc/llvm-project?rev=371201&view=rev
Log:
[llvm-readelf] - Print unknown st_other value if present in GNU output.

This is a fix for https://bugs.llvm.org/show_bug.cgi?id=40785.

llvm-readelf does not print the st_value of the symbol when
st_value has any non-visibility bits set.

This patch:

* Aligns "Ndx" row for the default and a new cases.
(it was 1 space character off for the case when "PROTECTED" visibility was printed)

* Prints "[<other>: 0x??]" for symbols which has an additional st_other bits set.
In compare with GNU, this logic is a bit simpler and seems to be more consistent.

For MIPS GNU can print named flags, though can't print a mix of them:
0: 00000000 0 NOTYPE LOCAL DEFAULT UND 
1: 00000000 0 NOTYPE GLOBAL DEFAULT [OPTIONAL] UND a1
2: 00000000 0 NOTYPE GLOBAL DEFAULT [MIPS PLT] UND a2
3: 00000000 0 NOTYPE GLOBAL DEFAULT [MIPS PIC] UND a3
4: 00000000 0 NOTYPE GLOBAL DEFAULT [MICROMIPS] UND a4
5: 00000000 0 NOTYPE GLOBAL DEFAULT [MIPS16] UND a5
6: 00000000 0 NOTYPE GLOBAL DEFAULT [<other>: c] UND b1
7: 00000000 0 NOTYPE GLOBAL DEFAULT [<other>: 28] UND b2

On PPC64 it can print a localentry value that is encoded in the high bits of st_other
63: 0000000000000850 208 FUNC GLOBAL DEFAULT [<localentry>: 8] 12

We chose to print the raw st_other field, prefixed with '0x'.

Differential revision: https://reviews.llvm.org/D67094

Modified:
    llvm/trunk/test/tools/llvm-readobj/elf-symbol-visibility.test
    llvm/trunk/tools/llvm-readobj/ELFDumper.cpp

Modified: llvm/trunk/test/tools/llvm-readobj/elf-symbol-visibility.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/elf-symbol-visibility.test?rev=371201&r1=371200&r2=371201&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/elf-symbol-visibility.test (original)
+++ llvm/trunk/test/tools/llvm-readobj/elf-symbol-visibility.test Fri Sep  6 06:05:34 2019
@@ -1,9 +1,12 @@
-# Show that llvm-readobj prints the symbol visibility where recognised, or
-# something sensible when not, for both GNU and LLVM output.
+## Show that llvm-readobj prints the symbol visibility where recognised, or
+## something sensible when not, for both GNU and LLVM output.
 
-# RUN: yaml2obj %s > %t
-# RUN: llvm-readobj --symbols %t | FileCheck %s --check-prefix=LLVM
-# RUN: llvm-readelf --symbols %t | FileCheck %s --check-prefix=GNU
+## Check how we dump symbols when they have only STV_* bits set for st_other.
+## (This is the most common case).
+
+# RUN: yaml2obj --docnum=1 %s > %t1.o
+# RUN: llvm-readobj --symbols %t1.o | FileCheck %s --check-prefix=LLVM
+# RUN: llvm-readelf --symbols %t1.o | FileCheck %s --strict-whitespace --check-prefix=GNU
 
 # LLVM:      Name: default
 # LLVM:      Other: 0
@@ -19,19 +22,15 @@
 # LLVM:      Other [ (0x3)
 # LLVM-NEXT:   STV_PROTECTED (0x3)
 # LLVM-NEXT: ]
-# LLVM:      Name: other
-# LLVM:      Other [ (0x4)
-# LLVM-NEXT: ]
 
-# FIXME - the "other" symbol should print something indicating its non-zero st_other value.
-# See https://bugs.llvm.org/show_bug.cgi?id=40785.
-# GNU:      DEFAULT   {{.*}} default
-# GNU-NEXT: INTERNAL  {{.*}} internal
-# GNU-NEXT: HIDDEN    {{.*}} hidden
-# GNU-NEXT: PROTECTED {{.*}} protected
-# GNU-NEXT: DEFAULT   {{.*}} other
+# GNU:      Vis       Ndx Name
+# GNU-NEXT: DEFAULT   UND
+# GNU-NEXT: DEFAULT   UND default
+# GNU-NEXT: INTERNAL  UND internal
+# GNU-NEXT: HIDDEN    UND hidden
+# GNU-NEXT: PROTECTED UND protected
 
-!ELF
+--- !ELF
 FileHeader:
   Class:   ELFCLASS32
   Data:    ELFDATA2LSB
@@ -50,6 +49,39 @@ Symbols:
   - Name: protected
     Other: [ STV_PROTECTED ]
     Binding: STB_GLOBAL
+
+## Check the output when we have non-visibility bits set for at least one of the symbols.
+
+# RUN: yaml2obj --docnum=2 %s > %t2.o
+# RUN: llvm-readobj --symbols %t2.o | FileCheck %s --check-prefixes=LLVM,LLVM-OTHER
+# RUN: llvm-readelf --symbols %t2.o | FileCheck %s --strict-whitespace --check-prefix=GNU-OTHER
+
+# LLVM-OTHER:      Name: other
+# LLVM-OTHER:      Other [ (0x4)
+# LLVM-OTHER-NEXT: ]
+
+#      GNU-OTHER: Vis                    Ndx Name
+# GNU-OTHER-NEXT: DEFAULT                UND
+# GNU-OTHER-NEXT: DEFAULT                UND default
+# GNU-OTHER-NEXT: INTERNAL               UND internal
+# GNU-OTHER-NEXT: HIDDEN                 UND hidden
+# GNU-OTHER-NEXT: PROTECTED              UND protected
+# GNU-OTHER-NEXT: DEFAULT [<other: 0x4>] UND other
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_386
+Symbols:
+  - Name: default
+    Other: [ STV_DEFAULT ]
+  - Name: internal
+    Other: [ STV_INTERNAL ]
+  - Name: hidden
+    Other: [ STV_HIDDEN ]
+  - Name: protected
+    Other: [ STV_PROTECTED ]
   - Name: other
-    Binding: STB_GLOBAL
     Other: [ 4 ]

Modified: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ELFDumper.cpp?rev=371201&r1=371200&r2=371201&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp Fri Sep  6 06:05:34 2019
@@ -347,9 +347,18 @@ void ELFDumper<ELFT>::printSymbolsHelper
   }
   if (Syms.begin() == Syms.end())
     return;
-  ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries);
+
+  // The st_other field has 2 logical parts. The first two bits hold the symbol
+  // visibility (STV_*) and the remainder hold other platform-specific values.
+  bool NonVisibilityBitsUsed = llvm::find_if(Syms, [](const Elf_Sym &S) {
+                                 return S.st_other & ~0x3;
+                               }) != Syms.end();
+
+  ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries,
+                                     NonVisibilityBitsUsed);
   for (const auto &Sym : Syms)
-    ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic);
+    ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic,
+                                NonVisibilityBitsUsed);
 }
 
 template <class ELFT> class MipsGOTParser;
@@ -384,10 +393,10 @@ public:
   virtual void printDynamic(const ELFFile<ELFT> *Obj) {}
   virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0;
   virtual void printSymtabMessage(const ELFFile<ELFT> *Obj, StringRef Name,
-                                  size_t Offset) {}
+                                  size_t Offset, bool NonVisibilityBitsUsed) {}
   virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol,
                            const Elf_Sym *FirstSym, StringRef StrTable,
-                           bool IsDynamic) = 0;
+                           bool IsDynamic, bool NonVisibilityBitsUsed) = 0;
   virtual void printProgramHeaders(const ELFFile<ELFT> *Obj,
                                    bool PrintProgramHeaders,
                                    cl::boolOrDefault PrintSectionMapping) = 0;
@@ -450,8 +459,8 @@ public:
   void printHashSymbols(const ELFO *Obj) override;
   void printDynamic(const ELFFile<ELFT> *Obj) override;
   void printDynamicRelocations(const ELFO *Obj) override;
-  void printSymtabMessage(const ELFO *Obj, StringRef Name,
-                          size_t Offset) override;
+  void printSymtabMessage(const ELFO *Obj, StringRef Name, size_t Offset,
+                          bool NonVisibilityBitsUsed) override;
   void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders,
                            cl::boolOrDefault PrintSectionMapping) override;
   void printVersionSymbolSection(const ELFFile<ELFT> *Obj,
@@ -529,7 +538,8 @@ private:
   void printRelocation(const ELFO *Obj, const Elf_Sym *Sym,
                        StringRef SymbolName, const Elf_Rela &R, bool IsRela);
   void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
-                   StringRef StrTable, bool IsDynamic) override;
+                   StringRef StrTable, bool IsDynamic,
+                   bool NonVisibilityBitsUsed) override;
   std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol,
                                   const Elf_Sym *FirstSym);
   void printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela);
@@ -581,7 +591,8 @@ private:
   void printSymbols(const ELFO *Obj);
   void printDynamicSymbols(const ELFO *Obj);
   void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
-                   StringRef StrTable, bool IsDynamic) override;
+                   StringRef StrTable, bool IsDynamic,
+                   bool /*NonVisibilityBitsUsed*/) override;
   void printProgramHeaders(const ELFO *Obj);
   void printSectionMapping(const ELFO *Obj) {}
 
@@ -3195,7 +3206,8 @@ void GNUStyle<ELFT>::printSectionHeaders
 
 template <class ELFT>
 void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name,
-                                        size_t Entries) {
+                                        size_t Entries,
+                                        bool NonVisibilityBitsUsed) {
   if (!Name.empty())
     OS << "\nSymbol table '" << Name << "' contains " << Entries
        << " entries:\n";
@@ -3203,9 +3215,13 @@ void GNUStyle<ELFT>::printSymtabMessage(
     OS << "\n Symbol table for image:\n";
 
   if (ELFT::Is64Bits)
-    OS << "   Num:    Value          Size Type    Bind   Vis      Ndx Name\n";
+    OS << "   Num:    Value          Size Type    Bind   Vis";
   else
-    OS << "   Num:    Value  Size Type    Bind   Vis      Ndx Name\n";
+    OS << "   Num:    Value  Size Type    Bind   Vis";
+
+  if (NonVisibilityBitsUsed)
+    OS << "             ";
+  OS << "       Ndx Name\n";
 }
 
 template <class ELFT>
@@ -3249,7 +3265,7 @@ std::string GNUStyle<ELFT>::getSymbolSec
 template <class ELFT>
 void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
                                  const Elf_Sym *FirstSym, StringRef StrTable,
-                                 bool IsDynamic) {
+                                 bool IsDynamic, bool NonVisibilityBitsUsed) {
   static int Idx = 0;
   static bool Dynamic = true;
 
@@ -3263,7 +3279,7 @@ void GNUStyle<ELFT>::printSymbol(const E
 
   unsigned Bias = ELFT::Is64Bits ? 8 : 0;
   Field Fields[8] = {0,         8,         17 + Bias, 23 + Bias,
-                     31 + Bias, 38 + Bias, 47 + Bias, 51 + Bias};
+                     31 + Bias, 38 + Bias, 48 + Bias, 51 + Bias};
   Fields[0].Str = to_string(format_decimal(Idx++, 6)) + ":";
   Fields[1].Str = to_string(
       format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 16 : 8));
@@ -3280,7 +3296,13 @@ void GNUStyle<ELFT>::printSymbol(const E
       printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
   Fields[5].Str =
       printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities));
+  if (Symbol->st_other & ~0x3)
+    Fields[5].Str +=
+        " [<other: " + to_string(format_hex(Symbol->st_other, 2)) + ">]";
+
+  Fields[6].Column += NonVisibilityBitsUsed ? 13 : 0;
   Fields[6].Str = getSymbolSectionNdx(Obj, Symbol, FirstSym);
+
   Fields[7].Str =
       this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic);
   for (auto &Entry : Fields)
@@ -5303,7 +5325,7 @@ void LLVMStyle<ELFT>::printSectionHeader
           printSymbol(
               Obj, &Sym,
               unwrapOrError(this->FileName, Obj->symbols(Symtab)).begin(),
-              StrTable, false);
+              StrTable, false, false);
       }
     }
 
@@ -5320,7 +5342,8 @@ void LLVMStyle<ELFT>::printSectionHeader
 template <class ELFT>
 void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
                                   const Elf_Sym *First, StringRef StrTable,
-                                  bool IsDynamic) {
+                                  bool IsDynamic,
+                                  bool /*NonVisibilityBitsUsed*/) {
   unsigned SectionIndex = 0;
   StringRef SectionName;
   this->dumper()->getSectionNameIndex(Symbol, First, SectionName, SectionIndex);




More information about the llvm-commits mailing list