11233c15bSLang Hames //===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//
21233c15bSLang Hames //
3c874dd53SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c874dd53SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information.
5c874dd53SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61233c15bSLang Hames //
71233c15bSLang Hames //===----------------------------------------------------------------------===//
81233c15bSLang Hames 
91233c15bSLang Hames #include "EHFrameSupportImpl.h"
101233c15bSLang Hames 
111233c15bSLang Hames #include "llvm/BinaryFormat/Dwarf.h"
12ae032e27SDavid Tenty #include "llvm/Config/config.h"
13d46409fcSShubham Sandeep Rastogi #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
141d0676b5SLang Hames #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
151233c15bSLang Hames #include "llvm/Support/DynamicLibrary.h"
161233c15bSLang Hames 
171233c15bSLang Hames #define DEBUG_TYPE "jitlink"
181233c15bSLang Hames 
191233c15bSLang Hames namespace llvm {
201233c15bSLang Hames namespace jitlink {
211233c15bSLang Hames 
EHFrameEdgeFixer(StringRef EHFrameSectionName,unsigned PointerSize,Edge::Kind Pointer32,Edge::Kind Pointer64,Edge::Kind Delta32,Edge::Kind Delta64,Edge::Kind NegDelta32)2276aee8a3SLang Hames EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName,
2343acef48SLang Hames                                    unsigned PointerSize, Edge::Kind Pointer32,
2443acef48SLang Hames                                    Edge::Kind Pointer64, Edge::Kind Delta32,
2543acef48SLang Hames                                    Edge::Kind Delta64, Edge::Kind NegDelta32)
26cda4d3d3SLang Hames     : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
2743acef48SLang Hames       Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),
2843acef48SLang Hames       Delta64(Delta64), NegDelta32(NegDelta32) {}
2976aee8a3SLang Hames 
operator ()(LinkGraph & G)3076aee8a3SLang Hames Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
3176aee8a3SLang Hames   auto *EHFrame = G.findSectionByName(EHFrameSectionName);
3276aee8a3SLang Hames 
3376aee8a3SLang Hames   if (!EHFrame) {
3476aee8a3SLang Hames     LLVM_DEBUG({
3576aee8a3SLang Hames       dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName
36*3a7986f5SLang Hames              << " section in \"" << G.getName() << "\". Nothing to do.\n";
3776aee8a3SLang Hames     });
3876aee8a3SLang Hames     return Error::success();
3976aee8a3SLang Hames   }
4076aee8a3SLang Hames 
41cda4d3d3SLang Hames   // Check that we support the graph's pointer size.
42cda4d3d3SLang Hames   if (G.getPointerSize() != 4 && G.getPointerSize() != 8)
43cda4d3d3SLang Hames     return make_error<JITLinkError>(
44cda4d3d3SLang Hames         "EHFrameEdgeFixer only supports 32 and 64 bit targets");
45cda4d3d3SLang Hames 
4676aee8a3SLang Hames   LLVM_DEBUG({
47*3a7986f5SLang Hames     dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << " in \""
48*3a7986f5SLang Hames            << G.getName() << "\"...\n";
4976aee8a3SLang Hames   });
5076aee8a3SLang Hames 
5176aee8a3SLang Hames   ParseContext PC(G);
5276aee8a3SLang Hames 
5376aee8a3SLang Hames   // Build a map of all blocks and symbols in the text sections. We will use
5476aee8a3SLang Hames   // these for finding / building edge targets when processing FDEs.
5576aee8a3SLang Hames   for (auto &Sec : G.sections()) {
5601bc5b70SLang Hames     // Just record the most-canonical symbol (for eh-frame purposes) at each
5701bc5b70SLang Hames     // address.
5801bc5b70SLang Hames     for (auto *Sym : Sec.symbols()) {
5901bc5b70SLang Hames       auto &CurSym = PC.AddrToSym[Sym->getAddress()];
6001bc5b70SLang Hames       if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(),
6101bc5b70SLang Hames                                       !Sym->hasName(), Sym->getName()) <
6201bc5b70SLang Hames                       std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),
6301bc5b70SLang Hames                                       !CurSym->hasName(), CurSym->getName())))
6401bc5b70SLang Hames         CurSym = Sym;
6501bc5b70SLang Hames     }
6676aee8a3SLang Hames     if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
6776aee8a3SLang Hames                                             BlockAddressMap::includeNonNull))
6876aee8a3SLang Hames       return Err;
6976aee8a3SLang Hames   }
7076aee8a3SLang Hames 
7176aee8a3SLang Hames   // Sort eh-frame blocks into address order to ensure we visit CIEs before
7276aee8a3SLang Hames   // their child FDEs.
7376aee8a3SLang Hames   std::vector<Block *> EHFrameBlocks;
7476aee8a3SLang Hames   for (auto *B : EHFrame->blocks())
7576aee8a3SLang Hames     EHFrameBlocks.push_back(B);
7676aee8a3SLang Hames   llvm::sort(EHFrameBlocks, [](const Block *LHS, const Block *RHS) {
7776aee8a3SLang Hames     return LHS->getAddress() < RHS->getAddress();
7876aee8a3SLang Hames   });
7976aee8a3SLang Hames 
8076aee8a3SLang Hames   // Loop over the blocks in address order.
8176aee8a3SLang Hames   for (auto *B : EHFrameBlocks)
8276aee8a3SLang Hames     if (auto Err = processBlock(PC, *B))
8376aee8a3SLang Hames       return Err;
8476aee8a3SLang Hames 
8576aee8a3SLang Hames   return Error::success();
8676aee8a3SLang Hames }
8776aee8a3SLang Hames 
processBlock(ParseContext & PC,Block & B)8876aee8a3SLang Hames Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
8976aee8a3SLang Hames 
9043acef48SLang Hames   LLVM_DEBUG(dbgs() << "  Processing block at " << B.getAddress() << "\n");
9176aee8a3SLang Hames 
9276aee8a3SLang Hames   // eh-frame should not contain zero-fill blocks.
9376aee8a3SLang Hames   if (B.isZeroFill())
9476aee8a3SLang Hames     return make_error<JITLinkError>("Unexpected zero-fill block in " +
9576aee8a3SLang Hames                                     EHFrameSectionName + " section");
9676aee8a3SLang Hames 
9776aee8a3SLang Hames   if (B.getSize() == 0) {
9876aee8a3SLang Hames     LLVM_DEBUG(dbgs() << "    Block is empty. Skipping.\n");
9976aee8a3SLang Hames     return Error::success();
10076aee8a3SLang Hames   }
10176aee8a3SLang Hames 
10276aee8a3SLang Hames   // Find the offsets of any existing edges from this block.
10376aee8a3SLang Hames   BlockEdgeMap BlockEdges;
10476aee8a3SLang Hames   for (auto &E : B.edges())
10576aee8a3SLang Hames     if (E.isRelocation()) {
10676aee8a3SLang Hames       if (BlockEdges.count(E.getOffset()))
10776aee8a3SLang Hames         return make_error<JITLinkError>(
10876aee8a3SLang Hames             "Multiple relocations at offset " +
10976aee8a3SLang Hames             formatv("{0:x16}", E.getOffset()) + " in " + EHFrameSectionName +
11076aee8a3SLang Hames             " block at address " + formatv("{0:x16}", B.getAddress()));
11176aee8a3SLang Hames 
11276aee8a3SLang Hames       BlockEdges[E.getOffset()] = EdgeTarget(E);
11376aee8a3SLang Hames     }
11476aee8a3SLang Hames 
11576aee8a3SLang Hames   CIEInfosMap CIEInfos;
1160269a407SLang Hames   BinaryStreamReader BlockReader(
1170269a407SLang Hames       StringRef(B.getContent().data(), B.getContent().size()),
1180269a407SLang Hames       PC.G.getEndianness());
11976aee8a3SLang Hames   while (!BlockReader.empty()) {
12076aee8a3SLang Hames     size_t RecordStartOffset = BlockReader.getOffset();
12176aee8a3SLang Hames 
12276aee8a3SLang Hames     LLVM_DEBUG({
12376aee8a3SLang Hames       dbgs() << "    Processing CFI record at "
12443acef48SLang Hames              << (B.getAddress() + RecordStartOffset) << "\n";
12576aee8a3SLang Hames     });
12676aee8a3SLang Hames 
12776aee8a3SLang Hames     // Get the record length.
12876aee8a3SLang Hames     size_t RecordRemaining;
12976aee8a3SLang Hames     {
13076aee8a3SLang Hames       uint32_t Length;
13176aee8a3SLang Hames       if (auto Err = BlockReader.readInteger(Length))
13276aee8a3SLang Hames         return Err;
13376aee8a3SLang Hames       // If Length < 0xffffffff then use the regular length field, otherwise
13476aee8a3SLang Hames       // read the extended length field.
13576aee8a3SLang Hames       if (Length != 0xffffffff)
13676aee8a3SLang Hames         RecordRemaining = Length;
13776aee8a3SLang Hames       else {
13876aee8a3SLang Hames         uint64_t ExtendedLength;
13976aee8a3SLang Hames         if (auto Err = BlockReader.readInteger(ExtendedLength))
14076aee8a3SLang Hames           return Err;
14176aee8a3SLang Hames         RecordRemaining = ExtendedLength;
14276aee8a3SLang Hames       }
14376aee8a3SLang Hames     }
14476aee8a3SLang Hames 
14576aee8a3SLang Hames     if (BlockReader.bytesRemaining() < RecordRemaining)
14676aee8a3SLang Hames       return make_error<JITLinkError>(
14776aee8a3SLang Hames           "Incomplete CFI record at " +
14876aee8a3SLang Hames           formatv("{0:x16}", B.getAddress() + RecordStartOffset));
14976aee8a3SLang Hames 
15076aee8a3SLang Hames     // Read the CIE delta for this record.
15176aee8a3SLang Hames     uint64_t CIEDeltaFieldOffset = BlockReader.getOffset() - RecordStartOffset;
15276aee8a3SLang Hames     uint32_t CIEDelta;
15376aee8a3SLang Hames     if (auto Err = BlockReader.readInteger(CIEDelta))
15476aee8a3SLang Hames       return Err;
15576aee8a3SLang Hames 
15676aee8a3SLang Hames     if (CIEDelta == 0) {
15776aee8a3SLang Hames       if (auto Err = processCIE(PC, B, RecordStartOffset,
15876aee8a3SLang Hames                                 CIEDeltaFieldOffset + RecordRemaining,
15943acef48SLang Hames                                 CIEDeltaFieldOffset, BlockEdges))
16076aee8a3SLang Hames         return Err;
16176aee8a3SLang Hames     } else {
16276aee8a3SLang Hames       if (auto Err = processFDE(PC, B, RecordStartOffset,
16376aee8a3SLang Hames                                 CIEDeltaFieldOffset + RecordRemaining,
16476aee8a3SLang Hames                                 CIEDeltaFieldOffset, CIEDelta, BlockEdges))
16576aee8a3SLang Hames         return Err;
16676aee8a3SLang Hames     }
16776aee8a3SLang Hames 
16876aee8a3SLang Hames     // Move to the next record.
16976aee8a3SLang Hames     BlockReader.setOffset(RecordStartOffset + CIEDeltaFieldOffset +
17076aee8a3SLang Hames                           RecordRemaining);
17176aee8a3SLang Hames   }
17276aee8a3SLang Hames 
17376aee8a3SLang Hames   return Error::success();
17476aee8a3SLang Hames }
17576aee8a3SLang Hames 
processCIE(ParseContext & PC,Block & B,size_t RecordOffset,size_t RecordLength,size_t CIEDeltaFieldOffset,const BlockEdgeMap & BlockEdges)17676aee8a3SLang Hames Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
17776aee8a3SLang Hames                                    size_t RecordOffset, size_t RecordLength,
17843acef48SLang Hames                                    size_t CIEDeltaFieldOffset,
17943acef48SLang Hames                                    const BlockEdgeMap &BlockEdges) {
18076aee8a3SLang Hames 
18176aee8a3SLang Hames   LLVM_DEBUG(dbgs() << "      Record is CIE\n");
18276aee8a3SLang Hames 
1830269a407SLang Hames   auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
1840269a407SLang Hames   BinaryStreamReader RecordReader(
1850269a407SLang Hames       StringRef(RecordContent.data(), RecordContent.size()),
1860269a407SLang Hames       PC.G.getEndianness());
18776aee8a3SLang Hames 
18876aee8a3SLang Hames   // Skip past the CIE delta field: we've already processed this far.
18976aee8a3SLang Hames   RecordReader.setOffset(CIEDeltaFieldOffset + 4);
19076aee8a3SLang Hames 
19176aee8a3SLang Hames   auto &CIESymbol =
19276aee8a3SLang Hames       PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
19376aee8a3SLang Hames   CIEInformation CIEInfo(CIESymbol);
19476aee8a3SLang Hames 
19576aee8a3SLang Hames   uint8_t Version = 0;
19676aee8a3SLang Hames   if (auto Err = RecordReader.readInteger(Version))
19776aee8a3SLang Hames     return Err;
19876aee8a3SLang Hames 
19976aee8a3SLang Hames   if (Version != 0x01)
20076aee8a3SLang Hames     return make_error<JITLinkError>("Bad CIE version " + Twine(Version) +
20176aee8a3SLang Hames                                     " (should be 0x01) in eh-frame");
20276aee8a3SLang Hames 
20376aee8a3SLang Hames   auto AugInfo = parseAugmentationString(RecordReader);
20476aee8a3SLang Hames   if (!AugInfo)
20576aee8a3SLang Hames     return AugInfo.takeError();
20676aee8a3SLang Hames 
20776aee8a3SLang Hames   // Skip the EH Data field if present.
20876aee8a3SLang Hames   if (AugInfo->EHDataFieldPresent)
20976aee8a3SLang Hames     if (auto Err = RecordReader.skip(PC.G.getPointerSize()))
21076aee8a3SLang Hames       return Err;
21176aee8a3SLang Hames 
21259c84774SZarko Todorovski   // Read and validate the code alignment factor.
21376aee8a3SLang Hames   {
21476aee8a3SLang Hames     uint64_t CodeAlignmentFactor = 0;
21576aee8a3SLang Hames     if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor))
21676aee8a3SLang Hames       return Err;
21776aee8a3SLang Hames   }
21876aee8a3SLang Hames 
21959c84774SZarko Todorovski   // Read and validate the data alignment factor.
22076aee8a3SLang Hames   {
22176aee8a3SLang Hames     int64_t DataAlignmentFactor = 0;
22276aee8a3SLang Hames     if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor))
22376aee8a3SLang Hames       return Err;
22476aee8a3SLang Hames   }
22576aee8a3SLang Hames 
22676aee8a3SLang Hames   // Skip the return address register field.
22776aee8a3SLang Hames   if (auto Err = RecordReader.skip(1))
22876aee8a3SLang Hames     return Err;
22976aee8a3SLang Hames 
23043acef48SLang Hames   if (AugInfo->AugmentationDataPresent) {
23143acef48SLang Hames 
23243acef48SLang Hames     CIEInfo.AugmentationDataPresent = true;
23343acef48SLang Hames 
23476aee8a3SLang Hames     uint64_t AugmentationDataLength = 0;
23576aee8a3SLang Hames     if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
23676aee8a3SLang Hames       return Err;
23776aee8a3SLang Hames 
23876aee8a3SLang Hames     uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
23976aee8a3SLang Hames 
24076aee8a3SLang Hames     uint8_t *NextField = &AugInfo->Fields[0];
24176aee8a3SLang Hames     while (uint8_t Field = *NextField++) {
24276aee8a3SLang Hames       switch (Field) {
24343acef48SLang Hames       case 'L':
24443acef48SLang Hames         CIEInfo.LSDAPresent = true;
24543acef48SLang Hames         if (auto PE = readPointerEncoding(RecordReader, B, "LSDA"))
24643acef48SLang Hames           CIEInfo.LSDAEncoding = *PE;
24743acef48SLang Hames         else
24843acef48SLang Hames           return PE.takeError();
24976aee8a3SLang Hames         break;
25076aee8a3SLang Hames       case 'P': {
25143acef48SLang Hames         auto PersonalityPointerEncoding =
25243acef48SLang Hames             readPointerEncoding(RecordReader, B, "personality");
25343acef48SLang Hames         if (!PersonalityPointerEncoding)
25443acef48SLang Hames           return PersonalityPointerEncoding.takeError();
25543acef48SLang Hames         if (auto Err =
25643acef48SLang Hames                 getOrCreateEncodedPointerEdge(
25743acef48SLang Hames                     PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,
25843acef48SLang Hames                     B, RecordOffset + RecordReader.getOffset(), "personality")
25943acef48SLang Hames                     .takeError())
26076aee8a3SLang Hames           return Err;
26176aee8a3SLang Hames         break;
26276aee8a3SLang Hames       }
26343acef48SLang Hames       case 'R':
26443acef48SLang Hames         if (auto PE = readPointerEncoding(RecordReader, B, "address")) {
26543acef48SLang Hames           CIEInfo.AddressEncoding = *PE;
26643acef48SLang Hames           if (CIEInfo.AddressEncoding == dwarf::DW_EH_PE_omit)
26776aee8a3SLang Hames             return make_error<JITLinkError>(
26843acef48SLang Hames                 "Invalid address encoding DW_EH_PE_omit in CIE at " +
26943acef48SLang Hames                 formatv("{0:x}", (B.getAddress() + RecordOffset).getValue()));
27043acef48SLang Hames         } else
27143acef48SLang Hames           return PE.takeError();
27276aee8a3SLang Hames         break;
27376aee8a3SLang Hames       default:
27476aee8a3SLang Hames         llvm_unreachable("Invalid augmentation string field");
27576aee8a3SLang Hames       }
27676aee8a3SLang Hames     }
27776aee8a3SLang Hames 
27876aee8a3SLang Hames     if (RecordReader.getOffset() - AugmentationDataStartOffset >
27976aee8a3SLang Hames         AugmentationDataLength)
28076aee8a3SLang Hames       return make_error<JITLinkError>("Read past the end of the augmentation "
28176aee8a3SLang Hames                                       "data while parsing fields");
28243acef48SLang Hames   }
28376aee8a3SLang Hames 
28476aee8a3SLang Hames   assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
28576aee8a3SLang Hames          "Multiple CIEs recorded at the same address?");
28676aee8a3SLang Hames   PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
28776aee8a3SLang Hames 
28876aee8a3SLang Hames   return Error::success();
28976aee8a3SLang Hames }
29076aee8a3SLang Hames 
processFDE(ParseContext & PC,Block & B,size_t RecordOffset,size_t RecordLength,size_t CIEDeltaFieldOffset,uint32_t CIEDelta,const BlockEdgeMap & BlockEdges)29176aee8a3SLang Hames Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
29276aee8a3SLang Hames                                    size_t RecordOffset, size_t RecordLength,
29376aee8a3SLang Hames                                    size_t CIEDeltaFieldOffset,
29476aee8a3SLang Hames                                    uint32_t CIEDelta,
29543acef48SLang Hames                                    const BlockEdgeMap &BlockEdges) {
29676aee8a3SLang Hames   LLVM_DEBUG(dbgs() << "      Record is FDE\n");
29776aee8a3SLang Hames 
298118e953bSLang Hames   orc::ExecutorAddr RecordAddress = B.getAddress() + RecordOffset;
29976aee8a3SLang Hames 
3000269a407SLang Hames   auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
3010269a407SLang Hames   BinaryStreamReader RecordReader(
3020269a407SLang Hames       StringRef(RecordContent.data(), RecordContent.size()),
3030269a407SLang Hames       PC.G.getEndianness());
30476aee8a3SLang Hames 
30576aee8a3SLang Hames   // Skip past the CIE delta field: we've already read this far.
30676aee8a3SLang Hames   RecordReader.setOffset(CIEDeltaFieldOffset + 4);
30776aee8a3SLang Hames 
30876aee8a3SLang Hames   auto &FDESymbol =
30976aee8a3SLang Hames       PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
31076aee8a3SLang Hames 
31176aee8a3SLang Hames   CIEInformation *CIEInfo = nullptr;
31276aee8a3SLang Hames 
31376aee8a3SLang Hames   {
31476aee8a3SLang Hames     // Process the CIE pointer field.
31576aee8a3SLang Hames     auto CIEEdgeItr = BlockEdges.find(RecordOffset + CIEDeltaFieldOffset);
316118e953bSLang Hames     orc::ExecutorAddr CIEAddress =
317118e953bSLang Hames         RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -
318118e953bSLang Hames         orc::ExecutorAddrDiff(CIEDelta);
31976aee8a3SLang Hames     if (CIEEdgeItr == BlockEdges.end()) {
32076aee8a3SLang Hames 
32176aee8a3SLang Hames       LLVM_DEBUG({
32276aee8a3SLang Hames         dbgs() << "        Adding edge at "
32343acef48SLang Hames                << (RecordAddress + CIEDeltaFieldOffset)
32443acef48SLang Hames                << " to CIE at: " << CIEAddress << "\n";
32576aee8a3SLang Hames       });
32676aee8a3SLang Hames       if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
32776aee8a3SLang Hames         CIEInfo = *CIEInfoOrErr;
32876aee8a3SLang Hames       else
32976aee8a3SLang Hames         return CIEInfoOrErr.takeError();
33076aee8a3SLang Hames       assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
33145ad6facSLang Hames       B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset,
33276aee8a3SLang Hames                 *CIEInfo->CIESymbol, 0);
33376aee8a3SLang Hames     } else {
33476aee8a3SLang Hames       LLVM_DEBUG({
33576aee8a3SLang Hames         dbgs() << "        Already has edge at "
33643acef48SLang Hames                << (RecordAddress + CIEDeltaFieldOffset) << " to CIE at "
33743acef48SLang Hames                << CIEAddress << "\n";
33876aee8a3SLang Hames       });
33976aee8a3SLang Hames       auto &EI = CIEEdgeItr->second;
34076aee8a3SLang Hames       if (EI.Addend)
34176aee8a3SLang Hames         return make_error<JITLinkError>(
34276aee8a3SLang Hames             "CIE edge at " +
34376aee8a3SLang Hames             formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
34476aee8a3SLang Hames             " has non-zero addend");
34576aee8a3SLang Hames       if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
34676aee8a3SLang Hames         CIEInfo = *CIEInfoOrErr;
34776aee8a3SLang Hames       else
34876aee8a3SLang Hames         return CIEInfoOrErr.takeError();
34976aee8a3SLang Hames     }
35076aee8a3SLang Hames   }
35176aee8a3SLang Hames 
35276aee8a3SLang Hames   // Process the PC-Begin field.
35376aee8a3SLang Hames   LLVM_DEBUG({
35443acef48SLang Hames     dbgs() << "        Processing PC-begin at "
35543acef48SLang Hames            << (RecordAddress + RecordReader.getOffset()) << "\n";
35676aee8a3SLang Hames   });
35743acef48SLang Hames   if (auto PCBegin = getOrCreateEncodedPointerEdge(
35843acef48SLang Hames           PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader, B,
35943acef48SLang Hames           RecordReader.getOffset(), "PC begin")) {
36043acef48SLang Hames     assert(*PCBegin && "PC-begin symbol not set");
36176aee8a3SLang Hames     // Add a keep-alive edge from the FDE target to the FDE to ensure that the
36276aee8a3SLang Hames     // FDE is kept alive if its target is.
363cda4d3d3SLang Hames     LLVM_DEBUG({
364cda4d3d3SLang Hames       dbgs() << "        Adding keep-alive edge from target at "
36543acef48SLang Hames              << (*PCBegin)->getBlock().getAddress() << " to FDE at "
36643acef48SLang Hames              << RecordAddress << "\n";
367cda4d3d3SLang Hames     });
36843acef48SLang Hames     (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
36943acef48SLang Hames   } else
37043acef48SLang Hames     return PCBegin.takeError();
37176aee8a3SLang Hames 
37276aee8a3SLang Hames   // Skip over the PC range size field.
37343acef48SLang Hames   if (auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))
37476aee8a3SLang Hames     return Err;
37576aee8a3SLang Hames 
37643acef48SLang Hames   if (CIEInfo->AugmentationDataPresent) {
37776aee8a3SLang Hames     uint64_t AugmentationDataSize;
37876aee8a3SLang Hames     if (auto Err = RecordReader.readULEB128(AugmentationDataSize))
37976aee8a3SLang Hames       return Err;
38076aee8a3SLang Hames 
38143acef48SLang Hames     if (CIEInfo->LSDAPresent)
38243acef48SLang Hames       if (auto Err = getOrCreateEncodedPointerEdge(
38343acef48SLang Hames                          PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader, B,
38443acef48SLang Hames                          RecordReader.getOffset(), "LSDA")
38543acef48SLang Hames                          .takeError())
38676aee8a3SLang Hames         return Err;
38776aee8a3SLang Hames   } else {
38876aee8a3SLang Hames     LLVM_DEBUG(dbgs() << "        Record does not have LSDA field.\n");
38976aee8a3SLang Hames   }
39076aee8a3SLang Hames 
39176aee8a3SLang Hames   return Error::success();
39276aee8a3SLang Hames }
39376aee8a3SLang Hames 
39476aee8a3SLang Hames Expected<EHFrameEdgeFixer::AugmentationInfo>
parseAugmentationString(BinaryStreamReader & RecordReader)39576aee8a3SLang Hames EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
3961233c15bSLang Hames   AugmentationInfo AugInfo;
3971233c15bSLang Hames   uint8_t NextChar;
3981233c15bSLang Hames   uint8_t *NextField = &AugInfo.Fields[0];
3991233c15bSLang Hames 
40076aee8a3SLang Hames   if (auto Err = RecordReader.readInteger(NextChar))
401c55cf4afSBill Wendling     return std::move(Err);
4021233c15bSLang Hames 
4031233c15bSLang Hames   while (NextChar != 0) {
4041233c15bSLang Hames     switch (NextChar) {
4051233c15bSLang Hames     case 'z':
4061233c15bSLang Hames       AugInfo.AugmentationDataPresent = true;
4071233c15bSLang Hames       break;
4081233c15bSLang Hames     case 'e':
40976aee8a3SLang Hames       if (auto Err = RecordReader.readInteger(NextChar))
410c55cf4afSBill Wendling         return std::move(Err);
4111233c15bSLang Hames       if (NextChar != 'h')
4121233c15bSLang Hames         return make_error<JITLinkError>("Unrecognized substring e" +
4131233c15bSLang Hames                                         Twine(NextChar) +
4141233c15bSLang Hames                                         " in augmentation string");
4151233c15bSLang Hames       AugInfo.EHDataFieldPresent = true;
4161233c15bSLang Hames       break;
4171233c15bSLang Hames     case 'L':
4181233c15bSLang Hames     case 'P':
4191233c15bSLang Hames     case 'R':
4201233c15bSLang Hames       *NextField++ = NextChar;
4211233c15bSLang Hames       break;
4221233c15bSLang Hames     default:
4231233c15bSLang Hames       return make_error<JITLinkError>("Unrecognized character " +
4241233c15bSLang Hames                                       Twine(NextChar) +
4251233c15bSLang Hames                                       " in augmentation string");
4261233c15bSLang Hames     }
4271233c15bSLang Hames 
42876aee8a3SLang Hames     if (auto Err = RecordReader.readInteger(NextChar))
429c55cf4afSBill Wendling       return std::move(Err);
4301233c15bSLang Hames   }
4311233c15bSLang Hames 
432c55cf4afSBill Wendling   return std::move(AugInfo);
4331233c15bSLang Hames }
4341233c15bSLang Hames 
readPointerEncoding(BinaryStreamReader & R,Block & InBlock,const char * FieldName)43543acef48SLang Hames Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,
43643acef48SLang Hames                                                         Block &InBlock,
43743acef48SLang Hames                                                         const char *FieldName) {
438cda4d3d3SLang Hames   using namespace dwarf;
439cda4d3d3SLang Hames 
44043acef48SLang Hames   uint8_t PointerEncoding;
44143acef48SLang Hames   if (auto Err = R.readInteger(PointerEncoding))
4420d11351bSLang Hames     return std::move(Err);
443cda4d3d3SLang Hames 
44443acef48SLang Hames   bool Supported = true;
445cda4d3d3SLang Hames   switch (PointerEncoding & 0xf) {
44643acef48SLang Hames   case DW_EH_PE_uleb128:
44743acef48SLang Hames   case DW_EH_PE_udata2:
44843acef48SLang Hames   case DW_EH_PE_sleb128:
44943acef48SLang Hames   case DW_EH_PE_sdata2:
45043acef48SLang Hames     Supported = false;
45143acef48SLang Hames     break;
452cda4d3d3SLang Hames   }
45343acef48SLang Hames   if (Supported) {
45443acef48SLang Hames     switch (PointerEncoding & 0x70) {
45543acef48SLang Hames     case DW_EH_PE_textrel:
45643acef48SLang Hames     case DW_EH_PE_datarel:
45743acef48SLang Hames     case DW_EH_PE_funcrel:
45843acef48SLang Hames     case DW_EH_PE_aligned:
45943acef48SLang Hames       Supported = false;
46043acef48SLang Hames       break;
461cda4d3d3SLang Hames     }
462cda4d3d3SLang Hames   }
463cda4d3d3SLang Hames 
46443acef48SLang Hames   if (Supported)
46543acef48SLang Hames     return PointerEncoding;
46643acef48SLang Hames 
46743acef48SLang Hames   return make_error<JITLinkError>("Unsupported pointer encoding " +
46843acef48SLang Hames                                   formatv("{0:x2}", PointerEncoding) + " for " +
46943acef48SLang Hames                                   FieldName + "in CFI record at " +
47043acef48SLang Hames                                   formatv("{0:x16}", InBlock.getAddress()));
47143acef48SLang Hames }
47243acef48SLang Hames 
skipEncodedPointer(uint8_t PointerEncoding,BinaryStreamReader & RecordReader)47343acef48SLang Hames Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,
47476aee8a3SLang Hames                                            BinaryStreamReader &RecordReader) {
475cda4d3d3SLang Hames   using namespace dwarf;
476cda4d3d3SLang Hames 
47743acef48SLang Hames   // Switch absptr to corresponding udata encoding.
47843acef48SLang Hames   if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
47943acef48SLang Hames     PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
480cda4d3d3SLang Hames 
48143acef48SLang Hames   switch (PointerEncoding & 0xf) {
48243acef48SLang Hames   case DW_EH_PE_udata4:
48343acef48SLang Hames   case DW_EH_PE_sdata4:
48443acef48SLang Hames     if (auto Err = RecordReader.skip(4))
48543acef48SLang Hames       return Err;
48643acef48SLang Hames     break;
48743acef48SLang Hames   case DW_EH_PE_udata8:
48843acef48SLang Hames   case DW_EH_PE_sdata8:
48943acef48SLang Hames     if (auto Err = RecordReader.skip(8))
49043acef48SLang Hames       return Err;
49143acef48SLang Hames     break;
49243acef48SLang Hames   default:
49343acef48SLang Hames     llvm_unreachable("Unrecognized encoding");
49443acef48SLang Hames   }
49543acef48SLang Hames   return Error::success();
49643acef48SLang Hames }
49743acef48SLang Hames 
getOrCreateEncodedPointerEdge(ParseContext & PC,const BlockEdgeMap & BlockEdges,uint8_t PointerEncoding,BinaryStreamReader & RecordReader,Block & BlockToFix,size_t PointerFieldOffset,const char * FieldName)49843acef48SLang Hames Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
49943acef48SLang Hames     ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding,
50043acef48SLang Hames     BinaryStreamReader &RecordReader, Block &BlockToFix,
50143acef48SLang Hames     size_t PointerFieldOffset, const char *FieldName) {
50243acef48SLang Hames   using namespace dwarf;
50343acef48SLang Hames 
50443acef48SLang Hames   if (PointerEncoding == DW_EH_PE_omit)
50543acef48SLang Hames     return nullptr;
50643acef48SLang Hames 
50743acef48SLang Hames   // If there's already an edge here then just skip the encoded pointer and
50843acef48SLang Hames   // return the edge's target.
50943acef48SLang Hames   {
51043acef48SLang Hames     auto EdgeI = BlockEdges.find(PointerFieldOffset);
51143acef48SLang Hames     if (EdgeI != BlockEdges.end()) {
51243acef48SLang Hames       LLVM_DEBUG({
51343acef48SLang Hames         dbgs() << "        Existing edge at "
51443acef48SLang Hames                << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
51543acef48SLang Hames                << FieldName << " at " << EdgeI->second.Target->getAddress();
51643acef48SLang Hames         if (EdgeI->second.Target->hasName())
51743acef48SLang Hames           dbgs() << " (" << EdgeI->second.Target->getName() << ")";
51843acef48SLang Hames         dbgs() << "\n";
51943acef48SLang Hames       });
52043acef48SLang Hames       if (auto Err = skipEncodedPointer(PointerEncoding, RecordReader))
5210d11351bSLang Hames         return std::move(Err);
52243acef48SLang Hames       return EdgeI->second.Target;
52343acef48SLang Hames     }
52443acef48SLang Hames   }
52543acef48SLang Hames 
52643acef48SLang Hames   // Switch absptr to corresponding udata encoding.
52743acef48SLang Hames   if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
52843acef48SLang Hames     PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
52943acef48SLang Hames 
53043acef48SLang Hames   // We need to create an edge. Start by reading the field value.
53143acef48SLang Hames   uint64_t FieldValue;
53243acef48SLang Hames   bool Is64Bit = false;
53343acef48SLang Hames   switch (PointerEncoding & 0xf) {
534cda4d3d3SLang Hames   case DW_EH_PE_udata4: {
535cda4d3d3SLang Hames     uint32_t Val;
536cda4d3d3SLang Hames     if (auto Err = RecordReader.readInteger(Val))
537c55cf4afSBill Wendling       return std::move(Err);
53843acef48SLang Hames     FieldValue = Val;
539cda4d3d3SLang Hames     break;
540cda4d3d3SLang Hames   }
541cda4d3d3SLang Hames   case DW_EH_PE_sdata4: {
54243acef48SLang Hames     uint32_t Val;
543cda4d3d3SLang Hames     if (auto Err = RecordReader.readInteger(Val))
544cda4d3d3SLang Hames       return std::move(Err);
54543acef48SLang Hames     FieldValue = Val;
546cda4d3d3SLang Hames     break;
547cda4d3d3SLang Hames   }
54843acef48SLang Hames   case DW_EH_PE_udata8:
54943acef48SLang Hames   case DW_EH_PE_sdata8:
55043acef48SLang Hames     Is64Bit = true;
55143acef48SLang Hames     if (auto Err = RecordReader.readInteger(FieldValue))
552cda4d3d3SLang Hames       return std::move(Err);
553cda4d3d3SLang Hames     break;
55443acef48SLang Hames   default:
55543acef48SLang Hames     llvm_unreachable("Unsupported encoding");
556cda4d3d3SLang Hames   }
557cda4d3d3SLang Hames 
55843acef48SLang Hames   // Find the edge target and edge kind to use.
55943acef48SLang Hames   orc::ExecutorAddr Target;
56043acef48SLang Hames   Edge::Kind PtrEdgeKind = Edge::Invalid;
56143acef48SLang Hames   if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) {
56243acef48SLang Hames     Target = BlockToFix.getAddress() + PointerFieldOffset;
56343acef48SLang Hames     PtrEdgeKind = Is64Bit ? Delta64 : Delta32;
56443acef48SLang Hames   } else
56543acef48SLang Hames     PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;
56643acef48SLang Hames   Target += FieldValue;
567cda4d3d3SLang Hames 
56843acef48SLang Hames   // Find or create a symbol to point the edge at.
56943acef48SLang Hames   auto TargetSym = getOrCreateSymbol(PC, Target);
57043acef48SLang Hames   if (!TargetSym)
57143acef48SLang Hames     return TargetSym.takeError();
57243acef48SLang Hames   BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);
57343acef48SLang Hames 
57443acef48SLang Hames   LLVM_DEBUG({
57543acef48SLang Hames     dbgs() << "        Adding edge at "
57643acef48SLang Hames            << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
57743acef48SLang Hames            << FieldName << " at " << TargetSym->getAddress();
57843acef48SLang Hames     if (TargetSym->hasName())
57943acef48SLang Hames       dbgs() << " (" << TargetSym->getName() << ")";
58043acef48SLang Hames     dbgs() << "\n";
58143acef48SLang Hames   });
58243acef48SLang Hames 
58343acef48SLang Hames   return &*TargetSym;
5841233c15bSLang Hames }
5851233c15bSLang Hames 
getOrCreateSymbol(ParseContext & PC,orc::ExecutorAddr Addr)58676aee8a3SLang Hames Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
587118e953bSLang Hames                                                        orc::ExecutorAddr Addr) {
58801bc5b70SLang Hames   // See whether we have a canonical symbol for the given address already.
58901bc5b70SLang Hames   auto CanonicalSymI = PC.AddrToSym.find(Addr);
59001bc5b70SLang Hames   if (CanonicalSymI != PC.AddrToSym.end())
59101bc5b70SLang Hames     return *CanonicalSymI->second;
5921233c15bSLang Hames 
59376aee8a3SLang Hames   // Otherwise search for a block covering the address and create a new symbol.
59476aee8a3SLang Hames   auto *B = PC.AddrToBlock.getBlockCovering(Addr);
59576aee8a3SLang Hames   if (!B)
59676aee8a3SLang Hames     return make_error<JITLinkError>("No symbol or block covering address " +
59776aee8a3SLang Hames                                     formatv("{0:x16}", Addr));
5981233c15bSLang Hames 
59901bc5b70SLang Hames   auto &S =
60001bc5b70SLang Hames       PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
60101bc5b70SLang Hames   PC.AddrToSym[S.getAddress()] = &S;
60201bc5b70SLang Hames   return S;
6031233c15bSLang Hames }
6041233c15bSLang Hames 
6050269a407SLang Hames char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
606bcb53999SLang Hames 
EHFrameNullTerminator(StringRef EHFrameSectionName)607bcb53999SLang Hames EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName)
608bcb53999SLang Hames     : EHFrameSectionName(EHFrameSectionName) {}
609bcb53999SLang Hames 
operator ()(LinkGraph & G)610bcb53999SLang Hames Error EHFrameNullTerminator::operator()(LinkGraph &G) {
611bcb53999SLang Hames   auto *EHFrame = G.findSectionByName(EHFrameSectionName);
612bcb53999SLang Hames 
613bcb53999SLang Hames   if (!EHFrame)
614bcb53999SLang Hames     return Error::success();
615bcb53999SLang Hames 
616bcb53999SLang Hames   LLVM_DEBUG({
617bcb53999SLang Hames     dbgs() << "EHFrameNullTerminator adding null terminator to "
618bcb53999SLang Hames            << EHFrameSectionName << "\n";
619bcb53999SLang Hames   });
620bcb53999SLang Hames 
621118e953bSLang Hames   auto &NullTerminatorBlock =
622118e953bSLang Hames       G.createContentBlock(*EHFrame, NullTerminatorBlockContent,
623118e953bSLang Hames                            orc::ExecutorAddr(~uint64_t(4)), 1, 0);
624bcb53999SLang Hames   G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true);
625bcb53999SLang Hames   return Error::success();
626bcb53999SLang Hames }
627bcb53999SLang Hames 
6283a3cb929SKazu Hirata EHFrameRegistrar::~EHFrameRegistrar() = default;
629f5a885fdSLang Hames 
registerEHFrames(orc::ExecutorAddrRange EHFrameSection)630605df811SLang Hames Error InProcessEHFrameRegistrar::registerEHFrames(
631089acf25SLang Hames     orc::ExecutorAddrRange EHFrameSection) {
632089acf25SLang Hames   return orc::registerEHFrameSection(EHFrameSection.Start.toPtr<void *>(),
633089acf25SLang Hames                                      EHFrameSection.size());
634f5a885fdSLang Hames }
635f5a885fdSLang Hames 
deregisterEHFrames(orc::ExecutorAddrRange EHFrameSection)636605df811SLang Hames Error InProcessEHFrameRegistrar::deregisterEHFrames(
637089acf25SLang Hames     orc::ExecutorAddrRange EHFrameSection) {
638089acf25SLang Hames   return orc::deregisterEHFrameSection(EHFrameSection.Start.toPtr<void *>(),
639089acf25SLang Hames                                        EHFrameSection.size());
640605df811SLang Hames }
641f5a885fdSLang Hames 
6424e920e58SLang Hames LinkGraphPassFunction
createEHFrameRecorderPass(const Triple & TT,StoreFrameRangeFunction StoreRangeAddress)643a9fdf375SLang Hames createEHFrameRecorderPass(const Triple &TT,
644c48f1f6dSLang Hames                           StoreFrameRangeFunction StoreRangeAddress) {
6451233c15bSLang Hames   const char *EHFrameSectionName = nullptr;
6461233c15bSLang Hames   if (TT.getObjectFormat() == Triple::MachO)
64719e402d2SLang Hames     EHFrameSectionName = "__TEXT,__eh_frame";
6481233c15bSLang Hames   else
6491233c15bSLang Hames     EHFrameSectionName = ".eh_frame";
6501233c15bSLang Hames 
651c48f1f6dSLang Hames   auto RecordEHFrame =
652c48f1f6dSLang Hames       [EHFrameSectionName,
6534e920e58SLang Hames        StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error {
6544e920e58SLang Hames     // Search for a non-empty eh-frame and record the address of the first
6554e920e58SLang Hames     // symbol in it.
656118e953bSLang Hames     orc::ExecutorAddr Addr;
657c48f1f6dSLang Hames     size_t Size = 0;
658c48f1f6dSLang Hames     if (auto *S = G.findSectionByName(EHFrameSectionName)) {
6594e920e58SLang Hames       auto R = SectionRange(*S);
660c48f1f6dSLang Hames       Addr = R.getStart();
661c48f1f6dSLang Hames       Size = R.getSize();
662c48f1f6dSLang Hames     }
663118e953bSLang Hames     if (!Addr && Size != 0)
66419e402d2SLang Hames       return make_error<JITLinkError>(
66519e402d2SLang Hames           StringRef(EHFrameSectionName) +
66619e402d2SLang Hames           " section can not have zero address with non-zero size");
667c48f1f6dSLang Hames     StoreFrameRange(Addr, Size);
6681233c15bSLang Hames     return Error::success();
6691233c15bSLang Hames   };
6701233c15bSLang Hames 
6711233c15bSLang Hames   return RecordEHFrame;
6721233c15bSLang Hames }
6731233c15bSLang Hames 
6741233c15bSLang Hames } // end namespace jitlink
6751233c15bSLang Hames } // end namespace llvm
676