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 545