[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