diff --git a/llvm/test/tools/llvm-readobj/elf-versioninfo.test b/llvm/test/tools/llvm-readobj/elf-versioninfo.test --- a/llvm/test/tools/llvm-readobj/elf-versioninfo.test +++ b/llvm/test/tools/llvm-readobj/elf-versioninfo.test @@ -82,7 +82,12 @@ GNU-VERDEF-NEXT: 000: 0 (*local*) 1 (*global*) 1 (*global*) 3 (VERSION2) GNU-VERDEF-NEXT: 004: 1 (*global*) 2 (VERSION1) 2 (VERSION1) 3 (VERSION2) -GNU-VERDEF: Dumper for .gnu.version_d is not implemented +GNU-VERDEF: Version definition section '.gnu.version_d' contains 3 entries: +GNU-VERDEF-NEXT: Addr: 0x000000000000025c Offset: 0x00025c Link: 2 (.dynstr) +GNU-VERDEF-NEXT: 000000: Rev: 1 Flags: BASE Index: 1 Cnt: 1 Name: blah +GNU-VERDEF-NEXT: 0x001c: Rev: 1 Flags: 0 Index: 2 Cnt: 1 Name: VERSION1 +GNU-VERDEF-NEXT: 0x0038: Rev: 1 Flags: 0 Index: 3 Cnt: 2 Name: VERSION2 +GNU-VERDEF-NEXT: 0x0054: Parent 1: VERSION1 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 diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -3414,8 +3414,60 @@ if (!Sec) return; + const uint8_t *SecStartAddress = + reinterpret_cast(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)); + + StringRef StrTabName = unwrapOrError(Obj->getSectionName(StrTab)); StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); - OS << "Dumper for " << SecName << " is not implemented\n"; + uint32_t Entries = Sec->sh_info; + OS << "Version definition section '" << SecName << "' contains " << Entries + << " entries:\n" + << " Addr: " << format_hex(Sec->sh_addr, 18) + << " Offset: " << format_hex(Sec->sh_offset, 8) + << " Link: " << Sec->sh_link << " (" << StrTabName << ")\n"; + + for (uint32_t VerdefOffset = 0, VerdefIndex = 0; VerdefIndex < Entries; + VerdefIndex++) { + 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); + + OS << format(" %#06x:", VerdefOffset) << " Rev: " << Verdef->vd_version + << " Flags: " + << printEnum(Verdef->vd_flags, makeArrayRef(SymVersionFlags)) + << " Index: " << Verdef->vd_ndx << " Cnt: " << Verdef->vd_cnt + << " Name: " + << StringRef((const char *)Obj->base() + StrTab->sh_offset + + Verdef->getAux()->vda_name) + << '\n'; + + 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); + + OS << format(" %#06x: Parent 1: ", + VerdefOffset + Verdef->vd_aux + Verdef->getAux()->vda_next) + << StringRef((const char *)Obj->base() + StrTab->sh_offset + + Verdaux->vda_name) + << '\n'; + } + VerdefBuf += Verdef->vd_next; + VerdefOffset += Verdef->vd_next; + } + OS << '\n'; } template