forked from OSchip/llvm-project
[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 llvm-svn: 371201
This commit is contained in:
parent
4fc3ad9e13
commit
edfd276cbc
|
@ -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 ]
|
||||
|
|
|
@ -347,9 +347,18 @@ void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
|
|||
}
|
||||
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(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";
|
||||
|
@ -3203,9 +3215,13 @@ void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name,
|
|||
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>::getSymbolSectionNdx(const ELFO *Obj,
|
|||
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 ELFO *Obj, const Elf_Sym *Symbol,
|
|||
|
||||
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 ELFO *Obj, const Elf_Sym *Symbol,
|
|||
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>::printSectionHeaders(const ELFO *Obj) {
|
|||
printSymbol(
|
||||
Obj, &Sym,
|
||||
unwrapOrError(this->FileName, Obj->symbols(Symtab)).begin(),
|
||||
StrTable, false);
|
||||
StrTable, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5320,7 +5342,8 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
|
|||
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);
|
||||
|
|
Loading…
Reference in New Issue