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: tools/llvm-objdump/ELFDump.cpp =================================================================== --- tools/llvm-objdump/ELFDump.cpp +++ tools/llvm-objdump/ELFDump.cpp @@ -267,6 +267,74 @@ outs() << "\n"; } +template +void printSymbolVersionDependency(const ELFFile *Elf, + StringRef Filename) { + typedef ELFFile ELFO; + typedef typename ELFO::Elf_Shdr Elf_Shdr; + typedef typename ELFO::Elf_Verneed Elf_Verneed; + typedef typename ELFO::Elf_Vernaux Elf_Vernaux; + + auto SectionsOrError = Elf->sections(); + if (!SectionsOrError) + report_error(Filename, SectionsOrError.takeError()); + + const Elf_Shdr *VerNeedSec = nullptr; + for (const Elf_Shdr &Sec : *SectionsOrError) { + if (Sec.sh_type == ELF::SHT_GNU_verneed) { + VerNeedSec = &Sec; + break; + } + } + + if (VerNeedSec == nullptr) + return; + + // we use sh_info to determine the entry of SHT_GNU_verneed. + if (VerNeedSec->sh_info == 0) + report_error(Filename, createError(".gnu.version_r invalid entry")); + + outs() << "Version References:\n"; + + const auto *VerNeed = + reinterpret_cast(Elf->base() + VerNeedSec->sh_offset); + + auto StrTabOrError = Elf->getSection(VerNeedSec->sh_link); + if (!StrTabOrError) + report_error(Filename, StrTabOrError.takeError()); + const Elf_Shdr *StrTab = *StrTabOrError; + + for (uint32_t VerNeedIndex = 0; VerNeedIndex < VerNeedSec->sh_info; + ++VerNeedIndex) { + const auto *Need = reinterpret_cast(VerNeed); + outs() << " required from " + << StringRef((const char *)Elf->base() + StrTab->sh_offset + + Need->vn_file) + << ":\n"; + + const auto *VerNeedAux = VerNeed + Need->vn_aux; + for (uint32_t VerNeedAuxIndex = 0; VerNeedAuxIndex < Need->vn_cnt; + ++VerNeedAuxIndex) { + const auto *Aux = reinterpret_cast(VerNeedAux); + outs() << " " << format("0x%08" PRIx32 " ", (uint32_t)Aux->vna_hash) + << format("0x%02" PRIx16 " ", (uint16_t)Aux->vna_flags) + << format("%02u" " ", (uint16_t)Aux->vna_other) + << StringRef((const char *)(Elf->base() + StrTab->sh_offset + + Aux->vna_name)) + << "\n"; + VerNeedAux += Aux->vna_next; + } + VerNeed += Need->vn_next; + } + outs() << "\n"; +} + +template +void printSymbolVersionInfo(const ELFFile *Elf, StringRef Filename) { + // TODO: printSymbolVersionDefinition(Elf, Filename); + printSymbolVersionDependency(Elf, Filename); +} + void llvm::printELFFileHeader(const object::ObjectFile *Obj) { if (const auto *ELFObj = dyn_cast(Obj)) printProgramHeaders(ELFObj->getELFFile()); @@ -288,3 +356,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);