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 (Header->sh_addr) { 97 OS << formatv(" {0:x16} {1}\n", Header->sh_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(ExecutorAddr(ROSeg.Addr), 170 ExecutorAddrDiff(ROSeg.WorkingMem.size())); 171 SimpleSegAlloc->finalize( 172 [this, DebugObjRange, 173 OnFinalize = std::move(OnFinalize)](Expected<FinalizedAlloc> FA) { 174 if (FA) { 175 Alloc = std::move(*FA); 176 OnFinalize(DebugObjRange); 177 } else 178 OnFinalize(FA.takeError()); 179 }); 180 } else 181 OnFinalize(SimpleSegAlloc.takeError()); 182 } 183 184 /// The current implementation of ELFDebugObject replicates the approach used in 185 /// RuntimeDyld: It patches executable and data section headers in the given 186 /// object buffer with load-addresses of their corresponding sections in target 187 /// memory. 188 /// 189 class ELFDebugObject : public DebugObject { 190 public: 191 static Expected<std::unique_ptr<DebugObject>> 192 Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, ExecutionSession &ES); 193 194 void reportSectionTargetMemoryRange(StringRef Name, 195 SectionRange TargetMem) override; 196 197 StringRef getBuffer() const { return Buffer->getMemBufferRef().getBuffer(); } 198 199 protected: 200 Expected<SimpleSegmentAlloc> finalizeWorkingMemory() override; 201 202 template <typename ELFT> 203 Error recordSection(StringRef Name, 204 std::unique_ptr<ELFDebugObjectSection<ELFT>> Section); 205 DebugObjectSection *getSection(StringRef Name); 206 207 private: 208 template <typename ELFT> 209 static Expected<std::unique_ptr<ELFDebugObject>> 210 CreateArchType(MemoryBufferRef Buffer, JITLinkMemoryManager &MemMgr, 211 const JITLinkDylib *JD, ExecutionSession &ES); 212 213 static std::unique_ptr<WritableMemoryBuffer> 214 CopyBuffer(MemoryBufferRef Buffer, Error &Err); 215 216 ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer, 217 JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD, 218 ExecutionSession &ES) 219 : DebugObject(MemMgr, JD, ES), Buffer(std::move(Buffer)) { 220 setFlags(ReportFinalSectionLoadAddresses); 221 } 222 223 std::unique_ptr<WritableMemoryBuffer> Buffer; 224 StringMap<std::unique_ptr<DebugObjectSection>> Sections; 225 }; 226 227 static const std::set<StringRef> DwarfSectionNames = { 228 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \ 229 ELF_NAME, 230 #include "llvm/BinaryFormat/Dwarf.def" 231 #undef HANDLE_DWARF_SECTION 232 }; 233 234 static bool isDwarfSection(StringRef SectionName) { 235 return DwarfSectionNames.count(SectionName) == 1; 236 } 237 238 std::unique_ptr<WritableMemoryBuffer> 239 ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer, Error &Err) { 240 ErrorAsOutParameter _(&Err); 241 size_t Size = Buffer.getBufferSize(); 242 StringRef Name = Buffer.getBufferIdentifier(); 243 if (auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(Size, Name)) { 244 memcpy(Copy->getBufferStart(), Buffer.getBufferStart(), Size); 245 return Copy; 246 } 247 248 Err = errorCodeToError(make_error_code(errc::not_enough_memory)); 249 return nullptr; 250 } 251 252 template <typename ELFT> 253 Expected<std::unique_ptr<ELFDebugObject>> 254 ELFDebugObject::CreateArchType(MemoryBufferRef Buffer, 255 JITLinkMemoryManager &MemMgr, 256 const JITLinkDylib *JD, ExecutionSession &ES) { 257 using SectionHeader = typename ELFT::Shdr; 258 259 Error Err = Error::success(); 260 std::unique_ptr<ELFDebugObject> DebugObj( 261 new ELFDebugObject(CopyBuffer(Buffer, Err), MemMgr, JD, ES)); 262 if (Err) 263 return std::move(Err); 264 265 Expected<ELFFile<ELFT>> ObjRef = ELFFile<ELFT>::create(DebugObj->getBuffer()); 266 if (!ObjRef) 267 return ObjRef.takeError(); 268 269 Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections(); 270 if (!Sections) 271 return Sections.takeError(); 272 273 for (const SectionHeader &Header : *Sections) { 274 Expected<StringRef> Name = ObjRef->getSectionName(Header); 275 if (!Name) 276 return Name.takeError(); 277 if (Name->empty()) 278 continue; 279 if (isDwarfSection(*Name)) 280 DebugObj->setFlags(HasDebugSections); 281 282 // Only record text and data sections (i.e. no bss, comments, rel, etc.) 283 if (Header.sh_type != ELF::SHT_PROGBITS && 284 Header.sh_type != ELF::SHT_X86_64_UNWIND) 285 continue; 286 if (!(Header.sh_flags & ELF::SHF_ALLOC)) 287 continue; 288 289 auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header); 290 if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped))) 291 return std::move(Err); 292 } 293 294 return std::move(DebugObj); 295 } 296 297 Expected<std::unique_ptr<DebugObject>> 298 ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, 299 ExecutionSession &ES) { 300 unsigned char Class, Endian; 301 std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer()); 302 303 if (Class == ELF::ELFCLASS32) { 304 if (Endian == ELF::ELFDATA2LSB) 305 return CreateArchType<ELF32LE>(Buffer, Ctx.getMemoryManager(), 306 Ctx.getJITLinkDylib(), ES); 307 if (Endian == ELF::ELFDATA2MSB) 308 return CreateArchType<ELF32BE>(Buffer, Ctx.getMemoryManager(), 309 Ctx.getJITLinkDylib(), ES); 310 return nullptr; 311 } 312 if (Class == ELF::ELFCLASS64) { 313 if (Endian == ELF::ELFDATA2LSB) 314 return CreateArchType<ELF64LE>(Buffer, Ctx.getMemoryManager(), 315 Ctx.getJITLinkDylib(), ES); 316 if (Endian == ELF::ELFDATA2MSB) 317 return CreateArchType<ELF64BE>(Buffer, Ctx.getMemoryManager(), 318 Ctx.getJITLinkDylib(), ES); 319 return nullptr; 320 } 321 return nullptr; 322 } 323 324 Expected<SimpleSegmentAlloc> ELFDebugObject::finalizeWorkingMemory() { 325 LLVM_DEBUG({ 326 dbgs() << "Section load-addresses in debug object for \"" 327 << Buffer->getBufferIdentifier() << "\":\n"; 328 for (const auto &KV : Sections) 329 KV.second->dump(dbgs(), KV.first()); 330 }); 331 332 // TODO: This works, but what actual alignment requirements do we have? 333 unsigned PageSize = sys::Process::getPageSizeEstimate(); 334 size_t Size = Buffer->getBufferSize(); 335 336 // Allocate working memory for debug object in read-only segment. 337 auto Alloc = SimpleSegmentAlloc::Create( 338 MemMgr, JD, {{MemProt::Read, {Size, Align(PageSize)}}}); 339 if (!Alloc) 340 return Alloc; 341 342 // Initialize working memory with a copy of our object buffer. 343 auto SegInfo = Alloc->getSegInfo(MemProt::Read); 344 memcpy(SegInfo.WorkingMem.data(), Buffer->getBufferStart(), Size); 345 Buffer.reset(); 346 347 return Alloc; 348 } 349 350 void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name, 351 SectionRange TargetMem) { 352 if (auto *DebugObjSection = getSection(Name)) 353 DebugObjSection->setTargetMemoryRange(TargetMem); 354 } 355 356 template <typename ELFT> 357 Error ELFDebugObject::recordSection( 358 StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) { 359 if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data())) 360 return Err; 361 bool Inserted = Sections.try_emplace(Name, std::move(Section)).second; 362 if (!Inserted) 363 LLVM_DEBUG(dbgs() << "Skipping debug registration for section '" << Name 364 << "' in object " << Buffer->getBufferIdentifier() 365 << " (duplicate name)\n"); 366 return Error::success(); 367 } 368 369 DebugObjectSection *ELFDebugObject::getSection(StringRef Name) { 370 auto It = Sections.find(Name); 371 return It == Sections.end() ? nullptr : It->second.get(); 372 } 373 374 /// Creates a debug object based on the input object file from 375 /// ObjectLinkingLayerJITLinkContext. 376 /// 377 static Expected<std::unique_ptr<DebugObject>> 378 createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G, 379 JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) { 380 switch (G.getTargetTriple().getObjectFormat()) { 381 case Triple::ELF: 382 return ELFDebugObject::Create(ObjBuffer, Ctx, ES); 383 384 default: 385 // TODO: Once we add support for other formats, we might want to split this 386 // into multiple files. 387 return nullptr; 388 } 389 } 390 391 DebugObjectManagerPlugin::DebugObjectManagerPlugin( 392 ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target, 393 bool RequireDebugSections) 394 : ES(ES), Target(std::move(Target)), 395 RequireDebugSections(RequireDebugSections) {} 396 397 DebugObjectManagerPlugin::DebugObjectManagerPlugin( 398 ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target) 399 : DebugObjectManagerPlugin(ES, std::move(Target), 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 = Target->registerDebugObject(*TargetMem)) { 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