diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -331,8 +331,8 @@ static constexpr uint32_t FPRSavedShift = 24; // Byte 6 - static constexpr uint32_t HasExtensionTableMask = 0x0080'0000; - static constexpr uint32_t HasVectorInfoMask = 0x0040'0000; + static constexpr uint32_t HasVectorInfoMask = 0x0080'0000; + static constexpr uint32_t HasExtensionTableMask = 0x0040'0000; static constexpr uint32_t GPRSavedMask = 0x003F'0000; static constexpr uint32_t GPRSavedShift = 16; @@ -348,6 +348,26 @@ // Masks to select leftmost bits for decoding parameter type information. static constexpr uint32_t ParmTypeIsFloatingBit = 0x8000'0000; static constexpr uint32_t ParmTypeFloatingIsDoubleBit = 0x4000'0000; + static constexpr uint32_t ParmTypeIsFixedBits = 0x0000'0000; + static constexpr uint32_t ParmTypeIsVectorBits = 0x4000'0000; + static constexpr uint32_t ParmTypeIsFloatingBits = 0x8000'0000; + static constexpr uint32_t ParmTypeIsDoubleBits = 0xC000'0000; + static constexpr uint32_t ParmTypeMask = 0xC000'0000; + + // Vector extension + static constexpr uint16_t NumberOfVRSavedMask = 0xFC00; + static constexpr uint16_t IsVRSavedOnStackMask = 0x0200; + static constexpr uint16_t HasVarArgsMask = 0x0100; + static constexpr uint8_t NumberOfVRSavedShift = 10; + + static constexpr uint16_t NumberOfVectorParmsMask = 0x00FE; + static constexpr uint16_t HasVMXInstructionMask = 0x0001; + static constexpr uint8_t NumberOfVectorParmsShift = 1; + + static constexpr uint32_t ParmTypeIsVectorCharBit = 0x0000'0000; + static constexpr uint32_t ParmTypeIsVectorShortBit = 0x4000'0000; + static constexpr uint32_t ParmTypeIsVectorIntBit = 0x8000'0000; + static constexpr uint32_t ParmTypeIsVectorFloatBit = 0xC000'0000; }; } // end namespace XCOFF diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -393,6 +393,23 @@ bool isFunction() const; }; +class TBVectorExt { + uint16_t Data; + uint32_t VecParmsInfo; + + TBVectorExt(uint16_t Data, uint32_t Vpi) : Data(Data), VecParmsInfo(Vpi) {} + +public: + uint8_t geNumberOfVRsSaved() const; + bool isVRSavedOnStack() const; + bool hasVarArgs() const; + uint8_t getNumberOfVectorParms() const; + bool hasVMXInstruction() const; + SmallString<32> getVectorParmsInfoString() const; + + friend class XCOFFTracebackTable; +}; + /// This class provides methods to extract traceback table data from a buffer. /// The various accessors may reference the buffer provided via the constructor. @@ -405,9 +422,10 @@ Optional> ControlledStorageInfoDisp; Optional FunctionName; Optional AllocaRegister; + Optional VecExt; + Optional ExtLongTBTable; XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, Error &Err); - public: /// Parse an XCOFF Traceback Table from \a Ptr with \a Size bytes. /// Returns an XCOFFTracebackTable upon successful parsing, otherwise an @@ -467,6 +485,8 @@ } const Optional &getFunctionName() const { return FunctionName; } const Optional &getAllocaRegister() const { return AllocaRegister; } + const Optional &getVectorExt() const { return VecExt; } + const Optional &getExtLongTBTable() const { return ExtLongTBTable; } }; bool doesXCOFFTracebackTableBegin(ArrayRef Bytes); diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -845,6 +845,98 @@ return support::endian::read32be(Bytes.data()) == 0; } +#define GETVALUEWITHMASK(X) (Data & (TracebackTable::X)) +#define GETVALUEWITHMASKSHIFT(X, S) \ + ((Data & (TracebackTable::X)) >> (TracebackTable::S)) +uint8_t TBVectorExt::geNumberOfVRsSaved() const { + return GETVALUEWITHMASKSHIFT(NumberOfVRSavedMask, NumberOfVRSavedShift); +} + +bool TBVectorExt::isVRSavedOnStack() const { + return GETVALUEWITHMASK(IsVRSavedOnStackMask); +} + +bool TBVectorExt::hasVarArgs() const { + return GETVALUEWITHMASK(HasVarArgsMask); +} +uint8_t TBVectorExt::getNumberOfVectorParms() const { + return GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask, + NumberOfVectorParmsShift); +} + +bool TBVectorExt::hasVMXInstruction() const { + return GETVALUEWITHMASK(HasVMXInstructionMask); +} +#undef GETVALUEWITHMASK +#undef GETVALUEWITHMASKSHIFT + +SmallString<32> TBVectorExt::getVectorParmsInfoString() const { + SmallString<32> ParmsType; + uint32_t Value = VecParmsInfo; + for (uint8_t I = 0; I < getNumberOfVectorParms(); ++I) { + if (I != 0) + ParmsType += ", "; + switch (Value & TracebackTable::ParmTypeMask) { + case TracebackTable::ParmTypeIsVectorCharBit: + ParmsType += "vc"; + break; + + case TracebackTable::ParmTypeIsVectorShortBit: + ParmsType += "vs"; + break; + + case TracebackTable::ParmTypeIsVectorIntBit: + ParmsType += "vi"; + break; + + case TracebackTable::ParmTypeIsVectorFloatBit: + ParmsType += "vf"; + break; + } + Value <<= 2; + } + return ParmsType; +} + +static SmallString<32> parseParmsTypeWithVecInfo(uint32_t Value, + unsigned int ParmsNum) { + SmallString<32> ParmsType; + unsigned I = 0; + bool Begin = false; + while (I < ParmsNum || Value) { + if (Begin) + ParmsType += ", "; + else + Begin = true; + + switch (Value & TracebackTable::ParmTypeMask) { + case TracebackTable::ParmTypeIsFixedBits: + ParmsType += "i"; + ++I; + break; + case TracebackTable::ParmTypeIsVectorBits: + ParmsType += "v"; + break; + case TracebackTable::ParmTypeIsFloatingBits: + ParmsType += "f"; + ++I; + break; + case TracebackTable::ParmTypeIsDoubleBits: + ParmsType += "d"; + ++I; + break; + default: + assert(true && + "Should not come here in function parseParmsTypeWithVecInfo!"); + } + Value <<= 2; + } + assert(I == ParmsNum && + "The total parameters number of fixed-point or floating-point " + "parameters not equal to the number in the parameter type!"); + return ParmsType; +} + static SmallString<32> parseParmsType(uint32_t Value, unsigned ParmsNum) { SmallString<32> ParmsType; for (unsigned I = 0; I < ParmsNum; ++I) { @@ -897,10 +989,10 @@ // indicates the presence of vector parameters. if (ParmNum > 0) { uint32_t ParamsTypeValue = DE.getU32(Cur); - // TODO: when hasVectorInfo() is true, we need to implement a new version - // of parsing parameter type for vector info. - if (Cur && !hasVectorInfo()) - ParmsType = parseParmsType(ParamsTypeValue, ParmNum); + if (Cur) + ParmsType = hasVectorInfo() + ? parseParmsTypeWithVecInfo(ParamsTypeValue, ParmNum) + : parseParmsType(ParamsTypeValue, ParmNum); } } @@ -931,7 +1023,17 @@ if (Cur && isAllocaUsed()) AllocaRegister = DE.getU8(Cur); - // TODO: Need to parse vector info and extension table if there is one. + if (Cur && hasVectorInfo()) { + uint16_t VRData = DE.getU16(Cur); + if (Cur) { + uint32_t VecParmsInfo = DE.getU32(Cur); + if (Cur) + VecExt = TBVectorExt(VRData, VecParmsInfo); + } + } + + if (Cur && hasExtensionTable()) + ExtLongTBTable = DE.getU8(Cur); if (!Cur) Err = Cur.takeError(); diff --git a/llvm/unittests/Object/XCOFFObjectFileTest.cpp b/llvm/unittests/Object/XCOFFObjectFileTest.cpp --- a/llvm/unittests/Object/XCOFFObjectFileTest.cpp +++ b/llvm/unittests/Object/XCOFFObjectFileTest.cpp @@ -123,14 +123,14 @@ EXPECT_EQ(TT3.getParmsType().getValue(), "d, i, f, f"); } -const uint8_t TBTableData[] = {0x00, 0x00, 0x2A, 0x40, 0x80, 0x40, 0x01, 0x05, - 0x58, 0x00, 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, 0x00, 0x00, 0x00}; +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, 0x00, 0x00, 0x00, 0x00}; TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIControlledStorageInfoDisp) { - uint64_t Size = 40; + uint64_t Size = sizeof(TBTableData); Expected TTOrErr = XCOFFTracebackTable::create(TBTableData, Size); ASSERT_THAT_EXPECTED(TTOrErr, Succeeded()); @@ -146,17 +146,84 @@ 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 = 40; + + 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_FALSE(TT.getParmsType()); + 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.geNumberOfVRsSaved(), 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.getExtLongTBTable()); + EXPECT_EQ(TT.getExtLongTBTable().getValue(), 0); + + 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, 0x00, 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.geNumberOfVRsSaved(), 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.getExtLongTBTable()); + EXPECT_EQ(TT.getExtLongTBTable().getValue(), 0); + + EXPECT_EQ(Size, 44u); } TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtMandatory) { @@ -167,7 +234,7 @@ TTOrErr.takeError(), FailedWithMessage( "unexpected end of data at offset 0x6 while reading [0x0, 0x8)")); - EXPECT_EQ(Size, 0UL); + EXPECT_EQ(Size, 0u); } TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtParmsType) { @@ -250,15 +317,48 @@ } TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtAllocaUsed) { - uint8_t V[] = {0x00, 0x00, 0x2A, 0x60, 0x80, 0x00, 0x01, 0x05, 0x58, 0x00, - 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}; - uint64_t Size = sizeof(V); - Expected TTOrErr = XCOFFTracebackTable::create(V, Size); + 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, 0x28)")); + 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 [0x28, 0x2c)")); + EXPECT_EQ(Size, 40u); +} + +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); +}