Index: test/tools/llvm-objdump/verneed-elf.test =================================================================== --- /dev/null +++ test/tools/llvm-objdump/verneed-elf.test @@ -0,0 +1,47 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objdump -p %t | FileCheck %s + +# CHECK: Version References: +# CHECK-NEXT: required from dso.so.0: +# CHECK-NEXT: 0x000004d2 0x0a 03 v1 +# CHECK-NEXT: 0x0000162e 0x0b 04 v2 +# CHECK-NEXT: required from dso.so.1: +# CHECK-NEXT: 0x000011d7 0x0c 02 v3 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + Entry: 0x0000000000201000 +Sections: + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Flags: [ SHF_ALLOC ] + Address: 0x0000000000200250 + Link: .dynstr + AddressAlign: 0x0000000000000004 + Info: 0x0000000000000002 + Dependencies: + - Version: 1 + File: dso.so.0 + Entries: + - Name: v1 + Hash: 1234 + Flags: 10 + Other: 3 + - Name: v2 + Hash: 5678 + Flags: 11 + Other: 4 + - Version: 1 + File: dso.so.1 + Entries: + - Name: v3 + Hash: 4567 + Flags: 12 + Other: 2 +DynamicSymbols: + Global: + - Name: f1 Index: test/tools/llvm-objdump/verneed-wrong-info.test =================================================================== --- /dev/null +++ test/tools/llvm-objdump/verneed-wrong-info.test @@ -0,0 +1,50 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objdump -p %t 2>&1 | FileCheck %s + +# We have a SHT_GNU_verneed section with a broken sh_info field +# that says the section contains more entries than it actually has. + +# CHECK: Version References: +# CHECK-NEXT: required from dso.so.0: +# CHECK-NEXT: 0x000004d2 0x0a 03 v1 +# CHECK-NEXT: 0x0000162e 0x0b 04 v2 +# CHECK-NEXT: required from dso.so.1: +# CHECK-NEXT: 0x000011d7 0x0c 02 v3 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + Entry: 0x0000000000201000 +Sections: + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Flags: [ SHF_ALLOC ] + Address: 0x0000000000200250 + Link: .dynstr + AddressAlign: 0x0000000000000004 + Info: 0x0000000000009999 + Dependencies: + - Version: 1 + File: dso.so.0 + Entries: + - Name: v1 + Hash: 1234 + Flags: 10 + Other: 3 + - Name: v2 + Hash: 5678 + Flags: 11 + Other: 4 + - Version: 1 + File: dso.so.1 + Entries: + - Name: v3 + Hash: 4567 + Flags: 12 + Other: 2 +DynamicSymbols: + Global: + - Name: f1 Index: tools/llvm-objdump/ELFDump.cpp =================================================================== --- tools/llvm-objdump/ELFDump.cpp +++ tools/llvm-objdump/ELFDump.cpp @@ -267,6 +267,68 @@ outs() << "\n"; } +template +void printSymbolVersionDependency(ArrayRef Contents, + StringRef StrTab) { + typedef ELFFile ELFO; + typedef typename ELFO::Elf_Verneed Elf_Verneed; + typedef typename ELFO::Elf_Vernaux Elf_Vernaux; + + outs() << "Version References:\n"; + + const uint8_t *Buf = Contents.data(); + while (Buf) { + const Elf_Verneed *Verneed = reinterpret_cast(Buf); + outs() << " required from " + << StringRef(StrTab.drop_front(Verneed->vn_file).data()) << ":\n"; + + const uint8_t *BufAux = Buf + Verneed->vn_aux; + while (BufAux) { + const Elf_Vernaux *Vernaux = + reinterpret_cast(BufAux); + outs() << " " + << format("0x%08" PRIx32 " ", (uint32_t)Vernaux->vna_hash) + << format("0x%02" PRIx16 " ", (uint16_t)Vernaux->vna_flags) + << format("%02u" + " ", + (uint16_t)Vernaux->vna_other) + << StringRef(StrTab.drop_front(Vernaux->vna_name).data()) << '\n'; + BufAux = Vernaux->vna_next ? BufAux + Vernaux->vna_next : nullptr; + } + Buf = Verneed->vn_next ? Buf + Verneed->vn_next : nullptr; + } +} + +template +void printSymbolVersionInfo(const ELFFile *Elf, StringRef FileName) { + typedef typename ELFT::Shdr Elf_Shdr; + + auto SectionsOrError = Elf->sections(); + if (!SectionsOrError) + report_error(FileName, SectionsOrError.takeError()); + + for (const Elf_Shdr &Shdr : *SectionsOrError) { + if (Shdr.sh_type != ELF::SHT_GNU_verneed) + continue; + + auto ContentsOrError = Elf->getSectionContents(&Shdr); + if (!ContentsOrError) + report_error(FileName, ContentsOrError.takeError()); + + auto StrTabSecOrError = Elf->getSection(Shdr.sh_link); + if (!StrTabSecOrError) + report_error(FileName, StrTabSecOrError.takeError()); + + auto StrTabOrError = Elf->getStringTable(*StrTabSecOrError); + if (!StrTabOrError) + report_error(FileName, StrTabOrError.takeError()); + + if (Shdr.sh_type == ELF::SHT_GNU_verneed) + printSymbolVersionDependency(*ContentsOrError, *StrTabOrError); + // TODO: Implement symbol version definitions dumper. + } +} + void llvm::printELFFileHeader(const object::ObjectFile *Obj) { if (const auto *ELFObj = dyn_cast(Obj)) printProgramHeaders(ELFObj->getELFFile()); @@ -288,3 +350,14 @@ else if (const auto *ELFObj = dyn_cast(Obj)) printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); } + +void llvm::printELFSymbolVersionInfo(const object::ObjectFile *Obj) { + if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); + else if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); + else if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); + else if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); +} Index: tools/llvm-objdump/llvm-objdump.h =================================================================== --- tools/llvm-objdump/llvm-objdump.h +++ tools/llvm-objdump/llvm-objdump.h @@ -153,6 +153,7 @@ void printMachOWeakBindTable(object::MachOObjectFile *O); void printELFFileHeader(const object::ObjectFile *O); void printELFDynamicSection(const object::ObjectFile *Obj); +void printELFSymbolVersionInfo(const object::ObjectFile *Obj); void printCOFFFileHeader(const object::ObjectFile *O); void printCOFFSymbolTable(const object::COFFImportFile *I); void printCOFFSymbolTable(const object::COFFObjectFile *O); Index: tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- tools/llvm-objdump/llvm-objdump.cpp +++ tools/llvm-objdump/llvm-objdump.cpp @@ -1887,7 +1887,9 @@ static void printPrivateFileHeaders(const ObjectFile *O, bool OnlyFirst) { if (O->isELF()) { printELFFileHeader(O); - return printELFDynamicSection(O); + printELFDynamicSection(O); + printELFSymbolVersionInfo(O); + return; } if (O->isCOFF()) return printCOFFFileHeader(O);