xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp (revision a7dea1671b87c07d2d266f836bfa8b58efc7c134)
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/Support/DynamicLibrary.h"
14 
15 #define DEBUG_TYPE "jitlink"
16 
17 namespace llvm {
18 namespace jitlink {
19 
20 EHFrameBinaryParser::EHFrameBinaryParser(JITTargetAddress EHFrameAddress,
21                                          StringRef EHFrameContent,
22                                          unsigned PointerSize,
23                                          support::endianness Endianness)
24     : EHFrameAddress(EHFrameAddress), EHFrameContent(EHFrameContent),
25       PointerSize(PointerSize), EHFrameReader(EHFrameContent, Endianness) {}
26 
27 Error EHFrameBinaryParser::addToGraph() {
28   while (!EHFrameReader.empty()) {
29     size_t RecordOffset = EHFrameReader.getOffset();
30 
31     LLVM_DEBUG({
32       dbgs() << "Processing eh-frame record at "
33              << format("0x%016" PRIx64, EHFrameAddress + RecordOffset)
34              << " (offset " << RecordOffset << ")\n";
35     });
36 
37     size_t RecordLength = 0;
38     uint32_t RecordLengthField;
39     if (auto Err = EHFrameReader.readInteger(RecordLengthField))
40       return Err;
41 
42     // Process CIE/FDE length/extended-length fields to build the blocks.
43     //
44     // The value of these fields describe the length of the *rest* of the CIE
45     // (not including data up to the end of the field itself) so we have to
46     // bump RecordLength to include the data up to the end of the field: 4 bytes
47     // for Length, or 12 bytes (4 bytes + 8 bytes) for ExtendedLength.
48     if (RecordLengthField == 0) // Length 0 means end of __eh_frame section.
49       break;
50 
51     // If the regular length field's value is 0xffffffff, use extended length.
52     if (RecordLengthField == 0xffffffff) {
53       uint64_t ExtendedLengthField;
54       if (auto Err = EHFrameReader.readInteger(ExtendedLengthField))
55         return Err;
56       if (ExtendedLengthField > EHFrameReader.bytesRemaining())
57         return make_error<JITLinkError>("CIE record extends past the end of "
58                                         "the __eh_frame section");
59       if (ExtendedLengthField + 12 > std::numeric_limits<size_t>::max())
60         return make_error<JITLinkError>("CIE record too large to process");
61       RecordLength = ExtendedLengthField + 12;
62     } else {
63       if (RecordLengthField > EHFrameReader.bytesRemaining())
64         return make_error<JITLinkError>("CIE record extends past the end of "
65                                         "the __eh_frame section");
66       RecordLength = RecordLengthField + 4;
67     }
68 
69     LLVM_DEBUG(dbgs() << "  length: " << RecordLength << "\n");
70 
71     // Read the CIE Pointer.
72     size_t CIEPointerAddress = EHFrameAddress + EHFrameReader.getOffset();
73     uint32_t CIEPointer;
74     if (auto Err = EHFrameReader.readInteger(CIEPointer))
75       return Err;
76 
77     // Based on the CIE pointer value, parse this as a CIE or FDE record.
78     if (CIEPointer == 0) {
79       if (auto Err = processCIE(RecordOffset, RecordLength))
80         return Err;
81     } else {
82       if (auto Err = processFDE(RecordOffset, RecordLength, CIEPointerAddress,
83                                 CIEPointer))
84         return Err;
85     }
86 
87     EHFrameReader.setOffset(RecordOffset + RecordLength);
88   }
89 
90   return Error::success();
91 }
92 
93 void EHFrameBinaryParser::anchor() {}
94 
95 Expected<EHFrameBinaryParser::AugmentationInfo>
96 EHFrameBinaryParser::parseAugmentationString() {
97   AugmentationInfo AugInfo;
98   uint8_t NextChar;
99   uint8_t *NextField = &AugInfo.Fields[0];
100 
101   if (auto Err = EHFrameReader.readInteger(NextChar))
102     return std::move(Err);
103 
104   while (NextChar != 0) {
105     switch (NextChar) {
106     case 'z':
107       AugInfo.AugmentationDataPresent = true;
108       break;
109     case 'e':
110       if (auto Err = EHFrameReader.readInteger(NextChar))
111         return std::move(Err);
112       if (NextChar != 'h')
113         return make_error<JITLinkError>("Unrecognized substring e" +
114                                         Twine(NextChar) +
115                                         " in augmentation string");
116       AugInfo.EHDataFieldPresent = true;
117       break;
118     case 'L':
119     case 'P':
120     case 'R':
121       *NextField++ = NextChar;
122       break;
123     default:
124       return make_error<JITLinkError>("Unrecognized character " +
125                                       Twine(NextChar) +
126                                       " in augmentation string");
127     }
128 
129     if (auto Err = EHFrameReader.readInteger(NextChar))
130       return std::move(Err);
131   }
132 
133   return std::move(AugInfo);
134 }
135 
136 Expected<JITTargetAddress> EHFrameBinaryParser::readAbsolutePointer() {
137   static_assert(sizeof(JITTargetAddress) == sizeof(uint64_t),
138                 "Result must be able to hold a uint64_t");
139   JITTargetAddress Addr;
140   if (PointerSize == 8) {
141     if (auto Err = EHFrameReader.readInteger(Addr))
142       return std::move(Err);
143   } else if (PointerSize == 4) {
144     uint32_t Addr32;
145     if (auto Err = EHFrameReader.readInteger(Addr32))
146       return std::move(Err);
147     Addr = Addr32;
148   } else
149     llvm_unreachable("Pointer size is not 32-bit or 64-bit");
150   return Addr;
151 }
152 
153 Error EHFrameBinaryParser::processCIE(size_t RecordOffset,
154                                       size_t RecordLength) {
155   // Use the dwarf namespace for convenient access to pointer encoding
156   // constants.
157   using namespace dwarf;
158 
159   LLVM_DEBUG(dbgs() << "  Record is CIE\n");
160 
161   auto &CIESymbol =
162       createCIERecord(EHFrameAddress + RecordOffset,
163                       EHFrameContent.substr(RecordOffset, RecordLength));
164 
165   CIEInformation CIEInfo(CIESymbol);
166 
167   uint8_t Version = 0;
168   if (auto Err = EHFrameReader.readInteger(Version))
169     return Err;
170 
171   if (Version != 0x01)
172     return make_error<JITLinkError>("Bad CIE version " + Twine(Version) +
173                                     " (should be 0x01) in eh-frame");
174 
175   auto AugInfo = parseAugmentationString();
176   if (!AugInfo)
177     return AugInfo.takeError();
178 
179   // Skip the EH Data field if present.
180   if (AugInfo->EHDataFieldPresent)
181     if (auto Err = EHFrameReader.skip(PointerSize))
182       return Err;
183 
184   // Read and sanity check the code alignment factor.
185   {
186     uint64_t CodeAlignmentFactor = 0;
187     if (auto Err = EHFrameReader.readULEB128(CodeAlignmentFactor))
188       return Err;
189     if (CodeAlignmentFactor != 1)
190       return make_error<JITLinkError>("Unsupported CIE code alignment factor " +
191                                       Twine(CodeAlignmentFactor) +
192                                       " (expected 1)");
193   }
194 
195   // Read and sanity check the data alignment factor.
196   {
197     int64_t DataAlignmentFactor = 0;
198     if (auto Err = EHFrameReader.readSLEB128(DataAlignmentFactor))
199       return Err;
200     if (DataAlignmentFactor != -8)
201       return make_error<JITLinkError>("Unsupported CIE data alignment factor " +
202                                       Twine(DataAlignmentFactor) +
203                                       " (expected -8)");
204   }
205 
206   // Skip the return address register field.
207   if (auto Err = EHFrameReader.skip(1))
208     return Err;
209 
210   uint64_t AugmentationDataLength = 0;
211   if (auto Err = EHFrameReader.readULEB128(AugmentationDataLength))
212     return Err;
213 
214   uint32_t AugmentationDataStartOffset = EHFrameReader.getOffset();
215 
216   uint8_t *NextField = &AugInfo->Fields[0];
217   while (uint8_t Field = *NextField++) {
218     switch (Field) {
219     case 'L': {
220       CIEInfo.FDEsHaveLSDAField = true;
221       uint8_t LSDAPointerEncoding;
222       if (auto Err = EHFrameReader.readInteger(LSDAPointerEncoding))
223         return Err;
224       if (LSDAPointerEncoding != (DW_EH_PE_pcrel | DW_EH_PE_absptr))
225         return make_error<JITLinkError>(
226             "Unsupported LSDA pointer encoding " +
227             formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " +
228             formatv("{0:x16}", CIESymbol.getAddress()));
229       break;
230     }
231     case 'P': {
232       uint8_t PersonalityPointerEncoding = 0;
233       if (auto Err = EHFrameReader.readInteger(PersonalityPointerEncoding))
234         return Err;
235       if (PersonalityPointerEncoding !=
236           (DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4))
237         return make_error<JITLinkError>(
238             "Unspported personality pointer "
239             "encoding " +
240             formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " +
241             formatv("{0:x16}", CIESymbol.getAddress()));
242       uint32_t PersonalityPointerAddress;
243       if (auto Err = EHFrameReader.readInteger(PersonalityPointerAddress))
244         return Err;
245       break;
246     }
247     case 'R': {
248       uint8_t FDEPointerEncoding;
249       if (auto Err = EHFrameReader.readInteger(FDEPointerEncoding))
250         return Err;
251       if (FDEPointerEncoding != (DW_EH_PE_pcrel | DW_EH_PE_absptr))
252         return make_error<JITLinkError>(
253             "Unsupported FDE address pointer "
254             "encoding " +
255             formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " +
256             formatv("{0:x16}", CIESymbol.getAddress()));
257       break;
258     }
259     default:
260       llvm_unreachable("Invalid augmentation string field");
261     }
262   }
263 
264   if (EHFrameReader.getOffset() - AugmentationDataStartOffset >
265       AugmentationDataLength)
266     return make_error<JITLinkError>("Read past the end of the augmentation "
267                                     "data while parsing fields");
268 
269   assert(!CIEInfos.count(CIESymbol.getAddress()) &&
270          "Multiple CIEs recorded at the same address?");
271   CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
272 
273   return Error::success();
274 }
275 
276 Error EHFrameBinaryParser::processFDE(size_t RecordOffset, size_t RecordLength,
277                                       JITTargetAddress CIEPointerAddress,
278                                       uint32_t CIEPointer) {
279   LLVM_DEBUG(dbgs() << "  Record is FDE\n");
280 
281   LLVM_DEBUG({
282     dbgs() << "  CIE pointer: "
283            << format("0x%016" PRIx64, CIEPointerAddress - CIEPointer) << "\n";
284   });
285 
286   auto CIEInfoItr = CIEInfos.find(CIEPointerAddress - CIEPointer);
287   if (CIEInfoItr == CIEInfos.end())
288     return make_error<JITLinkError>(
289         "FDE at " + formatv("{0:x16}", EHFrameAddress + RecordOffset) +
290         " points to non-existant CIE at " +
291         formatv("{0:x16}", CIEPointerAddress - CIEPointer));
292   auto &CIEInfo = CIEInfoItr->second;
293 
294   // Read and sanity check the PC-start pointer and size.
295   JITTargetAddress PCBeginAddress = EHFrameAddress + EHFrameReader.getOffset();
296 
297   auto PCBeginDelta = readAbsolutePointer();
298   if (!PCBeginDelta)
299     return PCBeginDelta.takeError();
300 
301   JITTargetAddress PCBegin = PCBeginAddress + *PCBeginDelta;
302   LLVM_DEBUG({
303     dbgs() << "    PC begin: " << format("0x%016" PRIx64, PCBegin) << "\n";
304   });
305 
306   auto *TargetSymbol = getSymbolAtAddress(PCBegin);
307 
308   if (!TargetSymbol)
309     return make_error<JITLinkError>("FDE PC-begin " +
310                                     formatv("{0:x16}", PCBegin) +
311                                     " does not point at symbol");
312 
313   if (TargetSymbol->getAddress() != PCBegin)
314     return make_error<JITLinkError>(
315         "FDE PC-begin " + formatv("{0:x16}", PCBegin) +
316         " does not point to start of symbol at " +
317         formatv("{0:x16}", TargetSymbol->getAddress()));
318 
319   LLVM_DEBUG(dbgs() << "  FDE target: " << *TargetSymbol << "\n");
320 
321   // Skip over the PC range size field.
322   if (auto Err = EHFrameReader.skip(PointerSize))
323     return Err;
324 
325   Symbol *LSDASymbol = nullptr;
326   JITTargetAddress LSDAAddress = 0;
327   if (CIEInfo.FDEsHaveLSDAField) {
328     uint64_t AugmentationDataSize;
329     if (auto Err = EHFrameReader.readULEB128(AugmentationDataSize))
330       return Err;
331     if (AugmentationDataSize != PointerSize)
332       return make_error<JITLinkError>(
333           "Unexpected FDE augmentation data size (expected " +
334           Twine(PointerSize) + ", got " + Twine(AugmentationDataSize) +
335           ") for FDE at " + formatv("{0:x16}", EHFrameAddress + RecordOffset));
336     LSDAAddress = EHFrameAddress + EHFrameReader.getOffset();
337     auto LSDADelta = readAbsolutePointer();
338     if (!LSDADelta)
339       return LSDADelta.takeError();
340 
341     JITTargetAddress LSDA = LSDAAddress + *LSDADelta;
342 
343     LSDASymbol = getSymbolAtAddress(LSDA);
344 
345     if (!LSDASymbol)
346       return make_error<JITLinkError>("FDE LSDA " + formatv("{0:x16}", LSDA) +
347                                       " does not point at symbol");
348 
349     if (LSDASymbol->getAddress() != LSDA)
350       return make_error<JITLinkError>(
351           "FDE LSDA " + formatv("{0:x16}", LSDA) +
352           " does not point to start of symbol at " +
353           formatv("{0:x16}", LSDASymbol->getAddress()));
354 
355     LLVM_DEBUG(dbgs() << "  FDE LSDA: " << *LSDASymbol << "\n");
356   }
357 
358   JITTargetAddress RecordAddress = EHFrameAddress + RecordOffset;
359   auto FDESymbol = createFDERecord(
360       RecordAddress, EHFrameContent.substr(RecordOffset, RecordLength),
361       *CIEInfo.CIESymbol, CIEPointerAddress - RecordAddress, *TargetSymbol,
362       PCBeginAddress - RecordAddress, LSDASymbol, LSDAAddress - RecordAddress);
363 
364   return FDESymbol.takeError();
365 }
366 
367 // Determine whether we can register EH tables.
368 #if (defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__ia64__) &&      \
369      !(defined(_AIX) && defined(__ibmxl__)) && !defined(__SEH__) &&            \
370      !defined(__USING_SJLJ_EXCEPTIONS__))
371 #define HAVE_EHTABLE_SUPPORT 1
372 #else
373 #define HAVE_EHTABLE_SUPPORT 0
374 #endif
375 
376 #if HAVE_EHTABLE_SUPPORT
377 extern "C" void __register_frame(const void *);
378 extern "C" void __deregister_frame(const void *);
379 
380 Error registerFrameWrapper(const void *P) {
381   __register_frame(P);
382   return Error::success();
383 }
384 
385 Error deregisterFrameWrapper(const void *P) {
386   __deregister_frame(P);
387   return Error::success();
388 }
389 
390 #else
391 
392 // The building compiler does not have __(de)register_frame but
393 // it may be found at runtime in a dynamically-loaded library.
394 // For example, this happens when building LLVM with Visual C++
395 // but using the MingW runtime.
396 static Error registerFrameWrapper(const void *P) {
397   static void((*RegisterFrame)(const void *)) = 0;
398 
399   if (!RegisterFrame)
400     *(void **)&RegisterFrame =
401         llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
402 
403   if (RegisterFrame) {
404     RegisterFrame(P);
405     return Error::success();
406   }
407 
408   return make_error<JITLinkError>("could not register eh-frame: "
409                                   "__register_frame function not found");
410 }
411 
412 static Error deregisterFrameWrapper(const void *P) {
413   static void((*DeregisterFrame)(const void *)) = 0;
414 
415   if (!DeregisterFrame)
416     *(void **)&DeregisterFrame =
417         llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
418             "__deregister_frame");
419 
420   if (DeregisterFrame) {
421     DeregisterFrame(P);
422     return Error::success();
423   }
424 
425   return make_error<JITLinkError>("could not deregister eh-frame: "
426                                   "__deregister_frame function not found");
427 }
428 #endif
429 
430 #ifdef __APPLE__
431 
432 template <typename HandleFDEFn>
433 Error walkAppleEHFrameSection(const char *const SectionStart,
434                               size_t SectionSize,
435                               HandleFDEFn HandleFDE) {
436   const char *CurCFIRecord = SectionStart;
437   const char *End = SectionStart + SectionSize;
438   uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
439 
440   while (CurCFIRecord != End && Size != 0) {
441     const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
442     if (Size == 0xffffffff)
443       Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
444     else
445       Size += 4;
446     uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
447     if (Offset != 0)
448       if (auto Err = HandleFDE(CurCFIRecord))
449         return Err;
450 
451     LLVM_DEBUG({
452       dbgs() << "Registering eh-frame section:\n";
453       dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
454              << (void *)CurCFIRecord << ": [";
455       for (unsigned I = 0; I < Size; ++I)
456         dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
457       dbgs() << " ]\n";
458     });
459     CurCFIRecord += Size;
460 
461     Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
462   }
463 
464   return Error::success();
465 }
466 
467 #endif // __APPLE__
468 
469 Error registerEHFrameSection(const void *EHFrameSectionAddr,
470                              size_t EHFrameSectionSize) {
471 #ifdef __APPLE__
472   // On Darwin __register_frame has to be called for each FDE entry.
473   return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
474                                  EHFrameSectionSize,
475                                  registerFrameWrapper);
476 #else
477   // On Linux __register_frame takes a single argument:
478   // a pointer to the start of the .eh_frame section.
479 
480   // How can it find the end? Because crtendS.o is linked
481   // in and it has an .eh_frame section with four zero chars.
482   return registerFrameWrapper(EHFrameSectionAddr);
483 #endif
484 }
485 
486 Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
487                                size_t EHFrameSectionSize) {
488 #ifdef __APPLE__
489   return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
490                                  EHFrameSectionSize,
491                                  deregisterFrameWrapper);
492 #else
493   return deregisterFrameWrapper(EHFrameSectionAddr);
494 #endif
495 }
496 
497 EHFrameRegistrar::~EHFrameRegistrar() {}
498 
499 InProcessEHFrameRegistrar &InProcessEHFrameRegistrar::getInstance() {
500   static InProcessEHFrameRegistrar Instance;
501   return Instance;
502 }
503 
504 InProcessEHFrameRegistrar::InProcessEHFrameRegistrar() {}
505 
506 LinkGraphPassFunction
507 createEHFrameRecorderPass(const Triple &TT,
508                           StoreFrameRangeFunction StoreRangeAddress) {
509   const char *EHFrameSectionName = nullptr;
510   if (TT.getObjectFormat() == Triple::MachO)
511     EHFrameSectionName = "__eh_frame";
512   else
513     EHFrameSectionName = ".eh_frame";
514 
515   auto RecordEHFrame =
516       [EHFrameSectionName,
517        StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error {
518     // Search for a non-empty eh-frame and record the address of the first
519     // symbol in it.
520     JITTargetAddress Addr = 0;
521     size_t Size = 0;
522     if (auto *S = G.findSectionByName(EHFrameSectionName)) {
523       auto R = SectionRange(*S);
524       Addr = R.getStart();
525       Size = R.getSize();
526     }
527     if (Addr == 0 && Size != 0)
528       return make_error<JITLinkError>("__eh_frame section can not have zero "
529                                       "address with non-zero size");
530     StoreFrameRange(Addr, Size);
531     return Error::success();
532   };
533 
534   return RecordEHFrame;
535 }
536 
537 } // end namespace jitlink
538 } // end namespace llvm
539