diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index 3aa1d7864fcb7..57a6db6c4e5aa 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -41,10 +41,10 @@ struct VerdAux { struct VerDef { unsigned Offset; - unsigned Version; - unsigned Flags; - unsigned Ndx; - unsigned Cnt; + uint16_t Version; + uint16_t Flags; + uint16_t Ndx; + uint16_t Cnt; unsigned Hash; std::string Name; std::vector AuxV; @@ -1057,8 +1057,8 @@ ELFFile::getVersionDefinitions(const Elf_Shdr &Sec) const { VerdAux Aux; Aux.Offset = VerdauxBuf - Start; - if (Verdaux->vda_name <= StrTabOrErr->size()) - Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name)); + if (Verdaux->vda_name < StrTabOrErr->size()) + Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name).data()); else Aux.Name = ("vda_name) + ">").str(); return Aux; diff --git a/llvm/test/tools/llvm-objdump/ELF/private-headers.test b/llvm/test/tools/llvm-objdump/ELF/private-headers.test index c90cf59f4ed7d..157e2a2ea0490 100644 --- a/llvm/test/tools/llvm-objdump/ELF/private-headers.test +++ b/llvm/test/tools/llvm-objdump/ELF/private-headers.test @@ -38,6 +38,7 @@ Sections: Value: 0x0 - Name: .gnu.version_d Type: SHT_GNU_verdef + AddressAlign: 4 Entries: - Version: 1 Flags: 1 diff --git a/llvm/test/tools/llvm-objdump/ELF/verdef-invalid.test b/llvm/test/tools/llvm-objdump/ELF/verdef-invalid.test new file mode 100644 index 0000000000000..45f2331eadc34 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ELF/verdef-invalid.test @@ -0,0 +1,77 @@ +## Adapted from test/llvm-readobj/ELF/verdef-invalid.test +## Check that we report a warning when a SHT_GNU_verdef section contains a version definition +## that refers to an auxiliary entry that goes past the end of the section. + +# RUN: yaml2obj %s -o %t +# RUN: llvm-objdump -p %t 2>&1 | FileCheck %s --check-prefix=AUX-PAST-END -DFILE=%t + +# AUX-PAST-END: warning: '[[FILE]]': invalid SHT_GNU_verdef section with index 1: version definition 1 refers to an auxiliary entry that goes past the end of the section + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN +Sections: + - Name: .gnu.version_d + Type: SHT_GNU_verdef + Entries: + - Names: + - FOO + ## The correct sh_size is 28. + ShSize: 27 +DynamicSymbols: + - Name: foo + +## Check we report a warning when a version definition is not correctly aligned in memory. + +# RUN: yaml2obj %s --docnum=2 -o %t2 +# RUN: llvm-objdump -p %t2 2>&1 | FileCheck %s --check-prefix=MISALIGNED-DEF -DFILE=%t2 + +# MISALIGNED-DEF: warning: '[[FILE]]': invalid SHT_GNU_verdef section with index 1: found a misaligned version definition entry at offset 0x0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN +Sections: + - Type: Fill + Size: 0x1 + - Name: .gnu.version_d + Type: SHT_GNU_verdef + Link: .dynstr + Info: 0x1 + Entries: + - Names: + - FOO +DynamicSymbols: + - Name: foo + +## Check we report "invalid vda_name" when vda_name = size(.dynstr) + +# RUN: yaml2obj %s --docnum=3 -o %t3 +# RUN: llvm-objdump -p %t3 2>&1 | FileCheck %s --check-prefix=VDANAME-PAST-END --implicit-check-not=warning: + +# VDANAME-PAST-END: Version definitions: +# VDANAME-PAST-END-NEXT: 0 0x00 0x00000000 V0 +# VDANAME-PAST-END-NEXT: + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN +Sections: + - Name: .gnu.version_d + Type: SHT_GNU_verdef + Flags: [ SHF_ALLOC ] + Link: .dynstr + Info: 0x1 +## The byte offset to the auxiliary entry is 0x13, i.e. it is not correctly aligned in memory. + Content: "010000000000020000000000140000000000000004000000080000000700000000000000" +DynamicSymbols: + - Name: V1 + Binding: STB_GLOBAL + - Name: V0 + Binding: STB_GLOBAL diff --git a/llvm/test/tools/llvm-objdump/ELF/verdef.test b/llvm/test/tools/llvm-objdump/ELF/verdef.test index e4ae33853deb4..dbb10bf87cbea 100644 --- a/llvm/test/tools/llvm-objdump/ELF/verdef.test +++ b/llvm/test/tools/llvm-objdump/ELF/verdef.test @@ -1,12 +1,14 @@ # RUN: yaml2obj %s -o %t -# RUN: llvm-objdump -p %t | FileCheck --strict-whitespace %s +# RUN: llvm-objdump -p %t | FileCheck --match-full-lines --strict-whitespace %s -# CHECK: Dynamic Section: -# CHECK-EMPTY: -# CHECK-NEXT: Version definitions: -# CHECK-NEXT: 1 0x01 0x075bcd15 foo -# CHECK-NEXT: 2 0x02 0x3ade68b1 VERSION_1 -# CHECK-NEXT: VERSION_2 +# CHECK:Dynamic Section: +#CHECK-EMPTY: +# CHECK-NEXT:Version definitions: +# CHECK-NEXT:2 0x01 0x075bcd15 foo +# CHECK-NEXT:3 0x02 0x3ade68b1 VERSION_1 +# CHECK-NEXT: VERSION_2 +# CHECK-NEXT:4 0x00 0x0000007b VERSION_3 +# CHECK-NEXT: VERSION_4 VERSION_5 --- !ELF FileHeader: @@ -24,17 +26,25 @@ Sections: Entries: - Version: 1 Flags: 1 - VersionNdx: 1 + VersionNdx: 2 Hash: 123456789 Names: - foo - Version: 1 Flags: 2 - VersionNdx: 2 + VersionNdx: 3 Hash: 987654321 Names: - VERSION_1 - VERSION_2 + - Version: 1 + Flags: 0 + VersionNdx: 4 + Hash: 123 + Names: + - VERSION_3 + - VERSION_4 + - VERSION_5 DynamicSymbols: - Name: bar Binding: STB_GLOBAL diff --git a/llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test b/llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test index e8bd4d21f7429..e768e13f4a1ec 100644 --- a/llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test +++ b/llvm/test/tools/llvm-readobj/ELF/verdef-invalid.test @@ -128,7 +128,8 @@ Sections: Entries: - Names: - FOO - ShSize: 21 + ## The correct sh_size is 28. + ShSize: 27 DynamicSymbols: - Name: foo @@ -290,3 +291,36 @@ Sections: DynamicSymbols: - Name: foo Binding: STB_GLOBAL + +## Check we report "invalid vda_name" when vda_name = size(.dynstr) + +# RUN: yaml2obj %s --docnum=10 -o %t11 +# RUN: llvm-readobj -V %t11 2>&1 | FileCheck %s --check-prefix=VDANAME-PAST-END-LLVM -DFILE=%t11 --implicit-check-not=warning: +# RUN: llvm-readelf -V %t11 2>&1 | FileCheck %s --check-prefix=VDANAME-PAST-END-GNU -DFILE=%t11 --implicit-check-not=warning: + +# VDANAME-PAST-END-LLVM: Name: V0 +# VDANAME-PAST-END-LLVM-NEXT: Predecessors: [] + +# VDANAME-PAST-END-GNU: Version definition section '.gnu.version_d' contains 1 entries: +# VDANAME-PAST-END-GNU-NEXT: Addr: 0000000000000000 Offset: 0x000040 Link: 3 (.dynstr) +# VDANAME-PAST-END-GNU-NEXT: 0x0000: Rev: 1 Flags: none Index: 0 Cnt: 2 Name: V0 +# VDANAME-PAST-END-GNU-NEXT: 0x001c: Parent 1: + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN +Sections: + - Name: .gnu.version_d + Type: SHT_GNU_verdef + Flags: [ SHF_ALLOC ] + Link: .dynstr + Info: 0x1 +## The byte offset to the auxiliary entry is 0x13, i.e. it is not correctly aligned in memory. + Content: "010000000000020000000000140000000000000004000000080000000700000000000000" +DynamicSymbols: + - Name: V1 + Binding: STB_GLOBAL + - Name: V0 + Binding: STB_GLOBAL diff --git a/llvm/tools/llvm-objdump/ELFDump.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp index bce308c870ddf..b7899bc3bcbee 100644 --- a/llvm/tools/llvm-objdump/ELFDump.cpp +++ b/llvm/tools/llvm-objdump/ELFDump.cpp @@ -378,38 +378,6 @@ void ELFDumper::printSymbolVersionDependency( } } -template -static void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr, - ArrayRef Contents, - StringRef StrTab) { - outs() << "\nVersion 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) { - auto *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) { - auto *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 ELFDumper::printSymbolVersion() { const ELFFile &Elf = getELFFile(); StringRef FileName = Obj.getFileName(); @@ -426,10 +394,26 @@ template void ELFDumper::printSymbolVersion() { unwrapOrError(Elf.getSection(Shdr.sh_link), FileName); StringRef StrTab = unwrapOrError(Elf.getStringTable(*StrTabSec), FileName); - if (Shdr.sh_type == ELF::SHT_GNU_verneed) + if (Shdr.sh_type == ELF::SHT_GNU_verneed) { printSymbolVersionDependency(Shdr); - else - printSymbolVersionDefinition(Shdr, Contents, StrTab); + } else { + OS << "\nVersion definitions:\n"; + Expected> V = + getELFFile().getVersionDefinitions(Shdr); + if (!V) { + this->reportUniqueWarning(V.takeError()); + continue; + } + for (const VerDef &Def : *V) { + OS << Def.Ndx << ' ' << format_hex(Def.Flags, 4) << ' ' + << format_hex(Def.Hash, 10) << ' ' << Def.Name << '\n'; + if (!Def.AuxV.empty()) { + for (auto [I, Aux] : enumerate(Def.AuxV)) + OS << (I ? ' ' : '\t') << Aux.Name; + OS << '\n'; + } + } + } } } diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp index 99e0440dce78d..115f04a4df778 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -360,7 +360,7 @@ static StringRef ToolName; std::unique_ptr BIDFetcher; -Dumper::Dumper(const object::ObjectFile &O) : O(O) { +Dumper::Dumper(const object::ObjectFile &O) : O(O), OS(outs()) { WarningHandler = [this](const Twine &Msg) { if (Warnings.insert(Msg.str()).second) reportWarning(Msg, this->O.getFileName()); diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h index 7253cc3f4d91b..25d9c1e106a6c 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/llvm/tools/llvm-objdump/llvm-objdump.h @@ -77,6 +77,7 @@ class Dumper { StringSet<> Warnings; protected: + llvm::raw_ostream &OS; std::function WarningHandler; public: diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index fdae09ac767e6..e7825419ef9ec 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -7668,7 +7668,7 @@ void LLVMELFDumper::printVersionDefinitionSection(const Elf_Shdr *Sec) { W.printFlags("Flags", D.Flags, ArrayRef(SymVersionFlags)); W.printNumber("Index", D.Ndx); W.printNumber("Hash", D.Hash); - W.printString("Name", D.Name.c_str()); + W.printString("Name", D.Name); W.printList( "Predecessors", D.AuxV, [](raw_ostream &OS, const VerdAux &Aux) { OS << Aux.Name.c_str(); });