1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
|
//=------- 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
|