[llvm] 2f0d755 - [AIX][XCOFF][Patch1] Provide decoding trace back table information API for xcoff object file for llvm-objdump -d
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 17 13:24:33 PDT 2020
Author: diggerlin
Date: 2020-08-17T16:23:47-04:00
New Revision: 2f0d755d81569c0b52ddcbc4e4e3caee9f7b6d14
URL: https://github.com/llvm/llvm-project/commit/2f0d755d81569c0b52ddcbc4e4e3caee9f7b6d14
DIFF: https://github.com/llvm/llvm-project/commit/2f0d755d81569c0b52ddcbc4e4e3caee9f7b6d14.diff
LOG: [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
Added:
llvm/unittests/Object/XCOFFObjectFileTest.cpp
Modified:
llvm/include/llvm/BinaryFormat/XCOFF.h
llvm/include/llvm/Object/XCOFFObjectFile.h
llvm/lib/Object/XCOFFObjectFile.cpp
llvm/unittests/Object/CMakeLists.txt
Removed:
################################################################################
diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h
index 5a7ce80a2f62..3fcac27cfa98 100644
--- a/llvm/include/llvm/BinaryFormat/XCOFF.h
+++ b/llvm/include/llvm/BinaryFormat/XCOFF.h
@@ -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
diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h
index 9c2470736023..53caeae0bdcc 100644
--- a/llvm/include/llvm/Object/XCOFFObjectFile.h
+++ b/llvm/include/llvm/Object/XCOFFObjectFile.h
@@ -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 @@ class XCOFFSymbolRef {
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
diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp
index 533361666cf2..23ecafde2670 100644
--- a/llvm/lib/Object/XCOFFObjectFile.cpp
+++ b/llvm/lib/Object/XCOFFObjectFile.cpp
@@ -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
diff --git a/llvm/unittests/Object/CMakeLists.txt b/llvm/unittests/Object/CMakeLists.txt
index 6fee67732ae5..b263e03396fd 100644
--- a/llvm/unittests/Object/CMakeLists.txt
+++ b/llvm/unittests/Object/CMakeLists.txt
@@ -12,6 +12,7 @@ add_llvm_unittest(ObjectTests
ObjectFileTest.cpp
SymbolSizeTest.cpp
SymbolicFileTest.cpp
+ XCOFFObjectFileTest.cpp
)
target_link_libraries(ObjectTests PRIVATE LLVMTestingSupport)
diff --git a/llvm/unittests/Object/XCOFFObjectFileTest.cpp b/llvm/unittests/Object/XCOFFObjectFileTest.cpp
new file mode 100644
index 000000000000..e96f3eb62343
--- /dev/null
+++ b/llvm/unittests/Object/XCOFFObjectFileTest.cpp
@@ -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);
+}
More information about the llvm-commits
mailing list