Index: test/tools/llvm-objdump/private-headers-symbol-version.test =================================================================== --- /dev/null +++ test/tools/llvm-objdump/private-headers-symbol-version.test @@ -0,0 +1,8 @@ +# RUN: llvm-objdump -p %p/Inputs/private-headers-x86_64.elf | FileCheck %s + +CHECK: Version References: +CHECK-NEXT: required from libstdc++.so.6: +CHECK-NEXT: 0x08922974 0x00 0x03 GLIBCXX_3.4 +CHECK-NEXT: required from libc.so.6: +CHECK-NEXT: 0x09691a75 0x00 0x02 GLIBC_2.2.5 + Index: tools/llvm-objdump/ELFDump.cpp =================================================================== --- tools/llvm-objdump/ELFDump.cpp +++ tools/llvm-objdump/ELFDump.cpp @@ -90,6 +90,7 @@ } outs() << format(Fmt, (uint64_t)Dyn.d_un.d_val); } + outs() << "\n"; } template void printProgramHeaders(const ELFFile *o) { @@ -157,6 +158,73 @@ outs() << "\n"; } +template +void printSymbolVersionRef(const ELFFile *Elf, StringRef Filename) { + + typedef ELFFile ELFO; + using VerNeed = typename ELFO::Elf_Verneed; + using VernAux = typename ELFO::Elf_Vernaux; + + auto DynamicEntriesOrError = Elf->dynamicEntries(); + if (!DynamicEntriesOrError) + report_error(Filename, DynamicEntriesOrError.takeError()); + + unsigned VerNeedNum = 0; + for (const auto &Dyn : *DynamicEntriesOrError) { + if (Dyn.d_tag == ELF::DT_VERNEEDNUM) { + VerNeedNum = Dyn.d_un.d_val; + break; + } + } + + if (VerNeedNum == 0) + return; + outs() << "Version References:\n"; + + auto SectionsOrError = Elf->sections(); + if (!SectionsOrError) + report_error(Filename, SectionsOrError.takeError()); + + const typename ELFO::Elf_Shdr *GNUVerDepSec = nullptr; + for (const typename ELFO::Elf_Shdr &Sec : *SectionsOrError) { + if (Sec.sh_type == ELF::SHT_GNU_verneed) { + GNUVerDepSec = &Sec; + break; + } + } + + if (GNUVerDepSec) { + const uint8_t *VNeed = + (const uint8_t *)Elf->base() + GNUVerDepSec->sh_offset; + auto SymTabOrErr = Elf->getSection(GNUVerDepSec->sh_link); + if (!SymTabOrErr) + report_error(Filename, SymTabOrErr.takeError()); + const typename ELFO::Elf_Shdr *SymTab = *SymTabOrErr; + for (unsigned I = 0; I < VerNeedNum; ++I) { + const auto *Need = reinterpret_cast(VNeed); + outs() << " required from " + << StringRef((const char *)Elf->base() + SymTab->sh_offset + + Need->vn_file) + << ":\n"; + unsigned DepCnt = Need->vn_cnt; + const uint8_t *VAux = VNeed + Need->vn_aux; + for (unsigned J = 0; J < DepCnt; ++J) { + const auto *Aux = reinterpret_cast(VAux); + outs() << " " + << format("0x%08" PRIx64 " ", (uint64_t)Aux->vna_hash) + << format("0x%02" PRIx64 " ", (uint64_t)Aux->vna_flags) + << format("0x%02" PRIx64 " ", (uint64_t)Aux->vna_other) + << StringRef((const char *)(Elf->base() + SymTab->sh_offset + + Aux->vna_name)) + << "\n"; + VAux += Aux->vna_next; + } + VNeed += Need->vn_next; + } + outs() << "\n"; + } +} + void llvm::printELFFileHeader(const object::ObjectFile *Obj) { if (const auto *ELFObj = dyn_cast(Obj)) printProgramHeaders(ELFObj->getELFFile()); @@ -178,3 +246,15 @@ else if (const auto *ELFObj = dyn_cast(Obj)) printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); } + +void llvm::printELFSymbolVersionRef(const object::ObjectFile *Obj) { + if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionRef(ELFObj->getELFFile(), Obj->getFileName()); + else if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionRef(ELFObj->getELFFile(), Obj->getFileName()); + else if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionRef(ELFObj->getELFFile(), Obj->getFileName()); + else if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionRef(ELFObj->getELFFile(), Obj->getFileName()); +} + Index: tools/llvm-objdump/llvm-objdump.h =================================================================== --- tools/llvm-objdump/llvm-objdump.h +++ tools/llvm-objdump/llvm-objdump.h @@ -82,6 +82,7 @@ void printMachOWeakBindTable(object::MachOObjectFile* o); void printELFFileHeader(const object::ObjectFile *o); void printELFDynamicSection(const object::ObjectFile *Obj); +void printELFSymbolVersionRef(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 @@ -2220,7 +2220,8 @@ static void printPrivateFileHeaders(const ObjectFile *o, bool onlyFirst) { if (o->isELF()) { printELFFileHeader(o); - return printELFDynamicSection(o); + printELFDynamicSection(o); + return printELFSymbolVersionRef(o); } if (o->isCOFF()) return printCOFFFileHeader(o);