[llvm] 1cf8127 - [JITLink] Add eh-frame CFI inspector, fix crash on malformed FDEs.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 14 10:52:26 PDT 2022


Author: Lang Hames
Date: 2022-08-14T10:49:26-07:00
New Revision: 1cf81274f425164ff701e180383cdb0be6add85e

URL: https://github.com/llvm/llvm-project/commit/1cf81274f425164ff701e180383cdb0be6add85e
DIFF: https://github.com/llvm/llvm-project/commit/1cf81274f425164ff701e180383cdb0be6add85e.diff

LOG: [JITLink] Add eh-frame CFI inspector, fix crash on malformed FDEs.

Add a fix to check that FDE pc-begin targets are defined before calling
getBlock (which will crash if the target is not defined). FDE pc-begins
pointing at undefined symbols are expected to arise only in obscure
circumstances (malformed objects, or removal of targets by JITLink
passes), but we want to handle them gracefully. With this patch the
FDE will be retained, but without any keepalive edge to it. Unless
some pass takes action to mark it as live it will be dead-stripped.

To make it easier for passes to connect FDEs to their targets a new
EHFrameCFIBlockInspector utility is added. This allows clients to
quickly determine whether a CFI record is a CIE or an FDE (assuming
that it's valid), and retrieve any personality, pc-begin, cie, or
LSDA edges associated with it.

Added: 
    llvm/unittests/ExecutionEngine/JITLink/EHFrameSupportTests.cpp

Modified: 
    llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
    llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h
    llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h
    llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
    llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
    llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h b/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
index 33eee7a75f390..49e1ce7278ffe 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/EHFrameSupport.h
@@ -21,6 +21,68 @@
 namespace llvm {
 namespace jitlink {
 
+/// Inspect an eh-frame CFI record.
+class EHFrameCFIBlockInspector {
+public:
+  /// Identify CFI record type and edges based on number and order of edges
+  /// in the given block only. This assumes that the block contains one CFI
+  /// record that has already been split out and fixed by the
+  /// DWARFRecordSplitter and EHFrameEdgeFixer passes.
+  ///
+  /// Zero or one outgoing edges: Record is CIE. If present, edge points to
+  /// personality.
+  ///
+  /// Two or three outgoing edges: Record is an FDE. First edge points to CIE,
+  /// second to PC-begin, third (if present) to LSDA.
+  ///
+  /// It is illegal to call this function on a block with four or more edges.
+  static EHFrameCFIBlockInspector FromEdgeScan(Block &B);
+
+  /// Returns true if this frame is an FDE, false for a CIE.
+  bool isFDE() const { return CIEEdge != nullptr; }
+
+  /// Returns true if this frame is a CIE, false for an FDE.
+  bool isCIE() const { return CIEEdge == nullptr; }
+
+  /// If this is a CIE record, returns the Edge pointing at the personality
+  /// function, if any.
+  /// It is illegal to call this method on FDE records.
+  Edge *getPersonalityEdge() const {
+    assert(isCIE() && "CFI record is not a CIE");
+    return PersonalityEdge;
+  }
+
+  /// If this is an FDE record, returns the Edge pointing to the CIE.
+  /// If this is a CIE record, returns null.
+  ///
+  /// The result is not valid if any modification has been made to the block
+  /// after parsing.
+  Edge *getCIEEdge() const { return CIEEdge; }
+
+  /// If this is an FDE record, returns the Edge pointing at the PC-begin
+  /// symbol.
+  /// If this a CIE record, returns null.
+  Edge *getPCBeginEdge() const { return PCBeginEdge; }
+
+  /// If this is an FDE record, returns the Edge pointing at the LSDA, if any.
+  /// It is illegal to call this method on CIE records.
+  Edge *getLSDAEdge() const {
+    assert(isFDE() && "CFI record is not an FDE");
+    return LSDAEdge;
+  }
+
+private:
+  EHFrameCFIBlockInspector(Edge *PersonalityEdge);
+  EHFrameCFIBlockInspector(Edge &CIEEdge, Edge &PCBeginEdge, Edge *LSDAEdge);
+
+  Edge *CIEEdge = nullptr;
+  Edge *PCBeginEdge = nullptr;
+  union {
+    Edge *PersonalityEdge;
+    Edge *LSDAEdge;
+  };
+};
+
 /// Supports registration/deregistration of EH-frames in a target process.
 class EHFrameRegistrar {
 public:

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h b/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h
index 6f2ff012697dd..31721bf999ec1 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h
@@ -38,6 +38,14 @@ createLinkGraphFromMachOObject_arm64(MemoryBufferRef ObjectBuffer);
 void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
                       std::unique_ptr<JITLinkContext> Ctx);
 
+/// Returns a pass suitable for splitting __eh_frame sections in MachO/x86-64
+/// objects.
+LinkGraphPassFunction createEHFrameSplitterPass_MachO_arm64();
+
+/// Returns a pass suitable for fixing missing edges in an __eh_frame section
+/// in a MachO/x86-64 object.
+LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_arm64();
+
 } // end namespace jitlink
 } // end namespace llvm
 

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h b/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h
index f2c3fba7bcde9..11fbbbd579d00 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h
@@ -244,8 +244,11 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
   return Error::success();
 }
 
+/// aarch64 pointer size.
+constexpr uint64_t PointerSize = 8;
+
 /// AArch64 null pointer content.
-extern const uint8_t NullGOTEntryContent[8];
+extern const uint8_t NullGOTEntryContent[PointerSize];
 
 /// AArch64 PLT stub content.
 extern const uint8_t StubContent[8];

diff  --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
index 389fd14c0f29a..b0d79276367d7 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
@@ -85,6 +85,32 @@ Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
   return Error::success();
 }
 
+static Expected<size_t> readCFIRecordLength(const Block &B,
+                                            BinaryStreamReader &R) {
+  uint32_t Length;
+  if (auto Err = R.readInteger(Length))
+    return Err;
+
+  // If Length < 0xffffffff then use the regular length field, otherwise
+  // read the extended length field.
+  if (Length != 0xffffffff)
+    return Length;
+
+  uint64_t ExtendedLength;
+  if (auto Err = R.readInteger(ExtendedLength))
+    return Err;
+
+  if (ExtendedLength > std::numeric_limits<size_t>::max())
+    return make_error<JITLinkError>(
+        "In CFI record at " +
+        formatv("{0:x}", B.getAddress() + R.getOffset() - 12) +
+        ", extended length of " + formatv("{0:x}", ExtendedLength) +
+        " exceeds address-range max (" +
+        formatv("{0:x}", std::numeric_limits<size_t>::max()));
+
+  return ExtendedLength;
+}
+
 Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
 
   LLVM_DEBUG(dbgs() << "  Processing block at " << B.getAddress() << "\n");
@@ -125,24 +151,11 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
     });
 
     // Get the record length.
-    size_t RecordRemaining;
-    {
-      uint32_t Length;
-      if (auto Err = BlockReader.readInteger(Length))
-        return Err;
-      // If Length < 0xffffffff then use the regular length field, otherwise
-      // read the extended length field.
-      if (Length != 0xffffffff)
-        RecordRemaining = Length;
-      else {
-        uint64_t ExtendedLength;
-        if (auto Err = BlockReader.readInteger(ExtendedLength))
-          return Err;
-        RecordRemaining = ExtendedLength;
-      }
-    }
+    Expected<size_t> RecordRemaining = readCFIRecordLength(B, BlockReader);
+    if (!RecordRemaining)
+      return RecordRemaining.takeError();
 
-    if (BlockReader.bytesRemaining() < RecordRemaining)
+    if (BlockReader.bytesRemaining() < *RecordRemaining)
       return make_error<JITLinkError>(
           "Incomplete CFI record at " +
           formatv("{0:x16}", B.getAddress() + RecordStartOffset));
@@ -155,19 +168,19 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
 
     if (CIEDelta == 0) {
       if (auto Err = processCIE(PC, B, RecordStartOffset,
-                                CIEDeltaFieldOffset + RecordRemaining,
+                                CIEDeltaFieldOffset + *RecordRemaining,
                                 CIEDeltaFieldOffset, BlockEdges))
         return Err;
     } else {
       if (auto Err = processFDE(PC, B, RecordStartOffset,
-                                CIEDeltaFieldOffset + RecordRemaining,
+                                CIEDeltaFieldOffset + *RecordRemaining,
                                 CIEDeltaFieldOffset, CIEDelta, BlockEdges))
         return Err;
     }
 
     // Move to the next record.
     BlockReader.setOffset(RecordStartOffset + CIEDeltaFieldOffset +
-                          RecordRemaining);
+                          *RecordRemaining);
   }
 
   return Error::success();
@@ -358,14 +371,25 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
           PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader, B,
           RecordReader.getOffset(), "PC begin")) {
     assert(*PCBegin && "PC-begin symbol not set");
-    // Add a keep-alive edge from the FDE target to the FDE to ensure that the
-    // FDE is kept alive if its target is.
-    LLVM_DEBUG({
-      dbgs() << "        Adding keep-alive edge from target at "
-             << (*PCBegin)->getBlock().getAddress() << " to FDE at "
-             << RecordAddress << "\n";
-    });
-    (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
+    if ((*PCBegin)->isDefined()) {
+      // Add a keep-alive edge from the FDE target to the FDE to ensure that the
+      // FDE is kept alive if its target is.
+      LLVM_DEBUG({
+        dbgs() << "        Adding keep-alive edge from target at "
+               << (*PCBegin)->getBlock().getAddress() << " to FDE at "
+               << RecordAddress << "\n";
+      });
+      (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
+    } else {
+      LLVM_DEBUG({
+        dbgs() << "        WARNING: Not adding keep-alive edge to FDE at "
+               << RecordAddress << ", which points to "
+               << ((*PCBegin)->isExternal() ? "external" : "absolute")
+               << " symbol \"" << (*PCBegin)->getName()
+               << "\" -- FDE must be kept alive manually or it will be "
+               << "dead stripped.\n";
+      });
+    }
   } else
     return PCBegin.takeError();
 
@@ -639,6 +663,31 @@ Error InProcessEHFrameRegistrar::deregisterEHFrames(
                                        EHFrameSection.size());
 }
 
+EHFrameCFIBlockInspector EHFrameCFIBlockInspector::FromEdgeScan(Block &B) {
+  if (B.edges_empty())
+    return EHFrameCFIBlockInspector(nullptr);
+  if (B.edges_size() == 1)
+    return EHFrameCFIBlockInspector(&*B.edges().begin());
+  SmallVector<Edge *, 3> Es;
+  for (auto &E : B.edges())
+    Es.push_back(&E);
+  assert(Es.size() >= 2 && Es.size() <= 3 && "Unexpected number of edges");
+  llvm::sort(Es, [](const Edge *LHS, const Edge *RHS) {
+    return LHS->getOffset() < RHS->getOffset();
+  });
+  return EHFrameCFIBlockInspector(*Es[0], *Es[1],
+                                  Es.size() == 3 ? Es[2] : nullptr);
+  return EHFrameCFIBlockInspector(nullptr);
+}
+
+EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge *PersonalityEdge)
+    : PersonalityEdge(PersonalityEdge) {}
+
+EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge &CIEEdge,
+                                                   Edge &PCBeginEdge,
+                                                   Edge *LSDAEdge)
+    : CIEEdge(&CIEEdge), PCBeginEdge(&PCBeginEdge), LSDAEdge(LSDAEdge) {}
+
 LinkGraphPassFunction
 createEHFrameRecorderPass(const Triple &TT,
                           StoreFrameRangeFunction StoreRangeAddress) {

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
index 04194318498fd..d243a1ff01cd9 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
@@ -563,11 +563,8 @@ void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
     // Add eh-frame passses.
     // FIXME: Prune eh-frames for which compact-unwind is available once
     // we support compact-unwind registration with libunwind.
-    Config.PrePrunePasses.push_back(
-        DWARFRecordSectionSplitter("__TEXT,__eh_frame"));
-    Config.PrePrunePasses.push_back(EHFrameEdgeFixer(
-        "__TEXT,__eh_frame", 8, aarch64::Pointer32, aarch64::Pointer64,
-        aarch64::Delta32, aarch64::Delta64, aarch64::NegDelta32));
+    Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_arm64());
+    Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_arm64());
 
     // Add an in-place GOT/Stubs pass.
     Config.PostPrunePasses.push_back(buildTables_MachO_arm64);
@@ -580,5 +577,16 @@ void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
   MachOJITLinker_arm64::link(std::move(Ctx), std::move(G), std::move(Config));
 }
 
+LinkGraphPassFunction createEHFrameSplitterPass_MachO_arm64() {
+  return DWARFRecordSectionSplitter("__TEXT,__eh_frame");
+}
+
+LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_arm64() {
+  return EHFrameEdgeFixer("__TEXT,__eh_frame", aarch64::PointerSize,
+                          aarch64::Pointer32, aarch64::Pointer64,
+                          aarch64::Delta32, aarch64::Delta64,
+                          aarch64::NegDelta32);
+}
+
 } // end namespace jitlink
 } // end namespace llvm

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
index 3cbb3e774e9e6..8162cbf39ff34 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
+++ b/llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt
@@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_llvm_unittest(JITLinkTests
+    EHFrameSupportTests.cpp
     LinkGraphTests.cpp
   )
 

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/EHFrameSupportTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/EHFrameSupportTests.cpp
new file mode 100644
index 0000000000000..3be932aa77cd6
--- /dev/null
+++ b/llvm/unittests/ExecutionEngine/JITLink/EHFrameSupportTests.cpp
@@ -0,0 +1,246 @@
+//===----- EHFrameSupportTests.cpp - Unit tests for eh-frame support ------===//
+//
+// 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/ADT/STLExtras.h"
+#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/ExecutionEngine/JITLink/MachO_arm64.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::jitlink;
+
+// TestObjectBytes contains a MachO arm64 object file with three symbols: foo,
+// bar, and main, with corresponding FDEs. It was generated with:
+//
+// % cat foo.cpp
+// extern "C" void e();
+// extern "C" void a() {
+//   try {
+//     e();
+//   } catch (int x) {
+//   }
+// }
+// extern "C" void b() noexcept {}
+// extern "C" void c() noexcept {}
+//
+// % clang++ --target=arm64-apple-darwin -femit-dwarf-unwind=always -c -o foo.o
+// \
+//   foo.c
+// % xxd -i foo.o
+
+static const uint8_t TestObjectBytes[] = {
+    0xcf, 0xfa, 0xed, 0xfe, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00,
+    0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
+    0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x28, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+    0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0xb8, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+    0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x67, 0x63, 0x63, 0x5f, 0x65, 0x78,
+    0x63, 0x65, 0x70, 0x74, 0x5f, 0x74, 0x61, 0x62, 0x5f, 0x5f, 0x54, 0x45,
+    0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x98, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0xd8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5f, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x5f, 0x75, 0x6e,
+    0x77, 0x69, 0x6e, 0x64, 0x5f, 0x5f, 0x4c, 0x44, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xb0, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x65, 0x68,
+    0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+    0x0b, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+    0x40, 0x04, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x05, 0x00, 0x00,
+    0x88, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xff, 0x83, 0x00, 0xd1, 0xfd, 0x7b, 0x01, 0xa9, 0xfd, 0x43, 0x00, 0x91,
+    0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x14,
+    0xe8, 0x03, 0x01, 0xaa, 0xe0, 0x07, 0x00, 0xf9, 0xe8, 0x07, 0x00, 0xb9,
+    0x01, 0x00, 0x00, 0x14, 0xe8, 0x07, 0x40, 0xb9, 0x08, 0x05, 0x00, 0x71,
+    0xe8, 0x07, 0x9f, 0x1a, 0x68, 0x01, 0x00, 0x37, 0x01, 0x00, 0x00, 0x14,
+    0xe0, 0x07, 0x40, 0xf9, 0x00, 0x00, 0x00, 0x94, 0x08, 0x00, 0x40, 0xb9,
+    0xe8, 0x03, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x14,
+    0xfd, 0x7b, 0x41, 0xa9, 0xff, 0x83, 0x00, 0x91, 0xc0, 0x03, 0x5f, 0xd6,
+    0xe0, 0x07, 0x40, 0xf9, 0x00, 0x00, 0x00, 0x94, 0xc0, 0x03, 0x5f, 0xd6,
+    0xc0, 0x03, 0x5f, 0xd6, 0xff, 0x9b, 0x11, 0x01, 0x08, 0x0c, 0x04, 0x18,
+    0x01, 0x10, 0x58, 0x00, 0x00, 0x01, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x7a, 0x52, 0x00, 0x01, 0x78, 0x1e, 0x01, 0x10, 0x0c, 0x1f, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xe4, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
+    0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7a, 0x50, 0x4c,
+    0x52, 0x00, 0x01, 0x78, 0x1e, 0x07, 0x9b, 0x9d, 0xff, 0xff, 0xff, 0x10,
+    0x10, 0x0c, 0x1f, 0x00, 0x38, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+    0x8c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x68, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x08, 0x7b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0x44, 0x0e, 0x20, 0x48, 0x0c, 0x1d, 0x10, 0x9e, 0x01, 0x9d, 0x02,
+    0x0a, 0x02, 0x48, 0x0c, 0x1f, 0x20, 0x48, 0x0e, 0x00, 0xde, 0xdd, 0x44,
+    0x0b, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x2d,
+    0x4c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x2d, 0x40, 0x00, 0x00, 0x00,
+    0x0a, 0x00, 0x00, 0x2d, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x2d,
+    0x10, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x7d, 0x40, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x85, 0x00, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x1e, 0x85, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0e,
+    0x74, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1e, 0x74, 0x00, 0x00, 0x00,
+    0x05, 0x00, 0x00, 0x0e, 0x63, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x7d,
+    0x38, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1e, 0x38, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1e,
+    0x1c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0e, 0x70, 0x00, 0x00, 0x00,
+    0x0e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x54, 0x00, 0x00, 0x00, 0x0e, 0x02, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x0e, 0x02, 0x00, 0x00,
+    0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00,
+    0x0e, 0x03, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x48, 0x00, 0x00, 0x00, 0x0e, 0x04, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
+    0x0f, 0x01, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x3f, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x5a, 0x54, 0x49, 0x69, 0x00,
+    0x5f, 0x5f, 0x5f, 0x63, 0x78, 0x61, 0x5f, 0x62, 0x65, 0x67, 0x69, 0x6e,
+    0x5f, 0x63, 0x61, 0x74, 0x63, 0x68, 0x00, 0x5f, 0x5f, 0x5f, 0x63, 0x78,
+    0x61, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x63, 0x61, 0x74, 0x63, 0x68, 0x00,
+    0x5f, 0x5f, 0x55, 0x6e, 0x77, 0x69, 0x6e, 0x64, 0x5f, 0x52, 0x65, 0x73,
+    0x75, 0x6d, 0x65, 0x00, 0x5f, 0x65, 0x00, 0x5f, 0x63, 0x00, 0x5f, 0x62,
+    0x00, 0x5f, 0x61, 0x00, 0x6c, 0x74, 0x6d, 0x70, 0x33, 0x00, 0x6c, 0x74,
+    0x6d, 0x70, 0x32, 0x00, 0x6c, 0x74, 0x6d, 0x70, 0x31, 0x00, 0x5f, 0x5f,
+    0x5f, 0x67, 0x78, 0x78, 0x5f, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61,
+    0x6c, 0x69, 0x74, 0x79, 0x5f, 0x76, 0x30, 0x00, 0x6c, 0x74, 0x6d, 0x70,
+    0x30, 0x00, 0x47, 0x43, 0x43, 0x5f, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74,
+    0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x30, 0x00};
+
+llvm::MemoryBufferRef
+    TestObject(StringRef(reinterpret_cast<const char *>(TestObjectBytes),
+                         sizeof(TestObjectBytes)),
+               "foo.o");
+
+TEST(EHFrameCFIBlockInspector, BasicSuccessCase) {
+  // Create a LinkGraph from the test object above and verify that
+  // (1) There are two CIEs -- one with a personality function and one
+  //     without.
+  // (2) There are three FDEs -- two attached to the CIE with no
+  //     personality, one attached to the CIE with a personality.
+  // (3) Each FDE has an edge pointing to the CIE at the correct offset.
+  // (4) Each function has exactly one FDE pointing at it.
+
+  auto G = cantFail(createLinkGraphFromMachOObject_arm64(TestObject));
+  cantFail(createEHFrameSplitterPass_MachO_arm64()(*G));
+  cantFail(createEHFrameEdgeFixerPass_MachO_arm64()(*G));
+
+  auto *EHFrame = G->findSectionByName("__TEXT,__eh_frame");
+  assert(EHFrame && "eh-frame missing?");
+
+  SmallVector<Block *, 2> CIEs;
+  for (auto *B : EHFrame->blocks()) {
+    auto CFIBI = EHFrameCFIBlockInspector::FromEdgeScan(*B);
+    if (CFIBI.isCIE()) {
+      CIEs.push_back(B);
+      // If this CIE has an edge, check that getPersonalityEdge returns it.
+      if (B->edges_size() != 0)
+        EXPECT_TRUE(!!CFIBI.getPersonalityEdge());
+    }
+  }
+  ASSERT_EQ(CIEs.size(), 2U);
+
+  // Make sure that the CIE with no edges is CIEs[0].
+  if (CIEs[1]->edges_empty())
+    std::swap(CIEs[0], CIEs[1]);
+
+  EXPECT_TRUE(CIEs[0]->edges_empty());
+  EXPECT_EQ(CIEs[1]->edges_size(), 1U);
+
+  std::set<StringRef> Targets;
+  for (auto *B : EHFrame->blocks()) {
+    auto CFIBI = EHFrameCFIBlockInspector::FromEdgeScan(*B);
+    if (CFIBI.isFDE()) {
+      ASSERT_TRUE(!!CFIBI.getCIEEdge());
+      ASSERT_TRUE(CFIBI.getCIEEdge()->getTarget().isDefined());
+      auto &CIE = CFIBI.getCIEEdge()->getTarget().getBlock();
+      ASSERT_TRUE(&CIE == CIEs[0] || &CIE == CIEs[1]);
+
+      ASSERT_TRUE(!!CFIBI.getPCBeginEdge());
+      auto &PCBeginTarget = CFIBI.getPCBeginEdge()->getTarget();
+      ASSERT_TRUE(PCBeginTarget.hasName());
+      Targets.insert(PCBeginTarget.getName());
+
+      // If the FDE points at CIEs[0] (the CIE without a personality) then it
+      // should not have an LSDA. If it points to CIEs[1] then it should have
+      // an LSDA.
+      if (&CIE == CIEs[0])
+        EXPECT_EQ(CFIBI.getLSDAEdge(), nullptr);
+      else
+        EXPECT_NE(CFIBI.getLSDAEdge(), nullptr);
+    }
+  }
+
+  EXPECT_EQ(Targets.size(), 3U) << "Unexpected number of FDEs";
+  EXPECT_EQ(Targets.count("_a"), 1U);
+  EXPECT_EQ(Targets.count("_b"), 1U);
+  EXPECT_EQ(Targets.count("_c"), 1U);
+}
+
+TEST(EHFrameCFIBlockInspector, ExternalPCBegin) {
+  // Check that we don't crash if we transform the target of an FDE into an
+  // external symbol before running edge-fixing.
+  auto G = cantFail(createLinkGraphFromMachOObject_arm64(TestObject));
+
+  // Make '_a' external.
+  for (auto *Sym : G->defined_symbols())
+    if (Sym->hasName() && Sym->getName() == "_a") {
+      G->makeExternal(*Sym);
+      break;
+    }
+
+  // Run the splitter and edge-fixer passes.
+  cantFail(createEHFrameSplitterPass_MachO_arm64()(*G));
+  cantFail(createEHFrameEdgeFixerPass_MachO_arm64()(*G));
+}


        


More information about the llvm-commits mailing list