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 @@ -21,6 +21,8 @@ namespace XCOFF { +#define TB_SSP_CANARY 0x20 // stack smasher canary present on stack + // Constants used in the XCOFF definition. constexpr size_t FileNamePadSize = 6; @@ -331,8 +333,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; @@ -346,8 +348,30 @@ static constexpr uint8_t NumberOfFloatingPointParmsShift = 1; // Masks to select leftmost bits for decoding parameter type information. + // Bit to use when vector info is not presented. static constexpr uint32_t ParmTypeIsFloatingBit = 0x8000'0000; static constexpr uint32_t ParmTypeFloatingIsDoubleBit = 0x4000'0000; + // Bits to use when vector info is presented. + 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 { + friend class XCOFFTracebackTable; + + uint16_t Data; + uint32_t VecParmsInfo; + + TBVectorExt(StringRef &TBvectorStrRef); + +public: + uint8_t geNumberOfVRSaved() const; + bool isVRSavedOnStack() const; + bool hasVarArgs() const; + uint8_t getNumberOfVectorParms() const; + bool hasVMXInstruction() const; + SmallString<32> getVectorParmsInfoString() const; +}; + /// 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 ExtensionTable; 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 &getExtensionTable() const { return ExtensionTable; } }; 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,103 @@ return support::endian::read32be(Bytes.data()) == 0; } +TBVectorExt::TBVectorExt(StringRef &TBvectorStrRef) { + const uint8_t *Ptr = reinterpret_cast(TBvectorStrRef.data()); + Data = support::endian::read16be(Ptr); + VecParmsInfo = support::endian::read32be(Ptr + 2); +} + +#define GETVALUEWITHMASK(X) (Data & (TracebackTable::X)) +#define GETVALUEWITHMASKSHIFT(X, S) \ + ((Data & (TracebackTable::X)) >> (TracebackTable::S)) +uint8_t TBVectorExt::geNumberOfVRSaved() 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(false && "Unrecognized bits in ParmsType."); + } + 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 +994,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 +1028,14 @@ if (Cur && isAllocaUsed()) AllocaRegister = DE.getU8(Cur); - // TODO: Need to parse vector info and extension table if there is one. + if (Cur && hasVectorInfo()) { + StringRef VectorExtRef = DE.getBytes(Cur, 6); + if (Cur) + VecExt = TBVectorExt(VectorExtRef); + } + + if (Cur && hasExtensionTable()) + ExtensionTable = 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, 0x20, 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.geNumberOfVRSaved(), 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(), 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.geNumberOfVRSaved(), 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(), TB_SSP_CANARY); + + 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, 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); +}