[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:
parent
33490acf24
commit
2f0d755d81
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -12,6 +12,7 @@ add_llvm_unittest(ObjectTests
|
||||
ObjectFileTest.cpp
|
||||
SymbolSizeTest.cpp
|
||||
SymbolicFileTest.cpp
|
||||
XCOFFObjectFileTest.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(ObjectTests PRIVATE LLVMTestingSupport)
|
||||
|
||||
264
llvm/unittests/Object/XCOFFObjectFileTest.cpp
Normal file
264
llvm/unittests/Object/XCOFFObjectFileTest.cpp
Normal 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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user