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