Index: test/tools/llvm-readobj/elf-versioninfo.test =================================================================== --- test/tools/llvm-readobj/elf-versioninfo.test +++ test/tools/llvm-readobj/elf-versioninfo.test @@ -82,3 +82,42 @@ CHECK-NEXT: } CHECK-NEXT: ] CHECK-NEXT: } + +RUN: llvm-readobj -V %p/Inputs/verneed.elf-x86-64 | FileCheck %s --check-prefix=VERNEED + +VERNEED: Version needs { +VERNEED-NEXT: Section Name: .gnu.version_r +VERNEED-NEXT: Address: 0x10230 +VERNEED-NEXT: Offset: 0x230 +VERNEED-NEXT: Link: 5 +VERNEED-NEXT: Entries [ +VERNEED-NEXT: Dependency { +VERNEED-NEXT: Version: 1 +VERNEED-NEXT: Count: 2 +VERNEED-NEXT: Name: verneed1.so.0 +VERNEED-NEXT: Entry { +VERNEED-NEXT: Hash: 1938 +VERNEED-NEXT: Flags: 0 +VERNEED-NEXT: Index: 3 +VERNEED-NEXT: Name: v2 +VERNEED-NEXT: } +VERNEED-NEXT: Entry { +VERNEED-NEXT: Hash: 1939 +VERNEED-NEXT: Flags: 0 +VERNEED-NEXT: Index: 2 +VERNEED-NEXT: Name: v3 +VERNEED-NEXT: } +VERNEED-NEXT: } +VERNEED-NEXT: Dependency { +VERNEED-NEXT: Version: 1 +VERNEED-NEXT: Count: 1 +VERNEED-NEXT: Name: verneed2.so.0 +VERNEED-NEXT: Entry { +VERNEED-NEXT: Hash: 1937 +VERNEED-NEXT: Flags: 0 +VERNEED-NEXT: Index: 4 +VERNEED-NEXT: Name: v1 +VERNEED-NEXT: } +VERNEED-NEXT: } +VERNEED-NEXT: ] +VERNEED-NEXT: } Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -568,12 +568,68 @@ } } +template +static void printVersionDependencySection(ELFDumper *Dumper, + const ELFO *Obj, + const typename ELFO::Elf_Shdr *Sec, + ScopedPrinter &W) { + typedef typename ELFO::Elf_Verneed VerNeed; + typedef typename ELFO::Elf_Vernaux VernAux; + + DictScope SD(W, "Version needs"); + if (!Sec) + return; + StringRef Name = unwrapOrError(Obj->getSectionName(Sec)); + W.printNumber("Section Name", Name, Sec->sh_name); + W.printHex("Address", Sec->sh_addr); + W.printHex("Offset", Sec->sh_offset); + W.printNumber("Link", Sec->sh_link); + + unsigned VerNeedNum = 0; + for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) + if (Dyn.d_tag == DT_VERNEEDNUM) + VerNeedNum = Dyn.d_un.d_val; + + const uint8_t *SecData = (const uint8_t *)Obj->base() + Sec->sh_offset; + const typename ELFO::Elf_Shdr *StrTab = + unwrapOrError(Obj->getSection(Sec->sh_link)); + + ListScope Entries(W, "Entries"); + const uint8_t *P = SecData; + for (unsigned I = 0; I < VerNeedNum; ++I) { + const VerNeed *Need = reinterpret_cast(P); + DictScope Entry(W, "Dependency"); + W.printNumber("Version", Need->vn_version); + W.printNumber("Count", Need->vn_cnt); + W.printString("Name", + StringRef((const char *)(Obj->base() + StrTab->sh_offset + + Need->vn_file))); + + const uint8_t *PAux = P + Need->vn_aux; + for (unsigned J = 0; J < Need->vn_cnt; ++J) { + const VernAux *Aux = reinterpret_cast(PAux); + DictScope Entry(W, "Entry"); + W.printNumber("Hash", Aux->vna_hash); + W.printNumber("Flags", Aux->vna_flags); + W.printNumber("Index", Aux->vna_other); + W.printString("Name", + StringRef((const char *)(Obj->base() + StrTab->sh_offset + + Aux->vna_name))); + PAux += Aux->vna_next; + } + P += Need->vn_next; + } +} + template void ELFDumper::printVersionInfo() { // Dump version symbol section. printVersionSymbolSection(this, Obj, dot_gnu_version_sec, W); // Dump version definition section. printVersionDefinitionSection(this, Obj, dot_gnu_version_d_sec, W); + + // Dump version dependency section. + printVersionDependencySection(this, Obj, dot_gnu_version_r_sec, W); } template