1//===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//
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#include "EHFrameSupportImpl.h"
10
11#include "llvm/BinaryFormat/Dwarf.h"
12#include "llvm/Config/config.h"
13#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
14#include "llvm/Support/DynamicLibrary.h"
15
16#define DEBUG_TYPE "jitlink"
17
18namespace llvm {
19namespace jitlink {
20
21EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName,
22 unsigned PointerSize, Edge::Kind Pointer32,
23 Edge::Kind Pointer64, Edge::Kind Delta32,
24 Edge::Kind Delta64, Edge::Kind NegDelta32)
25 : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
26 Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),
27 Delta64(Delta64), NegDelta32(NegDelta32) {}
28
29Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
30 auto *EHFrame = G.findSectionByName(Name: EHFrameSectionName);
31
32 if (!EHFrame) {
33 LLVM_DEBUG({
34 dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName
35 << " section in \"" << G.getName() << "\". Nothing to do.\n";
36 });
37 return Error::success();
38 }
39
40 // Check that we support the graph's pointer size.
41 if (G.getPointerSize() != 4 && G.getPointerSize() != 8)
42 return make_error<JITLinkError>(
43 Args: "EHFrameEdgeFixer only supports 32 and 64 bit targets");
44
45 LLVM_DEBUG({
46 dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << " in \""
47 << G.getName() << "\"...\n";
48 });
49
50 ParseContext PC(G);
51
52 // Build a map of all blocks and symbols in the text sections. We will use
53 // these for finding / building edge targets when processing FDEs.
54 for (auto &Sec : G.sections()) {
55 // Just record the most-canonical symbol (for eh-frame purposes) at each
56 // address.
57 for (auto *Sym : Sec.symbols()) {
58 auto &CurSym = PC.AddrToSym[Sym->getAddress()];
59 if (!CurSym || (std::make_tuple(args: Sym->getLinkage(), args: Sym->getScope(),
60 args: !Sym->hasName(), args: Sym->getName()) <
61 std::make_tuple(args: CurSym->getLinkage(), args: CurSym->getScope(),
62 args: !CurSym->hasName(), args: CurSym->getName())))
63 CurSym = Sym;
64 }
65 if (auto Err = PC.AddrToBlock.addBlocks(Blocks: Sec.blocks(),
66 Pred: BlockAddressMap::includeNonNull))
67 return Err;
68 }
69
70 // Sort eh-frame blocks into address order to ensure we visit CIEs before
71 // their child FDEs.
72 std::vector<Block *> EHFrameBlocks;
73 llvm::append_range(C&: EHFrameBlocks, R: EHFrame->blocks());
74 llvm::sort(C&: EHFrameBlocks, Comp: [](const Block *LHS, const Block *RHS) {
75 return LHS->getAddress() < RHS->getAddress();
76 });
77
78 // Loop over the blocks in address order.
79 for (auto *B : EHFrameBlocks)
80 if (auto Err = processBlock(PC, B&: *B))
81 return Err;
82
83 return Error::success();
84}
85
86static Expected<size_t> readCFIRecordLength(const Block &B,
87 BinaryStreamReader &R) {
88 uint32_t Length;
89 if (auto Err = R.readInteger(Dest&: Length))
90 return std::move(Err);
91
92 // If Length < 0xffffffff then use the regular length field, otherwise
93 // read the extended length field.
94 if (Length != 0xffffffff)
95 return Length;
96
97 uint64_t ExtendedLength;
98 if (auto Err = R.readInteger(Dest&: ExtendedLength))
99 return std::move(Err);
100
101 if (ExtendedLength > std::numeric_limits<size_t>::max())
102 return make_error<JITLinkError>(
103 Args: "In CFI record at " +
104 formatv(Fmt: "{0:x}", Vals: B.getAddress() + R.getOffset() - 12) +
105 ", extended length of " + formatv(Fmt: "{0:x}", Vals&: ExtendedLength) +
106 " exceeds address-range max (" +
107 formatv(Fmt: "{0:x}", Vals: std::numeric_limits<size_t>::max()));
108
109 return ExtendedLength;
110}
111
112Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
113
114 LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n");
115
116 // eh-frame should not contain zero-fill blocks.
117 if (B.isZeroFill())
118 return make_error<JITLinkError>(Args: "Unexpected zero-fill block in " +
119 EHFrameSectionName + " section");
120
121 if (B.getSize() == 0) {
122 LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");
123 return Error::success();
124 }
125
126 // Find the offsets of any existing edges from this block.
127 BlockEdgesInfo BlockEdges;
128 for (auto &E : B.edges())
129 if (E.isRelocation()) {
130 // Check if we already saw more than one relocation at this offset.
131 if (BlockEdges.Multiple.contains(V: E.getOffset()))
132 continue;
133
134 // Otherwise check if we previously had exactly one relocation at this
135 // offset. If so, we now have a second one and move it from the TargetMap
136 // into the Multiple set.
137 auto [It, Inserted] = BlockEdges.TargetMap.try_emplace(Key: E.getOffset(), Args&: E);
138 if (!Inserted) {
139 BlockEdges.TargetMap.erase(I: It);
140 BlockEdges.Multiple.insert(V: E.getOffset());
141 }
142 }
143
144 BinaryStreamReader BlockReader(
145 StringRef(B.getContent().data(), B.getContent().size()),
146 PC.G.getEndianness());
147
148 // Get the record length.
149 Expected<size_t> RecordRemaining = readCFIRecordLength(B, R&: BlockReader);
150 if (!RecordRemaining)
151 return RecordRemaining.takeError();
152
153 // We expect DWARFRecordSectionSplitter to split each CFI record into its own
154 // block.
155 if (BlockReader.bytesRemaining() != *RecordRemaining)
156 return make_error<JITLinkError>(Args: "Incomplete CFI record at " +
157 formatv(Fmt: "{0:x16}", Vals: B.getAddress()));
158
159 // Read the CIE delta for this record.
160 uint64_t CIEDeltaFieldOffset = BlockReader.getOffset();
161 uint32_t CIEDelta;
162 if (auto Err = BlockReader.readInteger(Dest&: CIEDelta))
163 return Err;
164
165 if (CIEDelta == 0) {
166 if (auto Err = processCIE(PC, B, CIEDeltaFieldOffset, BlockEdges))
167 return Err;
168 } else {
169 if (auto Err = processFDE(PC, B, CIEDeltaFieldOffset, CIEDelta, BlockEdges))
170 return Err;
171 }
172
173 return Error::success();
174}
175
176Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
177 size_t CIEDeltaFieldOffset,
178 const BlockEdgesInfo &BlockEdges) {
179
180 LLVM_DEBUG(dbgs() << " Record is CIE\n");
181
182 BinaryStreamReader RecordReader(
183 StringRef(B.getContent().data(), B.getContent().size()),
184 PC.G.getEndianness());
185
186 // Skip past the CIE delta field: we've already processed this far.
187 RecordReader.setOffset(CIEDeltaFieldOffset + 4);
188
189 auto &CIESymbol = PC.G.addAnonymousSymbol(Content&: B, Offset: 0, Size: B.getSize(), IsCallable: false, IsLive: false);
190 CIEInformation CIEInfo(CIESymbol);
191
192 uint8_t Version = 0;
193 if (auto Err = RecordReader.readInteger(Dest&: Version))
194 return Err;
195
196 if (Version != 0x01)
197 return make_error<JITLinkError>(Args: "Bad CIE version " + Twine(Version) +
198 " (should be 0x01) in eh-frame");
199
200 auto AugInfo = parseAugmentationString(RecordReader);
201 if (!AugInfo)
202 return AugInfo.takeError();
203
204 // Skip the EH Data field if present.
205 if (AugInfo->EHDataFieldPresent)
206 if (auto Err = RecordReader.skip(Amount: PC.G.getPointerSize()))
207 return Err;
208
209 // Read and validate the code alignment factor.
210 {
211 uint64_t CodeAlignmentFactor = 0;
212 if (auto Err = RecordReader.readULEB128(Dest&: CodeAlignmentFactor))
213 return Err;
214 }
215
216 // Read and validate the data alignment factor.
217 {
218 int64_t DataAlignmentFactor = 0;
219 if (auto Err = RecordReader.readSLEB128(Dest&: DataAlignmentFactor))
220 return Err;
221 }
222
223 // Skip the return address register field.
224 if (auto Err = RecordReader.skip(Amount: 1))
225 return Err;
226
227 if (AugInfo->AugmentationDataPresent) {
228
229 CIEInfo.AugmentationDataPresent = true;
230
231 uint64_t AugmentationDataLength = 0;
232 if (auto Err = RecordReader.readULEB128(Dest&: AugmentationDataLength))
233 return Err;
234
235 uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
236
237 uint8_t *NextField = &AugInfo->Fields[0];
238 while (uint8_t Field = *NextField++) {
239 switch (Field) {
240 case 'L':
241 CIEInfo.LSDAPresent = true;
242 if (auto PE = readPointerEncoding(RecordReader, InBlock&: B, FieldName: "LSDA"))
243 CIEInfo.LSDAEncoding = *PE;
244 else
245 return PE.takeError();
246 break;
247 case 'P': {
248 auto PersonalityPointerEncoding =
249 readPointerEncoding(RecordReader, InBlock&: B, FieldName: "personality");
250 if (!PersonalityPointerEncoding)
251 return PersonalityPointerEncoding.takeError();
252 if (auto Err =
253 getOrCreateEncodedPointerEdge(
254 PC, BlockEdges, PointerEncoding: *PersonalityPointerEncoding, RecordReader,
255 BlockToFix&: B, PointerFieldOffset: RecordReader.getOffset(), FieldName: "personality")
256 .takeError())
257 return Err;
258 break;
259 }
260 case 'R':
261 if (auto PE = readPointerEncoding(RecordReader, InBlock&: B, FieldName: "address")) {
262 CIEInfo.AddressEncoding = *PE;
263 if (CIEInfo.AddressEncoding == dwarf::DW_EH_PE_omit)
264 return make_error<JITLinkError>(
265 Args: "Invalid address encoding DW_EH_PE_omit in CIE at " +
266 formatv(Fmt: "{0:x}", Vals: B.getAddress().getValue()));
267 } else
268 return PE.takeError();
269 break;
270 default:
271 llvm_unreachable("Invalid augmentation string field");
272 }
273 }
274
275 if (RecordReader.getOffset() - AugmentationDataStartOffset >
276 AugmentationDataLength)
277 return make_error<JITLinkError>(Args: "Read past the end of the augmentation "
278 "data while parsing fields");
279 }
280
281 assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
282 "Multiple CIEs recorded at the same address?");
283 PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
284
285 return Error::success();
286}
287
288Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
289 size_t CIEDeltaFieldOffset,
290 uint32_t CIEDelta,
291 const BlockEdgesInfo &BlockEdges) {
292 LLVM_DEBUG(dbgs() << " Record is FDE\n");
293
294 orc::ExecutorAddr RecordAddress = B.getAddress();
295
296 BinaryStreamReader RecordReader(
297 StringRef(B.getContent().data(), B.getContent().size()),
298 PC.G.getEndianness());
299
300 // Skip past the CIE delta field: we've already read this far.
301 RecordReader.setOffset(CIEDeltaFieldOffset + 4);
302
303 auto &FDESymbol = PC.G.addAnonymousSymbol(Content&: B, Offset: 0, Size: B.getSize(), IsCallable: false, IsLive: false);
304
305 CIEInformation *CIEInfo = nullptr;
306
307 {
308 // Process the CIE pointer field.
309 if (BlockEdges.Multiple.contains(V: CIEDeltaFieldOffset))
310 return make_error<JITLinkError>(
311 Args: "CIE pointer field already has multiple edges at " +
312 formatv(Fmt: "{0:x16}", Vals: RecordAddress + CIEDeltaFieldOffset));
313
314 auto CIEEdgeItr = BlockEdges.TargetMap.find(Val: CIEDeltaFieldOffset);
315
316 orc::ExecutorAddr CIEAddress =
317 RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -
318 orc::ExecutorAddrDiff(CIEDelta);
319 if (CIEEdgeItr == BlockEdges.TargetMap.end()) {
320 LLVM_DEBUG({
321 dbgs() << " Adding edge at "
322 << (RecordAddress + CIEDeltaFieldOffset)
323 << " to CIE at: " << CIEAddress << "\n";
324 });
325 if (auto CIEInfoOrErr = PC.findCIEInfo(Address: CIEAddress))
326 CIEInfo = *CIEInfoOrErr;
327 else
328 return CIEInfoOrErr.takeError();
329 assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
330 B.addEdge(K: NegDelta32, Offset: CIEDeltaFieldOffset, Target&: *CIEInfo->CIESymbol, Addend: 0);
331 } else {
332 LLVM_DEBUG({
333 dbgs() << " Already has edge at "
334 << (RecordAddress + CIEDeltaFieldOffset) << " to CIE at "
335 << CIEAddress << "\n";
336 });
337 auto &EI = CIEEdgeItr->second;
338 if (EI.Addend)
339 return make_error<JITLinkError>(
340 Args: "CIE edge at " +
341 formatv(Fmt: "{0:x16}", Vals: RecordAddress + CIEDeltaFieldOffset) +
342 " has non-zero addend");
343 if (auto CIEInfoOrErr = PC.findCIEInfo(Address: EI.Target->getAddress()))
344 CIEInfo = *CIEInfoOrErr;
345 else
346 return CIEInfoOrErr.takeError();
347 }
348 }
349
350 // Process the PC-Begin field.
351 LLVM_DEBUG({
352 dbgs() << " Processing PC-begin at "
353 << (RecordAddress + RecordReader.getOffset()) << "\n";
354 });
355 if (auto PCBegin = getOrCreateEncodedPointerEdge(
356 PC, BlockEdges, PointerEncoding: CIEInfo->AddressEncoding, RecordReader, BlockToFix&: B,
357 PointerFieldOffset: RecordReader.getOffset(), FieldName: "PC begin")) {
358 assert(*PCBegin && "PC-begin symbol not set");
359 if ((*PCBegin)->isDefined()) {
360 // Add a keep-alive edge from the FDE target to the FDE to ensure that the
361 // FDE is kept alive if its target is.
362 LLVM_DEBUG({
363 dbgs() << " Adding keep-alive edge from target at "
364 << (*PCBegin)->getBlock().getAddress() << " to FDE at "
365 << RecordAddress << "\n";
366 });
367 (*PCBegin)->getBlock().addEdge(K: Edge::KeepAlive, Offset: 0, Target&: FDESymbol, Addend: 0);
368 } else {
369 LLVM_DEBUG({
370 dbgs() << " WARNING: Not adding keep-alive edge to FDE at "
371 << RecordAddress << ", which points to "
372 << ((*PCBegin)->isExternal() ? "external" : "absolute")
373 << " symbol \"" << (*PCBegin)->getName()
374 << "\" -- FDE must be kept alive manually or it will be "
375 << "dead stripped.\n";
376 });
377 }
378 } else
379 return PCBegin.takeError();
380
381 // Skip over the PC range size field.
382 if (auto Err = skipEncodedPointer(PointerEncoding: CIEInfo->AddressEncoding, RecordReader))
383 return Err;
384
385 if (CIEInfo->AugmentationDataPresent) {
386 uint64_t AugmentationDataSize;
387 if (auto Err = RecordReader.readULEB128(Dest&: AugmentationDataSize))
388 return Err;
389
390 if (CIEInfo->LSDAPresent)
391 if (auto Err = getOrCreateEncodedPointerEdge(
392 PC, BlockEdges, PointerEncoding: CIEInfo->LSDAEncoding, RecordReader, BlockToFix&: B,
393 PointerFieldOffset: RecordReader.getOffset(), FieldName: "LSDA")
394 .takeError())
395 return Err;
396 } else {
397 LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n");
398 }
399
400 return Error::success();
401}
402
403Expected<EHFrameEdgeFixer::AugmentationInfo>
404EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
405 AugmentationInfo AugInfo;
406 uint8_t NextChar;
407 uint8_t *NextField = &AugInfo.Fields[0];
408
409 if (auto Err = RecordReader.readInteger(Dest&: NextChar))
410 return std::move(Err);
411
412 while (NextChar != 0) {
413 switch (NextChar) {
414 case 'z':
415 AugInfo.AugmentationDataPresent = true;
416 break;
417 case 'e':
418 if (auto Err = RecordReader.readInteger(Dest&: NextChar))
419 return std::move(Err);
420 if (NextChar != 'h')
421 return make_error<JITLinkError>(Args: "Unrecognized substring e" +
422 Twine(NextChar) +
423 " in augmentation string");
424 AugInfo.EHDataFieldPresent = true;
425 break;
426 case 'L':
427 case 'P':
428 case 'R':
429 *NextField++ = NextChar;
430 break;
431 default:
432 return make_error<JITLinkError>(Args: "Unrecognized character " +
433 Twine(NextChar) +
434 " in augmentation string");
435 }
436
437 if (auto Err = RecordReader.readInteger(Dest&: NextChar))
438 return std::move(Err);
439 }
440
441 return std::move(AugInfo);
442}
443
444Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,
445 Block &InBlock,
446 const char *FieldName) {
447 using namespace dwarf;
448
449 uint8_t PointerEncoding;
450 if (auto Err = R.readInteger(Dest&: PointerEncoding))
451 return std::move(Err);
452
453 bool Supported = true;
454 switch (PointerEncoding & 0xf) {
455 case DW_EH_PE_uleb128:
456 case DW_EH_PE_udata2:
457 case DW_EH_PE_sleb128:
458 case DW_EH_PE_sdata2:
459 Supported = false;
460 break;
461 }
462 if (Supported) {
463 switch (PointerEncoding & 0x70) {
464 case DW_EH_PE_textrel:
465 case DW_EH_PE_datarel:
466 case DW_EH_PE_funcrel:
467 case DW_EH_PE_aligned:
468 Supported = false;
469 break;
470 }
471 }
472
473 if (Supported)
474 return PointerEncoding;
475
476 return make_error<JITLinkError>(Args: "Unsupported pointer encoding " +
477 formatv(Fmt: "{0:x2}", Vals&: PointerEncoding) + " for " +
478 FieldName + "in CFI record at " +
479 formatv(Fmt: "{0:x16}", Vals: InBlock.getAddress()));
480}
481
482Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,
483 BinaryStreamReader &RecordReader) {
484 using namespace dwarf;
485
486 // Switch absptr to corresponding udata encoding.
487 if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
488 PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
489
490 switch (PointerEncoding & 0xf) {
491 case DW_EH_PE_udata4:
492 case DW_EH_PE_sdata4:
493 if (auto Err = RecordReader.skip(Amount: 4))
494 return Err;
495 break;
496 case DW_EH_PE_udata8:
497 case DW_EH_PE_sdata8:
498 if (auto Err = RecordReader.skip(Amount: 8))
499 return Err;
500 break;
501 default:
502 llvm_unreachable("Unrecognized encoding");
503 }
504 return Error::success();
505}
506
507Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
508 ParseContext &PC, const BlockEdgesInfo &BlockEdges, uint8_t PointerEncoding,
509 BinaryStreamReader &RecordReader, Block &BlockToFix,
510 size_t PointerFieldOffset, const char *FieldName) {
511 using namespace dwarf;
512
513 if (PointerEncoding == DW_EH_PE_omit)
514 return nullptr;
515
516 // If there's already an edge here then just skip the encoded pointer and
517 // return the edge's target.
518 {
519 auto EdgeI = BlockEdges.TargetMap.find(Val: PointerFieldOffset);
520 if (EdgeI != BlockEdges.TargetMap.end()) {
521 LLVM_DEBUG({
522 dbgs() << " Existing edge at "
523 << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
524 << FieldName << " at " << EdgeI->second.Target->getAddress();
525 if (EdgeI->second.Target->hasName())
526 dbgs() << " (" << EdgeI->second.Target->getName() << ")";
527 dbgs() << "\n";
528 });
529 if (auto Err = skipEncodedPointer(PointerEncoding, RecordReader))
530 return std::move(Err);
531 return EdgeI->second.Target;
532 }
533
534 if (BlockEdges.Multiple.contains(V: PointerFieldOffset))
535 return make_error<JITLinkError>(Args: "Multiple relocations at offset " +
536 formatv(Fmt: "{0:x16}", Vals&: PointerFieldOffset));
537 }
538
539 // Switch absptr to corresponding udata encoding.
540 if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
541 PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
542
543 // We need to create an edge. Start by reading the field value.
544 uint64_t FieldValue;
545 bool Is64Bit = false;
546 switch (PointerEncoding & 0xf) {
547 case DW_EH_PE_udata4: {
548 uint32_t Val;
549 if (auto Err = RecordReader.readInteger(Dest&: Val))
550 return std::move(Err);
551 FieldValue = Val;
552 break;
553 }
554 case DW_EH_PE_sdata4: {
555 uint32_t Val;
556 if (auto Err = RecordReader.readInteger(Dest&: Val))
557 return std::move(Err);
558 FieldValue = Val;
559 break;
560 }
561 case DW_EH_PE_udata8:
562 case DW_EH_PE_sdata8:
563 Is64Bit = true;
564 if (auto Err = RecordReader.readInteger(Dest&: FieldValue))
565 return std::move(Err);
566 break;
567 default:
568 llvm_unreachable("Unsupported encoding");
569 }
570
571 // Find the edge target and edge kind to use.
572 orc::ExecutorAddr Target;
573 Edge::Kind PtrEdgeKind = Edge::Invalid;
574 if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) {
575 Target = BlockToFix.getAddress() + PointerFieldOffset;
576 PtrEdgeKind = Is64Bit ? Delta64 : Delta32;
577 } else
578 PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;
579 Target += FieldValue;
580
581 // Find or create a symbol to point the edge at.
582 auto TargetSym = getOrCreateSymbol(PC, Addr: Target);
583 if (!TargetSym)
584 return TargetSym.takeError();
585 BlockToFix.addEdge(K: PtrEdgeKind, Offset: PointerFieldOffset, Target&: *TargetSym, Addend: 0);
586
587 LLVM_DEBUG({
588 dbgs() << " Adding edge at "
589 << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
590 << FieldName << " at " << TargetSym->getAddress();
591 if (TargetSym->hasName())
592 dbgs() << " (" << TargetSym->getName() << ")";
593 dbgs() << "\n";
594 });
595
596 return &*TargetSym;
597}
598
599Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
600 orc::ExecutorAddr Addr) {
601 // See whether we have a canonical symbol for the given address already.
602 auto CanonicalSymI = PC.AddrToSym.find(Val: Addr);
603 if (CanonicalSymI != PC.AddrToSym.end())
604 return *CanonicalSymI->second;
605
606 // Otherwise search for a block covering the address and create a new symbol.
607 auto *B = PC.AddrToBlock.getBlockCovering(Addr);
608 if (!B)
609 return make_error<JITLinkError>(Args: "No symbol or block covering address " +
610 formatv(Fmt: "{0:x16}", Vals&: Addr));
611
612 auto &S =
613 PC.G.addAnonymousSymbol(Content&: *B, Offset: Addr - B->getAddress(), Size: 0, IsCallable: false, IsLive: false);
614 PC.AddrToSym[S.getAddress()] = &S;
615 return S;
616}
617
618char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
619
620EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName)
621 : EHFrameSectionName(EHFrameSectionName) {}
622
623Error EHFrameNullTerminator::operator()(LinkGraph &G) {
624 auto *EHFrame = G.findSectionByName(Name: EHFrameSectionName);
625
626 if (!EHFrame)
627 return Error::success();
628
629 LLVM_DEBUG({
630 dbgs() << "EHFrameNullTerminator adding null terminator to "
631 << EHFrameSectionName << "\n";
632 });
633
634 auto &NullTerminatorBlock =
635 G.createContentBlock(Parent&: *EHFrame, Content: NullTerminatorBlockContent,
636 Address: orc::ExecutorAddr(~uint64_t(4)), Alignment: 1, AlignmentOffset: 0);
637 G.addAnonymousSymbol(Content&: NullTerminatorBlock, Offset: 0, Size: 4, IsCallable: false, IsLive: true);
638 return Error::success();
639}
640
641EHFrameCFIBlockInspector EHFrameCFIBlockInspector::FromEdgeScan(Block &B) {
642 if (B.edges_empty())
643 return EHFrameCFIBlockInspector(nullptr);
644 if (B.edges_size() == 1)
645 return EHFrameCFIBlockInspector(&*B.edges().begin());
646 SmallVector<Edge *, 3> Es(llvm::make_pointer_range(Range: B.edges()));
647 assert(Es.size() >= 2 && Es.size() <= 3 && "Unexpected number of edges");
648 llvm::sort(C&: Es, Comp: [](const Edge *LHS, const Edge *RHS) {
649 return LHS->getOffset() < RHS->getOffset();
650 });
651 return EHFrameCFIBlockInspector(*Es[0], *Es[1],
652 Es.size() == 3 ? Es[2] : nullptr);
653 return EHFrameCFIBlockInspector(nullptr);
654}
655
656EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge *PersonalityEdge)
657 : PersonalityEdge(PersonalityEdge) {}
658
659EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge &CIEEdge,
660 Edge &PCBeginEdge,
661 Edge *LSDAEdge)
662 : CIEEdge(&CIEEdge), PCBeginEdge(&PCBeginEdge), LSDAEdge(LSDAEdge) {}
663
664Section *getEHFrameSection(LinkGraph &G) {
665 const char *EHFrameSectionName = nullptr;
666 switch (G.getTargetTriple().getObjectFormat()) {
667 case Triple::MachO:
668 EHFrameSectionName = "__TEXT,__eh_frame";
669 break;
670 case Triple::ELF:
671 EHFrameSectionName = ".eh_frame";
672 break;
673 default:
674 return nullptr;
675 }
676
677 if (auto *S = G.findSectionByName(Name: EHFrameSectionName))
678 if (!S->empty())
679 return S;
680
681 return nullptr;
682}
683
684} // end namespace jitlink
685} // end namespace llvm
686