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