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 153 private: 154 ExecutionSession &ES; 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, JD, {{MemProt::Read, {Size, Align(PageSize)}}}); 336 if (!Alloc) 337 return Alloc; 338 339 // Initialize working memory with a copy of our object buffer. 340 auto SegInfo = Alloc->getSegInfo(MemProt::Read); 341 memcpy(SegInfo.WorkingMem.data(), Buffer->getBufferStart(), Size); 342 Buffer.reset(); 343 344 return Alloc; 345 } 346 347 void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name, 348 SectionRange TargetMem) { 349 if (auto *DebugObjSection = getSection(Name)) 350 DebugObjSection->setTargetMemoryRange(TargetMem); 351 } 352 353 template <typename ELFT> 354 Error ELFDebugObject::recordSection( 355 StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) { 356 if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data())) 357 return Err; 358 bool Inserted = Sections.try_emplace(Name, std::move(Section)).second; 359 if (!Inserted) 360 LLVM_DEBUG(dbgs() << "Skipping debug registration for section '" << Name 361 << "' in object " << Buffer->getBufferIdentifier() 362 << " (duplicate name)\n"); 363 return Error::success(); 364 } 365 366 DebugObjectSection *ELFDebugObject::getSection(StringRef Name) { 367 auto It = Sections.find(Name); 368 return It == Sections.end() ? nullptr : It->second.get(); 369 } 370 371 /// Creates a debug object based on the input object file from 372 /// ObjectLinkingLayerJITLinkContext. 373 /// 374 static Expected<std::unique_ptr<DebugObject>> 375 createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G, 376 JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) { 377 switch (G.getTargetTriple().getObjectFormat()) { 378 case Triple::ELF: 379 return ELFDebugObject::Create(ObjBuffer, Ctx, ES); 380 381 default: 382 // TODO: Once we add support for other formats, we might want to split this 383 // into multiple files. 384 return nullptr; 385 } 386 } 387 388 DebugObjectManagerPlugin::DebugObjectManagerPlugin( 389 ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target, 390 bool RequireDebugSections, bool AutoRegisterCode) 391 : ES(ES), Target(std::move(Target)), 392 RequireDebugSections(RequireDebugSections), 393 AutoRegisterCode(AutoRegisterCode) {} 394 395 DebugObjectManagerPlugin::DebugObjectManagerPlugin( 396 ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target) 397 : DebugObjectManagerPlugin(ES, std::move(Target), true, true) {} 398 399 DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default; 400 401 void DebugObjectManagerPlugin::notifyMaterializing( 402 MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx, 403 MemoryBufferRef ObjBuffer) { 404 std::lock_guard<std::mutex> Lock(PendingObjsLock); 405 assert(PendingObjs.count(&MR) == 0 && 406 "Cannot have more than one pending debug object per " 407 "MaterializationResponsibility"); 408 409 if (auto DebugObj = createDebugObjectFromBuffer(ES, G, Ctx, ObjBuffer)) { 410 // Not all link artifacts allow debugging. 411 if (*DebugObj == nullptr) 412 return; 413 if (RequireDebugSections && !(**DebugObj).hasFlags(HasDebugSections)) { 414 LLVM_DEBUG(dbgs() << "Skipping debug registration for LinkGraph '" 415 << G.getName() << "': no debug info\n"); 416 return; 417 } 418 PendingObjs[&MR] = std::move(*DebugObj); 419 } else { 420 ES.reportError(DebugObj.takeError()); 421 } 422 } 423 424 void DebugObjectManagerPlugin::modifyPassConfig( 425 MaterializationResponsibility &MR, LinkGraph &G, 426 PassConfiguration &PassConfig) { 427 // Not all link artifacts have associated debug objects. 428 std::lock_guard<std::mutex> Lock(PendingObjsLock); 429 auto It = PendingObjs.find(&MR); 430 if (It == PendingObjs.end()) 431 return; 432 433 DebugObject &DebugObj = *It->second; 434 if (DebugObj.hasFlags(ReportFinalSectionLoadAddresses)) { 435 PassConfig.PostAllocationPasses.push_back( 436 [&DebugObj](LinkGraph &Graph) -> Error { 437 for (const Section &GraphSection : Graph.sections()) 438 DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(), 439 SectionRange(GraphSection)); 440 return Error::success(); 441 }); 442 } 443 } 444 445 Error DebugObjectManagerPlugin::notifyEmitted( 446 MaterializationResponsibility &MR) { 447 std::lock_guard<std::mutex> Lock(PendingObjsLock); 448 auto It = PendingObjs.find(&MR); 449 if (It == PendingObjs.end()) 450 return Error::success(); 451 452 // During finalization the debug object is registered with the target. 453 // Materialization must wait for this process to finish. Otherwise we might 454 // start running code before the debugger processed the corresponding debug 455 // info. 456 std::promise<MSVCPError> FinalizePromise; 457 std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future(); 458 459 It->second->finalizeAsync( 460 [this, &FinalizePromise, &MR](Expected<ExecutorAddrRange> TargetMem) { 461 // Any failure here will fail materialization. 462 if (!TargetMem) { 463 FinalizePromise.set_value(TargetMem.takeError()); 464 return; 465 } 466 if (Error Err = 467 Target->registerDebugObject(*TargetMem, AutoRegisterCode)) { 468 FinalizePromise.set_value(std::move(Err)); 469 return; 470 } 471 472 // Once our tracking info is updated, notifyEmitted() can return and 473 // finish materialization. 474 FinalizePromise.set_value(MR.withResourceKeyDo([&](ResourceKey K) { 475 assert(PendingObjs.count(&MR) && "We still hold PendingObjsLock"); 476 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 477 RegisteredObjs[K].push_back(std::move(PendingObjs[&MR])); 478 PendingObjs.erase(&MR); 479 })); 480 }); 481 482 return FinalizeErr.get(); 483 } 484 485 Error DebugObjectManagerPlugin::notifyFailed( 486 MaterializationResponsibility &MR) { 487 std::lock_guard<std::mutex> Lock(PendingObjsLock); 488 PendingObjs.erase(&MR); 489 return Error::success(); 490 } 491 492 void DebugObjectManagerPlugin::notifyTransferringResources(JITDylib &JD, 493 ResourceKey DstKey, 494 ResourceKey SrcKey) { 495 // Debug objects are stored by ResourceKey only after registration. 496 // Thus, pending objects don't need to be updated here. 497 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 498 auto SrcIt = RegisteredObjs.find(SrcKey); 499 if (SrcIt != RegisteredObjs.end()) { 500 // Resources from distinct MaterializationResponsibilitys can get merged 501 // after emission, so we can have multiple debug objects per resource key. 502 for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second) 503 RegisteredObjs[DstKey].push_back(std::move(DebugObj)); 504 RegisteredObjs.erase(SrcIt); 505 } 506 } 507 508 Error DebugObjectManagerPlugin::notifyRemovingResources(JITDylib &JD, 509 ResourceKey Key) { 510 // Removing the resource for a pending object fails materialization, so they 511 // get cleaned up in the notifyFailed() handler. 512 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 513 RegisteredObjs.erase(Key); 514 515 // TODO: Implement unregister notifications. 516 return Error::success(); 517 } 518 519 } // namespace orc 520 } // namespace llvm 521