12 #include "llvm/Config/config.h"
17 #define DEBUG_TYPE "jitlink"
31 auto *EHFrame =
G.findSectionByName(EHFrameSectionName);
35 dbgs() <<
"EHFrameEdgeFixer: No " << EHFrameSectionName
36 <<
" section in \"" <<
G.getName() <<
"\". Nothing to do.\n";
42 if (
G.getPointerSize() != 4 &&
G.getPointerSize() != 8)
43 return make_error<JITLinkError>(
44 "EHFrameEdgeFixer only supports 32 and 64 bit targets");
47 dbgs() <<
"EHFrameEdgeFixer: Processing " << EHFrameSectionName <<
" in \""
48 <<
G.getName() <<
"\"...\n";
55 for (
auto &Sec :
G.sections()) {
58 for (
auto *Sym : Sec.symbols()) {
59 auto &CurSym = PC.AddrToSym[Sym->getAddress()];
60 if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(),
61 !Sym->hasName(), Sym->getName()) <
62 std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),
63 !CurSym->hasName(), CurSym->getName())))
66 if (
auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
73 std::vector<Block *> EHFrameBlocks;
74 for (
auto *
B : EHFrame->blocks())
75 EHFrameBlocks.push_back(
B);
77 return LHS->getAddress() <
RHS->getAddress();
81 for (
auto *
B : EHFrameBlocks)
82 if (
auto Err = processBlock(PC, *
B))
91 if (
auto Err = R.readInteger(
Length))
100 if (
auto Err = R.readInteger(ExtendedLength))
104 return make_error<JITLinkError>(
105 "In CFI record at " +
106 formatv(
"{0:x}",
B.getAddress() + R.getOffset() - 12) +
107 ", extended length of " +
formatv(
"{0:x}", ExtendedLength) +
108 " exceeds address-range max (" +
111 return ExtendedLength;
114 Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &
B) {
116 LLVM_DEBUG(
dbgs() <<
" Processing block at " <<
B.getAddress() <<
"\n");
120 return make_error<JITLinkError>(
"Unexpected zero-fill block in " +
121 EHFrameSectionName +
" section");
123 if (
B.getSize() == 0) {
129 BlockEdgeMap BlockEdges;
130 for (
auto &
E :
B.edges())
131 if (
E.isRelocation()) {
132 if (BlockEdges.count(
E.getOffset()))
133 return make_error<JITLinkError>(
134 "Multiple relocations at offset " +
135 formatv(
"{0:x16}",
E.getOffset()) +
" in " + EHFrameSectionName +
136 " block at address " +
formatv(
"{0:x16}",
B.getAddress()));
138 BlockEdges[
E.getOffset()] = EdgeTarget(
E);
141 CIEInfosMap CIEInfos;
142 BinaryStreamReader BlockReader(
143 StringRef(
B.getContent().data(),
B.getContent().size()),
144 PC.G.getEndianness());
145 while (!BlockReader.empty()) {
146 size_t RecordStartOffset = BlockReader.getOffset();
149 dbgs() <<
" Processing CFI record at "
150 << (
B.getAddress() + RecordStartOffset) <<
"\n";
155 if (!RecordRemaining)
156 return RecordRemaining.takeError();
158 if (BlockReader.bytesRemaining() < *RecordRemaining)
159 return make_error<JITLinkError>(
160 "Incomplete CFI record at " +
161 formatv(
"{0:x16}",
B.getAddress() + RecordStartOffset));
164 uint64_t CIEDeltaFieldOffset = BlockReader.getOffset() - RecordStartOffset;
166 if (
auto Err = BlockReader.readInteger(CIEDelta))
170 if (
auto Err = processCIE(PC,
B, RecordStartOffset,
171 CIEDeltaFieldOffset + *RecordRemaining,
172 CIEDeltaFieldOffset, BlockEdges))
175 if (
auto Err = processFDE(PC,
B, RecordStartOffset,
176 CIEDeltaFieldOffset + *RecordRemaining,
177 CIEDeltaFieldOffset, CIEDelta, BlockEdges))
182 BlockReader.setOffset(RecordStartOffset + CIEDeltaFieldOffset +
189 Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &
B,
190 size_t RecordOffset,
size_t RecordLength,
191 size_t CIEDeltaFieldOffset,
192 const BlockEdgeMap &BlockEdges) {
196 auto RecordContent =
B.getContent().slice(RecordOffset, RecordLength);
197 BinaryStreamReader RecordReader(
198 StringRef(RecordContent.data(), RecordContent.size()),
199 PC.G.getEndianness());
202 RecordReader.setOffset(CIEDeltaFieldOffset + 4);
205 PC.G.addAnonymousSymbol(
B, RecordOffset, RecordLength,
false,
false);
206 CIEInformation CIEInfo(CIESymbol);
209 if (
auto Err = RecordReader.readInteger(
Version))
213 return make_error<JITLinkError>(
"Bad CIE version " + Twine(
Version) +
214 " (should be 0x01) in eh-frame");
216 auto AugInfo = parseAugmentationString(RecordReader);
218 return AugInfo.takeError();
221 if (AugInfo->EHDataFieldPresent)
222 if (
auto Err = RecordReader.skip(PC.G.getPointerSize()))
228 if (
auto Err = RecordReader.readULEB128(CodeAlignmentFactor))
234 int64_t DataAlignmentFactor = 0;
235 if (
auto Err = RecordReader.readSLEB128(DataAlignmentFactor))
240 if (
auto Err = RecordReader.skip(1))
243 if (AugInfo->AugmentationDataPresent) {
245 CIEInfo.AugmentationDataPresent =
true;
247 uint64_t AugmentationDataLength = 0;
248 if (
auto Err = RecordReader.readULEB128(AugmentationDataLength))
251 uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
253 uint8_t *NextField = &AugInfo->Fields[0];
254 while (uint8_t
Field = *NextField++) {
257 CIEInfo.LSDAPresent =
true;
258 if (
auto PE = readPointerEncoding(RecordReader,
B,
"LSDA"))
259 CIEInfo.LSDAEncoding = *PE;
261 return PE.takeError();
264 auto PersonalityPointerEncoding =
265 readPointerEncoding(RecordReader,
B,
"personality");
266 if (!PersonalityPointerEncoding)
267 return PersonalityPointerEncoding.takeError();
269 getOrCreateEncodedPointerEdge(
270 PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,
271 B, RecordOffset + RecordReader.getOffset(),
"personality")
277 if (
auto PE = readPointerEncoding(RecordReader,
B,
"address")) {
278 CIEInfo.AddressEncoding = *PE;
280 return make_error<JITLinkError>(
281 "Invalid address encoding DW_EH_PE_omit in CIE at " +
282 formatv(
"{0:x}", (
B.getAddress() + RecordOffset).getValue()));
284 return PE.takeError();
291 if (RecordReader.getOffset() - AugmentationDataStartOffset >
292 AugmentationDataLength)
293 return make_error<JITLinkError>(
"Read past the end of the augmentation "
294 "data while parsing fields");
297 assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
298 "Multiple CIEs recorded at the same address?");
299 PC.CIEInfos[CIESymbol.getAddress()] =
std::move(CIEInfo);
304 Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &
B,
305 size_t RecordOffset,
size_t RecordLength,
306 size_t CIEDeltaFieldOffset,
308 const BlockEdgeMap &BlockEdges) {
311 orc::ExecutorAddr RecordAddress =
B.getAddress() + RecordOffset;
313 auto RecordContent =
B.getContent().slice(RecordOffset, RecordLength);
314 BinaryStreamReader RecordReader(
315 StringRef(RecordContent.data(), RecordContent.size()),
316 PC.G.getEndianness());
319 RecordReader.setOffset(CIEDeltaFieldOffset + 4);
322 PC.G.addAnonymousSymbol(
B, RecordOffset, RecordLength,
false,
false);
324 CIEInformation *CIEInfo =
nullptr;
328 auto CIEEdgeItr = BlockEdges.find(RecordOffset + CIEDeltaFieldOffset);
329 orc::ExecutorAddr CIEAddress =
332 if (CIEEdgeItr == BlockEdges.end()) {
335 dbgs() <<
" Adding edge at "
336 << (RecordAddress + CIEDeltaFieldOffset)
337 <<
" to CIE at: " << CIEAddress <<
"\n";
339 if (
auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
340 CIEInfo = *CIEInfoOrErr;
342 return CIEInfoOrErr.takeError();
343 assert(CIEInfo->CIESymbol &&
"CIEInfo has no CIE symbol set");
344 B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset,
345 *CIEInfo->CIESymbol, 0);
348 dbgs() <<
" Already has edge at "
349 << (RecordAddress + CIEDeltaFieldOffset) <<
" to CIE at "
350 << CIEAddress <<
"\n";
352 auto &EI = CIEEdgeItr->second;
354 return make_error<JITLinkError>(
356 formatv(
"{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
357 " has non-zero addend");
358 if (
auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
359 CIEInfo = *CIEInfoOrErr;
361 return CIEInfoOrErr.takeError();
367 dbgs() <<
" Processing PC-begin at "
368 << (RecordAddress + RecordReader.getOffset()) <<
"\n";
370 if (
auto PCBegin = getOrCreateEncodedPointerEdge(
371 PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader,
B,
372 RecordReader.getOffset(),
"PC begin")) {
373 assert(*PCBegin &&
"PC-begin symbol not set");
374 if ((*PCBegin)->isDefined()) {
378 dbgs() <<
" Adding keep-alive edge from target at "
379 << (*PCBegin)->getBlock().getAddress() <<
" to FDE at "
380 << RecordAddress <<
"\n";
385 dbgs() <<
" WARNING: Not adding keep-alive edge to FDE at "
386 << RecordAddress <<
", which points to "
387 << ((*PCBegin)->isExternal() ?
"external" :
"absolute")
388 <<
" symbol \"" << (*PCBegin)->getName()
389 <<
"\" -- FDE must be kept alive manually or it will be "
390 <<
"dead stripped.\n";
394 return PCBegin.takeError();
397 if (
auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))
400 if (CIEInfo->AugmentationDataPresent) {
402 if (
auto Err = RecordReader.readULEB128(AugmentationDataSize))
405 if (CIEInfo->LSDAPresent)
406 if (
auto Err = getOrCreateEncodedPointerEdge(
407 PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader,
B,
408 RecordReader.getOffset(),
"LSDA")
418 Expected<EHFrameEdgeFixer::AugmentationInfo>
419 EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
420 AugmentationInfo AugInfo;
422 uint8_t *NextField = &AugInfo.Fields[0];
424 if (
auto Err = RecordReader.readInteger(NextChar))
427 while (NextChar != 0) {
430 AugInfo.AugmentationDataPresent =
true;
433 if (
auto Err = RecordReader.readInteger(NextChar))
436 return make_error<JITLinkError>(
"Unrecognized substring e" +
438 " in augmentation string");
439 AugInfo.EHDataFieldPresent =
true;
444 *NextField++ = NextChar;
447 return make_error<JITLinkError>(
"Unrecognized character " +
449 " in augmentation string");
452 if (
auto Err = RecordReader.readInteger(NextChar))
459 Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,
461 const char *FieldName) {
462 using namespace dwarf;
464 uint8_t PointerEncoding;
465 if (
auto Err =
R.readInteger(PointerEncoding))
468 bool Supported =
true;
469 switch (PointerEncoding & 0xf) {
478 switch (PointerEncoding & 0x70) {
489 return PointerEncoding;
491 return make_error<JITLinkError>(
"Unsupported pointer encoding " +
492 formatv(
"{0:x2}", PointerEncoding) +
" for " +
493 FieldName +
"in CFI record at " +
497 Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,
498 BinaryStreamReader &RecordReader) {
499 using namespace dwarf;
505 switch (PointerEncoding & 0xf) {
508 if (
auto Err = RecordReader.skip(4))
513 if (
auto Err = RecordReader.skip(8))
522 Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
523 ParseContext &PC,
const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding,
524 BinaryStreamReader &RecordReader, Block &BlockToFix,
525 size_t PointerFieldOffset,
const char *FieldName) {
526 using namespace dwarf;
534 auto EdgeI = BlockEdges.find(PointerFieldOffset);
535 if (EdgeI != BlockEdges.end()) {
537 dbgs() <<
" Existing edge at "
538 << (BlockToFix.getAddress() + PointerFieldOffset) <<
" to "
539 << FieldName <<
" at " << EdgeI->second.Target->getAddress();
540 if (EdgeI->second.Target->hasName())
541 dbgs() <<
" (" << EdgeI->second.Target->getName() <<
")";
544 if (
auto Err = skipEncodedPointer(PointerEncoding, RecordReader))
546 return EdgeI->second.Target;
556 bool Is64Bit =
false;
557 switch (PointerEncoding & 0xf) {
560 if (
auto Err = RecordReader.readInteger(Val))
567 if (
auto Err = RecordReader.readInteger(Val))
575 if (
auto Err = RecordReader.readInteger(FieldValue))
586 Target = BlockToFix.getAddress() + PointerFieldOffset;
593 auto TargetSym = getOrCreateSymbol(PC, Target);
595 return TargetSym.takeError();
596 BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);
599 dbgs() <<
" Adding edge at "
600 << (BlockToFix.getAddress() + PointerFieldOffset) <<
" to "
601 << FieldName <<
" at " << TargetSym->getAddress();
602 if (TargetSym->hasName())
603 dbgs() <<
" (" << TargetSym->getName() <<
")";
610 Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
611 orc::ExecutorAddr
Addr) {
613 auto CanonicalSymI = PC.AddrToSym.find(
Addr);
614 if (CanonicalSymI != PC.AddrToSym.end())
615 return *CanonicalSymI->second;
618 auto *
B = PC.AddrToBlock.getBlockCovering(
Addr);
620 return make_error<JITLinkError>(
"No symbol or block covering address " +
624 PC.G.addAnonymousSymbol(*
B,
Addr -
B->getAddress(), 0,
false,
false);
625 PC.AddrToSym[
S.getAddress()] = &
S;
629 char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
632 : EHFrameSectionName(EHFrameSectionName) {}
635 auto *EHFrame =
G.findSectionByName(EHFrameSectionName);
641 dbgs() <<
"EHFrameNullTerminator adding null terminator to "
642 << EHFrameSectionName <<
"\n";
645 auto &NullTerminatorBlock =
646 G.createContentBlock(*EHFrame, NullTerminatorBlockContent,
648 G.addAnonymousSymbol(NullTerminatorBlock, 0, 4,
false,
true);
657 EHFrameSection.
size());
663 EHFrameSection.
size());
669 if (
B.edges_size() == 1)
672 for (
auto &
E :
B.edges())
674 assert(Es.size() >= 2 && Es.size() <= 3 &&
"Unexpected number of edges");
676 return LHS->getOffset() <
RHS->getOffset();
679 Es.size() == 3 ? Es[2] :
nullptr);
683 EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(
Edge *PersonalityEdge)
684 : PersonalityEdge(PersonalityEdge) {}
686 EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge &CIEEdge,
689 : CIEEdge(&CIEEdge), PCBeginEdge(&PCBeginEdge), LSDAEdge(LSDAEdge) {}
694 const char *EHFrameSectionName =
nullptr;
696 EHFrameSectionName =
"__TEXT,__eh_frame";
698 EHFrameSectionName =
".eh_frame";
707 if (
auto *
S =
G.findSectionByName(EHFrameSectionName)) {
712 if (!
Addr && Size != 0)
713 return make_error<JITLinkError>(
715 " section can not have zero address with non-zero size");
716 StoreFrameRange(
Addr, Size);
720 return RecordEHFrame;