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