blob: bf051474b2d8f01f030227d78a8314649167540c [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
10#include "JITLink_EHFrameSupportImpl.h"
11
12#include "llvm/BinaryFormat/Dwarf.h"
13
14#define DEBUG_TYPE "jitlink"
15
16namespace llvm {
17namespace jitlink {
18
19EHFrameParser::EHFrameParser(AtomGraph &G, Section &EHFrameSection,
20 StringRef EHFrameContent,
21 JITTargetAddress EHFrameAddress,
22 Edge::Kind FDEToCIERelocKind,
23 Edge::Kind FDEToTargetRelocKind)
24 : G(G), EHFrameSection(EHFrameSection), EHFrameContent(EHFrameContent),
25 EHFrameAddress(EHFrameAddress),
26 EHFrameReader(EHFrameContent, G.getEndianness()),
27 FDEToCIERelocKind(FDEToCIERelocKind),
28 FDEToTargetRelocKind(FDEToTargetRelocKind) {}
29
30Error EHFrameParser::atomize() {
31 while (!EHFrameReader.empty()) {
32 size_t RecordOffset = EHFrameReader.getOffset();
33
34 LLVM_DEBUG({
35 dbgs() << "Processing eh-frame record at "
36 << format("0x%016" PRIx64, EHFrameAddress + RecordOffset)
37 << " (offset " << RecordOffset << ")\n";
38 });
39
40 size_t CIELength = 0;
41 uint32_t CIELengthField;
42 if (auto Err = EHFrameReader.readInteger(CIELengthField))
43 return Err;
44
45 // Process CIE length/extended-length fields to build the atom.
46 //
47 // The value of these fields describe the length of the *rest* of the CIE
48 // (not including data up to the end of the field itself) so we have to
49 // bump CIELength to include the data up to the end of the field: 4 bytes
50 // for Length, or 12 bytes (4 bytes + 8 bytes) for ExtendedLength.
51 if (CIELengthField == 0) // Length 0 means end of __eh_frame section.
52 break;
53
54 // If the regular length field's value is 0xffffffff, use extended length.
55 if (CIELengthField == 0xffffffff) {
56 uint64_t CIEExtendedLengthField;
57 if (auto Err = EHFrameReader.readInteger(CIEExtendedLengthField))
58 return Err;
59 if (CIEExtendedLengthField > EHFrameReader.bytesRemaining())
60 return make_error<JITLinkError>("CIE record extends past the end of "
61 "the __eh_frame section");
62 if (CIEExtendedLengthField + 12 > std::numeric_limits<size_t>::max())
63 return make_error<JITLinkError>("CIE record too large to process");
64 CIELength = CIEExtendedLengthField + 12;
65 } else {
66 if (CIELengthField > EHFrameReader.bytesRemaining())
67 return make_error<JITLinkError>("CIE record extends past the end of "
68 "the __eh_frame section");
69 CIELength = CIELengthField + 4;
70 }
71
72 LLVM_DEBUG(dbgs() << " length: " << CIELength << "\n");
73
74 // Add an atom for this record.
75 CurRecordAtom = &G.addAnonymousAtom(
76 EHFrameSection, EHFrameAddress + RecordOffset, G.getPointerSize());
77 CurRecordAtom->setContent(EHFrameContent.substr(RecordOffset, CIELength));
78
79 // Read the CIE Pointer.
80 size_t CIEPointerAddress = EHFrameAddress + EHFrameReader.getOffset();
81 uint32_t CIEPointer;
82 if (auto Err = EHFrameReader.readInteger(CIEPointer))
83 return Err;
84
85 // Based on the CIE pointer value, parse this as a CIE or FDE record.
86 if (CIEPointer == 0) {
87 if (auto Err = processCIE())
88 return Err;
89 } else {
90 if (auto Err = processFDE(CIEPointerAddress, CIEPointer))
91 return Err;
92 }
93
94 EHFrameReader.setOffset(RecordOffset + CIELength);
95 }
96
97 return Error::success();
98}
99
100Expected<EHFrameParser::AugmentationInfo>
101EHFrameParser::parseAugmentationString() {
102 AugmentationInfo AugInfo;
103 uint8_t NextChar;
104 uint8_t *NextField = &AugInfo.Fields[0];
105
106 if (auto Err = EHFrameReader.readInteger(NextChar))
107 return std::move(Err);
108
109 while (NextChar != 0) {
110 switch (NextChar) {
111 case 'z':
112 AugInfo.AugmentationDataPresent = true;
113 break;
114 case 'e':
115 if (auto Err = EHFrameReader.readInteger(NextChar))
116 return std::move(Err);
117 if (NextChar != 'h')
118 return make_error<JITLinkError>("Unrecognized substring e" +
119 Twine(NextChar) +
120 " in augmentation string");
121 AugInfo.EHDataFieldPresent = true;
122 break;
123 case 'L':
124 case 'P':
125 case 'R':
126 *NextField++ = NextChar;
127 break;
128 default:
129 return make_error<JITLinkError>("Unrecognized character " +
130 Twine(NextChar) +
131 " in augmentation string");
132 }
133
134 if (auto Err = EHFrameReader.readInteger(NextChar))
135 return std::move(Err);
136 }
137
138 return std::move(AugInfo);
139}
140
141Expected<JITTargetAddress> EHFrameParser::readAbsolutePointer() {
142 static_assert(sizeof(JITTargetAddress) == sizeof(uint64_t),
143 "Result must be able to hold a uint64_t");
144 JITTargetAddress Addr;
145 if (G.getPointerSize() == 8) {
146 if (auto Err = EHFrameReader.readInteger(Addr))
147 return std::move(Err);
148 } else if (G.getPointerSize() == 4) {
149 uint32_t Addr32;
150 if (auto Err = EHFrameReader.readInteger(Addr32))
151 return std::move(Err);
152 Addr = Addr32;
153 } else
154 llvm_unreachable("Pointer size is not 32-bit or 64-bit");
155 return Addr;
156}
157
158Error EHFrameParser::processCIE() {
159 // Use the dwarf namespace for convenient access to pointer encoding
160 // constants.
161 using namespace dwarf;
162
163 LLVM_DEBUG(dbgs() << " Record is CIE\n");
164
165 /// Reset state for the new CIE.
166 MostRecentCIE = CurRecordAtom;
167 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
278 // Sanity check the CIE pointer: if this is an FDE it must be proceeded by
279 // a CIE.
280 if (MostRecentCIE == nullptr)
281 return make_error<JITLinkError>("__eh_frame must start with CIE, not "
282 "FDE");
283
284 LLVM_DEBUG({
285 dbgs() << " CIE pointer: "
286 << format("0x%016" PRIx64, CIEPointerAddress - CIEPointer) << "\n";
287 });
288
289 // Verify that this FDE's CIE pointer points to the most recent CIE entry.
290 if (CIEPointerAddress - CIEPointer != MostRecentCIE->getAddress())
291 return make_error<JITLinkError>("__eh_frame FDE's CIE Pointer does not "
292 "point at the most recent CIE");
293
294 // The CIEPointer looks good. Add a relocation.
295 CurRecordAtom->addEdge(FDEToCIERelocKind,
296 CIEPointerAddress - CurRecordAtom->getAddress(),
297 *MostRecentCIE, 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 (LSDAFieldPresent) {
340 uint64_t AugmentationDataSize;
341 if (auto Err = EHFrameReader.readULEB128(AugmentationDataSize))
342 return Err;
343 if (AugmentationDataSize != G.getPointerSize())
344 return make_error<JITLinkError>("Unexpected FDE augmentation data size "
345 "(expected " +
346 Twine(G.getPointerSize()) + ", got " +
347 Twine(AugmentationDataSize) + ")");
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
378Error 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(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__))
390#define HAVE_EHTABLE_SUPPORT 1
391#else
392#define HAVE_EHTABLE_SUPPORT 0
393#endif
394
395#if HAVE_EHTABLE_SUPPORT
396extern "C" void __register_frame(const void *);
397extern "C" void __deregister_frame(const void *);
398
399Error registerFrameWrapper(const void *P) {
400 __register_frame(P);
401 return Error::success();
402}
403
404Error deregisterFrameWrapper(const void *P) {
405 __deregister_frame(P);
406 return Error::success();
407}
408
409#else
410
411// The building compiler does not have __(de)register_frame but
412// it may be found at runtime in a dynamically-loaded library.
413// For example, this happens when building LLVM with Visual C++
414// but using the MingW runtime.
415static Error registerFrameWrapper(const void *P) {
416 static void((*RegisterFrame)(const void *)) = 0;
417
418 if (!RegisterFrame)
419 *(void **)&RegisterFrame =
420 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
421
422 if (RegisterFrame) {
423 RegisterFrame(P);
424 return Error::success();
425 }
426
427 return make_error<JITLinkError>("could not register eh-frame: "
428 "__register_frame function not found");
429}
430
431static void deregisterFrameWrapper(const void *P) {
432 static void((*DeregisterFrame)(const void *)) = 0;
433
434 if (!DeregisterFrame)
435 *(void **)&DeregisterFrame =
436 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
437 "__deregister_frame");
438
439 if (DeregisterFrame) {
440 DeregisterFrame(P);
441 return Error::success();
442 }
443
444 return make_error<JITLinkError>("could not deregister eh-frame: "
445 "__deregister_frame function not found");
446}
447#endif
448
449#ifdef __APPLE__
450
451template <typename HandleFDEFn>
452Error walkAppleEHFrameSection(const char *const SectionStart,
453 HandleFDEFn HandleFDE) {
454 const char *CurCFIRecord = SectionStart;
455 uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
456
457 while (Size != 0) {
458 const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
459 if (Size == 0xffffffff)
460 Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
461 else
462 Size += 4;
463 uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
464 if (Offset != 0)
465 if (auto Err = HandleFDE(CurCFIRecord))
466 return Err;
467
468 LLVM_DEBUG({
469 dbgs() << "Registering eh-frame section:\n";
470 dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
471 << (void *)CurCFIRecord << ": [";
472 for (unsigned I = 0; I < Size; ++I)
473 dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
474 dbgs() << " ]\n";
475 });
476 CurCFIRecord += Size;
477
478 Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
479 }
480
481 return Error::success();
482}
483
484#endif // __APPLE__
485
486Error registerEHFrameSection(const void *EHFrameSectionAddr) {
487#ifdef __APPLE__
488 // On Darwin __register_frame has to be called for each FDE entry.
489 return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
490 registerFrameWrapper);
491#else
492 // On Linux __register_frame takes a single argument:
493 // a pointer to the start of the .eh_frame section.
494
495 // How can it find the end? Because crtendS.o is linked
496 // in and it has an .eh_frame section with four zero chars.
497 return registerFrameWrapper(EHFrameSectionAddr);
498#endif
499}
500
501Error deregisterEHFrameSection(const void *EHFrameSectionAddr) {
502#ifdef __APPLE__
503 return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
504 deregisterFrameWrapper);
505#else
506 return deregisterFrameWrapper(EHFrameSectionAddr);
507#endif
508}
509
510AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT,
511 JITTargetAddress &EHFrameAddr) {
512 const char *EHFrameSectionName = nullptr;
513 if (TT.getObjectFormat() == Triple::MachO)
514 EHFrameSectionName = "__eh_frame";
515 else
516 EHFrameSectionName = ".eh_frame";
517
518 auto RecordEHFrame = [EHFrameSectionName,
519 &EHFrameAddr](AtomGraph &G) -> Error {
520 // Search for a non-empty eh-frame and record the address of the first atom
521 // in it.
522 JITTargetAddress Addr = 0;
523 for (auto &S : G.sections())
524 if (S.getName() == EHFrameSectionName && !S.atoms_empty()) {
525 Addr = (*S.atoms().begin())->getAddress();
526 break;
527 }
528
529 EHFrameAddr = Addr;
530 return Error::success();
531 };
532
533 return RecordEHFrame;
534}
535
536} // end namespace jitlink
537} // end namespace llvm