blob: 6517b3b0d0ceded61724f6612f1a8ca666766d97 [file] [log] [blame]
Lang Hames11c8dfa52019-04-20 17:10:34 +00001//===-------- 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
Lang Hames1233c152019-04-22 03:03:09 +000010#include "EHFrameSupportImpl.h"
Lang Hames11c8dfa52019-04-20 17:10:34 +000011
12#include "llvm/BinaryFormat/Dwarf.h"
Lang Hames68b0b8c2019-04-20 17:29:57 +000013#include "llvm/Support/DynamicLibrary.h"
Lang Hames11c8dfa52019-04-20 17:10:34 +000014
15#define DEBUG_TYPE "jitlink"
16
17namespace llvm {
18namespace jitlink {
19
20EHFrameParser::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
31Error 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
101Expected<EHFrameParser::AugmentationInfo>
102EHFrameParser::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
142Expected<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
159Error 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 /// Reset state for the new CIE.
Lang Hames11c8dfa52019-04-20 17:10:34 +0000167 LSDAFieldPresent = false;
168
169 uint8_t Version = 0;
170 if (auto Err = EHFrameReader.readInteger(Version))
171 return Err;
172
173 if (Version != 0x01)
174 return make_error<JITLinkError>("Bad CIE version " + Twine(Version) +
175 " (should be 0x01) in eh-frame");
176
177 auto AugInfo = parseAugmentationString();
178 if (!AugInfo)
179 return AugInfo.takeError();
180
181 // Skip the EH Data field if present.
182 if (AugInfo->EHDataFieldPresent)
183 if (auto Err = EHFrameReader.skip(G.getPointerSize()))
184 return Err;
185
186 // Read and sanity check the code alignment factor.
187 {
188 uint64_t CodeAlignmentFactor = 0;
189 if (auto Err = EHFrameReader.readULEB128(CodeAlignmentFactor))
190 return Err;
191 if (CodeAlignmentFactor != 1)
192 return make_error<JITLinkError>("Unsupported CIE code alignment factor " +
193 Twine(CodeAlignmentFactor) +
194 " (expected 1)");
195 }
196
197 // Read and sanity check the data alignment factor.
198 {
199 int64_t DataAlignmentFactor = 0;
200 if (auto Err = EHFrameReader.readSLEB128(DataAlignmentFactor))
201 return Err;
202 if (DataAlignmentFactor != -8)
203 return make_error<JITLinkError>("Unsupported CIE data alignment factor " +
204 Twine(DataAlignmentFactor) +
205 " (expected -8)");
206 }
207
208 // Skip the return address register field.
209 if (auto Err = EHFrameReader.skip(1))
210 return Err;
211
212 uint64_t AugmentationDataLength = 0;
213 if (auto Err = EHFrameReader.readULEB128(AugmentationDataLength))
214 return Err;
215
216 uint32_t AugmentationDataStartOffset = EHFrameReader.getOffset();
217
218 uint8_t *NextField = &AugInfo->Fields[0];
219 while (uint8_t Field = *NextField++) {
220 switch (Field) {
221 case 'L': {
222 LSDAFieldPresent = true;
223 uint8_t LSDAPointerEncoding;
224 if (auto Err = EHFrameReader.readInteger(LSDAPointerEncoding))
225 return Err;
226 if (LSDAPointerEncoding != (DW_EH_PE_pcrel | DW_EH_PE_absptr))
227 return make_error<JITLinkError>(
228 "Unsupported LSDA pointer encoding " +
229 formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " +
230 formatv("{0:x16}", CurRecordAtom->getAddress()));
231 break;
232 }
233 case 'P': {
234 uint8_t PersonalityPointerEncoding = 0;
235 if (auto Err = EHFrameReader.readInteger(PersonalityPointerEncoding))
236 return Err;
237 if (PersonalityPointerEncoding !=
238 (DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4))
239 return make_error<JITLinkError>(
240 "Unspported personality pointer "
241 "encoding " +
242 formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " +
243 formatv("{0:x16}", CurRecordAtom->getAddress()));
244 uint32_t PersonalityPointerAddress;
245 if (auto Err = EHFrameReader.readInteger(PersonalityPointerAddress))
246 return Err;
247 break;
248 }
249 case 'R': {
250 uint8_t FDEPointerEncoding;
251 if (auto Err = EHFrameReader.readInteger(FDEPointerEncoding))
252 return Err;
253 if (FDEPointerEncoding != (DW_EH_PE_pcrel | DW_EH_PE_absptr))
254 return make_error<JITLinkError>(
255 "Unsupported FDE address pointer "
256 "encoding " +
257 formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " +
258 formatv("{0:x16}", CurRecordAtom->getAddress()));
259 break;
260 }
261 default:
262 llvm_unreachable("Invalid augmentation string field");
263 }
264 }
265
266 if (EHFrameReader.getOffset() - AugmentationDataStartOffset >
267 AugmentationDataLength)
268 return make_error<JITLinkError>("Read past the end of the augmentation "
269 "data while parsing fields");
270
271 return Error::success();
272}
273
274Error EHFrameParser::processFDE(JITTargetAddress CIEPointerAddress,
275 uint32_t CIEPointer) {
276 LLVM_DEBUG(dbgs() << " Record is FDE\n");
277
Lang Hames11c8dfa52019-04-20 17:10:34 +0000278 LLVM_DEBUG({
279 dbgs() << " CIE pointer: "
280 << format("0x%016" PRIx64, CIEPointerAddress - CIEPointer) << "\n";
281 });
282
Lang Hamesa97032e2019-04-21 04:48:32 +0000283 auto CIEAtom = G.findAtomByAddress(CIEPointerAddress - CIEPointer);
284 if (!CIEAtom)
285 return CIEAtom.takeError();
Lang Hames11c8dfa52019-04-20 17:10:34 +0000286
287 // The CIEPointer looks good. Add a relocation.
288 CurRecordAtom->addEdge(FDEToCIERelocKind,
289 CIEPointerAddress - CurRecordAtom->getAddress(),
Lang Hamesa97032e2019-04-21 04:48:32 +0000290 *CIEAtom, 0);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000291
292 // Read and sanity check the PC-start pointer and size.
293 JITTargetAddress PCBeginAddress = EHFrameAddress + EHFrameReader.getOffset();
294
295 auto PCBeginDelta = readAbsolutePointer();
296 if (!PCBeginDelta)
297 return PCBeginDelta.takeError();
298
299 JITTargetAddress PCBegin = PCBeginAddress + *PCBeginDelta;
300 LLVM_DEBUG({
301 dbgs() << " PC begin: " << format("0x%016" PRIx64, PCBegin) << "\n";
302 });
303
304 auto *TargetAtom = G.getAtomByAddress(PCBegin);
305
306 if (!TargetAtom)
307 return make_error<JITLinkError>("FDE PC-begin " +
308 formatv("{0:x16}", PCBegin) +
309 " does not point at atom");
310
311 if (TargetAtom->getAddress() != PCBegin)
312 return make_error<JITLinkError>(
313 "FDE PC-begin " + formatv("{0:x16}", PCBegin) +
314 " does not point to start of atom at " +
315 formatv("{0:x16}", TargetAtom->getAddress()));
316
317 LLVM_DEBUG(dbgs() << " FDE target: " << *TargetAtom << "\n");
318
319 // The PC-start pointer and size look good. Add relocations.
320 CurRecordAtom->addEdge(FDEToTargetRelocKind,
321 PCBeginAddress - CurRecordAtom->getAddress(),
322 *TargetAtom, 0);
323
324 // Add a keep-alive relocation from the function to the FDE to ensure it is
325 // not dead stripped.
326 TargetAtom->addEdge(Edge::KeepAlive, 0, *CurRecordAtom, 0);
327
328 // Skip over the PC range size field.
329 if (auto Err = EHFrameReader.skip(G.getPointerSize()))
330 return Err;
331
332 if (LSDAFieldPresent) {
333 uint64_t AugmentationDataSize;
334 if (auto Err = EHFrameReader.readULEB128(AugmentationDataSize))
335 return Err;
336 if (AugmentationDataSize != G.getPointerSize())
337 return make_error<JITLinkError>("Unexpected FDE augmentation data size "
338 "(expected " +
339 Twine(G.getPointerSize()) + ", got " +
340 Twine(AugmentationDataSize) + ")");
341 JITTargetAddress LSDAAddress = EHFrameAddress + EHFrameReader.getOffset();
342 auto LSDADelta = readAbsolutePointer();
343 if (!LSDADelta)
344 return LSDADelta.takeError();
345
346 JITTargetAddress LSDA = LSDAAddress + *LSDADelta;
347
348 auto *LSDAAtom = G.getAtomByAddress(LSDA);
349
350 if (!LSDAAtom)
351 return make_error<JITLinkError>("FDE LSDA " + formatv("{0:x16}", LSDA) +
352 " does not point at atom");
353
354 if (LSDAAtom->getAddress() != LSDA)
355 return make_error<JITLinkError>(
356 "FDE LSDA " + formatv("{0:x16}", LSDA) +
357 " does not point to start of atom at " +
358 formatv("{0:x16}", LSDAAtom->getAddress()));
359
360 LLVM_DEBUG(dbgs() << " FDE LSDA: " << *LSDAAtom << "\n");
361
362 // LSDA looks good. Add relocations.
363 CurRecordAtom->addEdge(FDEToTargetRelocKind,
364 LSDAAddress - CurRecordAtom->getAddress(), *LSDAAtom,
365 0);
366 }
367
368 return Error::success();
369}
370
371Error addEHFrame(AtomGraph &G, Section &EHFrameSection,
372 StringRef EHFrameContent, JITTargetAddress EHFrameAddress,
373 Edge::Kind FDEToCIERelocKind,
374 Edge::Kind FDEToTargetRelocKind) {
375 return EHFrameParser(G, EHFrameSection, EHFrameContent, EHFrameAddress,
376 FDEToCIERelocKind, FDEToTargetRelocKind)
377 .atomize();
378}
379
380// Determine whether we can register EH tables.
381#if (defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__ia64__) && \
382 !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__))
383#define HAVE_EHTABLE_SUPPORT 1
384#else
385#define HAVE_EHTABLE_SUPPORT 0
386#endif
387
388#if HAVE_EHTABLE_SUPPORT
389extern "C" void __register_frame(const void *);
390extern "C" void __deregister_frame(const void *);
391
392Error registerFrameWrapper(const void *P) {
393 __register_frame(P);
394 return Error::success();
395}
396
397Error deregisterFrameWrapper(const void *P) {
398 __deregister_frame(P);
399 return Error::success();
400}
401
402#else
403
404// The building compiler does not have __(de)register_frame but
405// it may be found at runtime in a dynamically-loaded library.
406// For example, this happens when building LLVM with Visual C++
407// but using the MingW runtime.
408static Error registerFrameWrapper(const void *P) {
409 static void((*RegisterFrame)(const void *)) = 0;
410
411 if (!RegisterFrame)
412 *(void **)&RegisterFrame =
413 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
414
415 if (RegisterFrame) {
416 RegisterFrame(P);
417 return Error::success();
418 }
419
420 return make_error<JITLinkError>("could not register eh-frame: "
421 "__register_frame function not found");
422}
423
Lang Hames68b0b8c2019-04-20 17:29:57 +0000424static Error deregisterFrameWrapper(const void *P) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000425 static void((*DeregisterFrame)(const void *)) = 0;
426
427 if (!DeregisterFrame)
428 *(void **)&DeregisterFrame =
429 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
430 "__deregister_frame");
431
432 if (DeregisterFrame) {
433 DeregisterFrame(P);
434 return Error::success();
435 }
436
437 return make_error<JITLinkError>("could not deregister eh-frame: "
438 "__deregister_frame function not found");
439}
440#endif
441
442#ifdef __APPLE__
443
444template <typename HandleFDEFn>
445Error walkAppleEHFrameSection(const char *const SectionStart,
446 HandleFDEFn HandleFDE) {
447 const char *CurCFIRecord = SectionStart;
448 uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
449
450 while (Size != 0) {
451 const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
452 if (Size == 0xffffffff)
453 Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
454 else
455 Size += 4;
456 uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
457 if (Offset != 0)
458 if (auto Err = HandleFDE(CurCFIRecord))
459 return Err;
460
461 LLVM_DEBUG({
462 dbgs() << "Registering eh-frame section:\n";
463 dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
464 << (void *)CurCFIRecord << ": [";
465 for (unsigned I = 0; I < Size; ++I)
466 dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
467 dbgs() << " ]\n";
468 });
469 CurCFIRecord += Size;
470
471 Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
472 }
473
474 return Error::success();
475}
476
477#endif // __APPLE__
478
479Error registerEHFrameSection(const void *EHFrameSectionAddr) {
480#ifdef __APPLE__
481 // On Darwin __register_frame has to be called for each FDE entry.
482 return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
483 registerFrameWrapper);
484#else
485 // On Linux __register_frame takes a single argument:
486 // a pointer to the start of the .eh_frame section.
487
488 // How can it find the end? Because crtendS.o is linked
489 // in and it has an .eh_frame section with four zero chars.
490 return registerFrameWrapper(EHFrameSectionAddr);
491#endif
492}
493
494Error deregisterEHFrameSection(const void *EHFrameSectionAddr) {
495#ifdef __APPLE__
496 return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
497 deregisterFrameWrapper);
498#else
499 return deregisterFrameWrapper(EHFrameSectionAddr);
500#endif
501}
502
503AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT,
504 JITTargetAddress &EHFrameAddr) {
505 const char *EHFrameSectionName = nullptr;
506 if (TT.getObjectFormat() == Triple::MachO)
507 EHFrameSectionName = "__eh_frame";
508 else
509 EHFrameSectionName = ".eh_frame";
510
511 auto RecordEHFrame = [EHFrameSectionName,
512 &EHFrameAddr](AtomGraph &G) -> Error {
513 // Search for a non-empty eh-frame and record the address of the first atom
514 // in it.
515 JITTargetAddress Addr = 0;
516 for (auto &S : G.sections())
517 if (S.getName() == EHFrameSectionName && !S.atoms_empty()) {
518 Addr = (*S.atoms().begin())->getAddress();
Lang Hamesd3dac472019-04-22 01:35:16 +0000519 for (auto *DA : S.atoms())
520 if (DA->getAddress() < Addr)
521 Addr = DA->getAddress();
Lang Hames11c8dfa52019-04-20 17:10:34 +0000522 break;
523 }
524
525 EHFrameAddr = Addr;
526 return Error::success();
527 };
528
529 return RecordEHFrame;
530}
531
532} // end namespace jitlink
533} // end namespace llvm