comparison lib/ExecutionEngine/JITLink/EHFrameSupport.cpp @ 148:63bd29f05246

merged
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Wed, 14 Aug 2019 19:46:37 +0900
parents c2174574ed3a
children
comparison
equal deleted inserted replaced
146:3fc4d5c3e21e 148:63bd29f05246
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