1 //===------- DebugObjectManagerPlugin.cpp - JITLink debug objects ---------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // FIXME: Update Plugin to poke the debug object into a new JITLink section, 10 // rather than creating a new allocation. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" 15 16 #include "llvm/ADT/ArrayRef.h" 17 #include "llvm/ADT/StringMap.h" 18 #include "llvm/ADT/StringRef.h" 19 #include "llvm/BinaryFormat/ELF.h" 20 #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h" 21 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" 22 #include "llvm/ExecutionEngine/JITSymbol.h" 23 #include "llvm/Object/ELFObjectFile.h" 24 #include "llvm/Object/ObjectFile.h" 25 #include "llvm/Support/Errc.h" 26 #include "llvm/Support/MSVCErrorWorkarounds.h" 27 #include "llvm/Support/MemoryBuffer.h" 28 #include "llvm/Support/Process.h" 29 #include "llvm/Support/raw_ostream.h" 30 31 #include <set> 32 33 #define DEBUG_TYPE "orc" 34 35 using namespace llvm::jitlink; 36 using namespace llvm::object; 37 38 namespace llvm { 39 namespace orc { 40 41 class DebugObjectSection { 42 public: 43 virtual void setTargetMemoryRange(SectionRange Range) = 0; 44 virtual void dump(raw_ostream &OS, StringRef Name) {} 45 virtual ~DebugObjectSection() = default; 46 }; 47 48 template <typename ELFT> 49 class ELFDebugObjectSection : public DebugObjectSection { 50 public: 51 // BinaryFormat ELF is not meant as a mutable format. We can only make changes 52 // that don't invalidate the file structure. 53 ELFDebugObjectSection(const typename ELFT::Shdr *Header) 54 : Header(const_cast<typename ELFT::Shdr *>(Header)) {} 55 56 void setTargetMemoryRange(SectionRange Range) override; 57 void dump(raw_ostream &OS, StringRef Name) override; 58 59 Error validateInBounds(StringRef Buffer, const char *Name) const; 60 61 private: 62 typename ELFT::Shdr *Header; 63 64 bool isTextOrDataSection() const; 65 }; 66 67 template <typename ELFT> 68 void ELFDebugObjectSection<ELFT>::setTargetMemoryRange(SectionRange Range) { 69 // All recorded sections are candidates for load-address patching. 70 Header->sh_addr = 71 static_cast<typename ELFT::uint>(Range.getStart().getValue()); 72 } 73 74 template <typename ELFT> 75 Error ELFDebugObjectSection<ELFT>::validateInBounds(StringRef Buffer, 76 const char *Name) const { 77 const uint8_t *Start = Buffer.bytes_begin(); 78 const uint8_t *End = Buffer.bytes_end(); 79 const uint8_t *HeaderPtr = reinterpret_cast<uint8_t *>(Header); 80 if (HeaderPtr < Start || HeaderPtr + sizeof(typename ELFT::Shdr) > End) 81 return make_error<StringError>( 82 formatv("{0} section header at {1:x16} not within bounds of the " 83 "given debug object buffer [{2:x16} - {3:x16}]", 84 Name, &Header->sh_addr, Start, End), 85 inconvertibleErrorCode()); 86 if (Header->sh_offset + Header->sh_size > Buffer.size()) 87 return make_error<StringError>( 88 formatv("{0} section data [{1:x16} - {2:x16}] not within bounds of " 89 "the given debug object buffer [{3:x16} - {4:x16}]", 90 Name, Start + Header->sh_offset, 91 Start + Header->sh_offset + Header->sh_size, Start, End), 92 inconvertibleErrorCode()); 93 return Error::success(); 94 } 95 96 template <typename ELFT> 97 void ELFDebugObjectSection<ELFT>::dump(raw_ostream &OS, StringRef Name) { 98 if (Header->sh_addr) { 99 OS << formatv(" {0:x16} {1}\n", Header->sh_addr, Name); 100 } else { 101 OS << formatv(" {0}\n", Name); 102 } 103 } 104 105 enum DebugObjectFlags : int { 106 // Request final target memory load-addresses for all sections. 107 ReportFinalSectionLoadAddresses = 1 << 0, 108 109 // We found sections with debug information when processing the input object. 110 HasDebugSections = 1 << 1, 111 }; 112 113 /// The plugin creates a debug object from when JITLink starts processing the 114 /// corresponding LinkGraph. It provides access to the pass configuration of 115 /// the LinkGraph and calls the finalization function, once the resulting link 116 /// artifact was emitted. 117 /// 118 class DebugObject { 119 public: 120 DebugObject(JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD, 121 ExecutionSession &ES) 122 : MemMgr(MemMgr), JD(JD), ES(ES), Flags(DebugObjectFlags{}) {} 123 124 bool hasFlags(DebugObjectFlags F) const { return Flags & F; } 125 void setFlags(DebugObjectFlags F) { 126 Flags = static_cast<DebugObjectFlags>(Flags | F); 127 } 128 void clearFlags(DebugObjectFlags F) { 129 Flags = static_cast<DebugObjectFlags>(Flags & ~F); 130 } 131 132 using FinalizeContinuation = std::function<void(Expected<ExecutorAddrRange>)>; 133 134 void finalizeAsync(FinalizeContinuation OnFinalize); 135 136 virtual ~DebugObject() { 137 if (Alloc) { 138 std::vector<FinalizedAlloc> Allocs; 139 Allocs.push_back(std::move(Alloc)); 140 if (Error Err = MemMgr.deallocate(std::move(Allocs))) 141 ES.reportError(std::move(Err)); 142 } 143 } 144 145 virtual void reportSectionTargetMemoryRange(StringRef Name, 146 SectionRange TargetMem) {} 147 148 protected: 149 using InFlightAlloc = JITLinkMemoryManager::InFlightAlloc; 150 using FinalizedAlloc = JITLinkMemoryManager::FinalizedAlloc; 151 152 virtual Expected<SimpleSegmentAlloc> finalizeWorkingMemory() = 0; 153 154 JITLinkMemoryManager &MemMgr; 155 const JITLinkDylib *JD = nullptr; 156 157 private: 158 ExecutionSession &ES; 159 DebugObjectFlags Flags; 160 FinalizedAlloc Alloc; 161 }; 162 163 // Finalize working memory and take ownership of the resulting allocation. Start 164 // copying memory over to the target and pass on the result once we're done. 165 // Ownership of the allocation remains with us for the rest of our lifetime. 166 void DebugObject::finalizeAsync(FinalizeContinuation OnFinalize) { 167 assert(!Alloc && "Cannot finalize more than once"); 168 169 if (auto SimpleSegAlloc = finalizeWorkingMemory()) { 170 auto ROSeg = SimpleSegAlloc->getSegInfo(MemProt::Read); 171 ExecutorAddrRange DebugObjRange(ExecutorAddr(ROSeg.Addr), 172 ExecutorAddrDiff(ROSeg.WorkingMem.size())); 173 SimpleSegAlloc->finalize( 174 [this, DebugObjRange, 175 OnFinalize = std::move(OnFinalize)](Expected<FinalizedAlloc> FA) { 176 if (FA) { 177 Alloc = std::move(*FA); 178 OnFinalize(DebugObjRange); 179 } else 180 OnFinalize(FA.takeError()); 181 }); 182 } else 183 OnFinalize(SimpleSegAlloc.takeError()); 184 } 185 186 /// The current implementation of ELFDebugObject replicates the approach used in 187 /// RuntimeDyld: It patches executable and data section headers in the given 188 /// object buffer with load-addresses of their corresponding sections in target 189 /// memory. 190 /// 191 class ELFDebugObject : public DebugObject { 192 public: 193 static Expected<std::unique_ptr<DebugObject>> 194 Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, ExecutionSession &ES); 195 196 void reportSectionTargetMemoryRange(StringRef Name, 197 SectionRange TargetMem) override; 198 199 StringRef getBuffer() const { return Buffer->getMemBufferRef().getBuffer(); } 200 201 protected: 202 Expected<SimpleSegmentAlloc> finalizeWorkingMemory() override; 203 204 template <typename ELFT> 205 Error recordSection(StringRef Name, 206 std::unique_ptr<ELFDebugObjectSection<ELFT>> Section); 207 DebugObjectSection *getSection(StringRef Name); 208 209 private: 210 template <typename ELFT> 211 static Expected<std::unique_ptr<ELFDebugObject>> 212 CreateArchType(MemoryBufferRef Buffer, JITLinkMemoryManager &MemMgr, 213 const JITLinkDylib *JD, ExecutionSession &ES); 214 215 static std::unique_ptr<WritableMemoryBuffer> 216 CopyBuffer(MemoryBufferRef Buffer, Error &Err); 217 218 ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer, 219 JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD, 220 ExecutionSession &ES) 221 : DebugObject(MemMgr, JD, ES), Buffer(std::move(Buffer)) { 222 setFlags(ReportFinalSectionLoadAddresses); 223 } 224 225 std::unique_ptr<WritableMemoryBuffer> Buffer; 226 StringMap<std::unique_ptr<DebugObjectSection>> Sections; 227 }; 228 229 static const std::set<StringRef> DwarfSectionNames = { 230 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \ 231 ELF_NAME, 232 #include "llvm/BinaryFormat/Dwarf.def" 233 #undef HANDLE_DWARF_SECTION 234 }; 235 236 static bool isDwarfSection(StringRef SectionName) { 237 return DwarfSectionNames.count(SectionName) == 1; 238 } 239 240 std::unique_ptr<WritableMemoryBuffer> 241 ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer, Error &Err) { 242 ErrorAsOutParameter _(&Err); 243 size_t Size = Buffer.getBufferSize(); 244 StringRef Name = Buffer.getBufferIdentifier(); 245 if (auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(Size, Name)) { 246 memcpy(Copy->getBufferStart(), Buffer.getBufferStart(), Size); 247 return Copy; 248 } 249 250 Err = errorCodeToError(make_error_code(errc::not_enough_memory)); 251 return nullptr; 252 } 253 254 template <typename ELFT> 255 Expected<std::unique_ptr<ELFDebugObject>> 256 ELFDebugObject::CreateArchType(MemoryBufferRef Buffer, 257 JITLinkMemoryManager &MemMgr, 258 const JITLinkDylib *JD, ExecutionSession &ES) { 259 using SectionHeader = typename ELFT::Shdr; 260 261 Error Err = Error::success(); 262 std::unique_ptr<ELFDebugObject> DebugObj( 263 new ELFDebugObject(CopyBuffer(Buffer, Err), MemMgr, JD, ES)); 264 if (Err) 265 return std::move(Err); 266 267 Expected<ELFFile<ELFT>> ObjRef = ELFFile<ELFT>::create(DebugObj->getBuffer()); 268 if (!ObjRef) 269 return ObjRef.takeError(); 270 271 // TODO: Add support for other architectures. 272 uint16_t TargetMachineArch = ObjRef->getHeader().e_machine; 273 if (TargetMachineArch != ELF::EM_X86_64) 274 return nullptr; 275 276 Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections(); 277 if (!Sections) 278 return Sections.takeError(); 279 280 for (const SectionHeader &Header : *Sections) { 281 Expected<StringRef> Name = ObjRef->getSectionName(Header); 282 if (!Name) 283 return Name.takeError(); 284 if (Name->empty()) 285 continue; 286 if (isDwarfSection(*Name)) 287 DebugObj->setFlags(HasDebugSections); 288 289 // Only record text and data sections (i.e. no bss, comments, rel, etc.) 290 if (Header.sh_type != ELF::SHT_PROGBITS && 291 Header.sh_type != ELF::SHT_X86_64_UNWIND) 292 continue; 293 if (!(Header.sh_flags & ELF::SHF_ALLOC)) 294 continue; 295 296 auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header); 297 if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped))) 298 return std::move(Err); 299 } 300 301 return std::move(DebugObj); 302 } 303 304 Expected<std::unique_ptr<DebugObject>> 305 ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, 306 ExecutionSession &ES) { 307 unsigned char Class, Endian; 308 std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer()); 309 310 if (Class == ELF::ELFCLASS32) { 311 if (Endian == ELF::ELFDATA2LSB) 312 return CreateArchType<ELF32LE>(Buffer, Ctx.getMemoryManager(), 313 Ctx.getJITLinkDylib(), ES); 314 if (Endian == ELF::ELFDATA2MSB) 315 return CreateArchType<ELF32BE>(Buffer, Ctx.getMemoryManager(), 316 Ctx.getJITLinkDylib(), ES); 317 return nullptr; 318 } 319 if (Class == ELF::ELFCLASS64) { 320 if (Endian == ELF::ELFDATA2LSB) 321 return CreateArchType<ELF64LE>(Buffer, Ctx.getMemoryManager(), 322 Ctx.getJITLinkDylib(), ES); 323 if (Endian == ELF::ELFDATA2MSB) 324 return CreateArchType<ELF64BE>(Buffer, Ctx.getMemoryManager(), 325 Ctx.getJITLinkDylib(), ES); 326 return nullptr; 327 } 328 return nullptr; 329 } 330 331 Expected<SimpleSegmentAlloc> ELFDebugObject::finalizeWorkingMemory() { 332 LLVM_DEBUG({ 333 dbgs() << "Section load-addresses in debug object for \"" 334 << Buffer->getBufferIdentifier() << "\":\n"; 335 for (const auto &KV : Sections) 336 KV.second->dump(dbgs(), KV.first()); 337 }); 338 339 // TODO: This works, but what actual alignment requirements do we have? 340 unsigned PageSize = sys::Process::getPageSizeEstimate(); 341 size_t Size = Buffer->getBufferSize(); 342 343 // Allocate working memory for debug object in read-only segment. 344 auto Alloc = SimpleSegmentAlloc::Create( 345 MemMgr, JD, {{MemProt::Read, {Size, Align(PageSize)}}}); 346 if (!Alloc) 347 return Alloc; 348 349 // Initialize working memory with a copy of our object buffer. 350 auto SegInfo = Alloc->getSegInfo(MemProt::Read); 351 memcpy(SegInfo.WorkingMem.data(), Buffer->getBufferStart(), Size); 352 Buffer.reset(); 353 354 return Alloc; 355 } 356 357 void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name, 358 SectionRange TargetMem) { 359 if (auto *DebugObjSection = getSection(Name)) 360 DebugObjSection->setTargetMemoryRange(TargetMem); 361 } 362 363 template <typename ELFT> 364 Error ELFDebugObject::recordSection( 365 StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) { 366 if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data())) 367 return Err; 368 bool Inserted = Sections.try_emplace(Name, std::move(Section)).second; 369 if (!Inserted) 370 LLVM_DEBUG(dbgs() << "Skipping debug registration for section '" << Name 371 << "' in object " << Buffer->getBufferIdentifier() 372 << " (duplicate name)\n"); 373 return Error::success(); 374 } 375 376 DebugObjectSection *ELFDebugObject::getSection(StringRef Name) { 377 auto It = Sections.find(Name); 378 return It == Sections.end() ? nullptr : It->second.get(); 379 } 380 381 /// Creates a debug object based on the input object file from 382 /// ObjectLinkingLayerJITLinkContext. 383 /// 384 static Expected<std::unique_ptr<DebugObject>> 385 createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G, 386 JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) { 387 switch (G.getTargetTriple().getObjectFormat()) { 388 case Triple::ELF: 389 return ELFDebugObject::Create(ObjBuffer, Ctx, ES); 390 391 default: 392 // TODO: Once we add support for other formats, we might want to split this 393 // into multiple files. 394 return nullptr; 395 } 396 } 397 398 DebugObjectManagerPlugin::DebugObjectManagerPlugin( 399 ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target, 400 bool RequireDebugSections) 401 : ES(ES), Target(std::move(Target)), 402 RequireDebugSections(RequireDebugSections) {} 403 404 DebugObjectManagerPlugin::DebugObjectManagerPlugin( 405 ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target) 406 : DebugObjectManagerPlugin(ES, std::move(Target), true) {} 407 408 DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default; 409 410 void DebugObjectManagerPlugin::notifyMaterializing( 411 MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx, 412 MemoryBufferRef ObjBuffer) { 413 std::lock_guard<std::mutex> Lock(PendingObjsLock); 414 assert(PendingObjs.count(&MR) == 0 && 415 "Cannot have more than one pending debug object per " 416 "MaterializationResponsibility"); 417 418 if (auto DebugObj = createDebugObjectFromBuffer(ES, G, Ctx, ObjBuffer)) { 419 // Not all link artifacts allow debugging. 420 if (*DebugObj == nullptr) 421 return; 422 if (RequireDebugSections && !(**DebugObj).hasFlags(HasDebugSections)) { 423 LLVM_DEBUG(dbgs() << "Skipping debug registration for LinkGraph '" 424 << G.getName() << "': no debug info\n"); 425 return; 426 } 427 PendingObjs[&MR] = std::move(*DebugObj); 428 } else { 429 ES.reportError(DebugObj.takeError()); 430 } 431 } 432 433 void DebugObjectManagerPlugin::modifyPassConfig( 434 MaterializationResponsibility &MR, LinkGraph &G, 435 PassConfiguration &PassConfig) { 436 // Not all link artifacts have associated debug objects. 437 std::lock_guard<std::mutex> Lock(PendingObjsLock); 438 auto It = PendingObjs.find(&MR); 439 if (It == PendingObjs.end()) 440 return; 441 442 DebugObject &DebugObj = *It->second; 443 if (DebugObj.hasFlags(ReportFinalSectionLoadAddresses)) { 444 PassConfig.PostAllocationPasses.push_back( 445 [&DebugObj](LinkGraph &Graph) -> Error { 446 for (const Section &GraphSection : Graph.sections()) 447 DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(), 448 SectionRange(GraphSection)); 449 return Error::success(); 450 }); 451 } 452 } 453 454 Error DebugObjectManagerPlugin::notifyEmitted( 455 MaterializationResponsibility &MR) { 456 std::lock_guard<std::mutex> Lock(PendingObjsLock); 457 auto It = PendingObjs.find(&MR); 458 if (It == PendingObjs.end()) 459 return Error::success(); 460 461 // During finalization the debug object is registered with the target. 462 // Materialization must wait for this process to finish. Otherwise we might 463 // start running code before the debugger processed the corresponding debug 464 // info. 465 std::promise<MSVCPError> FinalizePromise; 466 std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future(); 467 468 It->second->finalizeAsync( 469 [this, &FinalizePromise, &MR](Expected<ExecutorAddrRange> TargetMem) { 470 // Any failure here will fail materialization. 471 if (!TargetMem) { 472 FinalizePromise.set_value(TargetMem.takeError()); 473 return; 474 } 475 if (Error Err = Target->registerDebugObject(*TargetMem)) { 476 FinalizePromise.set_value(std::move(Err)); 477 return; 478 } 479 480 // Once our tracking info is updated, notifyEmitted() can return and 481 // finish materialization. 482 FinalizePromise.set_value(MR.withResourceKeyDo([&](ResourceKey K) { 483 assert(PendingObjs.count(&MR) && "We still hold PendingObjsLock"); 484 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 485 RegisteredObjs[K].push_back(std::move(PendingObjs[&MR])); 486 PendingObjs.erase(&MR); 487 })); 488 }); 489 490 return FinalizeErr.get(); 491 } 492 493 Error DebugObjectManagerPlugin::notifyFailed( 494 MaterializationResponsibility &MR) { 495 std::lock_guard<std::mutex> Lock(PendingObjsLock); 496 PendingObjs.erase(&MR); 497 return Error::success(); 498 } 499 500 void DebugObjectManagerPlugin::notifyTransferringResources(JITDylib &JD, 501 ResourceKey DstKey, 502 ResourceKey SrcKey) { 503 // Debug objects are stored by ResourceKey only after registration. 504 // Thus, pending objects don't need to be updated here. 505 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 506 auto SrcIt = RegisteredObjs.find(SrcKey); 507 if (SrcIt != RegisteredObjs.end()) { 508 // Resources from distinct MaterializationResponsibilitys can get merged 509 // after emission, so we can have multiple debug objects per resource key. 510 for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second) 511 RegisteredObjs[DstKey].push_back(std::move(DebugObj)); 512 RegisteredObjs.erase(SrcIt); 513 } 514 } 515 516 Error DebugObjectManagerPlugin::notifyRemovingResources(JITDylib &JD, 517 ResourceKey Key) { 518 // Removing the resource for a pending object fails materialization, so they 519 // get cleaned up in the notifyFailed() handler. 520 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 521 RegisteredObjs.erase(Key); 522 523 // TODO: Implement unregister notifications. 524 return Error::success(); 525 } 526 527 } // namespace orc 528 } // namespace llvm 529