| //=------- CompactUnwindSupport.cpp - Compact Unwind format 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // Compact Unwind support. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "CompactUnwindSupport.h" | |
| #include "llvm/ADT/Sequence.h" | |
| #define DEBUG_TYPE "jitlink" | |
| namespace llvm { | |
| namespace jitlink { | |
| Error splitCompactUnwindBlocks(LinkGraph &G, Section &CompactUnwindSection, | |
| size_t RecordSize) { | |
| std::vector<Block *> OriginalBlocks(CompactUnwindSection.blocks().begin(), | |
| CompactUnwindSection.blocks().end()); | |
| LLVM_DEBUG({ | |
| dbgs() << "In " << G.getName() << " splitting compact unwind section " | |
| << CompactUnwindSection.getName() << " containing " | |
| << OriginalBlocks.size() << " initial blocks...\n"; | |
| }); | |
| while (!OriginalBlocks.empty()) { | |
| auto *B = OriginalBlocks.back(); | |
| OriginalBlocks.pop_back(); | |
| if (B->getSize() == 0) { | |
| LLVM_DEBUG({ | |
| dbgs() << " Skipping empty block at " | |
| << formatv("{0:x16}", B->getAddress()) << "\n"; | |
| }); | |
| continue; | |
| } | |
| unsigned NumBlocks = B->getSize() / RecordSize; | |
| LLVM_DEBUG({ | |
| dbgs() << " Splitting block at " << formatv("{0:x16}", B->getAddress()) | |
| << " into " << NumBlocks << " compact unwind record(s)\n"; | |
| }); | |
| if (B->getSize() % RecordSize) | |
| return make_error<JITLinkError>( | |
| "Error splitting compact unwind record in " + G.getName() + | |
| ": block at " + formatv("{0:x}", B->getAddress()) + " has size " + | |
| formatv("{0:x}", B->getSize()) + | |
| " (not a multiple of CU record size of " + | |
| formatv("{0:x}", RecordSize) + ")"); | |
| auto Blocks = | |
| G.splitBlock(*B, map_range(seq(1U, NumBlocks), [=](Edge::OffsetT Idx) { | |
| return Idx * RecordSize; | |
| })); | |
| for (auto *CURec : Blocks) { | |
| bool AddedKeepAlive = false; | |
| for (auto &E : CURec->edges()) { | |
| if (E.getOffset() == 0) { | |
| LLVM_DEBUG({ | |
| dbgs() << " Updating compact unwind record at " | |
| << CURec->getAddress() << " to point to " | |
| << (E.getTarget().hasName() ? *E.getTarget().getName() | |
| : StringRef()) | |
| << " (at " << E.getTarget().getAddress() << ")\n"; | |
| }); | |
| if (E.getTarget().isExternal()) | |
| return make_error<JITLinkError>( | |
| "Error adding keep-alive edge for compact unwind record at " + | |
| formatv("{0:x}", CURec->getAddress()) + ": target " + | |
| *E.getTarget().getName() + " is an external symbol"); | |
| auto &TgtBlock = E.getTarget().getBlock(); | |
| auto &CURecSym = | |
| G.addAnonymousSymbol(*CURec, 0, RecordSize, false, false); | |
| TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0); | |
| AddedKeepAlive = true; | |
| } | |
| } | |
| if (!AddedKeepAlive) | |
| return make_error<JITLinkError>( | |
| "Error adding keep-alive edge for compact unwind record at " + | |
| formatv("{0:x}", CURec->getAddress()) + | |
| ": no outgoing target edge at offset 0"); | |
| } | |
| } | |
| return Error::success(); | |
| } | |
| } // end namespace jitlink | |
| } // end namespace llvm |