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-exception 6 // 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 19 namespace llvm { 20 namespace jitlink { 21 22 Error 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 jitlink 103 } // end namespace llvm 104