104 lines · cpp
1//=------- CompactUnwindSupport.cpp - Compact Unwind format support -------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Compact Unwind support.10//11//===----------------------------------------------------------------------===//12 13#include "CompactUnwindSupport.h"14 15#include "llvm/ADT/Sequence.h"16 17#define DEBUG_TYPE "jitlink"18 19namespace llvm {20namespace jitlink {21 22Error splitCompactUnwindBlocks(LinkGraph &G, Section &CompactUnwindSection,23 size_t RecordSize) {24 25 std::vector<Block *> OriginalBlocks(CompactUnwindSection.blocks().begin(),26 CompactUnwindSection.blocks().end());27 LLVM_DEBUG({28 dbgs() << "In " << G.getName() << " splitting compact unwind section "29 << CompactUnwindSection.getName() << " containing "30 << OriginalBlocks.size() << " initial blocks...\n";31 });32 33 while (!OriginalBlocks.empty()) {34 auto *B = OriginalBlocks.back();35 OriginalBlocks.pop_back();36 37 if (B->getSize() == 0) {38 LLVM_DEBUG({39 dbgs() << " Skipping empty block at "40 << formatv("{0:x16}", B->getAddress()) << "\n";41 });42 continue;43 }44 45 unsigned NumBlocks = B->getSize() / RecordSize;46 47 LLVM_DEBUG({48 dbgs() << " Splitting block at " << formatv("{0:x16}", B->getAddress())49 << " into " << NumBlocks << " compact unwind record(s)\n";50 });51 52 if (B->getSize() % RecordSize)53 return make_error<JITLinkError>(54 "Error splitting compact unwind record in " + G.getName() +55 ": block at " + formatv("{0:x}", B->getAddress()) + " has size " +56 formatv("{0:x}", B->getSize()) +57 " (not a multiple of CU record size of " +58 formatv("{0:x}", RecordSize) + ")");59 60 auto Blocks =61 G.splitBlock(*B, map_range(seq(1U, NumBlocks), [=](Edge::OffsetT Idx) {62 return Idx * RecordSize;63 }));64 65 for (auto *CURec : Blocks) {66 bool AddedKeepAlive = false;67 68 for (auto &E : CURec->edges()) {69 if (E.getOffset() == 0) {70 LLVM_DEBUG({71 dbgs() << " Updating compact unwind record at "72 << CURec->getAddress() << " to point to "73 << (E.getTarget().hasName() ? *E.getTarget().getName()74 : StringRef())75 << " (at " << E.getTarget().getAddress() << ")\n";76 });77 78 if (E.getTarget().isExternal())79 return make_error<JITLinkError>(80 "Error adding keep-alive edge for compact unwind record at " +81 formatv("{0:x}", CURec->getAddress()) + ": target " +82 *E.getTarget().getName() + " is an external symbol");83 auto &TgtBlock = E.getTarget().getBlock();84 auto &CURecSym =85 G.addAnonymousSymbol(*CURec, 0, RecordSize, false, false);86 TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0);87 AddedKeepAlive = true;88 }89 }90 91 if (!AddedKeepAlive)92 return make_error<JITLinkError>(93 "Error adding keep-alive edge for compact unwind record at " +94 formatv("{0:x}", CURec->getAddress()) +95 ": no outgoing target edge at offset 0");96 }97 }98 99 return Error::success();100}101 102} // end namespace jitlink103} // end namespace llvm104