| //===- XCOFFObjectFileTest.cpp - Tests for XCOFFObjectFile ----------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Object/ELFObjectFile.h" |
| #include "llvm/Object/XCOFFObjectFile.h" |
| #include "llvm/Testing/Support/Error.h" |
| #include "gtest/gtest.h" |
| |
| using namespace llvm; |
| using namespace llvm::object; |
| using namespace llvm::XCOFF; |
| |
| TEST(XCOFFObjectFileTest, XCOFFObjectType) { |
| // Create an arbitrary object of a non-XCOFF type and test that |
| // dyn_cast<XCOFFObjectFile> returns null for it. |
| char Buf[sizeof(typename ELF64LE::Ehdr)] = {}; |
| memcpy(Buf, "\177ELF", 4); |
| |
| auto *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(Buf); |
| EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64; |
| EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB; |
| |
| MemoryBufferRef Source(StringRef(Buf, sizeof(Buf)), "non-XCOFF"); |
| Expected<std::unique_ptr<ObjectFile>> ObjOrErr = |
| ObjectFile::createObjectFile(Source); |
| ASSERT_THAT_EXPECTED(ObjOrErr, Succeeded()); |
| |
| EXPECT_TRUE(dyn_cast<XCOFFObjectFile>((*ObjOrErr).get()) == nullptr); |
| } |
| |
| TEST(XCOFFObjectFileTest, doesXCOFFTracebackTableBegin) { |
| EXPECT_TRUE(doesXCOFFTracebackTableBegin({0, 0, 0, 0})); |
| EXPECT_TRUE(doesXCOFFTracebackTableBegin({0, 0, 0, 0, 1})); |
| EXPECT_FALSE(doesXCOFFTracebackTableBegin({0, 0, 0, 1})); |
| EXPECT_FALSE(doesXCOFFTracebackTableBegin({0, 0, 0})); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIGeneral) { |
| uint8_t V[] = {0x00, 0x00, 0x22, 0x40, 0x80, 0x00, 0x01, 0x05, 0x58, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x07, 0x61, 0x64, |
| 0x64, 0x5f, 0x61, 0x6c, 0x6c, 0x00, 0x00, 0x00}; |
| uint64_t Size = sizeof(V); |
| Expected<XCOFFTracebackTable> TTOrErr = XCOFFTracebackTable::create(V, Size); |
| ASSERT_THAT_EXPECTED(TTOrErr, Succeeded()); |
| XCOFFTracebackTable TT = *TTOrErr; |
| |
| EXPECT_EQ(TT.getVersion(), 0); |
| |
| EXPECT_EQ(TT.getLanguageID(), 0); |
| |
| EXPECT_FALSE(TT.isGlobalLinkage()); |
| EXPECT_FALSE(TT.isOutOfLineEpilogOrPrologue()); |
| EXPECT_TRUE(TT.hasTraceBackTableOffset()); |
| EXPECT_FALSE(TT.isInternalProcedure()); |
| EXPECT_FALSE(TT.hasControlledStorage()); |
| EXPECT_FALSE(TT.isTOCless()); |
| EXPECT_TRUE(TT.isFloatingPointPresent()); |
| EXPECT_FALSE(TT.isFloatingPointOperationLogOrAbortEnabled()); |
| |
| EXPECT_FALSE(TT.isInterruptHandler()); |
| EXPECT_TRUE(TT.isFuncNamePresent()); |
| EXPECT_FALSE(TT.isAllocaUsed()); |
| EXPECT_EQ(TT.getOnConditionDirective(), 0); |
| EXPECT_FALSE(TT.isCRSaved()); |
| EXPECT_FALSE(TT.isLRSaved()); |
| |
| EXPECT_TRUE(TT.isBackChainStored()); |
| EXPECT_FALSE(TT.isFixup()); |
| EXPECT_EQ(TT.getNumOfFPRsSaved(), 0); |
| |
| EXPECT_FALSE(TT.hasExtensionTable()); |
| EXPECT_FALSE(TT.hasVectorInfo()); |
| EXPECT_EQ(TT.getNumOfGPRsSaved(), 0); |
| |
| EXPECT_EQ(TT.getNumberOfFixedParms(), 1); |
| |
| EXPECT_EQ(TT.getNumberOfFPParms(), 2); |
| EXPECT_TRUE(TT.hasParmsOnStack()); |
| |
| ASSERT_TRUE(TT.getParmsType()); |
| EXPECT_EQ(TT.getParmsType().getValue(), "i, f, d"); |
| |
| ASSERT_TRUE(TT.getTraceBackTableOffset()); |
| EXPECT_EQ(TT.getTraceBackTableOffset().getValue(), 64u); |
| |
| EXPECT_FALSE(TT.getHandlerMask()); |
| |
| ASSERT_TRUE(TT.getFunctionName()); |
| EXPECT_EQ(TT.getFunctionName().getValue(), "add_all"); |
| EXPECT_EQ(TT.getFunctionName().getValue().size(), 7u); |
| |
| EXPECT_FALSE(TT.getAllocaRegister()); |
| EXPECT_EQ(Size, 25u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIParmsType) { |
| uint8_t V[] = {0x01, 0x02, 0xA2, 0x40, 0x80, 0x00, 0x02, 0x07, 0x2B, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x07, 0x61, 0x64, |
| 0x64, 0x5f, 0x61, 0x6c, 0x6c, 0x00, 0x00, 0x00}; |
| uint64_t Size = sizeof(V); |
| Expected<XCOFFTracebackTable> TTOrErr = XCOFFTracebackTable::create(V, Size); |
| |
| ASSERT_THAT_EXPECTED(TTOrErr, Succeeded()); |
| XCOFFTracebackTable TT = *TTOrErr; |
| EXPECT_EQ(TT.getVersion(), 1); |
| EXPECT_EQ(TT.getLanguageID(), 2); |
| |
| EXPECT_TRUE(TT.isGlobalLinkage()); |
| EXPECT_EQ(TT.getNumberOfFixedParms(), 2); |
| |
| EXPECT_EQ(TT.getNumberOfFPParms(), 3); |
| |
| ASSERT_TRUE(TT.getParmsType()); |
| EXPECT_EQ(TT.getParmsType().getValue(), "i, i, f, f, d"); |
| |
| V[8] = 0xAC; |
| Size = sizeof(V); |
| Expected<XCOFFTracebackTable> TTOrErr1 = XCOFFTracebackTable::create(V, Size); |
| ASSERT_THAT_EXPECTED(TTOrErr1, Succeeded()); |
| XCOFFTracebackTable TT1 = *TTOrErr1; |
| ASSERT_TRUE(TT1.getParmsType()); |
| EXPECT_EQ(TT1.getParmsType().getValue(), "f, f, d, i, i"); |
| |
| V[8] = 0xD4; |
| Size = sizeof(V); |
| Expected<XCOFFTracebackTable> TTOrErr2 = XCOFFTracebackTable::create(V, Size); |
| ASSERT_THAT_EXPECTED(TTOrErr2, Succeeded()); |
| XCOFFTracebackTable TT2 = *TTOrErr2; |
| ASSERT_TRUE(TT2.getParmsType()); |
| EXPECT_EQ(TT2.getParmsType().getValue(), "d, i, f, f, i"); |
| |
| V[6] = 0x01; |
| Size = sizeof(V); |
| Expected<XCOFFTracebackTable> TTOrErr3 = XCOFFTracebackTable::create(V, Size); |
| ASSERT_THAT_EXPECTED(TTOrErr3, Succeeded()); |
| XCOFFTracebackTable TT3 = *TTOrErr3; |
| ASSERT_TRUE(TT3.getParmsType()); |
| EXPECT_EQ(TT3.getParmsType().getValue(), "d, i, f, f"); |
| } |
| |
| const uint8_t TBTableData[] = { |
| 0x00, 0x00, 0x2A, 0x60, 0x80, 0xc0, 0x03, 0x05, 0x48, 0xc4, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x05, 0x05, 0x00, 0x00, |
| 0x06, 0x06, 0x00, 0x00, 0x00, 0x07, 0x61, 0x64, 0x64, 0x5f, 0x61, 0x6c, |
| 0x6c, 0x1f, 0x02, 0x05, 0xf0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00}; |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIControlledStorageInfoDisp) { |
| uint64_t Size = sizeof(TBTableData); |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| ASSERT_THAT_EXPECTED(TTOrErr, Succeeded()); |
| XCOFFTracebackTable TT = *TTOrErr; |
| EXPECT_TRUE(TT.hasControlledStorage()); |
| ASSERT_TRUE(TT.getNumOfCtlAnchors()); |
| EXPECT_EQ(TT.getNumOfCtlAnchors().getValue(), 2u); |
| |
| ASSERT_TRUE(TT.getControlledStorageInfoDisp()); |
| |
| SmallVector<uint32_t, 8> Disp = TT.getControlledStorageInfoDisp().getValue(); |
| |
| ASSERT_EQ(Disp.size(), 2UL); |
| EXPECT_EQ(Disp[0], 0x05050000u); |
| EXPECT_EQ(Disp[1], 0x06060000u); |
| EXPECT_EQ(Size, 45u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIAllocaRegister) { |
| uint64_t Size = sizeof(TBTableData); |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| ASSERT_THAT_EXPECTED(TTOrErr, Succeeded()); |
| XCOFFTracebackTable TT = *TTOrErr; |
| ASSERT_TRUE(TT.getAllocaRegister()); |
| EXPECT_EQ(TT.getAllocaRegister().getValue(), 31u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIHasVectorInfo) { |
| |
| uint64_t Size = sizeof(TBTableData); |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| ASSERT_THAT_EXPECTED(TTOrErr, Succeeded()); |
| XCOFFTracebackTable TT = *TTOrErr; |
| |
| EXPECT_EQ(TT.getNumberOfFixedParms(), 3); |
| EXPECT_EQ(TT.getNumberOfFPParms(), 2); |
| EXPECT_TRUE(TT.hasVectorInfo()); |
| EXPECT_TRUE(TT.hasExtensionTable()); |
| |
| ASSERT_TRUE(TT.getParmsType()); |
| EXPECT_EQ(TT.getParmsType().getValue(), "v, i, f, i, d, i, v"); |
| |
| ASSERT_TRUE(TT.getVectorExt()); |
| TBVectorExt VecExt = TT.getVectorExt().getValue(); |
| |
| EXPECT_EQ(VecExt.getNumberOfVRSaved(), 0); |
| EXPECT_TRUE(VecExt.isVRSavedOnStack()); |
| EXPECT_FALSE(VecExt.hasVarArgs()); |
| |
| EXPECT_EQ(VecExt.getNumberOfVectorParms(), 2u); |
| EXPECT_TRUE(VecExt.hasVMXInstruction()); |
| |
| EXPECT_EQ(VecExt.getVectorParmsInfoString(), "vf, vf"); |
| |
| ASSERT_TRUE(TT.getExtensionTable()); |
| EXPECT_EQ(TT.getExtensionTable().getValue(), |
| ExtendedTBTableFlag::TB_SSP_CANARY); |
| |
| EXPECT_EQ(Size, 45u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIHasVectorInfo1) { |
| const uint8_t TBTableData[] = { |
| 0x00, 0x00, 0x2A, 0x40, 0x80, 0xc0, 0x03, 0x05, 0x48, 0xc0, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x05, 0x05, 0x00, 0x00, |
| 0x06, 0x06, 0x00, 0x00, 0x00, 0x07, 0x61, 0x64, 0x64, 0x5f, 0x61, 0x6c, |
| 0x6c, 0x11, 0x07, 0x90, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00}; |
| uint64_t Size = sizeof(TBTableData); |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| ASSERT_THAT_EXPECTED(TTOrErr, Succeeded()); |
| XCOFFTracebackTable TT = *TTOrErr; |
| |
| ASSERT_TRUE(TT.getParmsType()); |
| EXPECT_EQ(TT.getParmsType().getValue(), "v, i, f, i, d, i"); |
| |
| ASSERT_TRUE(TT.getVectorExt()); |
| TBVectorExt VecExt = TT.getVectorExt().getValue(); |
| |
| EXPECT_EQ(VecExt.getNumberOfVRSaved(), 4); |
| EXPECT_FALSE(VecExt.isVRSavedOnStack()); |
| EXPECT_TRUE(VecExt.hasVarArgs()); |
| |
| EXPECT_EQ(VecExt.getNumberOfVectorParms(), 3u); |
| EXPECT_TRUE(VecExt.hasVMXInstruction()); |
| |
| EXPECT_EQ(VecExt.getVectorParmsInfoString(), "vi, vs, vc"); |
| |
| ASSERT_TRUE(TT.getExtensionTable()); |
| EXPECT_EQ(TT.getExtensionTable().getValue(), |
| ExtendedTBTableFlag::TB_SSP_CANARY); |
| |
| EXPECT_EQ(Size, 44u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtMandatory) { |
| uint64_t Size = 6; |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0x6 while reading [0x0, 0x8)")); |
| EXPECT_EQ(Size, 0u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtParmsType) { |
| uint64_t Size = 9; |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0x9 while reading [0x8, 0xc)")); |
| EXPECT_EQ(Size, 8u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtTBOffset) { |
| uint64_t Size = 14; |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0xe while reading [0xc, 0x10)")); |
| EXPECT_EQ(Size, 12u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtHandlerMask) { |
| uint8_t V[] = {0x00, 0x00, 0x22, 0xC0, 0x80, 0x00, 0x01, 0x05, 0x58, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x07}; |
| uint64_t Size = sizeof(V); |
| Expected<XCOFFTracebackTable> TTOrErr = XCOFFTracebackTable::create(V, Size); |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0x12 while reading [0x10, 0x14)")); |
| EXPECT_EQ(Size, 16u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtNumOfCtlAnchors) { |
| uint64_t Size = 19; |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0x13 while reading [0x10, 0x14)")); |
| EXPECT_EQ(Size, 16u); |
| } |
| |
| TEST(XCOFFObjectFileTest, |
| XCOFFTracebackTableTruncatedAtControlledStorageInfoDisp) { |
| uint64_t Size = 21; |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0x15 while reading [0x14, 0x18)")); |
| EXPECT_EQ(Size, 20u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtNameLen) { |
| uint64_t Size = 29; |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0x1d while reading [0x1c, 0x1e)")); |
| EXPECT_EQ(Size, 28u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtFunctionName) { |
| uint64_t Size = 36; |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0x24 while reading [0x1e, 0x25)")); |
| EXPECT_EQ(Size, 30u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtAllocaUsed) { |
| uint64_t Size = 37; |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0x25 while reading [0x25, 0x26)")); |
| EXPECT_EQ(Size, 37u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtVectorInfoData) { |
| uint64_t Size = 39; |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0x27 while reading [0x26, 0x2c)")); |
| EXPECT_EQ(Size, 38u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtVectorInfoParmsInfo) { |
| uint64_t Size = 43; |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0x2b while reading [0x26, 0x2c)")); |
| EXPECT_EQ(Size, 38u); |
| } |
| |
| TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtExtLongTBTable) { |
| uint64_t Size = 44; |
| Expected<XCOFFTracebackTable> TTOrErr = |
| XCOFFTracebackTable::create(TBTableData, Size); |
| |
| EXPECT_THAT_ERROR( |
| TTOrErr.takeError(), |
| FailedWithMessage( |
| "unexpected end of data at offset 0x2c while reading [0x2c, 0x2d)")); |
| EXPECT_EQ(Size, 44u); |
| } |