[llvm] 43acef4 - [JITLink] Refactor and expand DWARF pointer encoding support.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 15 12:51:51 PDT 2022


Author: Lang Hames
Date: 2022-04-15T12:51:46-07:00
New Revision: 43acef48d38ec0dd391f212144d4a25095e4fc5f

URL: https://github.com/llvm/llvm-project/commit/43acef48d38ec0dd391f212144d4a25095e4fc5f
DIFF: https://github.com/llvm/llvm-project/commit/43acef48d38ec0dd391f212144d4a25095e4fc5f.diff

LOG: [JITLink] Refactor and expand DWARF pointer encoding support.

Adds support for pointer encodings commonly used in large/static models,
including non-pcrel, sdata/udata8, indirect, and omit.

Also refactors pointer-encoding handling to consolidate error generation inside
common functions, rather than callees of those functions.

Added: 
    llvm/test/ExecutionEngine/JITLink/X86/ELF_ehframe_large_static_personality_encodings.s

Modified: 
    llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
    llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
    llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
    llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
    llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
    llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_ehframe.s

Removed: 
    


################################################################################
diff  --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
index cdf9277e58265..9427b93acdd5e 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
@@ -20,10 +20,12 @@ namespace llvm {
 namespace jitlink {
 
 EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName,
-                                   unsigned PointerSize, Edge::Kind Delta64,
-                                   Edge::Kind Delta32, Edge::Kind NegDelta32)
+                                   unsigned PointerSize, Edge::Kind Pointer32,
+                                   Edge::Kind Pointer64, Edge::Kind Delta32,
+                                   Edge::Kind Delta64, Edge::Kind NegDelta32)
     : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
-      Delta64(Delta64), Delta32(Delta32), NegDelta32(NegDelta32) {}
+      Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),
+      Delta64(Delta64), NegDelta32(NegDelta32) {}
 
 Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
   auto *EHFrame = G.findSectionByName(EHFrameSectionName);
@@ -84,10 +86,7 @@ Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
 
 Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
 
-  LLVM_DEBUG({
-    dbgs() << "  Processing block at " << formatv("{0:x16}", B.getAddress())
-           << "\n";
-  });
+  LLVM_DEBUG(dbgs() << "  Processing block at " << B.getAddress() << "\n");
 
   // eh-frame should not contain zero-fill blocks.
   if (B.isZeroFill())
@@ -121,7 +120,7 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
 
     LLVM_DEBUG({
       dbgs() << "    Processing CFI record at "
-             << formatv("{0:x16}", B.getAddress() + RecordStartOffset) << "\n";
+             << (B.getAddress() + RecordStartOffset) << "\n";
     });
 
     // Get the record length.
@@ -156,7 +155,7 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
     if (CIEDelta == 0) {
       if (auto Err = processCIE(PC, B, RecordStartOffset,
                                 CIEDeltaFieldOffset + RecordRemaining,
-                                CIEDeltaFieldOffset))
+                                CIEDeltaFieldOffset, BlockEdges))
         return Err;
     } else {
       if (auto Err = processFDE(PC, B, RecordStartOffset,
@@ -175,7 +174,8 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
 
 Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
                                    size_t RecordOffset, size_t RecordLength,
-                                   size_t CIEDeltaFieldOffset) {
+                                   size_t CIEDeltaFieldOffset,
+                                   const BlockEdgeMap &BlockEdges) {
 
   LLVM_DEBUG(dbgs() << "      Record is CIE\n");
 
@@ -234,66 +234,59 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
   if (auto Err = RecordReader.skip(1))
     return Err;
 
-  uint64_t AugmentationDataLength = 0;
-  if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
-    return Err;
+  if (AugInfo->AugmentationDataPresent) {
 
-  uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
+    CIEInfo.AugmentationDataPresent = true;
 
-  uint8_t *NextField = &AugInfo->Fields[0];
-  while (uint8_t Field = *NextField++) {
-    switch (Field) {
-    case 'L': {
-      CIEInfo.FDEsHaveLSDAField = true;
-      uint8_t LSDAPointerEncoding;
-      if (auto Err = RecordReader.readInteger(LSDAPointerEncoding))
-        return Err;
-      if (!isSupportedPointerEncoding(LSDAPointerEncoding))
-        return make_error<JITLinkError>(
-            "Unsupported LSDA pointer encoding " +
-            formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " +
-            formatv("{0:x16}", CIESymbol.getAddress()));
-      CIEInfo.LSDAPointerEncoding = LSDAPointerEncoding;
-      break;
-    }
-    case 'P': {
-      uint8_t PersonalityPointerEncoding = 0;
-      if (auto Err = RecordReader.readInteger(PersonalityPointerEncoding))
-        return Err;
-      if (PersonalityPointerEncoding !=
-          (dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
-           dwarf::DW_EH_PE_sdata4))
-        return make_error<JITLinkError>(
-            "Unspported personality pointer "
-            "encoding " +
-            formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " +
-            formatv("{0:x16}", CIESymbol.getAddress()));
-      uint32_t PersonalityPointerAddress;
-      if (auto Err = RecordReader.readInteger(PersonalityPointerAddress))
-        return Err;
-      break;
-    }
-    case 'R': {
-      uint8_t FDEPointerEncoding;
-      if (auto Err = RecordReader.readInteger(FDEPointerEncoding))
-        return Err;
-      if (!isSupportedPointerEncoding(FDEPointerEncoding))
-        return make_error<JITLinkError>(
-            "Unsupported FDE pointer encoding " +
-            formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " +
-            formatv("{0:x16}", CIESymbol.getAddress()));
-      CIEInfo.FDEPointerEncoding = FDEPointerEncoding;
-      break;
-    }
-    default:
-      llvm_unreachable("Invalid augmentation string field");
+    uint64_t AugmentationDataLength = 0;
+    if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
+      return Err;
+
+    uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
+
+    uint8_t *NextField = &AugInfo->Fields[0];
+    while (uint8_t Field = *NextField++) {
+      switch (Field) {
+      case 'L':
+        CIEInfo.LSDAPresent = true;
+        if (auto PE = readPointerEncoding(RecordReader, B, "LSDA"))
+          CIEInfo.LSDAEncoding = *PE;
+        else
+          return PE.takeError();
+        break;
+      case 'P': {
+        auto PersonalityPointerEncoding =
+            readPointerEncoding(RecordReader, B, "personality");
+        if (!PersonalityPointerEncoding)
+          return PersonalityPointerEncoding.takeError();
+        if (auto Err =
+                getOrCreateEncodedPointerEdge(
+                    PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,
+                    B, RecordOffset + RecordReader.getOffset(), "personality")
+                    .takeError())
+          return Err;
+        break;
+      }
+      case 'R':
+        if (auto PE = readPointerEncoding(RecordReader, B, "address")) {
+          CIEInfo.AddressEncoding = *PE;
+          if (CIEInfo.AddressEncoding == dwarf::DW_EH_PE_omit)
+            return make_error<JITLinkError>(
+                "Invalid address encoding DW_EH_PE_omit in CIE at " +
+                formatv("{0:x}", (B.getAddress() + RecordOffset).getValue()));
+        } else
+          return PE.takeError();
+        break;
+      default:
+        llvm_unreachable("Invalid augmentation string field");
+      }
     }
-  }
 
-  if (RecordReader.getOffset() - AugmentationDataStartOffset >
-      AugmentationDataLength)
-    return make_error<JITLinkError>("Read past the end of the augmentation "
-                                    "data while parsing fields");
+    if (RecordReader.getOffset() - AugmentationDataStartOffset >
+        AugmentationDataLength)
+      return make_error<JITLinkError>("Read past the end of the augmentation "
+                                      "data while parsing fields");
+  }
 
   assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
          "Multiple CIEs recorded at the same address?");
@@ -306,7 +299,7 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
                                    size_t RecordOffset, size_t RecordLength,
                                    size_t CIEDeltaFieldOffset,
                                    uint32_t CIEDelta,
-                                   BlockEdgeMap &BlockEdges) {
+                                   const BlockEdgeMap &BlockEdges) {
   LLVM_DEBUG(dbgs() << "      Record is FDE\n");
 
   orc::ExecutorAddr RecordAddress = B.getAddress() + RecordOffset;
@@ -334,8 +327,8 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
 
       LLVM_DEBUG({
         dbgs() << "        Adding edge at "
-               << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
-               << " to CIE at: " << formatv("{0:x16}", CIEAddress) << "\n";
+               << (RecordAddress + CIEDeltaFieldOffset)
+               << " to CIE at: " << CIEAddress << "\n";
       });
       if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
         CIEInfo = *CIEInfoOrErr;
@@ -347,8 +340,8 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
     } else {
       LLVM_DEBUG({
         dbgs() << "        Already has edge at "
-               << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
-               << " to CIE at " << formatv("{0:x16}", CIEAddress) << "\n";
+               << (RecordAddress + CIEDeltaFieldOffset) << " to CIE at "
+               << CIEAddress << "\n";
       });
       auto &EI = CIEEdgeItr->second;
       if (EI.Addend)
@@ -363,107 +356,41 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
     }
   }
 
-  {
-    // Process the PC-Begin field.
-    Block *PCBeginBlock = nullptr;
-    orc::ExecutorAddrDiff PCBeginFieldOffset = RecordReader.getOffset();
-    auto PCEdgeItr = BlockEdges.find(RecordOffset + PCBeginFieldOffset);
-    if (PCEdgeItr == BlockEdges.end()) {
-      auto PCBeginPtrInfo =
-          readEncodedPointer(CIEInfo->FDEPointerEncoding,
-                             RecordAddress + PCBeginFieldOffset, RecordReader);
-      if (!PCBeginPtrInfo)
-        return PCBeginPtrInfo.takeError();
-      orc::ExecutorAddr PCBegin = PCBeginPtrInfo->first;
-      Edge::Kind PCBeginEdgeKind = PCBeginPtrInfo->second;
-      LLVM_DEBUG({
-        dbgs() << "        Adding edge at "
-               << (RecordAddress + PCBeginFieldOffset) << " to PC at "
-               << formatv("{0:x16}", PCBegin) << "\n";
-      });
-      auto PCBeginSym = getOrCreateSymbol(PC, PCBegin);
-      if (!PCBeginSym)
-        return PCBeginSym.takeError();
-      B.addEdge(PCBeginEdgeKind, RecordOffset + PCBeginFieldOffset, *PCBeginSym,
-                0);
-      PCBeginBlock = &PCBeginSym->getBlock();
-    } else {
-      auto &EI = PCEdgeItr->second;
-      LLVM_DEBUG({
-        dbgs() << "        Already has edge at "
-               << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset)
-               << " to PC at " << formatv("{0:x16}", EI.Target->getAddress());
-        if (EI.Addend)
-          dbgs() << " + " << formatv("{0:x16}", EI.Addend);
-        dbgs() << "\n";
-      });
-
-      // Make sure the existing edge points at a defined block.
-      if (!EI.Target->isDefined()) {
-        auto EdgeAddr = RecordAddress + PCBeginFieldOffset;
-        return make_error<JITLinkError>("FDE edge at " +
-                                        formatv("{0:x16}", EdgeAddr) +
-                                        " points at external block");
-      }
-      PCBeginBlock = &EI.Target->getBlock();
-      if (auto Err = RecordReader.skip(
-              getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
-        return Err;
-    }
-
+  // Process the PC-Begin field.
+  LLVM_DEBUG({
+    dbgs() << "        Processing PC-begin at "
+           << (RecordAddress + RecordReader.getOffset()) << "\n";
+  });
+  if (auto PCBegin = getOrCreateEncodedPointerEdge(
+          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.
-    assert(PCBeginBlock && "PC-begin block not recorded");
     LLVM_DEBUG({
       dbgs() << "        Adding keep-alive edge from target at "
-             << formatv("{0:x16}", PCBeginBlock->getAddress()) << " to FDE at "
-             << formatv("{0:x16}", RecordAddress) << "\n";
+             << (*PCBegin)->getBlock().getAddress() << " to FDE at "
+             << RecordAddress << "\n";
     });
-    PCBeginBlock->addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
-  }
+    (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
+  } else
+    return PCBegin.takeError();
 
   // Skip over the PC range size field.
-  if (auto Err = RecordReader.skip(
-          getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
+  if (auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))
     return Err;
 
-  if (CIEInfo->FDEsHaveLSDAField) {
+  if (CIEInfo->AugmentationDataPresent) {
     uint64_t AugmentationDataSize;
     if (auto Err = RecordReader.readULEB128(AugmentationDataSize))
       return Err;
 
-    orc::ExecutorAddrDiff LSDAFieldOffset = RecordReader.getOffset();
-    auto LSDAEdgeItr = BlockEdges.find(RecordOffset + LSDAFieldOffset);
-    if (LSDAEdgeItr == BlockEdges.end()) {
-      auto LSDAPointerInfo =
-          readEncodedPointer(CIEInfo->LSDAPointerEncoding,
-                             RecordAddress + LSDAFieldOffset, RecordReader);
-      if (!LSDAPointerInfo)
-        return LSDAPointerInfo.takeError();
-      orc::ExecutorAddr LSDA = LSDAPointerInfo->first;
-      Edge::Kind LSDAEdgeKind = LSDAPointerInfo->second;
-      auto LSDASym = getOrCreateSymbol(PC, LSDA);
-      if (!LSDASym)
-        return LSDASym.takeError();
-      LLVM_DEBUG({
-        dbgs() << "        Adding edge at "
-               << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
-               << " to LSDA at " << formatv("{0:x16}", LSDA) << "\n";
-      });
-      B.addEdge(LSDAEdgeKind, RecordOffset + LSDAFieldOffset, *LSDASym, 0);
-    } else {
-      LLVM_DEBUG({
-        auto &EI = LSDAEdgeItr->second;
-        dbgs() << "        Already has edge at "
-               << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
-               << " to LSDA at " << formatv("{0:x16}", EI.Target->getAddress());
-        if (EI.Addend)
-          dbgs() << " + " << formatv("{0:x16}", EI.Addend);
-        dbgs() << "\n";
-      });
-      if (auto Err = RecordReader.skip(AugmentationDataSize))
+    if (CIEInfo->LSDAPresent)
+      if (auto Err = getOrCreateEncodedPointerEdge(
+                         PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader, B,
+                         RecordReader.getOffset(), "LSDA")
+                         .takeError())
         return Err;
-    }
   } else {
     LLVM_DEBUG(dbgs() << "        Record does not have LSDA field.\n");
   }
@@ -512,108 +439,155 @@ EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
   return std::move(AugInfo);
 }
 
-bool EHFrameEdgeFixer::isSupportedPointerEncoding(uint8_t PointerEncoding) {
+Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,
+                                                        Block &InBlock,
+                                                        const char *FieldName) {
   using namespace dwarf;
 
-  // We only support PC-rel for now.
-  if ((PointerEncoding & 0x70) != DW_EH_PE_pcrel)
-    return false;
-
-  // readEncodedPointer does not handle indirect.
-  if (PointerEncoding & DW_EH_PE_indirect)
-    return false;
+  uint8_t PointerEncoding;
+  if (auto Err = R.readInteger(PointerEncoding))
+    return Err;
 
-  // Supported datatypes.
+  bool Supported = true;
   switch (PointerEncoding & 0xf) {
-  case DW_EH_PE_absptr:
-  case DW_EH_PE_udata4:
-  case DW_EH_PE_udata8:
-  case DW_EH_PE_sdata4:
-  case DW_EH_PE_sdata8:
-    return true;
+  case DW_EH_PE_uleb128:
+  case DW_EH_PE_udata2:
+  case DW_EH_PE_sleb128:
+  case DW_EH_PE_sdata2:
+    Supported = false;
+    break;
+  }
+  if (Supported) {
+    switch (PointerEncoding & 0x70) {
+    case DW_EH_PE_textrel:
+    case DW_EH_PE_datarel:
+    case DW_EH_PE_funcrel:
+    case DW_EH_PE_aligned:
+      Supported = false;
+      break;
+    }
   }
 
-  return false;
+  if (Supported)
+    return PointerEncoding;
+
+  return make_error<JITLinkError>("Unsupported pointer encoding " +
+                                  formatv("{0:x2}", PointerEncoding) + " for " +
+                                  FieldName + "in CFI record at " +
+                                  formatv("{0:x16}", InBlock.getAddress()));
 }
 
-unsigned EHFrameEdgeFixer::getPointerEncodingDataSize(uint8_t PointerEncoding) {
+Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,
+                                           BinaryStreamReader &RecordReader) {
   using namespace dwarf;
 
-  assert(isSupportedPointerEncoding(PointerEncoding) &&
-         "Unsupported pointer encoding");
+  // Switch absptr to corresponding udata encoding.
+  if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
+    PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
+
   switch (PointerEncoding & 0xf) {
-  case DW_EH_PE_absptr:
-    return PointerSize;
   case DW_EH_PE_udata4:
   case DW_EH_PE_sdata4:
-    return 4;
+    if (auto Err = RecordReader.skip(4))
+      return Err;
+    break;
   case DW_EH_PE_udata8:
   case DW_EH_PE_sdata8:
-    return 8;
+    if (auto Err = RecordReader.skip(8))
+      return Err;
+    break;
   default:
-    llvm_unreachable("Unsupported encoding");
+    llvm_unreachable("Unrecognized encoding");
   }
+  return Error::success();
 }
 
-Expected<std::pair<orc::ExecutorAddr, Edge::Kind>>
-EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding,
-                                     orc::ExecutorAddr PointerFieldAddress,
-                                     BinaryStreamReader &RecordReader) {
-  assert(isSupportedPointerEncoding(PointerEncoding) &&
-         "Unsupported pointer encoding");
-
+Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
+    ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding,
+    BinaryStreamReader &RecordReader, Block &BlockToFix,
+    size_t PointerFieldOffset, const char *FieldName) {
   using namespace dwarf;
 
-  // Isolate data type, remap absptr to udata4 or udata8. This relies on us
-  // having verified that the graph uses 32-bit or 64-bit pointers only at the
-  // start of this pass.
-  uint8_t EffectiveType = PointerEncoding & 0xf;
-  if (EffectiveType == DW_EH_PE_absptr)
-    EffectiveType = (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
+  if (PointerEncoding == DW_EH_PE_omit)
+    return nullptr;
 
-  orc::ExecutorAddr Addr;
-  Edge::Kind PointerEdgeKind = Edge::Invalid;
-  switch (EffectiveType) {
+  // If there's already an edge here then just skip the encoded pointer and
+  // return the edge's target.
+  {
+    auto EdgeI = BlockEdges.find(PointerFieldOffset);
+    if (EdgeI != BlockEdges.end()) {
+      LLVM_DEBUG({
+        dbgs() << "        Existing edge at "
+               << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
+               << FieldName << " at " << EdgeI->second.Target->getAddress();
+        if (EdgeI->second.Target->hasName())
+          dbgs() << " (" << EdgeI->second.Target->getName() << ")";
+        dbgs() << "\n";
+      });
+      if (auto Err = skipEncodedPointer(PointerEncoding, RecordReader))
+        return Err;
+      return EdgeI->second.Target;
+    }
+  }
+
+  // Switch absptr to corresponding udata encoding.
+  if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
+    PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
+
+  // We need to create an edge. Start by reading the field value.
+  uint64_t FieldValue;
+  bool Is64Bit = false;
+  switch (PointerEncoding & 0xf) {
   case DW_EH_PE_udata4: {
     uint32_t Val;
     if (auto Err = RecordReader.readInteger(Val))
       return std::move(Err);
-    Addr = PointerFieldAddress + Val;
-    PointerEdgeKind = Delta32;
-    break;
-  }
-  case DW_EH_PE_udata8: {
-    uint64_t Val;
-    if (auto Err = RecordReader.readInteger(Val))
-      return std::move(Err);
-    Addr = PointerFieldAddress + Val;
-    PointerEdgeKind = Delta64;
+    FieldValue = Val;
     break;
   }
   case DW_EH_PE_sdata4: {
-    int32_t Val;
+    uint32_t Val;
     if (auto Err = RecordReader.readInteger(Val))
       return std::move(Err);
-    Addr = PointerFieldAddress + Val;
-    PointerEdgeKind = Delta32;
+    FieldValue = Val;
     break;
   }
-  case DW_EH_PE_sdata8: {
-    int64_t Val;
-    if (auto Err = RecordReader.readInteger(Val))
+  case DW_EH_PE_udata8:
+  case DW_EH_PE_sdata8:
+    Is64Bit = true;
+    if (auto Err = RecordReader.readInteger(FieldValue))
       return std::move(Err);
-    Addr = PointerFieldAddress + Val;
-    PointerEdgeKind = Delta64;
     break;
-  }
+  default:
+    llvm_unreachable("Unsupported encoding");
   }
 
-  if (PointerEdgeKind == Edge::Invalid)
-    return make_error<JITLinkError>(
-        "Unspported edge kind for encoded pointer at " +
-        formatv("{0:x}", PointerFieldAddress));
+  // Find the edge target and edge kind to use.
+  orc::ExecutorAddr Target;
+  Edge::Kind PtrEdgeKind = Edge::Invalid;
+  if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) {
+    Target = BlockToFix.getAddress() + PointerFieldOffset;
+    PtrEdgeKind = Is64Bit ? Delta64 : Delta32;
+  } else
+    PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;
+  Target += FieldValue;
+
+  // Find or create a symbol to point the edge at.
+  auto TargetSym = getOrCreateSymbol(PC, Target);
+  if (!TargetSym)
+    return TargetSym.takeError();
+  BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);
+
+  LLVM_DEBUG({
+    dbgs() << "        Adding edge at "
+           << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
+           << FieldName << " at " << TargetSym->getAddress();
+    if (TargetSym->hasName())
+      dbgs() << " (" << TargetSym->getName() << ")";
+    dbgs() << "\n";
+  });
 
-  return std::make_pair(Addr, Delta64);
+  return &*TargetSym;
 }
 
 Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,

diff  --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
index 66e1e8eccf0c3..55cf7fc63ee79 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
@@ -25,8 +25,12 @@ namespace jitlink {
 /// edges.
 class EHFrameEdgeFixer {
 public:
+  /// Create an eh-frame edge fixer.
+  /// If a given edge-kind is not supported on the target architecture then
+  /// Edge::Invalid should be used.
   EHFrameEdgeFixer(StringRef EHFrameSectionName, unsigned PointerSize,
-                   Edge::Kind Delta64, Edge::Kind Delta32,
+                   Edge::Kind Pointer32, Edge::Kind Pointer64,
+                   Edge::Kind Delta32, Edge::Kind Delta64,
                    Edge::Kind NegDelta32);
   Error operator()(LinkGraph &G);
 
@@ -42,9 +46,10 @@ class EHFrameEdgeFixer {
     CIEInformation() = default;
     CIEInformation(Symbol &CIESymbol) : CIESymbol(&CIESymbol) {}
     Symbol *CIESymbol = nullptr;
-    bool FDEsHaveLSDAField = false;
-    uint8_t FDEPointerEncoding = 0;
-    uint8_t LSDAPointerEncoding = 0;
+    bool AugmentationDataPresent = false;
+    bool LSDAPresent = false;
+    uint8_t LSDAEncoding = 0;
+    uint8_t AddressEncoding = 0;
   };
 
   struct EdgeTarget {
@@ -77,28 +82,33 @@ class EHFrameEdgeFixer {
 
   Error processBlock(ParseContext &PC, Block &B);
   Error processCIE(ParseContext &PC, Block &B, size_t RecordOffset,
-                   size_t RecordLength, size_t CIEDeltaFieldOffset);
+                   size_t RecordLength, size_t CIEDeltaFieldOffset,
+                   const BlockEdgeMap &BlockEdges);
   Error processFDE(ParseContext &PC, Block &B, size_t RecordOffset,
                    size_t RecordLength, size_t CIEDeltaFieldOffset,
-                   uint32_t CIEDelta, BlockEdgeMap &BlockEdges);
+                   uint32_t CIEDelta, const BlockEdgeMap &BlockEdges);
 
   Expected<AugmentationInfo>
   parseAugmentationString(BinaryStreamReader &RecordReader);
 
-  static bool isSupportedPointerEncoding(uint8_t PointerEncoding);
-  unsigned getPointerEncodingDataSize(uint8_t PointerEncoding);
-  Expected<std::pair<orc::ExecutorAddr, Edge::Kind>>
-  readEncodedPointer(uint8_t PointerEncoding,
-                     orc::ExecutorAddr PointerFieldAddress,
-                     BinaryStreamReader &RecordReader);
+  Expected<uint8_t> readPointerEncoding(BinaryStreamReader &RecordReader,
+                                        Block &InBlock, const char *FieldName);
+  Error skipEncodedPointer(uint8_t PointerEncoding,
+                           BinaryStreamReader &RecordReader);
+  Expected<Symbol *> getOrCreateEncodedPointerEdge(
+      ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding,
+      BinaryStreamReader &RecordReader, Block &BlockToFix,
+      size_t PointerFieldOffset, const char *FieldName);
 
   Expected<Symbol &> getOrCreateSymbol(ParseContext &PC,
                                        orc::ExecutorAddr Addr);
 
   StringRef EHFrameSectionName;
   unsigned PointerSize;
-  Edge::Kind Delta64;
+  Edge::Kind Pointer32;
+  Edge::Kind Pointer64;
   Edge::Kind Delta32;
+  Edge::Kind Delta64;
   Edge::Kind NegDelta32;
 };
 

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
index 7648ad6e9730c..ca9a2964ff146 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
@@ -381,9 +381,9 @@ void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
   if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
 
     Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
-    Config.PrePrunePasses.push_back(
-        EHFrameEdgeFixer(".eh_frame", x86_64::PointerSize, x86_64::Delta64,
-                         x86_64::Delta32, x86_64::NegDelta32));
+    Config.PrePrunePasses.push_back(EHFrameEdgeFixer(
+        ".eh_frame", x86_64::PointerSize, x86_64::Pointer32, x86_64::Pointer64,
+        x86_64::Delta32, x86_64::Delta64, x86_64::NegDelta32));
     Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
 
     // Construct a JITLinker and run the link function.

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
index d3db3d1e5d151..873c820e5be49 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
@@ -716,7 +716,8 @@ void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
     Config.PrePrunePasses.push_back(
         DWARFRecordSectionSplitter("__TEXT,__eh_frame"));
     Config.PrePrunePasses.push_back(
-        EHFrameEdgeFixer("__TEXT,__eh_frame", 8, Delta64, Delta32, NegDelta32));
+        EHFrameEdgeFixer("__TEXT,__eh_frame", 8, Pointer32, Pointer64, Delta32,
+                         Delta64, NegDelta32));
 
     // Add an in-place GOT/Stubs pass.
     Config.PostPrunePasses.push_back(

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
index 21b815856598f..2f61b31ae3832 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
@@ -510,7 +510,8 @@ LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
 
 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() {
   return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize,
-                          x86_64::Delta64, x86_64::Delta32, x86_64::NegDelta32);
+                          x86_64::Pointer32, x86_64::Pointer64, x86_64::Delta32,
+                          x86_64::Delta64, x86_64::NegDelta32);
 }
 
 } // end namespace jitlink

diff  --git a/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_ehframe.s b/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_ehframe.s
index 425f981c48471..6ae5973fb8230 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_ehframe.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_ehframe.s
@@ -19,9 +19,9 @@
 # CHECK:     Processing CFI record at
 # CHECK:       Record is FDE
 # CHECK:         Adding edge at {{.*}} to CIE at: {{.*}}
-# CHECK:         Already has edge at {{.*}} to PC at {{.*}}
+# CHECK:         Existing edge at {{.*}} to PC begin at {{.*}}
 # CHECK:         Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
-# CHECK:         Already has edge at {{.*}} to LSDA at {{.*}}
+# CHECK:         Existing edge at {{.*}} to LSDA at {{.*}}
 
 	.section	__TEXT,__text,regular,pure_instructions
  	.globl	_main

diff  --git a/llvm/test/ExecutionEngine/JITLink/X86/ELF_ehframe_large_static_personality_encodings.s b/llvm/test/ExecutionEngine/JITLink/X86/ELF_ehframe_large_static_personality_encodings.s
new file mode 100644
index 0000000000000..83e46f8a12d42
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/X86/ELF_ehframe_large_static_personality_encodings.s
@@ -0,0 +1,203 @@
+# REQUIRES: asserts
+# UNSUPPORTED: system-windows
+# RUN: llvm-mc -triple=x86_64-pc-linux-gnu -large-code-model \
+# RUN:   -filetype=obj -o %t %s
+# RUN: llvm-jitlink -debug-only=jitlink -noexec %t 2>&1 | FileCheck %s
+#
+# Check handling of pointer encodings for personality functions when compiling
+# with `-mcmodel=large -static`.
+#
+
+# CHECK: Record is CIE
+# CHECK-NEXT: edge at {{.*}} to personality at {{.*}} (DW.ref.__gxx_personality_v0)
+# CHECK: Record is CIE
+# CHECK-NEXT: edge at {{.*}} to personality at {{.*}} (__gxx_personality_v0)
+
+        .text
+        .file   "eh.cpp"
+
+        .globl main
+        .p2align        4, 0x90
+        .type   main, at function
+main:
+        xorl    %eax, %eax
+        retq
+.Lfunc_end_main:
+        .size   main, .Lfunc_end_main-main
+
+# pe_absptr uses absptr encoding for __gxx_personality_v0
+	.text
+	.globl	pe_absptr
+	.p2align	4, 0x90
+	.type	pe_absptr, at function
+pe_absptr:
+.Lfunc_begin0:
+	.cfi_startproc
+	.cfi_personality 0, __gxx_personality_v0
+	.cfi_lsda 0, .Lexception0
+	pushq	%rax
+	.cfi_def_cfa_offset 16
+	movabsq	$__cxa_allocate_exception, %rax
+	movl	$4, %edi
+	callq	*%rax
+	movl	$42, (%rax)
+.Ltmp0:
+	movabsq	$_ZTIi, %rsi
+	movabsq	$__cxa_throw, %rcx
+	movq	%rax, %rdi
+	xorl	%edx, %edx
+	callq	*%rcx
+.Ltmp1:
+.LBB0_2:
+.Ltmp2:
+	movabsq	$__cxa_begin_catch, %rcx
+	movq	%rax, %rdi
+	callq	*%rcx
+	movabsq	$__cxa_end_catch, %rax
+	popq	%rcx
+	.cfi_def_cfa_offset 8
+	jmpq	*%rax
+.Lfunc_end0:
+	.size	pe_absptr, .Lfunc_end0-pe_absptr
+	.cfi_endproc
+	.section	.gcc_except_table,"a", at progbits
+	.p2align	2
+GCC_except_table0:
+.Lexception0:
+	.byte	255                             # @LPStart Encoding = omit
+	.byte	0                               # @TType Encoding = absptr
+	.uleb128 .Lttbase0-.Lttbaseref0
+.Lttbaseref0:
+	.byte	1                               # Call site Encoding = uleb128
+	.uleb128 .Lcst_end0-.Lcst_begin0
+.Lcst_begin0:
+	.uleb128 .Lfunc_begin0-.Lfunc_begin0    # >> Call Site 1 <<
+	.uleb128 .Ltmp0-.Lfunc_begin0           #   Call between .Lfunc_begin0 and .Ltmp0
+	.byte	0                               #     has no landing pad
+	.byte	0                               #   On action: cleanup
+	.uleb128 .Ltmp0-.Lfunc_begin0           # >> Call Site 2 <<
+	.uleb128 .Ltmp1-.Ltmp0                  #   Call between .Ltmp0 and .Ltmp1
+	.uleb128 .Ltmp2-.Lfunc_begin0           #     jumps to .Ltmp2
+	.byte	1                               #   On action: 1
+	.uleb128 .Ltmp1-.Lfunc_begin0           # >> Call Site 3 <<
+	.uleb128 .Lfunc_end0-.Ltmp1             #   Call between .Ltmp1 and .Lfunc_end0
+	.byte	0                               #     has no landing pad
+	.byte	0                               #   On action: cleanup
+.Lcst_end0:
+	.byte	1                               # >> Action Record 1 <<
+                                        #   Catch TypeInfo 1
+	.byte	0                               #   No further actions
+	.p2align	2
+                                        # >> Catch TypeInfos <<
+	.quad	_ZTIi                           # TypeInfo 1
+.Lttbase0:
+	.p2align	2
+                                        # -- End function
+
+# pe_indir_pcrel_sdata8 uses 0x9C -- Indirect, pc-rel, sdata8 encoding to
+# DW.ref.__gxx_personality_v0
+	.text
+	.globl	pe_indir_pcrel_sdata8
+	.p2align	4, 0x90
+	.type	pe_indir_pcrel_sdata8, at function
+pe_indir_pcrel_sdata8:
+.Lfunc_begin1:
+	.cfi_startproc
+	.cfi_personality 156, DW.ref.__gxx_personality_v0
+	.cfi_lsda 28, .Lexception1
+	pushq	%r14
+	.cfi_def_cfa_offset 16
+	pushq	%rbx
+	.cfi_def_cfa_offset 24
+	pushq	%rax
+	.cfi_def_cfa_offset 32
+	.cfi_offset %rbx, -24
+	.cfi_offset %r14, -16
+.L1$pb:
+	leaq	.L1$pb(%rip), %rax
+	movabsq	$_GLOBAL_OFFSET_TABLE_-.L1$pb, %rbx
+	addq	%rax, %rbx
+	movabsq	$__cxa_allocate_exception at GOT, %rax
+	movl	$4, %edi
+	callq	*(%rbx,%rax)
+	movl	$42, (%rax)
+.Ltmp4:
+	movabsq	$_ZTIi at GOT, %rcx
+	movq	(%rbx,%rcx), %rsi
+	movabsq	$__cxa_throw at GOT, %rcx
+	movq	%rax, %rdi
+	xorl	%edx, %edx
+	movq	%rbx, %r14
+	callq	*(%rbx,%rcx)
+.Ltmp5:
+.LBB1_2:
+.Ltmp6:
+	movabsq	$__cxa_begin_catch at GOT, %rcx
+	movq	%rax, %rdi
+	callq	*(%r14,%rcx)
+	movabsq	$__cxa_end_catch at GOT, %rax
+	movq	%r14, %rcx
+	addq	$8, %rsp
+	.cfi_def_cfa_offset 24
+	popq	%rbx
+	.cfi_def_cfa_offset 16
+	popq	%r14
+	.cfi_def_cfa_offset 8
+	jmpq	*(%rcx,%rax)
+.Lfunc_end1:
+	.size	pe_indir_pcrel_sdata8, .Lfunc_end1-pe_indir_pcrel_sdata8
+	.cfi_endproc
+	.section	.gcc_except_table,"a", at progbits
+	.p2align	2
+GCC_except_table1:
+.Lexception1:
+	.byte	255                             # @LPStart Encoding = omit
+	.byte	156                             # @TType Encoding = indirect pcrel sdata8
+	.uleb128 .Lttbase1-.Lttbaseref1
+.Lttbaseref1:
+	.byte	1                               # Call site Encoding = uleb128
+	.uleb128 .Lcst_end1-.Lcst_begin1
+.Lcst_begin1:
+	.uleb128 .Lfunc_begin1-.Lfunc_begin1    # >> Call Site 1 <<
+	.uleb128 .Ltmp4-.Lfunc_begin1           #   Call between .Lfunc_begin1 and .Ltmp4
+	.byte	0                               #     has no landing pad
+	.byte	0                               #   On action: cleanup
+	.uleb128 .Ltmp4-.Lfunc_begin1           # >> Call Site 2 <<
+	.uleb128 .Ltmp5-.Ltmp4                  #   Call between .Ltmp4 and .Ltmp5
+	.uleb128 .Ltmp6-.Lfunc_begin1           #     jumps to .Ltmp6
+	.byte	1                               #   On action: 1
+	.uleb128 .Ltmp5-.Lfunc_begin1           # >> Call Site 3 <<
+	.uleb128 .Lfunc_end1-.Ltmp5             #   Call between .Ltmp5 and .Lfunc_end1
+	.byte	0                               #     has no landing pad
+	.byte	0                               #   On action: cleanup
+.Lcst_end1:
+	.byte	1                               # >> Action Record 1 <<
+                                        #   Catch TypeInfo 1
+	.byte	0                               #   No further actions
+	.p2align	2
+                                        # >> Catch TypeInfos <<
+.Ltmp7:                                 # TypeInfo 1
+	.quad	.L_ZTIi.DW.stub-.Ltmp7
+.Lttbase1:
+	.p2align	2
+                                        # -- End function
+
+	.data
+	.p2align	3
+.L_ZTIi.DW.stub:
+	.quad	_ZTIi
+	.hidden	DW.ref.__gxx_personality_v0
+	.weak	DW.ref.__gxx_personality_v0
+
+	.section	.data.DW.ref.__gxx_personality_v0,"aGw", at progbits,DW.ref.__gxx_personality_v0,comdat
+	.p2align	3
+	.type	DW.ref.__gxx_personality_v0, at object
+	.size	DW.ref.__gxx_personality_v0, 8
+DW.ref.__gxx_personality_v0:
+	.quad	__gxx_personality_v0
+
+	.ident	"clang version 13.0.1"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.addrsig_sym __gxx_personality_v0
+	.addrsig_sym _ZTIi


        


More information about the llvm-commits mailing list