//===- 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 returns null for it. char Buf[sizeof(typename ELF64LE::Ehdr)] = {}; memcpy(Buf, "\177ELF", 4); auto *EHdr = reinterpret_cast(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> ObjOrErr = ObjectFile::createObjectFile(Source); ASSERT_THAT_EXPECTED(ObjOrErr, Succeeded()); EXPECT_TRUE(dyn_cast((*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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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); }