[AIX][XCOFF][Patch1] Provide decoding trace back table information API for xcoff object file for llvm-objdump -d

SUMMARY:

1. This patch provided API for decoding the traceback table info and unit test for the these API.

2. Another patchs will do the following things:
2.1 added a new option --traceback-table to decode the trace back table information for xcoff object file when
using llvm-objdump to disassemble the xcoff objfile.

2.2 print out the  traceback table information for llvm-objdump.

Reviewers:  Jason liu, Hubert Tong, James Henderson

Differential Revision: https://reviews.llvm.org/D81585
This commit is contained in:
diggerlin 2020-08-17 16:23:47 -04:00
parent 33490acf24
commit 2f0d755d81
5 changed files with 614 additions and 0 deletions

View File

@ -295,6 +295,61 @@ enum CFileCpuId : uint8_t {
StringRef getMappingClassString(XCOFF::StorageMappingClass SMC);
StringRef getRelocationTypeString(XCOFF::RelocationType Type);
struct TracebackTable {
// Byte 1
static constexpr uint32_t VersionMask = 0xFF00'0000;
static constexpr uint8_t VersionShift = 24;
// Byte 2
static constexpr uint32_t LanguageIdMask = 0x00FF'0000;
static constexpr uint8_t LanguageIdShift = 16;
// Byte 3
static constexpr uint32_t IsGlobaLinkageMask = 0x0000'8000;
static constexpr uint32_t IsOutOfLineEpilogOrPrologueMask = 0x0000'4000;
static constexpr uint32_t HasTraceBackTableOffsetMask = 0x0000'2000;
static constexpr uint32_t IsInternalProcedureMask = 0x0000'1000;
static constexpr uint32_t HasControlledStorageMask = 0x0000'0800;
static constexpr uint32_t IsTOClessMask = 0x0000'0400;
static constexpr uint32_t IsFloatingPointPresentMask = 0x0000'0200;
static constexpr uint32_t IsFloatingPointOperationLogOrAbortEnabledMask =
0x0000'0100;
// Byte 4
static constexpr uint32_t IsInterruptHandlerMask = 0x0000'0080;
static constexpr uint32_t IsFunctionNamePresentMask = 0x0000'0040;
static constexpr uint32_t IsAllocaUsedMask = 0x0000'0020;
static constexpr uint32_t OnConditionDirectiveMask = 0x0000'001C;
static constexpr uint32_t IsCRSavedMask = 0x0000'0002;
static constexpr uint32_t IsLRSavedMask = 0x0000'0001;
static constexpr uint8_t OnConditionDirectiveShift = 2;
// Byte 5
static constexpr uint32_t IsBackChainStoredMask = 0x8000'0000;
static constexpr uint32_t IsFixupMask = 0x4000'0000;
static constexpr uint32_t FPRSavedMask = 0x3F00'0000;
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 GPRSavedMask = 0x003F'0000;
static constexpr uint32_t GPRSavedShift = 16;
// Byte 7
static constexpr uint32_t NumberOfFixedParmsMask = 0x0000'FF00;
static constexpr uint8_t NumberOfFixedParmsShift = 8;
// Byte 8
static constexpr uint32_t NumberOfFloatingPointParmsMask = 0x0000'00FE;
static constexpr uint32_t HasParmsOnStackMask = 0x0000'0001;
static constexpr uint8_t NumberOfFloatingPointParmsShift = 1;
// Masks to select leftmost bits for decoding parameter type information.
static constexpr uint32_t ParmTypeIsFloatingBit = 0x8000'0000;
static constexpr uint32_t ParmTypeFloatingIsDoubleBit = 0x4000'0000;
};
} // end namespace XCOFF
} // end namespace llvm

View File

@ -13,6 +13,8 @@
#ifndef LLVM_OBJECT_XCOFFOBJECTFILE_H
#define LLVM_OBJECT_XCOFFOBJECTFILE_H
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/BinaryFormat/XCOFF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Endian.h"
@ -391,6 +393,83 @@ public:
bool isFunction() const;
};
/// This class provides methods to extract traceback table data from a buffer.
/// The various accessors may reference the buffer provided via the constructor.
class XCOFFTracebackTable {
const uint8_t *const TBPtr;
Optional<SmallString<32>> ParmsType;
Optional<uint32_t> TraceBackTableOffset;
Optional<uint32_t> HandlerMask;
Optional<uint32_t> NumOfCtlAnchors;
Optional<SmallVector<uint32_t, 8>> ControlledStorageInfoDisp;
Optional<StringRef> FunctionName;
Optional<uint8_t> AllocaRegister;
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
/// Error is returned.
///
/// \param[in] Ptr
/// A pointer that points just past the initial 4 bytes of zeros at the
/// beginning of an XCOFF Traceback Table.
///
/// \param[in, out] Size
/// A pointer that points to the length of the XCOFF Traceback Table.
/// If the XCOFF Traceback Table is not parsed successfully or there are
/// extra bytes that are not recognized, \a Size will be updated to be the
/// size up to the end of the last successfully parsed field of the table.
static Expected<XCOFFTracebackTable> create(const uint8_t *Ptr,
uint64_t &Size);
uint8_t getVersion() const;
uint8_t getLanguageID() const;
bool isGlobalLinkage() const;
bool isOutOfLineEpilogOrPrologue() const;
bool hasTraceBackTableOffset() const;
bool isInternalProcedure() const;
bool hasControlledStorage() const;
bool isTOCless() const;
bool isFloatingPointPresent() const;
bool isFloatingPointOperationLogOrAbortEnabled() const;
bool isInterruptHandler() const;
bool isFuncNamePresent() const;
bool isAllocaUsed() const;
uint8_t getOnConditionDirective() const;
bool isCRSaved() const;
bool isLRSaved() const;
bool isBackChainStored() const;
bool isFixup() const;
uint8_t getNumOfFPRsSaved() const;
bool hasVectorInfo() const;
bool hasExtensionTable() const;
uint8_t getNumofGPRsSaved() const;
uint8_t getNumberOfFixedParms() const;
uint8_t getNumberOfFPParms() const;
bool hasParmsOnStack() const;
const Optional<SmallString<32>> &getParmsType() const { return ParmsType; }
const Optional<uint32_t> &getTraceBackTableOffset() const {
return TraceBackTableOffset;
}
const Optional<uint32_t> &getHandlerMask() const { return HandlerMask; }
const Optional<uint32_t> &getNumOfCtlAnchors() { return NumOfCtlAnchors; }
const Optional<SmallVector<uint32_t, 8>> &getControlledStorageInfoDisp() {
return ControlledStorageInfoDisp;
}
const Optional<StringRef> &getFunctionName() const { return FunctionName; }
const Optional<uint8_t> &getAllocaRegister() const { return AllocaRegister; }
};
bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes);
} // namespace object
} // namespace llvm

View File

@ -12,10 +12,14 @@
#include "llvm/Object/XCOFFObjectFile.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/DataExtractor.h"
#include <cstddef>
#include <cstring>
namespace llvm {
using namespace XCOFF;
namespace object {
static const uint8_t FunctionSym = 0x20;
@ -834,5 +838,216 @@ bool XCOFFSymbolRef::isFunction() const {
template struct XCOFFSectionHeader<XCOFFSectionHeader32>;
template struct XCOFFSectionHeader<XCOFFSectionHeader64>;
bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes) {
if (Bytes.size() < 4)
return false;
return support::endian::read32be(Bytes.data()) == 0;
}
static SmallString<32> parseParmsType(uint32_t Value, unsigned ParmsNum) {
SmallString<32> ParmsType;
for (unsigned I = 0; I < ParmsNum; ++I) {
if (I != 0)
ParmsType += ", ";
if ((Value & TracebackTable::ParmTypeIsFloatingBit) == 0) {
// Fixed parameter type.
ParmsType += "i";
Value <<= 1;
} else {
if ((Value & TracebackTable::ParmTypeFloatingIsDoubleBit) == 0)
// Float parameter type.
ParmsType += "f";
else
// Double parameter type.
ParmsType += "d";
Value <<= 2;
}
}
return ParmsType;
}
Expected<XCOFFTracebackTable> XCOFFTracebackTable::create(const uint8_t *Ptr,
uint64_t &Size) {
Error Err = Error::success();
XCOFFTracebackTable TBT(Ptr, Size, Err);
if (Err)
return std::move(Err);
return TBT;
}
XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size,
Error &Err)
: TBPtr(Ptr) {
ErrorAsOutParameter EAO(&Err);
DataExtractor DE(ArrayRef<uint8_t>(Ptr, Size), /*IsLittleEndian=*/false,
/*AddressSize=*/0);
DataExtractor::Cursor Cur(/*Offset=*/0);
// Skip 8 bytes of mandatory fields.
DE.getU64(Cur);
// Begin to parse optional fields.
if (Cur) {
unsigned ParmNum = getNumberOfFixedParms() + getNumberOfFPParms();
// As long as there are no "fixed-point" or floating-point parameters, this
// field remains not present even when hasVectorInfo gives true and
// 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 && hasTraceBackTableOffset())
TraceBackTableOffset = DE.getU32(Cur);
if (Cur && isInterruptHandler())
HandlerMask = DE.getU32(Cur);
if (Cur && hasControlledStorage()) {
NumOfCtlAnchors = DE.getU32(Cur);
if (Cur && NumOfCtlAnchors) {
SmallVector<uint32_t, 8> Disp;
Disp.reserve(NumOfCtlAnchors.getValue());
for (uint32_t I = 0; I < NumOfCtlAnchors && Cur; ++I)
Disp.push_back(DE.getU32(Cur));
if (Cur)
ControlledStorageInfoDisp = std::move(Disp);
}
}
if (Cur && isFuncNamePresent()) {
uint16_t FunctionNameLen = DE.getU16(Cur);
if (Cur)
FunctionName = DE.getBytes(Cur, FunctionNameLen);
}
if (Cur && isAllocaUsed())
AllocaRegister = DE.getU8(Cur);
// TODO: Need to parse vector info and extension table if there is one.
if (!Cur)
Err = Cur.takeError();
Size = Cur.tell();
}
#define GETBITWITHMASK(P, X) \
(support::endian::read32be(TBPtr + (P)) & (TracebackTable::X))
#define GETBITWITHMASKSHIFT(P, X, S) \
((support::endian::read32be(TBPtr + (P)) & (TracebackTable::X)) >> \
(TracebackTable::S))
uint8_t XCOFFTracebackTable::getVersion() const {
return GETBITWITHMASKSHIFT(0, VersionMask, VersionShift);
}
uint8_t XCOFFTracebackTable::getLanguageID() const {
return GETBITWITHMASKSHIFT(0, LanguageIdMask, LanguageIdShift);
}
bool XCOFFTracebackTable::isGlobalLinkage() const {
return GETBITWITHMASK(0, IsGlobaLinkageMask);
}
bool XCOFFTracebackTable::isOutOfLineEpilogOrPrologue() const {
return GETBITWITHMASK(0, IsOutOfLineEpilogOrPrologueMask);
}
bool XCOFFTracebackTable::hasTraceBackTableOffset() const {
return GETBITWITHMASK(0, HasTraceBackTableOffsetMask);
}
bool XCOFFTracebackTable::isInternalProcedure() const {
return GETBITWITHMASK(0, IsInternalProcedureMask);
}
bool XCOFFTracebackTable::hasControlledStorage() const {
return GETBITWITHMASK(0, HasControlledStorageMask);
}
bool XCOFFTracebackTable::isTOCless() const {
return GETBITWITHMASK(0, IsTOClessMask);
}
bool XCOFFTracebackTable::isFloatingPointPresent() const {
return GETBITWITHMASK(0, IsFloatingPointPresentMask);
}
bool XCOFFTracebackTable::isFloatingPointOperationLogOrAbortEnabled() const {
return GETBITWITHMASK(0, IsFloatingPointOperationLogOrAbortEnabledMask);
}
bool XCOFFTracebackTable::isInterruptHandler() const {
return GETBITWITHMASK(0, IsInterruptHandlerMask);
}
bool XCOFFTracebackTable::isFuncNamePresent() const {
return GETBITWITHMASK(0, IsFunctionNamePresentMask);
}
bool XCOFFTracebackTable::isAllocaUsed() const {
return GETBITWITHMASK(0, IsAllocaUsedMask);
}
uint8_t XCOFFTracebackTable::getOnConditionDirective() const {
return GETBITWITHMASKSHIFT(0, OnConditionDirectiveMask,
OnConditionDirectiveShift);
}
bool XCOFFTracebackTable::isCRSaved() const {
return GETBITWITHMASK(0, IsCRSavedMask);
}
bool XCOFFTracebackTable::isLRSaved() const {
return GETBITWITHMASK(0, IsLRSavedMask);
}
bool XCOFFTracebackTable::isBackChainStored() const {
return GETBITWITHMASK(4, IsBackChainStoredMask);
}
bool XCOFFTracebackTable::isFixup() const {
return GETBITWITHMASK(4, IsFixupMask);
}
uint8_t XCOFFTracebackTable::getNumOfFPRsSaved() const {
return GETBITWITHMASKSHIFT(4, FPRSavedMask, FPRSavedShift);
}
bool XCOFFTracebackTable::hasExtensionTable() const {
return GETBITWITHMASK(4, HasExtensionTableMask);
}
bool XCOFFTracebackTable::hasVectorInfo() const {
return GETBITWITHMASK(4, HasVectorInfoMask);
}
uint8_t XCOFFTracebackTable::getNumofGPRsSaved() const {
return GETBITWITHMASKSHIFT(4, GPRSavedMask, GPRSavedShift);
}
uint8_t XCOFFTracebackTable::getNumberOfFixedParms() const {
return GETBITWITHMASKSHIFT(4, NumberOfFixedParmsMask,
NumberOfFixedParmsShift);
}
uint8_t XCOFFTracebackTable::getNumberOfFPParms() const {
return GETBITWITHMASKSHIFT(4, NumberOfFloatingPointParmsMask,
NumberOfFloatingPointParmsShift);
}
bool XCOFFTracebackTable::hasParmsOnStack() const {
return GETBITWITHMASK(4, HasParmsOnStackMask);
}
#undef GETBITWITHMASK
#undef GETBITWITHMASKSHIFT
} // namespace object
} // namespace llvm

View File

@ -12,6 +12,7 @@ add_llvm_unittest(ObjectTests
ObjectFileTest.cpp
SymbolSizeTest.cpp
SymbolicFileTest.cpp
XCOFFObjectFileTest.cpp
)
target_link_libraries(ObjectTests PRIVATE LLVMTestingSupport)

View File

@ -0,0 +1,264 @@
//===- 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/XCOFFObjectFile.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace llvm::object;
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<XCOFFTracebackTable> 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<XCOFFTracebackTable> 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<XCOFFTracebackTable> 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<XCOFFTracebackTable> 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<XCOFFTracebackTable> 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, 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};
TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIControlledStorageInfoDisp) {
uint64_t Size = 40;
Expected<XCOFFTracebackTable> 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<uint32_t, 8> Disp = TT.getControlledStorageInfoDisp().getValue();
ASSERT_EQ(Disp.size(), 2);
EXPECT_EQ(Disp[0], 0x05050000u);
EXPECT_EQ(Disp[1], 0x06060000u);
}
TEST(XCOFFObjectFileTest, XCOFFTracebackTableAPIHasVectorInfo) {
uint64_t Size = 40;
Expected<XCOFFTracebackTable> TTOrErr =
XCOFFTracebackTable::create(TBTableData, Size);
ASSERT_THAT_EXPECTED(TTOrErr, Succeeded());
XCOFFTracebackTable TT = *TTOrErr;
EXPECT_TRUE(TT.hasVectorInfo());
EXPECT_FALSE(TT.getParmsType());
}
TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtMandatory) {
uint64_t Size = 6;
Expected<XCOFFTracebackTable> 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, 0);
}
TEST(XCOFFObjectFileTest, XCOFFTracebackTableTruncatedAtParmsType) {
uint64_t Size = 9;
Expected<XCOFFTracebackTable> 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<XCOFFTracebackTable> 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<XCOFFTracebackTable> 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<XCOFFTracebackTable> 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<XCOFFTracebackTable> 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<XCOFFTracebackTable> 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<XCOFFTracebackTable> 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) {
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);
EXPECT_THAT_ERROR(
TTOrErr.takeError(),
FailedWithMessage(
"unexpected end of data at offset 0x25 while reading [0x25, 0x26)"));
EXPECT_EQ(Size, 37u);
}