Mercurial > hg > CbC > CbC_llvm
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 |