Index: llvm/trunk/test/tools/llvm-readobj/elf-verneed-flags.yaml =================================================================== --- llvm/trunk/test/tools/llvm-readobj/elf-verneed-flags.yaml +++ llvm/trunk/test/tools/llvm-readobj/elf-verneed-flags.yaml @@ -0,0 +1,107 @@ +## Check how llvm-readobj/llvm-readelf tools dump the flags of SHT_GNU_verneed +## section entries. + +# RUN: yaml2obj %s -o %t +# RUN: llvm-readobj -V %t | FileCheck %s --check-prefix=LLVM-VERDEF +# RUN: llvm-readelf -V %t | FileCheck %s --check-prefix=GNU-VERDEF + +# LLVM-VERDEF: SHT_GNU_verneed { +# LLVM-VERDEF-NEXT: Dependency { +# LLVM-VERDEF-NEXT: Version: 1 +# LLVM-VERDEF-NEXT: Count: 6 +# LLVM-VERDEF-NEXT: FileName: dso.so.0 +# LLVM-VERDEF-NEXT: Entries [ +# LLVM-VERDEF-NEXT: Entry { +# LLVM-VERDEF-NEXT: Hash: 0 +# LLVM-VERDEF-NEXT: Flags: Base (0x1) +# LLVM-VERDEF-NEXT: Index: 0 +# LLVM-VERDEF-NEXT: Name: base +# LLVM-VERDEF-NEXT: } +# LLVM-VERDEF-NEXT: Entry { +# LLVM-VERDEF-NEXT: Hash: 0 +# LLVM-VERDEF-NEXT: Flags: Weak (0x2) +# LLVM-VERDEF-NEXT: Index: 0 +# LLVM-VERDEF-NEXT: Name: weak +# LLVM-VERDEF-NEXT: } +# LLVM-VERDEF-NEXT: Entry { +# LLVM-VERDEF-NEXT: Hash: 0 +# LLVM-VERDEF-NEXT: Flags: Info (0x4) +# LLVM-VERDEF-NEXT: Index: 0 +# LLVM-VERDEF-NEXT: Name: info +# LLVM-VERDEF-NEXT: } +# LLVM-VERDEF-NEXT: Entry { +# LLVM-VERDEF-NEXT: Hash: 0 +# LLVM-VERDEF-NEXT: Flags: 0x7 +# LLVM-VERDEF-NEXT: Index: 0 +# LLVM-VERDEF-NEXT: Name: all +# LLVM-VERDEF-NEXT: } +# LLVM-VERDEF-NEXT: Entry { +# LLVM-VERDEF-NEXT: Hash: 0 +# LLVM-VERDEF-NEXT: Flags: 0x8 +# LLVM-VERDEF-NEXT: Index: 0 +# LLVM-VERDEF-NEXT: Name: unknown +# LLVM-VERDEF-NEXT: } +# LLVM-VERDEF-NEXT: Entry { +# LLVM-VERDEF-NEXT: Hash: 0 +# LLVM-VERDEF-NEXT: Flags: 0xF +# LLVM-VERDEF-NEXT: Index: 0 +# LLVM-VERDEF-NEXT: Name: all_and_unknown +# LLVM-VERDEF-NEXT: } +# LLVM-VERDEF-NEXT: ] +# LLVM-VERDEF-NEXT: } +# LLVM-VERDEF-NEXT: } + +# GNU-VERDEF: Version needs section '.gnu.version_r' contains 1 entries: +# GNU-VERDEF-NEXT: Addr: 0000000000000000 Offset: 0x000200 Link: 6 (.dynstr) +# GNU-VERDEF-NEXT: 0x0000: Version: 1 File: dso.so.0 Cnt: 6 +# GNU-VERDEF-NEXT: 0x0010: Name: base Flags: BASE Version: 0 +# GNU-VERDEF-NEXT: 0x0020: Name: weak Flags: WEAK Version: 0 +# GNU-VERDEF-NEXT: 0x0030: Name: info Flags: INFO Version: 0 +# GNU-VERDEF-NEXT: 0x0040: Name: all Flags: BASE | WEAK | INFO Version: 0 +# GNU-VERDEF-NEXT: 0x0050: Name: unknown Flags: Version: 0 +# GNU-VERDEF-NEXT: 0x0060: Name: all_and_unknown Flags: BASE | WEAK | INFO | Version: 0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + Entry: 0x0000000000201000 +Sections: + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Link: .dynstr + Info: 0x0000000000000001 + Dependencies: + - Version: 1 + File: dso.so.0 + Entries: + - Name: base + Hash: 0 + Flags: 0x1 + Other: 0 + - Name: weak + Hash: 0 + Flags: 0x2 + Other: 0 + - Name: info + Hash: 0 + Flags: 0x4 + Other: 0 + - Name: all + Hash: 0 + Flags: 0x7 + Other: 0 + - Name: unknown + Hash: 0 + Flags: 0x8 + Other: 0 + - Name: all_and_unknown + Hash: 0 + Flags: 0xf + Other: 0 +## Needed to trigger .dynstr creation, which is required by .gnu.version_r +DynamicSymbols: + - Name: f1 + Binding: STB_GLOBAL Index: llvm/trunk/test/tools/llvm-readobj/elf-versioninfo.test =================================================================== --- llvm/trunk/test/tools/llvm-readobj/elf-versioninfo.test +++ llvm/trunk/test/tools/llvm-readobj/elf-versioninfo.test @@ -173,6 +173,13 @@ # GNU-NEXT: Addr: 0000000000000000 Offset: 0x000280 Link: 7 (.dynsym) # GNU-NEXT: 000: 0 (*local*) 2 (VERSION1) 3 (VERSION2) 4 (v1) # GNU-NEXT: 004: 5 (v2) 6 (v3) - -# GNU: Dumper for .gnu.version_d is not implemented -# GNU: Dumper for .gnu.version_r is not implemented +# GNU-EMPTY: +# GNU-NEXT: Dumper for .gnu.version_d is not implemented +# GNU-EMPTY: +# GNU-NEXT: Version needs section '.gnu.version_r' contains 2 entries: +# GNU-NEXT: Addr: 0000000000000000 Offset: 0x0002cc Link: 8 (.dynstr) +# GNU-NEXT: 0x0000: Version: 1 File: verneed1.so.0 Cnt: 2 +# GNU-NEXT: 0x0010: Name: v1 Flags: none Version: 4 +# GNU-NEXT: 0x0020: Name: v2 Flags: none Version: 5 +# GNU-NEXT: 0x0030: Version: 1 File: verneed2.so.0 Cnt: 1 +# GNU-NEXT: 0x0040: Name: v3 Flags: none Version: 6 Index: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp +++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp @@ -3424,22 +3424,30 @@ } template -void GNUStyle::printVersionSymbolSection(const ELFFile *Obj, - const Elf_Shdr *Sec) { - if (!Sec) - return; - +static void printGNUVersionSectionProlog(formatted_raw_ostream &OS, + const Twine &Name, unsigned EntriesNum, + const ELFFile *Obj, + const typename ELFT::Shdr *Sec) { StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); - uint64_t Entries = Sec->sh_size / sizeof(Elf_Versym); - - OS << "Version symbols section '" << SecName << "' " - << "contains " << Entries << " entries:\n"; + OS << Name << " section '" << SecName << "' " + << "contains " << EntriesNum << " entries:\n"; - const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec->sh_link)); + const typename ELFT::Shdr *SymTab = + unwrapOrError(Obj->getSection(Sec->sh_link)); StringRef SymTabName = unwrapOrError(Obj->getSectionName(SymTab)); OS << " Addr: " << format_hex_no_prefix(Sec->sh_addr, 16) << " Offset: " << format_hex(Sec->sh_offset, 8) << " Link: " << Sec->sh_link << " (" << SymTabName << ")\n"; +} + +template +void GNUStyle::printVersionSymbolSection(const ELFFile *Obj, + const Elf_Shdr *Sec) { + if (!Sec) + return; + + unsigned Entries = Sec->sh_size / sizeof(Elf_Versym); + printGNUVersionSectionProlog(OS, "Version symbols", Entries, Obj, Sec); const uint8_t *VersymBuf = reinterpret_cast(Obj->base() + Sec->sh_offset); @@ -3491,6 +3499,28 @@ StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); OS << "Dumper for " << SecName << " is not implemented\n"; + OS << '\n'; +} + +static std::string verNeedFlagToString(unsigned Flags) { + if (Flags == 0) + return "none"; + + std::string Ret; + auto AddFlag = [&Ret, &Flags](unsigned Flag, StringRef Name) { + if (!(Flags & Flag)) + return; + if (!Ret.empty()) + Ret += " | "; + Ret += Name; + Flags &= ~Flag; + }; + + AddFlag(VER_FLG_BASE, "BASE"); + AddFlag(VER_FLG_WEAK, "WEAK"); + AddFlag(VER_FLG_INFO, "INFO"); + AddFlag(~0, ""); + return Ret; } template @@ -3499,8 +3529,42 @@ if (!Sec) return; - StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); - OS << "Dumper for " << SecName << " is not implemented\n"; + unsigned VerneedNum = Sec->sh_info; + printGNUVersionSectionProlog(OS, "Version needs", VerneedNum, Obj, Sec); + + ArrayRef SecData = unwrapOrError(Obj->getSectionContents(Sec)); + + const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link)); + StringRef StringTable = { + reinterpret_cast(Obj->base() + StrTabSec->sh_offset), + StrTabSec->sh_size}; + + const uint8_t *VerneedBuf = SecData.data(); + for (unsigned I = 0; I < VerneedNum; ++I) { + const Elf_Verneed *Verneed = + reinterpret_cast(VerneedBuf); + + OS << format(" 0x%04x: Version: %u File: %s Cnt: %u\n", + reinterpret_cast(Verneed) - SecData.begin(), + (unsigned)Verneed->vn_version, + StringTable.drop_front(Verneed->vn_file).data(), + (unsigned)Verneed->vn_cnt); + + const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; + for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { + const Elf_Vernaux *Vernaux = + reinterpret_cast(VernauxBuf); + + OS << format(" 0x%04x: Name: %s Flags: %s Version: %u\n", + reinterpret_cast(Vernaux) - SecData.begin(), + StringTable.drop_front(Vernaux->vna_name).data(), + verNeedFlagToString(Vernaux->vna_flags).c_str(), + (unsigned)Vernaux->vna_other); + VernauxBuf += Vernaux->vna_next; + } + VerneedBuf += Verneed->vn_next; + } + OS << '\n'; } // Hash histogram shows statistics of how efficient the hash was for the