Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -20,6 +20,7 @@ #include "llvm/Object/ELFTypes.h" #include "llvm/ObjectYAML/DWARFYAML.h" #include "llvm/ObjectYAML/YAML.h" +#include "llvm/Support/MipsABIFlags.h" #include "llvm/Support/YAMLTraits.h" #include #include @@ -112,12 +113,12 @@ struct FileHeader { ELF_ELFCLASS Class; ELF_ELFDATA Data; - ELF_ELFOSABI OSABI; - llvm::yaml::Hex8 ABIVersion; + ELF_ELFOSABI OSABI{0}; + llvm::yaml::Hex8 ABIVersion{0}; ELF_ET Type; Optional Machine; - ELF_EF Flags; - llvm::yaml::Hex64 Entry; + ELF_EF Flags{0}; + llvm::yaml::Hex64 Entry{0}; Optional EPhOff; Optional EPhEntSize; @@ -134,10 +135,10 @@ struct Symbol { StringRef Name; - ELF_STT Type; + ELF_STT Type{0}; Optional Section; Optional Index; - ELF_STB Binding; + ELF_STB Binding{0}; Optional Value; Optional Size; Optional Other; @@ -160,13 +161,13 @@ llvm::yaml::Hex64 Size; llvm::yaml::Hex64 Metadata; }; - llvm::yaml::Hex64 Address; + llvm::yaml::Hex64 Address{0}; Optional NumBlocks; Optional> BBEntries; }; struct StackSizeEntry { - llvm::yaml::Hex64 Address; + llvm::yaml::Hex64 Address{0}; llvm::yaml::Hex64 Size; }; @@ -223,14 +224,14 @@ Optional Flags; Optional Address; Optional Link; - llvm::yaml::Hex64 AddressAlign; + llvm::yaml::Hex64 AddressAlign{0}; Optional EntSize; Optional Content; Optional Size; // Holds the original section index. - unsigned OriginalSecNdx; + unsigned OriginalSecNdx{0}; Section(ChunkKind Kind, bool IsImplicit = false) : Chunk(Kind, IsImplicit) {} @@ -587,8 +588,8 @@ }; struct Relocation { - llvm::yaml::Hex64 Offset; - YAMLIntUInt Addend; + llvm::yaml::Hex64 Offset{0}; + YAMLIntUInt Addend{0}; ELF_REL Type; Optional Symbol; }; @@ -657,17 +658,17 @@ // Represents .MIPS.abiflags section struct MipsABIFlags : Section { - llvm::yaml::Hex16 Version; + llvm::yaml::Hex16 Version{0}; MIPS_ISA ISALevel; - llvm::yaml::Hex8 ISARevision; - MIPS_AFL_REG GPRSize; - MIPS_AFL_REG CPR1Size; - MIPS_AFL_REG CPR2Size; - MIPS_ABI_FP FpABI; - MIPS_AFL_EXT ISAExtension; - MIPS_AFL_ASE ASEs; - MIPS_AFL_FLAGS1 Flags1; - llvm::yaml::Hex32 Flags2; + llvm::yaml::Hex8 ISARevision{0}; + MIPS_AFL_REG GPRSize{Mips::AFL_REG_NONE}; + MIPS_AFL_REG CPR1Size{Mips::AFL_REG_NONE}; + MIPS_AFL_REG CPR2Size{Mips::AFL_REG_NONE}; + MIPS_ABI_FP FpABI{Mips::Val_GNU_MIPS_ABI_FP_ANY}; + MIPS_AFL_EXT ISAExtension{Mips::AFL_EXT_NONE}; + MIPS_AFL_ASE ASEs{0}; + MIPS_AFL_FLAGS1 Flags1{0}; + llvm::yaml::Hex32 Flags2{0}; MipsABIFlags() : Section(ChunkKind::MipsABIFlags) {} @@ -678,9 +679,9 @@ struct ProgramHeader { ELF_PT Type; - ELF_PF Flags; - llvm::yaml::Hex64 VAddr; - llvm::yaml::Hex64 PAddr; + ELF_PF Flags{0}; + llvm::yaml::Hex64 VAddr{0}; + llvm::yaml::Hex64 PAddr{0}; Optional Align; Optional FileSize; Optional MemSize; Index: llvm/unittests/ObjectYAML/ELFYAMLTest.cpp =================================================================== --- llvm/unittests/ObjectYAML/ELFYAMLTest.cpp +++ llvm/unittests/ObjectYAML/ELFYAMLTest.cpp @@ -6,13 +6,16 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ObjectYAML/ELFYAML.h" #include "llvm/Object/ELF.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFTypes.h" #include "llvm/ObjectYAML/yaml2obj.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" +#include using namespace llvm; using namespace llvm::object; @@ -132,3 +135,230 @@ } } } + +TEST(ELFOutput, OptionalMembersInit) { + // Test that the optional members of ELFYAML types are initialized + // to their default values in the constructors. + ELFYAML::FileHeader FileHeader; + FileHeader.Class = ELF::ELFCLASS64; + FileHeader.Data = ELF::ELFDATA2LSB; + FileHeader.Type = ELF::ET_REL; + + ELFYAML::ProgramHeader ProgramHeader; + ProgramHeader.Type = ELF::PT_NOTE; + + ELFYAML::StackSizeEntry SSEntry; + SSEntry.Size = llvm::yaml::Hex64(0x777); + ELFYAML::StackSizesSection SSSection; + SSSection.Type = ELF::SHT_PROGBITS; + SSSection.Name = ".stack_sizes"; + SSSection.Entries.emplace( + std::initializer_list{SSEntry}); + + ELFYAML::BBAddrMapEntry BBAMEntry; + ELFYAML::BBAddrMapSection BBAMSection; + BBAMSection.Type = ELF::SHT_LLVM_BB_ADDR_MAP; + BBAMSection.Name = ".whatever"; + BBAMSection.Entries.emplace( + std::initializer_list{BBAMEntry}); + + ELFYAML::Symbol Symbol; + Symbol.Name = "__some_symbol"; + // For some reason Other is not optional. + Symbol.Other.emplace(0); + + ELFYAML::Relocation Relocation; + Relocation.Type = ELF::R_X86_64_64; + Relocation.Symbol.emplace(Symbol.Name); + + ELFYAML::RelocationSection RSection; + RSection.Type = ELF::SHT_RELA; + RSection.Name = ".rela.section"; + RSection.Relocations.emplace( + std::initializer_list{Relocation}); + + ELFYAML::Object Object; + Object.Header = FileHeader; + Object.ProgramHeaders.push_back(ProgramHeader); + + Object.Chunks.push_back( + std::make_unique(std::move(SSSection))); + Object.Chunks.push_back( + std::make_unique(std::move(BBAMSection))); + Object.Symbols.emplace(std::initializer_list{Symbol}); + Object.Chunks.push_back( + std::make_unique(std::move(RSection))); + + SmallString<0> YAMLStorage; + raw_svector_ostream YAMLOS(YAMLStorage); + { + yaml::Output YAMLOut(YAMLOS); + YAMLOut << Object; + } + + SmallString<0> ELFStorage; + Expected> ExpectedFile = + toBinary(ELFStorage, YAMLStorage); + ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded()); + const ELFObjectFile &File = *ExpectedFile; + + // Check FileHeader: + const auto &EFile = File.getELFFile(); + const auto &EHeader = EFile.getHeader(); + const auto &EIdent = EHeader.e_ident; + EXPECT_EQ(ELF::ELFCLASS64, EIdent[ELF::EI_CLASS]); + EXPECT_EQ(ELF::ELFDATA2LSB, EIdent[ELF::EI_DATA]); + EXPECT_EQ(ELF::ET_REL, EHeader.e_type); + EXPECT_EQ(0, EIdent[ELF::EI_OSABI]); + EXPECT_EQ(0, EIdent[ELF::EI_ABIVERSION]); + EXPECT_EQ(ELF::EM_NONE, EHeader.e_machine); + EXPECT_EQ(0u, EHeader.e_flags); + EXPECT_EQ(0u, EHeader.e_entry); + + // Check ProgramHeader: + Expected::Elf_Phdr_Range> ExpectedPHeaders = + EFile.program_headers(); + ASSERT_THAT_EXPECTED(ExpectedPHeaders, Succeeded()); + for (const auto &PHdr : *ExpectedPHeaders) { + EXPECT_EQ(ELF::PT_NOTE, PHdr.p_type); + EXPECT_EQ(0u, PHdr.p_flags); + EXPECT_EQ(0u, PHdr.p_vaddr); + EXPECT_EQ(0u, PHdr.p_paddr); + } + + Expected::Elf_Shdr_Range> ExpectedSHeaders = + EFile.sections(); + ASSERT_THAT_EXPECTED(ExpectedSHeaders, Succeeded()); + + bool StackSizesSectionSeen = false; + bool BBAddrMapSectionSeen = false; + + for (const auto &SHdr : *ExpectedSHeaders) { + Expected ExpectedSName = EFile.getSectionName(SHdr); + ASSERT_THAT_EXPECTED(ExpectedSName, Succeeded()); + if (*ExpectedSName == ".stack_sizes") { + // Required: + EXPECT_EQ(ELF::SHT_PROGBITS, SHdr.sh_type); + EXPECT_EQ(0u, SHdr.sh_addralign); + + Expected> ExpectedSContents = + EFile.getSectionContents(SHdr); + ASSERT_THAT_EXPECTED(ExpectedSContents, Succeeded()); + uint64_t Address = llvm::support::endian::read64le( + reinterpret_cast(ExpectedSContents->data())); + EXPECT_EQ(0u, Address); + uint64_t Size = decodeULEB128(ExpectedSContents->data() + 8); + EXPECT_EQ(0x777u, Size); + StackSizesSectionSeen = true; + } else if (*ExpectedSName == ".whatever") { + EXPECT_EQ(ELF::SHT_LLVM_BB_ADDR_MAP, SHdr.sh_type); + EXPECT_EQ(0u, SHdr.sh_addralign); + + Expected> ExpectedSContents = + EFile.getSectionContents(SHdr); + ASSERT_THAT_EXPECTED(ExpectedSContents, Succeeded()); + uint64_t Address = llvm::support::endian::read64le( + reinterpret_cast(ExpectedSContents->data())); + EXPECT_EQ(0u, Address); + BBAddrMapSectionSeen = true; + } + } + + EXPECT_EQ(true, StackSizesSectionSeen); + EXPECT_EQ(true, BBAddrMapSectionSeen); + + bool SomeSymbolSeen = false; + for (const auto &SymRef : File.symbols()) { + Expected ExpectedSName = SymRef.getName(); + ASSERT_THAT_EXPECTED(ExpectedSName, Succeeded()); + if (*ExpectedSName == "__some_symbol") { + EXPECT_EQ(ELF::STT_NOTYPE, SymRef.getELFType()); + EXPECT_EQ(ELF::STB_LOCAL, SymRef.getBinding()); + SomeSymbolSeen = true; + } + } + EXPECT_EQ(true, SomeSymbolSeen); + + bool RelaSectionSeen = false; + for (SectionRef SecRef : File.sections()) { + Expected ExpectedSName = SecRef.getName(); + ASSERT_THAT_EXPECTED(ExpectedSName, Succeeded()); + if (*ExpectedSName == ".rela.section") { + RelaSectionSeen = true; + for (ELFRelocationRef RelocRef : SecRef.relocations()) { + EXPECT_EQ(0u, RelocRef.getOffset()); + Expected ExpectedAddend = RelocRef.getAddend(); + ASSERT_THAT_EXPECTED(ExpectedAddend, Succeeded()); + EXPECT_EQ(0u, *ExpectedAddend); + EXPECT_EQ(ELF::R_X86_64_64, RelocRef.getType()); + } + } + } + + EXPECT_EQ(true, RelaSectionSeen); +} + +TEST(ELFOutput, OptionalMembersInitMips) { + // Test that the optional members of ELFYAML types are initialized + // to their default values in the constructors. + ELFYAML::FileHeader FileHeader; + FileHeader.Class = ELF::ELFCLASS64; + FileHeader.Data = ELF::ELFDATA2LSB; + FileHeader.Type = ELF::ET_REL; + FileHeader.Machine = ELF::EM_MIPS; + + ELFYAML::MipsABIFlags MipsSection; + MipsSection.Type = ELF::SHT_MIPS_ABIFLAGS; + MipsSection.Name = ".MIPS.abiflags"; + MipsSection.ISALevel = 1; // MIPS1 + + ELFYAML::Object Object; + Object.Header = FileHeader; + + Object.Chunks.push_back( + std::make_unique(std::move(MipsSection))); + + SmallString<0> YAMLStorage; + raw_svector_ostream YAMLOS(YAMLStorage); + { + yaml::Output YAMLOut(YAMLOS); + YAMLOut << Object; + } + + SmallString<0> ELFStorage; + Expected> ExpectedFile = + toBinary(ELFStorage, YAMLStorage); + ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded()); + const ELFObjectFile &File = *ExpectedFile; + + bool MipsSectionSeen = false; + for (SectionRef SecRef : File.sections()) { + Expected ExpectedSName = SecRef.getName(); + ASSERT_THAT_EXPECTED(ExpectedSName, Succeeded()); + if (*ExpectedSName == ".MIPS.abiflags") { + MipsSectionSeen = true; + Expected ExpectedContents = SecRef.getContents(); + ASSERT_THAT_EXPECTED(ExpectedContents, Succeeded()); + EXPECT_EQ(false, ExpectedContents->empty()); + // For some reason ELFEmitter writes these flags + // with the endianness of the compilation host. + const object::Elf_Mips_ABIFlags *Flags = + reinterpret_cast *>( + ExpectedContents->data()); + EXPECT_EQ(0u, Flags->version); + EXPECT_EQ(1u, Flags->isa_level); + EXPECT_EQ(0u, Flags->isa_rev); + EXPECT_EQ(0u, Flags->gpr_size); + EXPECT_EQ(0u, Flags->cpr1_size); + EXPECT_EQ(0u, Flags->cpr2_size); + EXPECT_EQ(0u, Flags->fp_abi); + EXPECT_EQ(0u, Flags->isa_ext); + EXPECT_EQ(0u, Flags->ases); + EXPECT_EQ(0u, Flags->flags1); + EXPECT_EQ(0u, Flags->flags2); + (void)Flags; + } + } + + EXPECT_EQ(true, MipsSectionSeen); +}