Index: test/tools/llvm-objdump/verdef-elf.test =================================================================== --- /dev/null +++ test/tools/llvm-objdump/verdef-elf.test @@ -0,0 +1,41 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objdump -p %t | FileCheck --strict-whitespace %s + +# CHECK: Version definitions: +# CHECK-NEXT: 1 0x01 0x075bcd15 foo +# CHECK-NEXT: 2 0x02 0x3ade68b1 VERSION_1 +# CHECK-NEXT: VERSION_2 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 + Entry: 0x0000000000001000 +Sections: + - Name: .gnu.version_d + Type: SHT_GNU_verdef + Flags: [ SHF_ALLOC ] + Address: 0x0000000000000230 + Link: .dynstr + AddressAlign: 0x0000000000000004 + Info: 0x0000000000000003 + Entries: + - Version: 1 + Flags: 1 + VersionNdx: 1 + Hash: 123456789 + Names: + - foo + - Version: 1 + Flags: 2 + VersionNdx: 2 + Hash: 987654321 + Names: + - VERSION_1 + - VERSION_2 +DynamicSymbols: + Global: + - Name: bar +... Index: tools/llvm-objdump/ELFDump.cpp =================================================================== --- tools/llvm-objdump/ELFDump.cpp +++ tools/llvm-objdump/ELFDump.cpp @@ -298,6 +298,43 @@ } template +void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr, + ArrayRef Contents, + StringRef StrTab) { + typedef ELFFile ELFO; + typedef typename ELFO::Elf_Verdef Elf_Verdef; + typedef typename ELFO::Elf_Verdaux Elf_Verdaux; + + outs() << "Version definitions:\n"; + + const uint8_t *Buf = Contents.data(); + uint32_t VerdefIndex = 1; + // sh_info contains the number of entries in the SHT_GNU_verdef section. To + // make the index column have consistent width, we should insert blank spaces + // according to sh_info. + uint16_t VerdefIndexWidth = std::to_string(Shdr.sh_info).size(); + while (Buf) { + const Elf_Verdef *Verdef = reinterpret_cast(Buf); + outs() << format_decimal(VerdefIndex++, VerdefIndexWidth) << " " + << format("0x%02" PRIx16 " ", (uint16_t)Verdef->vd_flags) + << format("0x%08" PRIx32 " ", (uint32_t)Verdef->vd_hash); + + const uint8_t *BufAux = Buf + Verdef->vd_aux; + uint16_t VerdauxIndex = 0; + while (BufAux) { + const Elf_Verdaux *Verdaux = + reinterpret_cast(BufAux); + if (VerdauxIndex) + outs() << std::string(VerdefIndexWidth + 17, ' '); + outs() << StringRef(StrTab.drop_front(Verdaux->vda_name).data()) << '\n'; + BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr; + ++VerdauxIndex; + } + Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr; + } +} + +template void printSymbolVersionInfo(const ELFFile *Elf, StringRef FileName) { typedef typename ELFT::Shdr Elf_Shdr; @@ -306,7 +343,8 @@ report_error(FileName, SectionsOrError.takeError()); for (const Elf_Shdr &Shdr : *SectionsOrError) { - if (Shdr.sh_type != ELF::SHT_GNU_verneed) + if (Shdr.sh_type != ELF::SHT_GNU_verneed && + Shdr.sh_type != ELF::SHT_GNU_verdef) continue; auto ContentsOrError = Elf->getSectionContents(&Shdr); @@ -321,8 +359,11 @@ if (!StrTabOrError) report_error(FileName, StrTabOrError.takeError()); - printSymbolVersionDependency(*ContentsOrError, *StrTabOrError); - // TODO: Implement symbol version definitions dumper. + if (Shdr.sh_type == ELF::SHT_GNU_verneed) + printSymbolVersionDependency(*ContentsOrError, *StrTabOrError); + else + printSymbolVersionDefinition(Shdr, *ContentsOrError, + *StrTabOrError); } }