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 /// Reset state for the new CIE. 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 274 Error EHFrameParser::processFDE(JITTargetAddress CIEPointerAddress, 275 uint32_t CIEPointer) { 276 LLVM_DEBUG(dbgs() << " Record is FDE\n"); 277 278 LLVM_DEBUG({ 279 dbgs() << " CIE pointer: " 280 << format("0x%016" PRIx64, CIEPointerAddress - CIEPointer) << "\n"; 281 }); 282 283 auto CIEAtom = G.findAtomByAddress(CIEPointerAddress - CIEPointer); 284 if (!CIEAtom) 285 return CIEAtom.takeError(); 286 287 // The CIEPointer looks good. Add a relocation. 288 CurRecordAtom->addEdge(FDEToCIERelocKind, 289 CIEPointerAddress - CurRecordAtom->getAddress(), 290 *CIEAtom, 0); 291 292 // Read and sanity check the PC-start pointer and size. 293 JITTargetAddress PCBeginAddress = EHFrameAddress + EHFrameReader.getOffset(); 294 295 auto PCBeginDelta = readAbsolutePointer(); 296 if (!PCBeginDelta) 297 return PCBeginDelta.takeError(); 298 299 JITTargetAddress PCBegin = PCBeginAddress + *PCBeginDelta; 300 LLVM_DEBUG({ 301 dbgs() << " PC begin: " << format("0x%016" PRIx64, PCBegin) << "\n"; 302 }); 303 304 auto *TargetAtom = G.getAtomByAddress(PCBegin); 305 306 if (!TargetAtom) 307 return make_error<JITLinkError>("FDE PC-begin " + 308 formatv("{0:x16}", PCBegin) + 309 " does not point at atom"); 310 311 if (TargetAtom->getAddress() != PCBegin) 312 return make_error<JITLinkError>( 313 "FDE PC-begin " + formatv("{0:x16}", PCBegin) + 314 " does not point to start of atom at " + 315 formatv("{0:x16}", TargetAtom->getAddress())); 316 317 LLVM_DEBUG(dbgs() << " FDE target: " << *TargetAtom << "\n"); 318 319 // The PC-start pointer and size look good. Add relocations. 320 CurRecordAtom->addEdge(FDEToTargetRelocKind, 321 PCBeginAddress - CurRecordAtom->getAddress(), 322 *TargetAtom, 0); 323 324 // Add a keep-alive relocation from the function to the FDE to ensure it is 325 // not dead stripped. 326 TargetAtom->addEdge(Edge::KeepAlive, 0, *CurRecordAtom, 0); 327 328 // Skip over the PC range size field. 329 if (auto Err = EHFrameReader.skip(G.getPointerSize())) 330 return Err; 331 332 if (LSDAFieldPresent) { 333 uint64_t AugmentationDataSize; 334 if (auto Err = EHFrameReader.readULEB128(AugmentationDataSize)) 335 return Err; 336 if (AugmentationDataSize != G.getPointerSize()) 337 return make_error<JITLinkError>("Unexpected FDE augmentation data size " 338 "(expected " + 339 Twine(G.getPointerSize()) + ", got " + 340 Twine(AugmentationDataSize) + ")"); 341 JITTargetAddress LSDAAddress = EHFrameAddress + EHFrameReader.getOffset(); 342 auto LSDADelta = readAbsolutePointer(); 343 if (!LSDADelta) 344 return LSDADelta.takeError(); 345 346 JITTargetAddress LSDA = LSDAAddress + *LSDADelta; 347 348 auto *LSDAAtom = G.getAtomByAddress(LSDA); 349 350 if (!LSDAAtom) 351 return make_error<JITLinkError>("FDE LSDA " + formatv("{0:x16}", LSDA) + 352 " does not point at atom"); 353 354 if (LSDAAtom->getAddress() != LSDA) 355 return make_error<JITLinkError>( 356 "FDE LSDA " + formatv("{0:x16}", LSDA) + 357 " does not point to start of atom at " + 358 formatv("{0:x16}", LSDAAtom->getAddress())); 359 360 LLVM_DEBUG(dbgs() << " FDE LSDA: " << *LSDAAtom << "\n"); 361 362 // LSDA looks good. Add relocations. 363 CurRecordAtom->addEdge(FDEToTargetRelocKind, 364 LSDAAddress - CurRecordAtom->getAddress(), *LSDAAtom, 365 0); 366 } 367 368 return Error::success(); 369 } 370 371 Error addEHFrame(AtomGraph &G, Section &EHFrameSection, 372 StringRef EHFrameContent, JITTargetAddress EHFrameAddress, 373 Edge::Kind FDEToCIERelocKind, 374 Edge::Kind FDEToTargetRelocKind) { 375 return EHFrameParser(G, EHFrameSection, EHFrameContent, EHFrameAddress, 376 FDEToCIERelocKind, FDEToTargetRelocKind) 377 .atomize(); 378 } 379 380 // Determine whether we can register EH tables. 381 #if (defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__ia64__) && \ 382 !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)) 383 #define HAVE_EHTABLE_SUPPORT 1 384 #else 385 #define HAVE_EHTABLE_SUPPORT 0 386 #endif 387 388 #if HAVE_EHTABLE_SUPPORT 389 extern "C" void __register_frame(const void *); 390 extern "C" void __deregister_frame(const void *); 391 392 Error registerFrameWrapper(const void *P) { 393 __register_frame(P); 394 return Error::success(); 395 } 396 397 Error deregisterFrameWrapper(const void *P) { 398 __deregister_frame(P); 399 return Error::success(); 400 } 401 402 #else 403 404 // The building compiler does not have __(de)register_frame but 405 // it may be found at runtime in a dynamically-loaded library. 406 // For example, this happens when building LLVM with Visual C++ 407 // but using the MingW runtime. 408 static Error registerFrameWrapper(const void *P) { 409 static void((*RegisterFrame)(const void *)) = 0; 410 411 if (!RegisterFrame) 412 *(void **)&RegisterFrame = 413 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame"); 414 415 if (RegisterFrame) { 416 RegisterFrame(P); 417 return Error::success(); 418 } 419 420 return make_error<JITLinkError>("could not register eh-frame: " 421 "__register_frame function not found"); 422 } 423 424 static Error deregisterFrameWrapper(const void *P) { 425 static void((*DeregisterFrame)(const void *)) = 0; 426 427 if (!DeregisterFrame) 428 *(void **)&DeregisterFrame = 429 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol( 430 "__deregister_frame"); 431 432 if (DeregisterFrame) { 433 DeregisterFrame(P); 434 return Error::success(); 435 } 436 437 return make_error<JITLinkError>("could not deregister eh-frame: " 438 "__deregister_frame function not found"); 439 } 440 #endif 441 442 #ifdef __APPLE__ 443 444 template <typename HandleFDEFn> 445 Error walkAppleEHFrameSection(const char *const SectionStart, 446 HandleFDEFn HandleFDE) { 447 const char *CurCFIRecord = SectionStart; 448 uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord); 449 450 while (Size != 0) { 451 const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4); 452 if (Size == 0xffffffff) 453 Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12; 454 else 455 Size += 4; 456 uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField); 457 if (Offset != 0) 458 if (auto Err = HandleFDE(CurCFIRecord)) 459 return Err; 460 461 LLVM_DEBUG({ 462 dbgs() << "Registering eh-frame section:\n"; 463 dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @" 464 << (void *)CurCFIRecord << ": ["; 465 for (unsigned I = 0; I < Size; ++I) 466 dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I)); 467 dbgs() << " ]\n"; 468 }); 469 CurCFIRecord += Size; 470 471 Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord); 472 } 473 474 return Error::success(); 475 } 476 477 #endif // __APPLE__ 478 479 Error registerEHFrameSection(const void *EHFrameSectionAddr) { 480 #ifdef __APPLE__ 481 // On Darwin __register_frame has to be called for each FDE entry. 482 return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr), 483 registerFrameWrapper); 484 #else 485 // On Linux __register_frame takes a single argument: 486 // a pointer to the start of the .eh_frame section. 487 488 // How can it find the end? Because crtendS.o is linked 489 // in and it has an .eh_frame section with four zero chars. 490 return registerFrameWrapper(EHFrameSectionAddr); 491 #endif 492 } 493 494 Error deregisterEHFrameSection(const void *EHFrameSectionAddr) { 495 #ifdef __APPLE__ 496 return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr), 497 deregisterFrameWrapper); 498 #else 499 return deregisterFrameWrapper(EHFrameSectionAddr); 500 #endif 501 } 502 503 AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT, 504 JITTargetAddress &EHFrameAddr) { 505 const char *EHFrameSectionName = nullptr; 506 if (TT.getObjectFormat() == Triple::MachO) 507 EHFrameSectionName = "__eh_frame"; 508 else 509 EHFrameSectionName = ".eh_frame"; 510 511 auto RecordEHFrame = [EHFrameSectionName, 512 &EHFrameAddr](AtomGraph &G) -> Error { 513 // Search for a non-empty eh-frame and record the address of the first atom 514 // in it. 515 JITTargetAddress Addr = 0; 516 for (auto &S : G.sections()) 517 if (S.getName() == EHFrameSectionName && !S.atoms_empty()) { 518 Addr = (*S.atoms().begin())->getAddress(); 519 for (auto *DA : S.atoms()) 520 if (DA->getAddress() < Addr) 521 Addr = DA->getAddress(); 522 break; 523 } 524 525 EHFrameAddr = Addr; 526 return Error::success(); 527 }; 528 529 return RecordEHFrame; 530 } 531 532 } // end namespace jitlink 533 } // end namespace llvm 534