1//===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "EHFrameSupportImpl.h"
11
12#include "llvm/BinaryFormat/Dwarf.h"
13#include "llvm/Config/config.h"
14#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
15#include "llvm/Support/DynamicLibrary.h"
16
17#define DEBUG_TYPE "jitlink"
18
19namespace llvm {
20namespace jitlink {
21
22EHFrameSplitter::EHFrameSplitter(StringRef EHFrameSectionName)
23 : EHFrameSectionName(EHFrameSectionName) {}
24
25Error EHFrameSplitter::operator()(LinkGraph &G) {
26 auto *EHFrame = G.findSectionByName(EHFrameSectionName);
27
28 if (!EHFrame) {
29 LLVM_DEBUG({
30 dbgs() << "EHFrameSplitter: No " << EHFrameSectionName
31 << " section. Nothing to do\n";
32 });
33 return Error::success();
34 }
35
36 LLVM_DEBUG({
37 dbgs() << "EHFrameSplitter: Processing " << EHFrameSectionName << "...\n";
38 });
39
40 DenseMap<Block *, LinkGraph::SplitBlockCache> Caches;
41
42 {
43 // Pre-build the split caches.
44 for (auto *B : EHFrame->blocks())
45 Caches[B] = LinkGraph::SplitBlockCache::value_type();
46 for (auto *Sym : EHFrame->symbols())
47 Caches[&Sym->getBlock()]->push_back(Sym);
48 for (auto *B : EHFrame->blocks())
49 llvm::sort(*Caches[B], [](const Symbol *LHS, const Symbol *RHS) {
50 return LHS->getOffset() > RHS->getOffset();
51 });
52 }
53
54 // Iterate over blocks (we do this by iterating over Caches entries rather
55 // than EHFrame->blocks() as we will be inserting new blocks along the way,
56 // which would invalidate iterators in the latter sequence.
57 for (auto &KV : Caches) {
58 auto &B = *KV.first;
59 auto &BCache = KV.second;
60 if (auto Err = processBlock(G, B, BCache))
61 return Err;
62 }
63
64 return Error::success();
65}
66
67Error EHFrameSplitter::processBlock(LinkGraph &G, Block &B,
68 LinkGraph::SplitBlockCache &Cache) {
69 LLVM_DEBUG({
70 dbgs() << " Processing block at " << formatv("{0:x16}", B.getAddress())
71 << "\n";
72 });
73
74 // eh-frame should not contain zero-fill blocks.
75 if (B.isZeroFill())
76 return make_error<JITLinkError>("Unexpected zero-fill block in " +
77 EHFrameSectionName + " section");
78
79 if (B.getSize() == 0) {
80 LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");
81 return Error::success();
82 }
83
84 BinaryStreamReader BlockReader(
85 StringRef(B.getContent().data(), B.getContent().size()),
86 G.getEndianness());
87
88 while (true) {
89 uint64_t RecordStartOffset = BlockReader.getOffset();
90
91 LLVM_DEBUG({
92 dbgs() << " Processing CFI record at "
93 << formatv("{0:x16}", B.getAddress()) << "\n";
94 });
95
96 uint32_t Length;
97 if (auto Err = BlockReader.readInteger(Length))
98 return Err;
99 if (Length != 0xffffffff) {
100 if (auto Err = BlockReader.skip(Length))
101 return Err;
102 } else {
103 uint64_t ExtendedLength;
104 if (auto Err = BlockReader.readInteger(ExtendedLength))
105 return Err;
106 if (auto Err = BlockReader.skip(ExtendedLength))
107 return Err;
108 }
109
110 // If this was the last block then there's nothing to split
111 if (BlockReader.empty()) {
112 LLVM_DEBUG(dbgs() << " Extracted " << B << "\n");
113 return Error::success();
114 }
115
116 uint64_t BlockSize = BlockReader.getOffset() - RecordStartOffset;
117 auto &NewBlock = G.splitBlock(B, BlockSize);
118 (void)NewBlock;
119 LLVM_DEBUG(dbgs() << " Extracted " << NewBlock << "\n");
120 }
121}
122
123EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName,
124 unsigned PointerSize, Edge::Kind Delta64,
125 Edge::Kind Delta32, Edge::Kind NegDelta32)
126 : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
127 Delta64(Delta64), Delta32(Delta32), NegDelta32(NegDelta32) {}
128
129Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
130 auto *EHFrame = G.findSectionByName(EHFrameSectionName);
131
132 if (!EHFrame) {
133 LLVM_DEBUG({
134 dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName
135 << " section. Nothing to do\n";
136 });
137 return Error::success();
138 }
139
140 // Check that we support the graph's pointer size.
141 if (G.getPointerSize() != 4 && G.getPointerSize() != 8)
142 return make_error<JITLinkError>(
143 "EHFrameEdgeFixer only supports 32 and 64 bit targets");
144
145 LLVM_DEBUG({
146 dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << "...\n";
147 });
148
149 ParseContext PC(G);
150
151 // Build a map of all blocks and symbols in the text sections. We will use
152 // these for finding / building edge targets when processing FDEs.
153 for (auto &Sec : G.sections()) {
154 PC.AddrToSyms.addSymbols(Sec.symbols());
155 if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
156 BlockAddressMap::includeNonNull))
157 return Err;
158 }
159
160 // Sort eh-frame blocks into address order to ensure we visit CIEs before
161 // their child FDEs.
162 std::vector<Block *> EHFrameBlocks;
163 for (auto *B : EHFrame->blocks())
164 EHFrameBlocks.push_back(B);
165 llvm::sort(EHFrameBlocks, [](const Block *LHS, const Block *RHS) {
166 return LHS->getAddress() < RHS->getAddress();
167 });
168
169 // Loop over the blocks in address order.
170 for (auto *B : EHFrameBlocks)
171 if (auto Err = processBlock(PC, *B))
172 return Err;
173
174 return Error::success();
175}
176
177Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
178
179 LLVM_DEBUG({
180 dbgs() << " Processing block at " << formatv("{0:x16}", B.getAddress())
181 << "\n";
182 });
183
184 // eh-frame should not contain zero-fill blocks.
185 if (B.isZeroFill())
186 return make_error<JITLinkError>("Unexpected zero-fill block in " +
187 EHFrameSectionName + " section");
188
189 if (B.getSize() == 0) {
190 LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");
191 return Error::success();
192 }
193
194 // Find the offsets of any existing edges from this block.
195 BlockEdgeMap BlockEdges;
196 for (auto &E : B.edges())
197 if (E.isRelocation()) {
198 if (BlockEdges.count(E.getOffset()))
199 return make_error<JITLinkError>(
200 "Multiple relocations at offset " +
201 formatv("{0:x16}", E.getOffset()) + " in " + EHFrameSectionName +
202 " block at address " + formatv("{0:x16}", B.getAddress()));
203
204 BlockEdges[E.getOffset()] = EdgeTarget(E);
205 }
206
207 CIEInfosMap CIEInfos;
208 BinaryStreamReader BlockReader(
209 StringRef(B.getContent().data(), B.getContent().size()),
210 PC.G.getEndianness());
211 while (!BlockReader.empty()) {
212 size_t RecordStartOffset = BlockReader.getOffset();
213
214 LLVM_DEBUG({
215 dbgs() << " Processing CFI record at "
216 << formatv("{0:x16}", B.getAddress() + RecordStartOffset) << "\n";
217 });
218
219 // Get the record length.
220 size_t RecordRemaining;
221 {
222 uint32_t Length;
223 if (auto Err = BlockReader.readInteger(Length))
224 return Err;
225 // If Length < 0xffffffff then use the regular length field, otherwise
226 // read the extended length field.
227 if (Length != 0xffffffff)
228 RecordRemaining = Length;
229 else {
230 uint64_t ExtendedLength;
231 if (auto Err = BlockReader.readInteger(ExtendedLength))
232 return Err;
233 RecordRemaining = ExtendedLength;
234 }
235 }
236
237 if (BlockReader.bytesRemaining() < RecordRemaining)
238 return make_error<JITLinkError>(
239 "Incomplete CFI record at " +
240 formatv("{0:x16}", B.getAddress() + RecordStartOffset));
241
242 // Read the CIE delta for this record.
243 uint64_t CIEDeltaFieldOffset = BlockReader.getOffset() - RecordStartOffset;
244 uint32_t CIEDelta;
245 if (auto Err = BlockReader.readInteger(CIEDelta))
246 return Err;
247
248 if (CIEDelta == 0) {
249 if (auto Err = processCIE(PC, B, RecordStartOffset,
250 CIEDeltaFieldOffset + RecordRemaining,
251 CIEDeltaFieldOffset))
252 return Err;
253 } else {
254 if (auto Err = processFDE(PC, B, RecordStartOffset,
255 CIEDeltaFieldOffset + RecordRemaining,
256 CIEDeltaFieldOffset, CIEDelta, BlockEdges))
257 return Err;
258 }
259
260 // Move to the next record.
261 BlockReader.setOffset(RecordStartOffset + CIEDeltaFieldOffset +
262 RecordRemaining);
263 }
264
265 return Error::success();
266}
267
268Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
269 size_t RecordOffset, size_t RecordLength,
270 size_t CIEDeltaFieldOffset) {
271
272 LLVM_DEBUG(dbgs() << " Record is CIE\n");
273
274 auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
275 BinaryStreamReader RecordReader(
276 StringRef(RecordContent.data(), RecordContent.size()),
277 PC.G.getEndianness());
278
279 // Skip past the CIE delta field: we've already processed this far.
280 RecordReader.setOffset(CIEDeltaFieldOffset + 4);
281
282 auto &CIESymbol =
283 PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
284 CIEInformation CIEInfo(CIESymbol);
285
286 uint8_t Version = 0;
287 if (auto Err = RecordReader.readInteger(Version))
288 return Err;
289
290 if (Version != 0x01)
291 return make_error<JITLinkError>("Bad CIE version " + Twine(Version) +
292 " (should be 0x01) in eh-frame");
293
294 auto AugInfo = parseAugmentationString(RecordReader);
295 if (!AugInfo)
296 return AugInfo.takeError();
297
298 // Skip the EH Data field if present.
299 if (AugInfo->EHDataFieldPresent)
300 if (auto Err = RecordReader.skip(PC.G.getPointerSize()))
301 return Err;
302
303 // Read and sanity check the code alignment factor.
304 {
305 uint64_t CodeAlignmentFactor = 0;
306 if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor))
307 return Err;
308 if (CodeAlignmentFactor != 1)
309 return make_error<JITLinkError>("Unsupported CIE code alignment factor " +
310 Twine(CodeAlignmentFactor) +
311 " (expected 1)");
312 }
313
314 // Read and sanity check the data alignment factor.
315 {
316 int64_t DataAlignmentFactor = 0;
317 if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor))
318 return Err;
319 if (DataAlignmentFactor != -8)
320 return make_error<JITLinkError>("Unsupported CIE data alignment factor " +
321 Twine(DataAlignmentFactor) +
322 " (expected -8)");
323 }
324
325 // Skip the return address register field.
326 if (auto Err = RecordReader.skip(1))
327 return Err;
328
329 uint64_t AugmentationDataLength = 0;
330 if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
331 return Err;
332
333 uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
334
335 uint8_t *NextField = &AugInfo->Fields[0];
336 while (uint8_t Field = *NextField++) {
337 switch (Field) {
338 case 'L': {
339 CIEInfo.FDEsHaveLSDAField = true;
340 uint8_t LSDAPointerEncoding;
341 if (auto Err = RecordReader.readInteger(LSDAPointerEncoding))
342 return Err;
343 if (!isSupportedPointerEncoding(LSDAPointerEncoding))
344 return make_error<JITLinkError>(
345 "Unsupported LSDA pointer encoding " +
346 formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " +
347 formatv("{0:x16}", CIESymbol.getAddress()));
348 CIEInfo.LSDAPointerEncoding = LSDAPointerEncoding;
349 break;
350 }
351 case 'P': {
352 uint8_t PersonalityPointerEncoding = 0;
353 if (auto Err = RecordReader.readInteger(PersonalityPointerEncoding))
354 return Err;
355 if (PersonalityPointerEncoding !=
356 (dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
357 dwarf::DW_EH_PE_sdata4))
358 return make_error<JITLinkError>(
359 "Unspported personality pointer "
360 "encoding " +
361 formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " +
362 formatv("{0:x16}", CIESymbol.getAddress()));
363 uint32_t PersonalityPointerAddress;
364 if (auto Err = RecordReader.readInteger(PersonalityPointerAddress))
365 return Err;
366 break;
367 }
368 case 'R': {
369 uint8_t FDEPointerEncoding;
370 if (auto Err = RecordReader.readInteger(FDEPointerEncoding))
371 return Err;
372 if (!isSupportedPointerEncoding(FDEPointerEncoding))
373 return make_error<JITLinkError>(
374 "Unsupported FDE pointer encoding " +
375 formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " +
376 formatv("{0:x16}", CIESymbol.getAddress()));
377 CIEInfo.FDEPointerEncoding = FDEPointerEncoding;
378 break;
379 }
380 default:
381 llvm_unreachable("Invalid augmentation string field");
382 }
383 }
384
385 if (RecordReader.getOffset() - AugmentationDataStartOffset >
386 AugmentationDataLength)
387 return make_error<JITLinkError>("Read past the end of the augmentation "
388 "data while parsing fields");
389
390 assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
391 "Multiple CIEs recorded at the same address?");
392 PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
393
394 return Error::success();
395}
396
397Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
398 size_t RecordOffset, size_t RecordLength,
399 size_t CIEDeltaFieldOffset,
400 uint32_t CIEDelta,
401 BlockEdgeMap &BlockEdges) {
402 LLVM_DEBUG(dbgs() << " Record is FDE\n");
403
404 JITTargetAddress RecordAddress = B.getAddress() + RecordOffset;
405
406 auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
407 BinaryStreamReader RecordReader(
408 StringRef(RecordContent.data(), RecordContent.size()),
409 PC.G.getEndianness());
410
411 // Skip past the CIE delta field: we've already read this far.
412 RecordReader.setOffset(CIEDeltaFieldOffset + 4);
413
414 auto &FDESymbol =
415 PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
416
417 CIEInformation *CIEInfo = nullptr;
418
419 {
420 // Process the CIE pointer field.
421 auto CIEEdgeItr = BlockEdges.find(RecordOffset + CIEDeltaFieldOffset);
422 JITTargetAddress CIEAddress =
423 RecordAddress + CIEDeltaFieldOffset - CIEDelta;
424 if (CIEEdgeItr == BlockEdges.end()) {
425
426 LLVM_DEBUG({
427 dbgs() << " Adding edge at "
428 << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
429 << " to CIE at: " << formatv("{0:x16}", CIEAddress) << "\n";
430 });
431 if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
432 CIEInfo = *CIEInfoOrErr;
433 else
434 return CIEInfoOrErr.takeError();
435 assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
436 B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset,
437 *CIEInfo->CIESymbol, 0);
438 } else {
439 LLVM_DEBUG({
440 dbgs() << " Already has edge at "
441 << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
442 << " to CIE at " << formatv("{0:x16}", CIEAddress) << "\n";
443 });
444 auto &EI = CIEEdgeItr->second;
445 if (EI.Addend)
446 return make_error<JITLinkError>(
447 "CIE edge at " +
448 formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
449 " has non-zero addend");
450 if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
451 CIEInfo = *CIEInfoOrErr;
452 else
453 return CIEInfoOrErr.takeError();
454 }
455 }
456
457 {
458 // Process the PC-Begin field.
459 Block *PCBeginBlock = nullptr;
460 JITTargetAddress PCBeginFieldOffset = RecordReader.getOffset();
461 auto PCEdgeItr = BlockEdges.find(RecordOffset + PCBeginFieldOffset);
462 if (PCEdgeItr == BlockEdges.end()) {
463 auto PCBeginPtrInfo =
464 readEncodedPointer(CIEInfo->FDEPointerEncoding,
465 RecordAddress + PCBeginFieldOffset, RecordReader);
466 if (!PCBeginPtrInfo)
467 return PCBeginPtrInfo.takeError();
468 JITTargetAddress PCBegin = PCBeginPtrInfo->first;
469 Edge::Kind PCBeginEdgeKind = PCBeginPtrInfo->second;
470 LLVM_DEBUG({
471 dbgs() << " Adding edge at "
472 << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset)
473 << " to PC at " << formatv("{0:x16}", PCBegin) << "\n";
474 });
475 auto PCBeginSym = getOrCreateSymbol(PC, PCBegin);
476 if (!PCBeginSym)
477 return PCBeginSym.takeError();
478 B.addEdge(PCBeginEdgeKind, RecordOffset + PCBeginFieldOffset, *PCBeginSym,
479 0);
480 PCBeginBlock = &PCBeginSym->getBlock();
481 } else {
482 auto &EI = PCEdgeItr->second;
483 LLVM_DEBUG({
484 dbgs() << " Already has edge at "
485 << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset)
486 << " to PC at " << formatv("{0:x16}", EI.Target->getAddress());
487 if (EI.Addend)
488 dbgs() << " + " << formatv("{0:x16}", EI.Addend);
489 dbgs() << "\n";
490 });
491
492 // Make sure the existing edge points at a defined block.
493 if (!EI.Target->isDefined()) {
494 auto EdgeAddr = RecordAddress + PCBeginFieldOffset;
495 return make_error<JITLinkError>("FDE edge at " +
496 formatv("{0:x16}", EdgeAddr) +
497 " points at external block");
498 }
499 PCBeginBlock = &EI.Target->getBlock();
500 if (auto Err = RecordReader.skip(
501 getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
502 return Err;
503 }
504
505 // Add a keep-alive edge from the FDE target to the FDE to ensure that the
506 // FDE is kept alive if its target is.
507 assert(PCBeginBlock && "PC-begin block not recorded");
508 LLVM_DEBUG({
509 dbgs() << " Adding keep-alive edge from target at "
510 << formatv("{0:x16}", PCBeginBlock->getAddress()) << " to FDE at "
511 << formatv("{0:x16}", RecordAddress) << "\n";
512 });
513 PCBeginBlock->addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
514 }
515
516 // Skip over the PC range size field.
517 if (auto Err = RecordReader.skip(
518 getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
519 return Err;
520
521 if (CIEInfo->FDEsHaveLSDAField) {
522 uint64_t AugmentationDataSize;
523 if (auto Err = RecordReader.readULEB128(AugmentationDataSize))
524 return Err;
525
526 JITTargetAddress LSDAFieldOffset = RecordReader.getOffset();
527 auto LSDAEdgeItr = BlockEdges.find(RecordOffset + LSDAFieldOffset);
528 if (LSDAEdgeItr == BlockEdges.end()) {
529 auto LSDAPointerInfo =
530 readEncodedPointer(CIEInfo->LSDAPointerEncoding,
531 RecordAddress + LSDAFieldOffset, RecordReader);
532 if (!LSDAPointerInfo)
533 return LSDAPointerInfo.takeError();
534 JITTargetAddress LSDA = LSDAPointerInfo->first;
535 Edge::Kind LSDAEdgeKind = LSDAPointerInfo->second;
536 auto LSDASym = getOrCreateSymbol(PC, LSDA);
537 if (!LSDASym)
538 return LSDASym.takeError();
539 LLVM_DEBUG({
540 dbgs() << " Adding edge at "
541 << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
542 << " to LSDA at " << formatv("{0:x16}", LSDA) << "\n";
543 });
544 B.addEdge(LSDAEdgeKind, RecordOffset + LSDAFieldOffset, *LSDASym, 0);
545 } else {
546 LLVM_DEBUG({
547 auto &EI = LSDAEdgeItr->second;
548 dbgs() << " Already has edge at "
549 << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
550 << " to LSDA at " << formatv("{0:x16}", EI.Target->getAddress());
551 if (EI.Addend)
552 dbgs() << " + " << formatv("{0:x16}", EI.Addend);
553 dbgs() << "\n";
554 });
555 if (auto Err = RecordReader.skip(AugmentationDataSize))
556 return Err;
557 }
558 } else {
559 LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n");
560 }
561
562 return Error::success();
563}
564
565Expected<EHFrameEdgeFixer::AugmentationInfo>
566EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
567 AugmentationInfo AugInfo;
568 uint8_t NextChar;
569 uint8_t *NextField = &AugInfo.Fields[0];
570
571 if (auto Err = RecordReader.readInteger(NextChar))
572 return std::move(Err);
573
574 while (NextChar != 0) {
575 switch (NextChar) {
576 case 'z':
577 AugInfo.AugmentationDataPresent = true;
578 break;
579 case 'e':
580 if (auto Err = RecordReader.readInteger(NextChar))
581 return std::move(Err);
582 if (NextChar != 'h')
583 return make_error<JITLinkError>("Unrecognized substring e" +
584 Twine(NextChar) +
585 " in augmentation string");
586 AugInfo.EHDataFieldPresent = true;
587 break;
588 case 'L':
589 case 'P':
590 case 'R':
591 *NextField++ = NextChar;
592 break;
593 default:
594 return make_error<JITLinkError>("Unrecognized character " +
595 Twine(NextChar) +
596 " in augmentation string");
597 }
598
599 if (auto Err = RecordReader.readInteger(NextChar))
600 return std::move(Err);
601 }
602
603 return std::move(AugInfo);
604}
605
606bool EHFrameEdgeFixer::isSupportedPointerEncoding(uint8_t PointerEncoding) {
607 using namespace dwarf;
608
609 // We only support PC-rel for now.
610 if ((PointerEncoding & 0x70) != DW_EH_PE_pcrel)
611 return false;
612
613 // readEncodedPointer does not handle indirect.
614 if (PointerEncoding & DW_EH_PE_indirect)
615 return false;
616
617 // Supported datatypes.
618 switch (PointerEncoding & 0xf) {
619 case DW_EH_PE_absptr:
620 case DW_EH_PE_udata4:
621 case DW_EH_PE_udata8:
622 case DW_EH_PE_sdata4:
623 case DW_EH_PE_sdata8:
624 return true;
625 }
626
627 return false;
628}
629
630unsigned EHFrameEdgeFixer::getPointerEncodingDataSize(uint8_t PointerEncoding) {
631 using namespace dwarf;
632
633 assert(isSupportedPointerEncoding(PointerEncoding) &&
634 "Unsupported pointer encoding");
635 switch (PointerEncoding & 0xf) {
636 case DW_EH_PE_absptr:
637 return PointerSize;
638 case DW_EH_PE_udata4:
639 case DW_EH_PE_sdata4:
640 return 4;
641 case DW_EH_PE_udata8:
642 case DW_EH_PE_sdata8:
643 return 8;
644 default:
645 llvm_unreachable("Unsupported encoding");
646 }
647}
648
649Expected<std::pair<JITTargetAddress, Edge::Kind>>
650EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding,
651 JITTargetAddress PointerFieldAddress,
652 BinaryStreamReader &RecordReader) {
653 static_assert(sizeof(JITTargetAddress) == sizeof(uint64_t),
654 "Result must be able to hold a uint64_t");
655 assert(isSupportedPointerEncoding(PointerEncoding) &&
656 "Unsupported pointer encoding");
657
658 using namespace dwarf;
659
660 // Isolate data type, remap absptr to udata4 or udata8. This relies on us
661 // having verified that the graph uses 32-bit or 64-bit pointers only at the
662 // start of this pass.
663 uint8_t EffectiveType = PointerEncoding & 0xf;
664 if (EffectiveType == DW_EH_PE_absptr)
665 EffectiveType = (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
666
667 JITTargetAddress Addr;
668 Edge::Kind PointerEdgeKind;
669 switch (EffectiveType) {
670 case DW_EH_PE_udata4: {
671 uint32_t Val;
672 if (auto Err = RecordReader.readInteger(Val))
673 return std::move(Err);
674 Addr = PointerFieldAddress + Val;
675 PointerEdgeKind = Delta32;
676 break;
677 }
678 case DW_EH_PE_udata8: {
679 uint64_t Val;
680 if (auto Err = RecordReader.readInteger(Val))
681 return std::move(Err);
682 Addr = PointerFieldAddress + Val;
683 PointerEdgeKind = Delta64;
684 break;
685 }
686 case DW_EH_PE_sdata4: {
687 int32_t Val;
688 if (auto Err = RecordReader.readInteger(Val))
689 return std::move(Err);
690 Addr = PointerFieldAddress + Val;
691 PointerEdgeKind = Delta32;
692 break;
693 }
694 case DW_EH_PE_sdata8: {
695 int64_t Val;
696 if (auto Err = RecordReader.readInteger(Val))
697 return std::move(Err);
698 Addr = PointerFieldAddress + Val;
699 PointerEdgeKind = Delta64;
700 break;
701 }
702 }
703
704 if (PointerEdgeKind == Edge::Invalid)
705 return make_error<JITLinkError>(
706 "Unspported edge kind for encoded pointer at " +
707 formatv("{0:x}", PointerFieldAddress));
708
709 return std::make_pair(Addr, Delta64);
710}
711
712Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
713 JITTargetAddress Addr) {
714 Symbol *CanonicalSym = nullptr;
715
716 auto UpdateCanonicalSym = [&](Symbol *Sym) {
717 if (!CanonicalSym || Sym->getLinkage() < CanonicalSym->getLinkage() ||
718 Sym->getScope() < CanonicalSym->getScope() ||
719 (Sym->hasName() && !CanonicalSym->hasName()) ||
720 Sym->getName() < CanonicalSym->getName())
721 CanonicalSym = Sym;
722 };
723
724 if (auto *SymbolsAtAddr = PC.AddrToSyms.getSymbolsAt(Addr))
725 for (auto *Sym : *SymbolsAtAddr)
726 UpdateCanonicalSym(Sym);
727
728 // If we found an existing symbol at the given address then use it.
729 if (CanonicalSym)
730 return *CanonicalSym;
731
732 // Otherwise search for a block covering the address and create a new symbol.
733 auto *B = PC.AddrToBlock.getBlockCovering(Addr);
734 if (!B)
735 return make_error<JITLinkError>("No symbol or block covering address " +
736 formatv("{0:x16}", Addr));
737
738 return PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
739}
740
741char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
742
743EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName)
744 : EHFrameSectionName(EHFrameSectionName) {}
745
746Error EHFrameNullTerminator::operator()(LinkGraph &G) {
747 auto *EHFrame = G.findSectionByName(EHFrameSectionName);
748
749 if (!EHFrame)
750 return Error::success();
751
752 LLVM_DEBUG({
753 dbgs() << "EHFrameNullTerminator adding null terminator to "
754 << EHFrameSectionName << "\n";
755 });
756
757 auto &NullTerminatorBlock = G.createContentBlock(
758 *EHFrame, NullTerminatorBlockContent, 0xfffffffffffffffc, 1, 0);
759 G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true);
760 return Error::success();
761}
762
763EHFrameRegistrar::~EHFrameRegistrar() {}
764
765Error InProcessEHFrameRegistrar::registerEHFrames(
766 JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
767 return orc::registerEHFrameSection(
768 jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
769 EHFrameSectionSize);
770}
771
772Error InProcessEHFrameRegistrar::deregisterEHFrames(
773 JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
774 return orc::deregisterEHFrameSection(
775 jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
776 EHFrameSectionSize);
777}
778
779LinkGraphPassFunction
780createEHFrameRecorderPass(const Triple &TT,
781 StoreFrameRangeFunction StoreRangeAddress) {
782 const char *EHFrameSectionName = nullptr;
783 if (TT.getObjectFormat() == Triple::MachO)
784 EHFrameSectionName = "__TEXT,__eh_frame";
785 else
786 EHFrameSectionName = ".eh_frame";
787
788 auto RecordEHFrame =
789 [EHFrameSectionName,
790 StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error {
791 // Search for a non-empty eh-frame and record the address of the first
792 // symbol in it.
793 JITTargetAddress Addr = 0;
794 size_t Size = 0;
795 if (auto *S = G.findSectionByName(EHFrameSectionName)) {
796 auto R = SectionRange(*S);
797 Addr = R.getStart();
798 Size = R.getSize();
799 }
800 if (Addr == 0 && Size != 0)
801 return make_error<JITLinkError>(
802 StringRef(EHFrameSectionName) +
803 " section can not have zero address with non-zero size");
804 StoreFrameRange(Addr, Size);
805 return Error::success();
806 };
807
808 return RecordEHFrame;
809}
810
811} // end namespace jitlink
812} // end namespace llvm
813