From ab77fa515583ca906f2cb09a5f5e1ea3c48ec725 Mon Sep 17 00:00:00 2001 From: diggerlin Date: Thu, 19 Nov 2020 10:23:43 -0500 Subject: [PATCH] [AIX][XCOFF][Patch2] decode vector information and extent long table of the traceback table of the xcoff. SUMMARY: 1. decode the Vector extension if has_vec is set 2. decode long table fields, if longtbtable is set. There is conflict on the bit order of HasVectorInfoMask and HasExtensionTableMask between AIX os header and IBM aix compiler XLC. In the /usr/include/sys/debug.h defines static constexpr uint32_t HasVectorInfoMask = 0x0040'0000; static constexpr uint32_t HasExtensionTableMask = 0x0080'0000; but the XLC defines as static constexpr uint32_t HasVectorInfoMask = 0x0080'0000; static constexpr uint32_t HasExtensionTableMask = 0x0040'0000; we follows the definition of the IBM AIX compiler XLC here. Reviewer: Jason Liu Differential Revision: https://reviews.llvm.org/D86461 --- llvm/include/llvm/BinaryFormat/XCOFF.h | 35 ++++++- llvm/include/llvm/Object/XCOFFObjectFile.h | 22 ++++- llvm/lib/Object/XCOFFObjectFile.cpp | 114 +++++++++++++++++++++- llvm/unittests/Object/XCOFFObjectFileTest.cpp | 133 +++++++++++++++++++++++--- 4 files changed, 281 insertions(+), 23 deletions(-) diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h index 3fcac27..dc5c214 100644 --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -331,8 +331,8 @@ struct TracebackTable { 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 +346,39 @@ struct TracebackTable { 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; +}; + +// Extended Traceback table flags. +enum ExtendedTBTableFlag : uint8_t { + TB_OS1 = 0x80, ///< Reserved for OS use + TB_RESERVED = 0x40, ///< Reserved for compiler + TB_SSP_CANARY = 0x20, ///< stack smasher canary present on stack + TB_OS2 = 0x10, ///< Reserved for OS use + TB_LONGTBTABLE2 = 0x01 ///< Additional tbtable extension exists }; } // end namespace XCOFF diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h index fbc542f..b649c12 100644 --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -395,6 +395,23 @@ public: 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. @@ -407,9 +424,10 @@ class XCOFFTracebackTable { 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 @@ -469,6 +487,8 @@ public: } 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 index 23ecafd..9c4f97d 100644 --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -845,6 +845,103 @@ bool doesXCOFFTracebackTableBegin(ArrayRef Bytes) { 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 @@ XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, // 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 @@ XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, 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 index 47e200c..c4c59d9 100644 --- a/llvm/unittests/Object/XCOFFObjectFileTest.cpp +++ b/llvm/unittests/Object/XCOFFObjectFileTest.cpp @@ -13,6 +13,7 @@ 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 @@ -142,14 +143,14 @@ TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIParmsType) { 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()); @@ -165,17 +166,86 @@ TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIControlledStorageInfoDisp) { 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(), + 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.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(), + ExtendedTBTableFlag::TB_SSP_CANARY); + + EXPECT_EQ(Size, 44u); } TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtMandatory) { @@ -186,7 +256,7 @@ TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtMandatory) { 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) { @@ -269,15 +339,48 @@ TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtFunctionName) { } 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); +} -- 2.7.4