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,134 @@ outs() << "\n"; } +template +void printSymbolVersionDefinition(const ELFFile *Elf, + StringRef Filename) { + typedef ELFFile ELFO; + typedef typename ELFO::Elf_Shdr Elf_Shdr; + typedef typename ELFO::Elf_Verdef Elf_Verdef; + typedef typename ELFO::Elf_Verdaux Elf_Verdaux; + + auto SectionsOrError = Elf->sections(); + if (!SectionsOrError) + report_error(Filename, SectionsOrError.takeError()); + + const Elf_Shdr *VDefSec = nullptr; + for (const Elf_Shdr &Sec : *SectionsOrError) { + if (Sec.sh_type == ELF::SHT_GNU_verdef) { + VDefSec = &Sec; + break; + } + } + + if (VDefSec == nullptr) + return; + + // we should use sh_info to determin the entry of SHT_GNU_verdef + if (VDefSec->sh_info == 0) + report_error(Filename, createError(".gnu.version_d invalid entry")); + + outs() << "Version definitions:\n"; + + const auto *VDef = + reinterpret_cast(Elf->base() + VDefSec->sh_offset); + + auto StrTabOrError = Elf->getSection(VDefSec->sh_link); + if (!StrTabOrError) + report_error(Filename, StrTabOrError.takeError()); + const Elf_Shdr *StrTab = *StrTabOrError; + + for (uint64_t VDefIndex = 0; VDefIndex < VDefSec->sh_info; ++VDefIndex) { + const auto *Def = reinterpret_cast(VDef); + outs() << VDefIndex + 1 << ' ' + << format("0x%02" PRIx16 " ", (uint16_t)Def->vd_flags) + << format("0x%08" PRIx32 " ", (uint32_t)Def->vd_hash); + + const auto *VDefAux = VDef + Def->vd_aux; + for (uint32_t VDefAuxIndex = 0; VDefAuxIndex < Def->vd_cnt; + ++VDefAuxIndex) { + const auto *Aux = reinterpret_cast(VDefAux); + // The first entry pointed to by the Elfxx_Verdef entry, contains + // the actual defined name. The second and all later entries name + // predecessor versions. (https://akkadia.org/drepper/symbol-versioning) + outs() << ((VDefAuxIndex == 0) ? "" : " "); + outs() << StringRef((const char *)Elf->base() + StrTab->sh_offset + + Aux->vda_name) + << '\n'; + VDefAux += Aux->vda_next; + } + VDef += Def->vd_next; + } + 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 *VNeedSec = nullptr; + for (const Elf_Shdr &Sec : *SectionsOrError) { + if (Sec.sh_type == ELF::SHT_GNU_verneed) { + VNeedSec = &Sec; + break; + } + } + + if (VNeedSec == nullptr) + return; + + // we use sh_info to determine the entry of SHT_GNU_verneed. + if (VNeedSec->sh_info == 0) + report_error(Filename, createError(".gnu.version_r invalid entry")); + + outs() << "Version References:\n"; + + const auto *VNeed = + reinterpret_cast(Elf->base() + VNeedSec->sh_offset); + + auto StrTabOrError = Elf->getSection(VNeedSec->sh_link); + if (!StrTabOrError) + report_error(Filename, StrTabOrError.takeError()); + const Elf_Shdr *StrTab = *StrTabOrError; + + for (uint64_t VNeedIndex = 0; VNeedIndex < VNeedSec->sh_info; ++VNeedIndex) { + const auto *Need = reinterpret_cast(VNeed); + outs() << " required from " + << StringRef((const char *)Elf->base() + StrTab->sh_offset + + Need->vn_file) + << ":\n"; + const auto *VNeedAux = VNeed + Need->vn_aux; + for (uint32_t VNeedAuxIndex = 0; VNeedAuxIndex < Need->vn_cnt; + ++VNeedAuxIndex) { + const auto *Aux = reinterpret_cast(VNeedAux); + outs() << " " + << format("0x%08" PRIx32 " ", (uint32_t)Aux->vna_hash) + << format("0x%02" PRIx16 " ", (uint16_t)Aux->vna_flags) + << format("0x%02" PRIx16 " ", (uint16_t)Aux->vna_other) + << StringRef((const char *)(Elf->base() + StrTab->sh_offset + + Aux->vna_name)) + << "\n"; + VNeedAux += Aux->vna_next; + } + VNeed += Need->vn_next; + } + outs() << "\n"; +} + +template +void printSymbolVersionInfo(const ELFFile *Elf, StringRef Filename) { + printSymbolVersionDefinition(Elf, Filename); + printSymbolVersionDependency(Elf, Filename); +} + void llvm::printELFFileHeader(const object::ObjectFile *Obj) { if (const auto *ELFObj = dyn_cast(Obj)) printProgramHeaders(ELFObj->getELFFile()); @@ -178,3 +307,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 @@ -82,6 +82,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 @@ -2220,7 +2220,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);