[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
This commit is contained in:
diggerlin 2020-11-19 10:23:43 -05:00
parent 341f3c1120
commit ab77fa5155
4 changed files with 281 additions and 23 deletions

View File

@ -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

View File

@ -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<SmallVector<uint32_t, 8>> ControlledStorageInfoDisp;
Optional<StringRef> FunctionName;
Optional<uint8_t> AllocaRegister;
Optional<TBVectorExt> VecExt;
Optional<uint8_t> 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<StringRef> &getFunctionName() const { return FunctionName; }
const Optional<uint8_t> &getAllocaRegister() const { return AllocaRegister; }
const Optional<TBVectorExt> &getVectorExt() const { return VecExt; }
const Optional<uint8_t> &getExtensionTable() const { return ExtensionTable; }
};
bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes);

View File

@ -845,6 +845,103 @@ bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes) {
return support::endian::read32be(Bytes.data()) == 0;
}
TBVectorExt::TBVectorExt(StringRef TBvectorStrRef) {
const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(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();

View File

@ -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<XCOFFTracebackTable> 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<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 = 40;
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_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<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.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<XCOFFTracebackTable> TTOrErr = XCOFFTracebackTable::create(V, Size);
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);
}