Index: test/tools/llvm-objdump/private-headers-symbol-version.test =================================================================== --- /dev/null +++ test/tools/llvm-objdump/private-headers-symbol-version.test @@ -0,0 +1,7 @@ +# 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 @@ -14,6 +14,7 @@ #include "llvm-objdump.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/ELFTypes.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" @@ -90,6 +91,7 @@ } outs() << format(Fmt, (uint64_t)Dyn.d_un.d_val); } + outs() << "\n"; } template void printProgramHeaders(const ELFFile *o) { @@ -157,6 +159,75 @@ outs() << "\n"; } +template +void printSymbolVersionRefs(const ELFFile *Elf, StringRef Filename) { + typedef ELFFile ELFO; + typedef typename ELFO::Elf_Shdr Elf_Shdr; + typedef typename ELFO::Elf_Verneed VerNeed; + typedef typename ELFO::Elf_Vernaux VernAux; + + auto DynamicEntriesOrError = Elf->dynamicEntries(); + if (!DynamicEntriesOrError) + report_error(Filename, DynamicEntriesOrError.takeError()); + + uint64_t VerNeedNum = 0; + for (const auto &Dyn : *DynamicEntriesOrError) { + if (Dyn.d_tag == ELF::DT_VERNEEDNUM) { + VerNeedNum = Dyn.d_un.d_val; + break; + } + } + + // if this ELF file doesn't contain DT_VERNEEDNUM entry or + // DT_VERNEEDNUM is zero, we just return like what gnu-objdump does. + if (VerNeedNum == 0) + return; + outs() << "Version References:\n"; + + 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; + const auto *VNeed = + reinterpret_cast(Elf->base() + VerNeedSec->sh_offset); + auto SymTabOrErr = Elf->getSection(VerNeedSec->sh_link); + if (!SymTabOrErr) + report_error(Filename, SymTabOrErr.takeError()); + const Elf_Shdr *SymTab = *SymTabOrErr; + for (uint64_t VNeedIndex = 0; VNeedIndex < VerNeedNum; ++VNeedIndex) { + const auto *Need = reinterpret_cast(VNeed); + outs() << " required from " + << StringRef((const char *)Elf->base() + SymTab->sh_offset + + Need->vn_file) + << ":\n"; + uint64_t VernAuxNum = Need->vn_cnt; + const auto *VAux = VNeed + Need->vn_aux; + for (uint64_t VAuxIndex = 0; VAuxIndex < VernAuxNum; ++VAuxIndex) { + const auto *Aux = reinterpret_cast(VAux); + outs() << " " + << format("0x%08" PRIx64 " ", (uint64_t)Aux->vna_hash) + << format("0x%02" PRIx32 " ", (uint32_t)Aux->vna_flags) + << format("0x%02" PRIx32 " ", (uint32_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 +249,14 @@ else if (const auto *ELFObj = dyn_cast(Obj)) printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); } + +void llvm::printELFSymbolVersionRefs(const object::ObjectFile *Obj) { + if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionRefs(ELFObj->getELFFile(), Obj->getFileName()); + else if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionRefs(ELFObj->getELFFile(), Obj->getFileName()); + else if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionRefs(ELFObj->getELFFile(), Obj->getFileName()); + else if (const auto *ELFObj = dyn_cast(Obj)) + printSymbolVersionRefs(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 printELFSymbolVersionRefs(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,9 @@ static void printPrivateFileHeaders(const ObjectFile *o, bool onlyFirst) { if (o->isELF()) { printELFFileHeader(o); - return printELFDynamicSection(o); + printELFDynamicSection(o); + printELFSymbolVersionRefs(o); + return; } if (o->isCOFF()) return printCOFFFileHeader(o);