Index: test/tools/llvm-readobj/elf-versioninfo.test =================================================================== --- test/tools/llvm-readobj/elf-versioninfo.test +++ test/tools/llvm-readobj/elf-versioninfo.test @@ -1,106 +1,118 @@ // Test that llvm-readobj dumps version info tags correctly. -RUN: llvm-readobj -dynamic-table -V %p/Inputs/verdef.elf-x86-64 | FileCheck %s +RUN: llvm-readobj -dynamic-table -V %p/Inputs/verdef.elf-x86-64 | FileCheck %s --check-prefix=LLVM_VERDEF +RUN: llvm-readelf -dynamic-table -V %p/Inputs/verdef.elf-x86-64 | FileCheck %s --check-prefix=GNU_VERDEF -CHECK: 0x000000006FFFFFF0 VERSYM 0x24C -CHECK: 0x000000006FFFFFFC VERDEF 0x25C -CHECK: 0x000000006FFFFFFD VERDEFNUM 3 - -CHECK: Version symbols { -CHECK-NEXT: Section Name: .gnu.version (20) -CHECK-NEXT: Address: 0x24C -CHECK-NEXT: Offset: 0x24C -CHECK-NEXT: Link: 1 -CHECK-NEXT: Symbols [ -CHECK-NEXT: Symbol { -CHECK-NEXT: Version: 0 -CHECK-NEXT: Name: {{$}} -CHECK-NEXT: } -CHECK-NEXT: Symbol { -CHECK-NEXT: Version: 1 -CHECK-NEXT: Name: _end{{$}} -CHECK-NEXT: } -CHECK-NEXT: Symbol { -CHECK-NEXT: Version: 1 -CHECK-NEXT: Name: _edata{{$}} -CHECK-NEXT: } -CHECK-NEXT: Symbol { -CHECK-NEXT: Version: 3 -CHECK-NEXT: Name: goo@@VERSION2 -CHECK-NEXT: } -CHECK-NEXT: Symbol { -CHECK-NEXT: Version: 1 -CHECK-NEXT: Name: __bss_start{{$}} -CHECK-NEXT: } -CHECK-NEXT: Symbol { -CHECK-NEXT: Version: 2 -CHECK-NEXT: Name: foo@@VERSION1 -CHECK-NEXT: } -CHECK-NEXT: Symbol { -CHECK-NEXT: Version: 2 -CHECK-NEXT: Name: VERSION1@@VERSION1 -CHECK-NEXT: } -CHECK-NEXT: Symbol { -CHECK-NEXT: Version: 3 -CHECK-NEXT: Name: VERSION2@@VERSION2 -CHECK-NEXT: } -CHECK-NEXT: ] -CHECK-NEXT: } - -CHECK: SHT_GNU_verdef { -CHECK-NEXT: Definition { -CHECK-NEXT: Version: 1 -CHECK-NEXT: Flags: Base (0x1) -CHECK-NEXT: Index: 1 -CHECK-NEXT: Hash: 430712 -CHECK-NEXT: Name: blah -CHECK-NEXT: } -CHECK-NEXT: Definition { -CHECK-NEXT: Version: 1 -CHECK-NEXT: Flags: 0x0 -CHECK-NEXT: Index: 2 -CHECK-NEXT: Hash: 175630257 -CHECK-NEXT: Name: VERSION1 -CHECK-NEXT: } -CHECK-NEXT: Definition { -CHECK-NEXT: Version: 1 -CHECK-NEXT: Flags: 0x0 -CHECK-NEXT: Index: 3 -CHECK-NEXT: Hash: 175630258 -CHECK-NEXT: Name: VERSION2 -CHECK-NEXT: Predecessor: VERSION1 -CHECK-NEXT: } -CHECK-NEXT: } - -RUN: llvm-readobj -V %p/Inputs/verneed.elf-x86-64 | FileCheck %s --check-prefix=VERNEED - -VERNEED: SHT_GNU_verneed { -VERNEED-NEXT: Dependency { -VERNEED-NEXT: Version: 1 -VERNEED-NEXT: Count: 2 -VERNEED-NEXT: FileName: verneed1.so.0 -VERNEED-NEXT: Entry { -VERNEED-NEXT: Hash: 1938 -VERNEED-NEXT: Flags: 0x0 -VERNEED-NEXT: Index: 3 -VERNEED-NEXT: Name: v2 -VERNEED-NEXT: } -VERNEED-NEXT: Entry { -VERNEED-NEXT: Hash: 1939 -VERNEED-NEXT: Flags: 0x0 -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: FileName: verneed2.so.0 -VERNEED-NEXT: Entry { -VERNEED-NEXT: Hash: 1937 -VERNEED-NEXT: Flags: 0x0 -VERNEED-NEXT: Index: 4 -VERNEED-NEXT: Name: v1 -VERNEED-NEXT: } -VERNEED-NEXT: } -VERNEED-NEXT: } +LLVM_VERDEF: 0x000000006FFFFFF0 VERSYM 0x24C +LLVM_VERDEF: 0x000000006FFFFFFC VERDEF 0x25C +LLVM_VERDEF: 0x000000006FFFFFFD VERDEFNUM 3 + +LLVM_VERDEF: Version symbols { +LLVM_VERDEF-NEXT: Section Name: .gnu.version (20) +LLVM_VERDEF-NEXT: Address: 0x24C +LLVM_VERDEF-NEXT: Offset: 0x24C +LLVM_VERDEF-NEXT: Link: 1 +LLVM_VERDEF-NEXT: Symbols [ +LLVM_VERDEF-NEXT: Symbol { +LLVM_VERDEF-NEXT: Version: 0 +LLVM_VERDEF-NEXT: Name: {{$}} +LLVM_VERDEF-NEXT: } +LLVM_VERDEF-NEXT: Symbol { +LLVM_VERDEF-NEXT: Version: 1 +LLVM_VERDEF-NEXT: Name: _end{{$}} +LLVM_VERDEF-NEXT: } +LLVM_VERDEF-NEXT: Symbol { +LLVM_VERDEF-NEXT: Version: 1 +LLVM_VERDEF-NEXT: Name: _edata{{$}} +LLVM_VERDEF-NEXT: } +LLVM_VERDEF-NEXT: Symbol { +LLVM_VERDEF-NEXT: Version: 3 +LLVM_VERDEF-NEXT: Name: goo@@VERSION2 +LLVM_VERDEF-NEXT: } +LLVM_VERDEF-NEXT: Symbol { +LLVM_VERDEF-NEXT: Version: 1 +LLVM_VERDEF-NEXT: Name: __bss_start{{$}} +LLVM_VERDEF-NEXT: } +LLVM_VERDEF-NEXT: Symbol { +LLVM_VERDEF-NEXT: Version: 2 +LLVM_VERDEF-NEXT: Name: foo@@VERSION1 +LLVM_VERDEF-NEXT: } +LLVM_VERDEF-NEXT: Symbol { +LLVM_VERDEF-NEXT: Version: 2 +LLVM_VERDEF-NEXT: Name: VERSION1@@VERSION1 +LLVM_VERDEF-NEXT: } +LLVM_VERDEF-NEXT: Symbol { +LLVM_VERDEF-NEXT: Version: 3 +LLVM_VERDEF-NEXT: Name: VERSION2@@VERSION2 +LLVM_VERDEF-NEXT: } +LLVM_VERDEF-NEXT: ] +LLVM_VERDEF-NEXT: } + +LLVM_VERDEF: SHT_GNU_verdef { +LLVM_VERDEF-NEXT: Definition { +LLVM_VERDEF-NEXT: Version: 1 +LLVM_VERDEF-NEXT: Flags: Base (0x1) +LLVM_VERDEF-NEXT: Index: 1 +LLVM_VERDEF-NEXT: Hash: 430712 +LLVM_VERDEF-NEXT: Name: blah +LLVM_VERDEF-NEXT: } +LLVM_VERDEF-NEXT: Definition { +LLVM_VERDEF-NEXT: Version: 1 +LLVM_VERDEF-NEXT: Flags: 0x0 +LLVM_VERDEF-NEXT: Index: 2 +LLVM_VERDEF-NEXT: Hash: 175630257 +LLVM_VERDEF-NEXT: Name: VERSION1 +LLVM_VERDEF-NEXT: } +LLVM_VERDEF-NEXT: Definition { +LLVM_VERDEF-NEXT: Version: 1 +LLVM_VERDEF-NEXT: Flags: 0x0 +LLVM_VERDEF-NEXT: Index: 3 +LLVM_VERDEF-NEXT: Hash: 175630258 +LLVM_VERDEF-NEXT: Name: VERSION2 +LLVM_VERDEF-NEXT: Predecessor: VERSION1 +LLVM_VERDEF-NEXT: } +LLVM_VERDEF-NEXT: } + +GNU_VERDEF: 0x000000006ffffff0 VERSYM 0x24c +GNU_VERDEF: 0x000000006ffffffc VERDEF 0x25c +GNU_VERDEF: 0x000000006ffffffd VERDEFNUM 3 + +GNU_VERDEF: Dumper for .gnu.version is not implemented +GNU_VERDEF: Dumper for .gnu.version_d is not implemented + +RUN: llvm-readobj -V %p/Inputs/verneed.elf-x86-64 | FileCheck %s --check-prefix=LLVM_VERNEED +RUN: llvm-readelf -V %p/Inputs/verneed.elf-x86-64 | FileCheck %s --check-prefix=GNU_VERNEED + +LLVM_VERNEED: SHT_GNU_verneed { +LLVM_VERNEED-NEXT: Dependency { +LLVM_VERNEED-NEXT: Version: 1 +LLVM_VERNEED-NEXT: Count: 2 +LLVM_VERNEED-NEXT: FileName: verneed1.so.0 +LLVM_VERNEED-NEXT: Entry { +LLVM_VERNEED-NEXT: Hash: 1938 +LLVM_VERNEED-NEXT: Flags: 0x0 +LLVM_VERNEED-NEXT: Index: 3 +LLVM_VERNEED-NEXT: Name: v2 +LLVM_VERNEED-NEXT: } +LLVM_VERNEED-NEXT: Entry { +LLVM_VERNEED-NEXT: Hash: 1939 +LLVM_VERNEED-NEXT: Flags: 0x0 +LLVM_VERNEED-NEXT: Index: 2 +LLVM_VERNEED-NEXT: Name: v3 +LLVM_VERNEED-NEXT: } +LLVM_VERNEED-NEXT: } +LLVM_VERNEED-NEXT: Dependency { +LLVM_VERNEED-NEXT: Version: 1 +LLVM_VERNEED-NEXT: Count: 1 +LLVM_VERNEED-NEXT: FileName: verneed2.so.0 +LLVM_VERNEED-NEXT: Entry { +LLVM_VERNEED-NEXT: Hash: 1937 +LLVM_VERNEED-NEXT: Flags: 0x0 +LLVM_VERNEED-NEXT: Index: 4 +LLVM_VERNEED-NEXT: Name: v1 +LLVM_VERNEED-NEXT: } +LLVM_VERNEED-NEXT: } +LLVM_VERNEED-NEXT: } + +GNU_VERNEED: Dumper for .gnu.version is not implemented +GNU_VERNEED: Dumper for .gnu.version_r is not implemented Index: test/tools/yaml2obj/verdef-section.yaml =================================================================== --- test/tools/yaml2obj/verdef-section.yaml +++ test/tools/yaml2obj/verdef-section.yaml @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: llvm-readelf -V %t | FileCheck %s +# RUN: llvm-readobj -V %t | FileCheck %s # Check we are able to handle the SHT_GNU_verdef sections. Index: test/tools/yaml2obj/verneed-section.yaml =================================================================== --- test/tools/yaml2obj/verneed-section.yaml +++ test/tools/yaml2obj/verneed-section.yaml @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: llvm-readelf -V %t | FileCheck %s +# RUN: llvm-readobj -V %t | FileCheck %s # Check we are able to handle the SHT_GNU_verneed sections. Index: test/tools/yaml2obj/versym-section.yaml =================================================================== --- test/tools/yaml2obj/versym-section.yaml +++ test/tools/yaml2obj/versym-section.yaml @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: llvm-readelf -V %t | FileCheck %s +# RUN: llvm-readobj -V %t | FileCheck %s ## Check we are able to produce a valid SHT_GNU_versym ## section from its description. Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -342,6 +342,12 @@ virtual void printProgramHeaders(const ELFFile *Obj, bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) = 0; + virtual void printVersionSymbolSection(const ELFFile *Obj, + const Elf_Shdr *Sec) = 0; + virtual void printVersionDefinitionSection(const ELFFile *Obj, + const Elf_Shdr *Sec) = 0; + virtual void printVersionDependencySection(const ELFFile *Obj, + const Elf_Shdr *Sec) = 0; virtual void printHashHistogram(const ELFFile *Obj) = 0; virtual void printCGProfile(const ELFFile *Obj) = 0; virtual void printAddrsig(const ELFFile *Obj) = 0; @@ -376,6 +382,12 @@ size_t Offset) override; void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) override; + void printVersionSymbolSection(const ELFFile *Obj, + const Elf_Shdr *Sec) override; + void printVersionDefinitionSection(const ELFFile *Obj, + const Elf_Shdr *Sec) override; + void printVersionDependencySection(const ELFFile *Obj, + const Elf_Shdr *Sec) override; void printHashHistogram(const ELFFile *Obj) override; void printCGProfile(const ELFFile *Obj) override; void printAddrsig(const ELFFile *Obj) override; @@ -470,6 +482,12 @@ void printDynamicRelocations(const ELFO *Obj) override; void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) override; + void printVersionSymbolSection(const ELFFile *Obj, + const Elf_Shdr *Sec) override; + void printVersionDefinitionSection(const ELFFile *Obj, + const Elf_Shdr *Sec) override; + void printVersionDependencySection(const ELFFile *Obj, + const Elf_Shdr *Sec) override; void printHashHistogram(const ELFFile *Obj) override; void printCGProfile(const ELFFile *Obj) override; void printAddrsig(const ELFFile *Obj) override; @@ -635,113 +653,18 @@ } } -static const EnumEntry SymVersionFlags[] = { - {"Base", "BASE", VER_FLG_BASE}, - {"Weak", "WEAK", VER_FLG_WEAK}, - {"Info", "INFO", VER_FLG_INFO}}; - -template -static void printVersionDefinitionSection(ELFDumper *Dumper, - const ELFO *Obj, - const typename ELFO::Elf_Shdr *Sec, - ScopedPrinter &W) { - using VerDef = typename ELFO::Elf_Verdef; - using VerdAux = typename ELFO::Elf_Verdaux; - - DictScope SD(W, "SHT_GNU_verdef"); - if (!Sec) - return; - - const uint8_t *SecStartAddress = - (const uint8_t *)Obj->base() + Sec->sh_offset; - const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size; - const uint8_t *P = SecStartAddress; - const typename ELFO::Elf_Shdr *StrTab = - unwrapOrError(Obj->getSection(Sec->sh_link)); - - unsigned VerDefsNum = Sec->sh_info; - while (VerDefsNum--) { - if (P + sizeof(VerDef) > SecEndAddress) - report_fatal_error("invalid offset in the section"); - - auto *VD = reinterpret_cast(P); - DictScope Def(W, "Definition"); - W.printNumber("Version", VD->vd_version); - W.printEnum("Flags", VD->vd_flags, makeArrayRef(SymVersionFlags)); - W.printNumber("Index", VD->vd_ndx); - W.printNumber("Hash", VD->vd_hash); - W.printString("Name", - StringRef((const char *)(Obj->base() + StrTab->sh_offset + - VD->getAux()->vda_name))); - if (!VD->vd_cnt) - report_fatal_error("at least one definition string must exist"); - if (VD->vd_cnt > 2) - report_fatal_error("more than one predecessor is not expected"); - - if (VD->vd_cnt == 2) { - const uint8_t *PAux = P + VD->vd_aux + VD->getAux()->vda_next; - const VerdAux *Aux = reinterpret_cast(PAux); - W.printString("Predecessor", - StringRef((const char *)(Obj->base() + StrTab->sh_offset + - Aux->vda_name))); - } - - P += VD->vd_next; - } -} - -template -static void printVersionDependencySection(ELFDumper *Dumper, - const ELFO *Obj, - const typename ELFO::Elf_Shdr *Sec, - ScopedPrinter &W) { - using VerNeed = typename ELFO::Elf_Verneed; - using VernAux = typename ELFO::Elf_Vernaux; - - DictScope SD(W, "SHT_GNU_verneed"); - if (!Sec) - return; - - const uint8_t *SecData = (const uint8_t *)Obj->base() + Sec->sh_offset; - const typename ELFO::Elf_Shdr *StrTab = - unwrapOrError(Obj->getSection(Sec->sh_link)); - - const uint8_t *P = SecData; - unsigned VerNeedNum = Sec->sh_info; - 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("FileName", - 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.printEnum("Flags", Aux->vna_flags, makeArrayRef(SymVersionFlags)); - 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, ObjF->getELFFile(), dot_gnu_version_sec, W); + ELFDumperStyle->printVersionSymbolSection(ObjF->getELFFile(), + dot_gnu_version_sec); // Dump version definition section. - printVersionDefinitionSection(this, ObjF->getELFFile(), dot_gnu_version_d_sec, W); + ELFDumperStyle->printVersionDefinitionSection(ObjF->getELFFile(), + dot_gnu_version_d_sec); // Dump version dependency section. - printVersionDependencySection(this, ObjF->getELFFile(), dot_gnu_version_r_sec, W); + ELFDumperStyle->printVersionDependencySection(ObjF->getELFFile(), + dot_gnu_version_r_sec); } template @@ -925,6 +848,11 @@ {"Standalone", "Standalone App", ELF::ELFOSABI_STANDALONE} }; +static const EnumEntry SymVersionFlags[] = { + {"Base", "BASE", VER_FLG_BASE}, + {"Weak", "WEAK", VER_FLG_WEAK}, + {"Info", "INFO", VER_FLG_INFO}}; + static const EnumEntry AMDGPUElfOSABI[] = { {"AMDGPU_HSA", "AMDGPU - HSA", ELF::ELFOSABI_AMDGPU_HSA}, {"AMDGPU_PAL", "AMDGPU - PAL", ELF::ELFOSABI_AMDGPU_PAL}, @@ -3460,6 +3388,36 @@ } } +template +void GNUStyle::printVersionSymbolSection(const ELFFile *Obj, + const Elf_Shdr *Sec) { + if (!Sec) + return; + + StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); + OS << "Dumper for " << SecName << " is not implemented\n"; +} + +template +void GNUStyle::printVersionDefinitionSection(const ELFFile *Obj, + const Elf_Shdr *Sec) { + if (!Sec) + return; + + StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); + OS << "Dumper for " << SecName << " is not implemented\n"; +} + +template +void GNUStyle::printVersionDependencySection(const ELFFile *Obj, + const Elf_Shdr *Sec) { + if (!Sec) + return; + + StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); + OS << "Dumper for " << SecName << " is not implemented\n"; +} + // Hash histogram shows statistics of how efficient the hash was for the // dynamic symbol table. The table shows number of hash buckets for different // lengths of chains as absolute number and percentage of the total buckets. @@ -4550,6 +4508,122 @@ } template +void LLVMStyle::printVersionSymbolSection(const ELFFile *Obj, + const Elf_Shdr *Sec) { + DictScope SS(W, "Version symbols"); + if (!Sec) + return; + + StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); + W.printNumber("Section Name", SecName, Sec->sh_name); + W.printHex("Address", Sec->sh_addr); + W.printHex("Offset", Sec->sh_offset); + W.printNumber("Link", Sec->sh_link); + + const uint8_t *VersymBuf = (const uint8_t *)Obj->base() + Sec->sh_offset; + const ELFDumper *Dumper = this->dumper(); + StringRef StrTable = Dumper->getDynamicStringTable(); + + // Same number of entries in the dynamic symbol table (DT_SYMTAB). + ListScope Syms(W, "Symbols"); + for (const Elf_Sym &Sym : Dumper->dynamic_symbols()) { + DictScope S(W, "Symbol"); + const Elf_Versym *Versym = reinterpret_cast(VersymBuf); + std::string FullSymbolName = + Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */); + W.printNumber("Version", Versym->vs_index); + W.printString("Name", FullSymbolName); + VersymBuf += sizeof(Elf_Versym); + } +} + +template +void LLVMStyle::printVersionDefinitionSection(const ELFFile *Obj, + const Elf_Shdr *Sec) { + DictScope SD(W, "SHT_GNU_verdef"); + if (!Sec) + return; + + const uint8_t *SecStartAddress = + (const uint8_t *)Obj->base() + Sec->sh_offset; + const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size; + const uint8_t *VerdefBuf = SecStartAddress; + const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link)); + + unsigned VerDefsNum = Sec->sh_info; + while (VerDefsNum--) { + if (VerdefBuf + sizeof(Elf_Verdef) > SecEndAddress) + // FIXME: report_fatal_error is not a good way to report error. We should + // emit a parsing error here and below. + report_fatal_error("invalid offset in the section"); + + const Elf_Verdef *Verdef = reinterpret_cast(VerdefBuf); + DictScope Def(W, "Definition"); + W.printNumber("Version", Verdef->vd_version); + W.printEnum("Flags", Verdef->vd_flags, makeArrayRef(SymVersionFlags)); + W.printNumber("Index", Verdef->vd_ndx); + W.printNumber("Hash", Verdef->vd_hash); + W.printString("Name", + StringRef((const char *)(Obj->base() + StrTab->sh_offset + + Verdef->getAux()->vda_name))); + if (!Verdef->vd_cnt) + report_fatal_error("at least one definition string must exist"); + if (Verdef->vd_cnt > 2) + report_fatal_error("more than one predecessor is not expected"); + + if (Verdef->vd_cnt == 2) { + const uint8_t *VerdauxBuf = + VerdefBuf + Verdef->vd_aux + Verdef->getAux()->vda_next; + const Elf_Verdaux *Verdaux = + reinterpret_cast(VerdauxBuf); + W.printString("Predecessor", + StringRef((const char *)(Obj->base() + StrTab->sh_offset + + Verdaux->vda_name))); + } + VerdefBuf += Verdef->vd_next; + } +} + +template +void LLVMStyle::printVersionDependencySection(const ELFFile *Obj, + const Elf_Shdr *Sec) { + DictScope SD(W, "SHT_GNU_verneed"); + if (!Sec) + return; + + const uint8_t *SecData = (const uint8_t *)Obj->base() + Sec->sh_offset; + const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link)); + + const uint8_t *VerneedBuf = SecData; + unsigned VerneedNum = Sec->sh_info; + for (unsigned I = 0; I < VerneedNum; ++I) { + const Elf_Verneed *Verneed = + reinterpret_cast(VerneedBuf); + DictScope Entry(W, "Dependency"); + W.printNumber("Version", Verneed->vn_version); + W.printNumber("Count", Verneed->vn_cnt); + W.printString("FileName", + StringRef((const char *)(Obj->base() + StrTab->sh_offset + + Verneed->vn_file))); + + const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; + for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { + const Elf_Vernaux *Vernaux = + reinterpret_cast(VernauxBuf); + DictScope Entry(W, "Entry"); + W.printNumber("Hash", Vernaux->vna_hash); + W.printEnum("Flags", Vernaux->vna_flags, makeArrayRef(SymVersionFlags)); + W.printNumber("Index", Vernaux->vna_other); + W.printString("Name", + StringRef((const char *)(Obj->base() + StrTab->sh_offset + + Vernaux->vna_name))); + VernauxBuf += Vernaux->vna_next; + } + VerneedBuf += Verneed->vn_next; + } +} + +template void LLVMStyle::printHashHistogram(const ELFFile *Obj) { W.startLine() << "Hash Histogram not implemented!\n"; }