Index: test/tools/llvm-readobj/elf-symbol-visibility.test =================================================================== --- test/tools/llvm-readobj/elf-symbol-visibility.test +++ test/tools/llvm-readobj/elf-symbol-visibility.test @@ -1,9 +1,13 @@ -# 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 a 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 \ +# RUN: | FileCheck %s --strict-whitespace --match-full-lines --check-prefix=GNU # LLVM: Name: default # LLVM: Other: 0 @@ -19,19 +23,16 @@ # 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:Symbol table '.symtab' contains 5 entries: +# GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name +# GNU-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND +# GNU-NEXT: 1: 00000000 0 NOTYPE GLOBAL DEFAULT UND default +# GNU-NEXT: 2: 00000000 0 NOTYPE GLOBAL INTERNAL UND internal +# GNU-NEXT: 3: 00000000 0 NOTYPE GLOBAL HIDDEN UND hidden +# GNU-NEXT: 4: 00000000 0 NOTYPE GLOBAL PROTECTED UND protected -!ELF +--- !ELF FileHeader: Class: ELFCLASS32 Data: ELFDATA2LSB @@ -50,6 +51,41 @@ - 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 \ +# RUN: | FileCheck %s --strict-whitespace --match-full-lines --check-prefix=GNU-OTHER + +# LLVM-OTHER: Name: other +# LLVM-OTHER: Other [ (0x4) +# LLVM-OTHER-NEXT: ] + +# GNU-OTHER:Symbol table '.symtab' contains 6 entries: +# GNU-OTHER-NEXT: Num: Value Size Type Bind Vis Ndx Name +# GNU-OTHER-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND +# GNU-OTHER-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT UND default +# GNU-OTHER-NEXT: 2: 00000000 0 NOTYPE LOCAL INTERNAL UND internal +# GNU-OTHER-NEXT: 3: 00000000 0 NOTYPE LOCAL HIDDEN UND hidden +# GNU-OTHER-NEXT: 4: 00000000 0 NOTYPE LOCAL PROTECTED UND protected +# GNU-OTHER-NEXT: 5: 00000000 0 NOTYPE LOCAL DEFAULT [] 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 ] Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -347,9 +347,19 @@ } if (Syms.begin() == Syms.end()) return; - ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries); + + // The st_other field has 2 logical parts. One holds visibility (STV_* bits) + // and another holds other values (STO_* bits usually, but also sometimes + // values which depends on a target platform). Here we find if any + // non-visibility bits were set for at least one symbol. + bool OtherBitsUsed = llvm::find_if(Syms, [](const Elf_Sym &S) { + return S.st_other & ~0x3; + }) != Syms.end(); + + ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries, OtherBitsUsed); for (const auto &Sym : Syms) - ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic); + ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic, + OtherBitsUsed); } template class MipsGOTParser; @@ -384,10 +394,10 @@ virtual void printDynamic(const ELFFile *Obj) {} virtual void printDynamicRelocations(const ELFFile *Obj) = 0; virtual void printSymtabMessage(const ELFFile *Obj, StringRef Name, - size_t Offset) {} + size_t Offset, bool OtherBitsUsed) {} virtual void printSymbol(const ELFFile *Obj, const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef StrTable, - bool IsDynamic) = 0; + bool IsDynamic, bool OtherBitsUsed) = 0; virtual void printProgramHeaders(const ELFFile *Obj, bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) = 0; @@ -450,8 +460,8 @@ void printHashSymbols(const ELFO *Obj) override; void printDynamic(const ELFFile *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 OtherBitsUsed) override; void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) override; void printVersionSymbolSection(const ELFFile *Obj, @@ -529,7 +539,8 @@ 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 OtherBitsUsed) 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 +592,7 @@ 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) override; void printProgramHeaders(const ELFO *Obj); void printSectionMapping(const ELFO *Obj) {} @@ -3170,7 +3181,7 @@ template void GNUStyle::printSymtabMessage(const ELFO *Obj, StringRef Name, - size_t Entries) { + size_t Entries, bool OtherBitsUsed) { if (!Name.empty()) OS << "\nSymbol table '" << Name << "' contains " << Entries << " entries:\n"; @@ -3178,9 +3189,13 @@ 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 (OtherBitsUsed) + OS << " "; + OS << " Ndx Name\n"; } template @@ -3224,7 +3239,7 @@ template void GNUStyle::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef StrTable, - bool IsDynamic) { + bool IsDynamic, bool OtherBitsUsed) { static int Idx = 0; static bool Dynamic = true; @@ -3238,7 +3253,7 @@ 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)); @@ -3255,7 +3270,13 @@ printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); Fields[5].Str = printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities)); + if (Symbol->st_other & ~0x3) + Fields[5].Str += + " [st_other, 2)) + ">]"; + + Fields[6].Column += OtherBitsUsed ? 16 : 0; Fields[6].Str = getSymbolSectionNdx(Obj, Symbol, FirstSym); + Fields[7].Str = this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic); for (auto &Entry : Fields) @@ -5278,7 +5299,7 @@ printSymbol( Obj, &Sym, unwrapOrError(this->FileName, Obj->symbols(Symtab)).begin(), - StrTable, false); + StrTable, false, false); } } @@ -5295,7 +5316,7 @@ template void LLVMStyle::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, StringRef StrTable, - bool IsDynamic) { + bool IsDynamic, bool) { unsigned SectionIndex = 0; StringRef SectionName; this->dumper()->getSectionNameIndex(Symbol, First, SectionName, SectionIndex);