blob: 355a000bb9821a70a3e58bf732a95b8e14dffef5 [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
Lang Hames4e920e52019-10-04 03:55:26 +000020EHFrameBinaryParser::EHFrameBinaryParser(JITTargetAddress EHFrameAddress,
21 StringRef EHFrameContent,
22 unsigned PointerSize,
23 support::endianness Endianness)
24 : EHFrameAddress(EHFrameAddress), EHFrameContent(EHFrameContent),
25 PointerSize(PointerSize), EHFrameReader(EHFrameContent, Endianness) {}
Lang Hames11c8dfa52019-04-20 17:10:34 +000026
Lang Hames4e920e52019-10-04 03:55:26 +000027Error EHFrameBinaryParser::addToGraph() {
Lang Hames11c8dfa52019-04-20 17:10:34 +000028 while (!EHFrameReader.empty()) {
29 size_t RecordOffset = EHFrameReader.getOffset();
Lang Hames4e920e52019-10-04 03:55:26 +000030 JITTargetAddress RecordAddress = EHFrameAddress + RecordOffset;
Lang Hames11c8dfa52019-04-20 17:10:34 +000031
32 LLVM_DEBUG({
33 dbgs() << "Processing eh-frame record at "
Lang Hames4e920e52019-10-04 03:55:26 +000034 << format("0x%016" PRIx64, RecordAddress) << " (offset "
35 << RecordOffset << ")\n";
Lang Hames11c8dfa52019-04-20 17:10:34 +000036 });
37
Lang Hames4e920e52019-10-04 03:55:26 +000038 size_t RecordLength = 0;
39 uint32_t RecordLengthField;
40 if (auto Err = EHFrameReader.readInteger(RecordLengthField))
Lang Hames11c8dfa52019-04-20 17:10:34 +000041 return Err;
42
Lang Hames4e920e52019-10-04 03:55:26 +000043 // Process CIE/FDE length/extended-length fields to build the blocks.
Lang Hames11c8dfa52019-04-20 17:10:34 +000044 //
45 // The value of these fields describe the length of the *rest* of the CIE
46 // (not including data up to the end of the field itself) so we have to
Lang Hames4e920e52019-10-04 03:55:26 +000047 // bump RecordLength to include the data up to the end of the field: 4 bytes
Lang Hames11c8dfa52019-04-20 17:10:34 +000048 // for Length, or 12 bytes (4 bytes + 8 bytes) for ExtendedLength.
Lang Hames4e920e52019-10-04 03:55:26 +000049 if (RecordLengthField == 0) // Length 0 means end of __eh_frame section.
Lang Hames11c8dfa52019-04-20 17:10:34 +000050 break;
51
52 // If the regular length field's value is 0xffffffff, use extended length.
Lang Hames4e920e52019-10-04 03:55:26 +000053 if (RecordLengthField == 0xffffffff) {
54 uint64_t ExtendedLengthField;
55 if (auto Err = EHFrameReader.readInteger(ExtendedLengthField))
Lang Hames11c8dfa52019-04-20 17:10:34 +000056 return Err;
Lang Hames4e920e52019-10-04 03:55:26 +000057 if (ExtendedLengthField > EHFrameReader.bytesRemaining())
Lang Hames11c8dfa52019-04-20 17:10:34 +000058 return make_error<JITLinkError>("CIE record extends past the end of "
59 "the __eh_frame section");
Lang Hames4e920e52019-10-04 03:55:26 +000060 if (ExtendedLengthField + 12 > std::numeric_limits<size_t>::max())
Lang Hames11c8dfa52019-04-20 17:10:34 +000061 return make_error<JITLinkError>("CIE record too large to process");
Lang Hames4e920e52019-10-04 03:55:26 +000062 RecordLength = ExtendedLengthField + 12;
Lang Hames11c8dfa52019-04-20 17:10:34 +000063 } else {
Lang Hames4e920e52019-10-04 03:55:26 +000064 if (RecordLengthField > EHFrameReader.bytesRemaining())
Lang Hames11c8dfa52019-04-20 17:10:34 +000065 return make_error<JITLinkError>("CIE record extends past the end of "
66 "the __eh_frame section");
Lang Hames4e920e52019-10-04 03:55:26 +000067 RecordLength = RecordLengthField + 4;
Lang Hames11c8dfa52019-04-20 17:10:34 +000068 }
69
Lang Hames4e920e52019-10-04 03:55:26 +000070 LLVM_DEBUG(dbgs() << " length: " << RecordLength << "\n");
Lang Hames11c8dfa52019-04-20 17:10:34 +000071
72 // Read the CIE Pointer.
73 size_t CIEPointerAddress = EHFrameAddress + EHFrameReader.getOffset();
74 uint32_t CIEPointer;
75 if (auto Err = EHFrameReader.readInteger(CIEPointer))
76 return Err;
77
78 // Based on the CIE pointer value, parse this as a CIE or FDE record.
79 if (CIEPointer == 0) {
Lang Hames4e920e52019-10-04 03:55:26 +000080 if (auto Err = processCIE(RecordOffset, RecordLength))
Lang Hames11c8dfa52019-04-20 17:10:34 +000081 return Err;
82 } else {
Lang Hames4e920e52019-10-04 03:55:26 +000083 if (auto Err = processFDE(RecordOffset, RecordLength, CIEPointerAddress,
84 CIEPointer))
Lang Hames11c8dfa52019-04-20 17:10:34 +000085 return Err;
86 }
87
Lang Hames4e920e52019-10-04 03:55:26 +000088 EHFrameReader.setOffset(RecordOffset + RecordLength);
Lang Hames11c8dfa52019-04-20 17:10:34 +000089 }
90
91 return Error::success();
92}
93
Lang Hames4e920e52019-10-04 03:55:26 +000094void EHFrameBinaryParser::anchor() {}
95
96Expected<EHFrameBinaryParser::AugmentationInfo>
97EHFrameBinaryParser::parseAugmentationString() {
Lang Hames11c8dfa52019-04-20 17:10:34 +000098 AugmentationInfo AugInfo;
99 uint8_t NextChar;
100 uint8_t *NextField = &AugInfo.Fields[0];
101
102 if (auto Err = EHFrameReader.readInteger(NextChar))
103 return std::move(Err);
104
105 while (NextChar != 0) {
106 switch (NextChar) {
107 case 'z':
108 AugInfo.AugmentationDataPresent = true;
109 break;
110 case 'e':
111 if (auto Err = EHFrameReader.readInteger(NextChar))
112 return std::move(Err);
113 if (NextChar != 'h')
114 return make_error<JITLinkError>("Unrecognized substring e" +
115 Twine(NextChar) +
116 " in augmentation string");
117 AugInfo.EHDataFieldPresent = true;
118 break;
119 case 'L':
120 case 'P':
121 case 'R':
122 *NextField++ = NextChar;
123 break;
124 default:
125 return make_error<JITLinkError>("Unrecognized character " +
126 Twine(NextChar) +
127 " in augmentation string");
128 }
129
130 if (auto Err = EHFrameReader.readInteger(NextChar))
131 return std::move(Err);
132 }
133
134 return std::move(AugInfo);
135}
136
Lang Hames4e920e52019-10-04 03:55:26 +0000137Expected<JITTargetAddress> EHFrameBinaryParser::readAbsolutePointer() {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000138 static_assert(sizeof(JITTargetAddress) == sizeof(uint64_t),
139 "Result must be able to hold a uint64_t");
140 JITTargetAddress Addr;
Lang Hames4e920e52019-10-04 03:55:26 +0000141 if (PointerSize == 8) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000142 if (auto Err = EHFrameReader.readInteger(Addr))
143 return std::move(Err);
Lang Hames4e920e52019-10-04 03:55:26 +0000144 } else if (PointerSize == 4) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000145 uint32_t Addr32;
146 if (auto Err = EHFrameReader.readInteger(Addr32))
147 return std::move(Err);
148 Addr = Addr32;
149 } else
150 llvm_unreachable("Pointer size is not 32-bit or 64-bit");
151 return Addr;
152}
153
Lang Hames4e920e52019-10-04 03:55:26 +0000154Error EHFrameBinaryParser::processCIE(size_t RecordOffset,
155 size_t RecordLength) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000156 // Use the dwarf namespace for convenient access to pointer encoding
157 // constants.
158 using namespace dwarf;
159
160 LLVM_DEBUG(dbgs() << " Record is CIE\n");
161
Lang Hames4e920e52019-10-04 03:55:26 +0000162 auto &CIESymbol =
163 createCIERecord(EHFrameAddress + RecordOffset,
164 EHFrameContent.substr(RecordOffset, RecordLength));
165
166 CIEInformation CIEInfo(CIESymbol);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000167
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)
Lang Hames4e920e52019-10-04 03:55:26 +0000182 if (auto Err = EHFrameReader.skip(PointerSize))
Lang Hames11c8dfa52019-04-20 17:10:34 +0000183 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': {
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000221 CIEInfo.FDEsHaveLSDAField = true;
Lang Hames11c8dfa52019-04-20 17:10:34 +0000222 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 " +
Lang Hames4e920e52019-10-04 03:55:26 +0000229 formatv("{0:x16}", CIESymbol.getAddress()));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000230 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 " +
Lang Hames4e920e52019-10-04 03:55:26 +0000242 formatv("{0:x16}", CIESymbol.getAddress()));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000243 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 " +
Lang Hames4e920e52019-10-04 03:55:26 +0000257 formatv("{0:x16}", CIESymbol.getAddress()));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000258 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
Lang Hames4e920e52019-10-04 03:55:26 +0000270 assert(!CIEInfos.count(CIESymbol.getAddress()) &&
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000271 "Multiple CIEs recorded at the same address?");
Lang Hames4e920e52019-10-04 03:55:26 +0000272 CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000273
Lang Hames11c8dfa52019-04-20 17:10:34 +0000274 return Error::success();
275}
276
Lang Hames4e920e52019-10-04 03:55:26 +0000277Error EHFrameBinaryParser::processFDE(size_t RecordOffset, size_t RecordLength,
278 JITTargetAddress CIEPointerAddress,
279 uint32_t CIEPointer) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000280 LLVM_DEBUG(dbgs() << " Record is FDE\n");
281
Lang Hames11c8dfa52019-04-20 17:10:34 +0000282 LLVM_DEBUG({
283 dbgs() << " CIE pointer: "
284 << format("0x%016" PRIx64, CIEPointerAddress - CIEPointer) << "\n";
285 });
286
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000287 auto CIEInfoItr = CIEInfos.find(CIEPointerAddress - CIEPointer);
288 if (CIEInfoItr == CIEInfos.end())
289 return make_error<JITLinkError>(
Lang Hames4e920e52019-10-04 03:55:26 +0000290 "FDE at " + formatv("{0:x16}", EHFrameAddress + RecordOffset) +
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000291 " points to non-existant CIE at " +
292 formatv("{0:x16}", CIEPointerAddress - CIEPointer));
293 auto &CIEInfo = CIEInfoItr->second;
Lang Hames11c8dfa52019-04-20 17:10:34 +0000294
Lang Hames11c8dfa52019-04-20 17:10:34 +0000295 // Read and sanity check the PC-start pointer and size.
296 JITTargetAddress PCBeginAddress = EHFrameAddress + EHFrameReader.getOffset();
297
298 auto PCBeginDelta = readAbsolutePointer();
299 if (!PCBeginDelta)
300 return PCBeginDelta.takeError();
301
302 JITTargetAddress PCBegin = PCBeginAddress + *PCBeginDelta;
303 LLVM_DEBUG({
Lang Hames4e920e52019-10-04 03:55:26 +0000304 dbgs() << " PC begin: " << format("0x%016" PRIx64, PCBegin) << "\n";
Lang Hames11c8dfa52019-04-20 17:10:34 +0000305 });
306
Lang Hames4e920e52019-10-04 03:55:26 +0000307 auto *TargetSymbol = getSymbolAtAddress(PCBegin);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000308
Lang Hames4e920e52019-10-04 03:55:26 +0000309 if (!TargetSymbol)
Lang Hames11c8dfa52019-04-20 17:10:34 +0000310 return make_error<JITLinkError>("FDE PC-begin " +
311 formatv("{0:x16}", PCBegin) +
Lang Hames4e920e52019-10-04 03:55:26 +0000312 " does not point at symbol");
Lang Hames11c8dfa52019-04-20 17:10:34 +0000313
Lang Hames4e920e52019-10-04 03:55:26 +0000314 if (TargetSymbol->getAddress() != PCBegin)
Lang Hames11c8dfa52019-04-20 17:10:34 +0000315 return make_error<JITLinkError>(
316 "FDE PC-begin " + formatv("{0:x16}", PCBegin) +
Lang Hames4e920e52019-10-04 03:55:26 +0000317 " does not point to start of symbol at " +
318 formatv("{0:x16}", TargetSymbol->getAddress()));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000319
Lang Hames4e920e52019-10-04 03:55:26 +0000320 LLVM_DEBUG(dbgs() << " FDE target: " << *TargetSymbol << "\n");
Lang Hames11c8dfa52019-04-20 17:10:34 +0000321
322 // Skip over the PC range size field.
Lang Hames4e920e52019-10-04 03:55:26 +0000323 if (auto Err = EHFrameReader.skip(PointerSize))
Lang Hames11c8dfa52019-04-20 17:10:34 +0000324 return Err;
325
Lang Hames4e920e52019-10-04 03:55:26 +0000326 Symbol *LSDASymbol = nullptr;
327 JITTargetAddress LSDAAddress = 0;
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000328 if (CIEInfo.FDEsHaveLSDAField) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000329 uint64_t AugmentationDataSize;
330 if (auto Err = EHFrameReader.readULEB128(AugmentationDataSize))
331 return Err;
Lang Hames4e920e52019-10-04 03:55:26 +0000332 if (AugmentationDataSize != PointerSize)
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000333 return make_error<JITLinkError>(
334 "Unexpected FDE augmentation data size (expected " +
Lang Hames4e920e52019-10-04 03:55:26 +0000335 Twine(PointerSize) + ", got " + Twine(AugmentationDataSize) +
336 ") for FDE at " + formatv("{0:x16}", EHFrameAddress + RecordOffset));
337 LSDAAddress = EHFrameAddress + EHFrameReader.getOffset();
Lang Hames11c8dfa52019-04-20 17:10:34 +0000338 auto LSDADelta = readAbsolutePointer();
339 if (!LSDADelta)
340 return LSDADelta.takeError();
341
342 JITTargetAddress LSDA = LSDAAddress + *LSDADelta;
343
Lang Hames4e920e52019-10-04 03:55:26 +0000344 LSDASymbol = getSymbolAtAddress(LSDA);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000345
Lang Hames4e920e52019-10-04 03:55:26 +0000346 if (!LSDASymbol)
Lang Hames11c8dfa52019-04-20 17:10:34 +0000347 return make_error<JITLinkError>("FDE LSDA " + formatv("{0:x16}", LSDA) +
Lang Hames4e920e52019-10-04 03:55:26 +0000348 " does not point at symbol");
Lang Hames11c8dfa52019-04-20 17:10:34 +0000349
Lang Hames4e920e52019-10-04 03:55:26 +0000350 if (LSDASymbol->getAddress() != LSDA)
Lang Hames11c8dfa52019-04-20 17:10:34 +0000351 return make_error<JITLinkError>(
352 "FDE LSDA " + formatv("{0:x16}", LSDA) +
Lang Hames4e920e52019-10-04 03:55:26 +0000353 " does not point to start of symbol at " +
354 formatv("{0:x16}", LSDASymbol->getAddress()));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000355
Lang Hames4e920e52019-10-04 03:55:26 +0000356 LLVM_DEBUG(dbgs() << " FDE LSDA: " << *LSDASymbol << "\n");
Lang Hames11c8dfa52019-04-20 17:10:34 +0000357 }
358
Lang Hames4e920e52019-10-04 03:55:26 +0000359 JITTargetAddress RecordAddress = EHFrameAddress + RecordOffset;
360 auto FDESymbol = createFDERecord(
361 RecordAddress, EHFrameContent.substr(RecordOffset, RecordLength),
362 *CIEInfo.CIESymbol, CIEPointerAddress - RecordAddress, *TargetSymbol,
363 PCBeginAddress - RecordAddress, LSDASymbol, LSDAAddress - RecordAddress);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000364
Lang Hames4e920e52019-10-04 03:55:26 +0000365 return FDESymbol.takeError();
Lang Hames11c8dfa52019-04-20 17:10:34 +0000366}
367
368// Determine whether we can register EH tables.
369#if (defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__ia64__) && \
Xing Xue4246b752019-05-22 17:41:27 +0000370 !(defined(_AIX) && defined(__ibmxl__)) && !defined(__SEH__) && \
371 !defined(__USING_SJLJ_EXCEPTIONS__))
Lang Hames11c8dfa52019-04-20 17:10:34 +0000372#define HAVE_EHTABLE_SUPPORT 1
373#else
374#define HAVE_EHTABLE_SUPPORT 0
375#endif
376
377#if HAVE_EHTABLE_SUPPORT
378extern "C" void __register_frame(const void *);
379extern "C" void __deregister_frame(const void *);
380
381Error registerFrameWrapper(const void *P) {
382 __register_frame(P);
383 return Error::success();
384}
385
386Error deregisterFrameWrapper(const void *P) {
387 __deregister_frame(P);
388 return Error::success();
389}
390
391#else
392
393// The building compiler does not have __(de)register_frame but
394// it may be found at runtime in a dynamically-loaded library.
395// For example, this happens when building LLVM with Visual C++
396// but using the MingW runtime.
397static Error registerFrameWrapper(const void *P) {
398 static void((*RegisterFrame)(const void *)) = 0;
399
400 if (!RegisterFrame)
401 *(void **)&RegisterFrame =
402 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
403
404 if (RegisterFrame) {
405 RegisterFrame(P);
406 return Error::success();
407 }
408
409 return make_error<JITLinkError>("could not register eh-frame: "
410 "__register_frame function not found");
411}
412
Lang Hames68b0b8c2019-04-20 17:29:57 +0000413static Error deregisterFrameWrapper(const void *P) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000414 static void((*DeregisterFrame)(const void *)) = 0;
415
416 if (!DeregisterFrame)
417 *(void **)&DeregisterFrame =
418 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
419 "__deregister_frame");
420
421 if (DeregisterFrame) {
422 DeregisterFrame(P);
423 return Error::success();
424 }
425
426 return make_error<JITLinkError>("could not deregister eh-frame: "
427 "__deregister_frame function not found");
428}
429#endif
430
431#ifdef __APPLE__
432
433template <typename HandleFDEFn>
434Error walkAppleEHFrameSection(const char *const SectionStart,
Lang Hamesc48f1f62019-08-27 15:50:32 +0000435 size_t SectionSize,
Lang Hames11c8dfa52019-04-20 17:10:34 +0000436 HandleFDEFn HandleFDE) {
437 const char *CurCFIRecord = SectionStart;
Lang Hamesc48f1f62019-08-27 15:50:32 +0000438 const char *End = SectionStart + SectionSize;
Lang Hames11c8dfa52019-04-20 17:10:34 +0000439 uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
440
Lang Hamesc48f1f62019-08-27 15:50:32 +0000441 while (CurCFIRecord != End && Size != 0) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000442 const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
443 if (Size == 0xffffffff)
444 Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
445 else
446 Size += 4;
447 uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
448 if (Offset != 0)
449 if (auto Err = HandleFDE(CurCFIRecord))
450 return Err;
451
452 LLVM_DEBUG({
453 dbgs() << "Registering eh-frame section:\n";
454 dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
455 << (void *)CurCFIRecord << ": [";
456 for (unsigned I = 0; I < Size; ++I)
457 dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
458 dbgs() << " ]\n";
459 });
460 CurCFIRecord += Size;
461
462 Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
463 }
464
465 return Error::success();
466}
467
468#endif // __APPLE__
469
Lang Hamesc48f1f62019-08-27 15:50:32 +0000470Error registerEHFrameSection(const void *EHFrameSectionAddr,
471 size_t EHFrameSectionSize) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000472#ifdef __APPLE__
473 // On Darwin __register_frame has to be called for each FDE entry.
474 return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
Lang Hamesc48f1f62019-08-27 15:50:32 +0000475 EHFrameSectionSize,
Lang Hames11c8dfa52019-04-20 17:10:34 +0000476 registerFrameWrapper);
477#else
478 // On Linux __register_frame takes a single argument:
479 // a pointer to the start of the .eh_frame section.
480
481 // How can it find the end? Because crtendS.o is linked
482 // in and it has an .eh_frame section with four zero chars.
483 return registerFrameWrapper(EHFrameSectionAddr);
484#endif
485}
486
Lang Hamesc48f1f62019-08-27 15:50:32 +0000487Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
488 size_t EHFrameSectionSize) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000489#ifdef __APPLE__
490 return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
Lang Hamesc48f1f62019-08-27 15:50:32 +0000491 EHFrameSectionSize,
Lang Hames11c8dfa52019-04-20 17:10:34 +0000492 deregisterFrameWrapper);
493#else
494 return deregisterFrameWrapper(EHFrameSectionAddr);
495#endif
496}
497
Lang Hamesf5a885f2019-07-04 00:05:12 +0000498EHFrameRegistrar::~EHFrameRegistrar() {}
499
500InProcessEHFrameRegistrar &InProcessEHFrameRegistrar::getInstance() {
501 static InProcessEHFrameRegistrar Instance;
502 return Instance;
503}
504
505InProcessEHFrameRegistrar::InProcessEHFrameRegistrar() {}
506
Lang Hames4e920e52019-10-04 03:55:26 +0000507LinkGraphPassFunction
Lang Hamesa9fdf372019-04-26 22:58:39 +0000508createEHFrameRecorderPass(const Triple &TT,
Lang Hamesc48f1f62019-08-27 15:50:32 +0000509 StoreFrameRangeFunction StoreRangeAddress) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000510 const char *EHFrameSectionName = nullptr;
511 if (TT.getObjectFormat() == Triple::MachO)
512 EHFrameSectionName = "__eh_frame";
513 else
514 EHFrameSectionName = ".eh_frame";
515
Lang Hamesc48f1f62019-08-27 15:50:32 +0000516 auto RecordEHFrame =
Lang Hames4e920e52019-10-04 03:55:26 +0000517 [EHFrameSectionName,
518 StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error {
519 // Search for a non-empty eh-frame and record the address of the first
520 // symbol in it.
Lang Hames11c8dfa52019-04-20 17:10:34 +0000521 JITTargetAddress Addr = 0;
Lang Hamesc48f1f62019-08-27 15:50:32 +0000522 size_t Size = 0;
523 if (auto *S = G.findSectionByName(EHFrameSectionName)) {
Lang Hames4e920e52019-10-04 03:55:26 +0000524 auto R = SectionRange(*S);
Lang Hamesc48f1f62019-08-27 15:50:32 +0000525 Addr = R.getStart();
526 Size = R.getSize();
527 }
528 if (Addr == 0 && Size != 0)
529 return make_error<JITLinkError>("__eh_frame section can not have zero "
530 "address with non-zero size");
531 StoreFrameRange(Addr, Size);
Lang Hames11c8dfa52019-04-20 17:10:34 +0000532 return Error::success();
533 };
534
535 return RecordEHFrame;
536}
537
538} // end namespace jitlink
539} // end namespace llvm