-# 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
# 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
- 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 ]
}
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;
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;
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,
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);
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) {}
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";
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>
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;
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));
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)
printSymbol(
Obj, &Sym,
unwrapOrError(this->FileName, Obj->symbols(Symtab)).begin(),
- StrTable, false);
+ StrTable, false, false);
}
}
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);