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 110 /// The plugin creates a debug object from when JITLink starts processing the 111 /// corresponding LinkGraph. It provides access to the pass configuration of 112 /// the LinkGraph and calls the finalization function, once the resulting link 113 /// artifact was emitted. 114 /// 115 class DebugObject { 116 public: 117 DebugObject(JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD, 118 ExecutionSession &ES) 119 : MemMgr(MemMgr), JD(JD), ES(ES) {} 120 121 bool hasFlags(DebugObjectFlags F) const { return Flags & F; } 122 void setFlags(DebugObjectFlags F) { 123 Flags = static_cast<DebugObjectFlags>(Flags | F); 124 } 125 void clearFlags(DebugObjectFlags F) { 126 Flags = static_cast<DebugObjectFlags>(Flags & ~F); 127 } 128 129 using FinalizeContinuation = std::function<void(Expected<ExecutorAddrRange>)>; 130 131 void finalizeAsync(FinalizeContinuation OnFinalize); 132 133 virtual ~DebugObject() { 134 if (Alloc) { 135 std::vector<FinalizedAlloc> Allocs; 136 Allocs.push_back(std::move(Alloc)); 137 if (Error Err = MemMgr.deallocate(std::move(Allocs))) 138 ES.reportError(std::move(Err)); 139 } 140 } 141 142 virtual void reportSectionTargetMemoryRange(StringRef Name, 143 SectionRange TargetMem) {} 144 145 protected: 146 using InFlightAlloc = JITLinkMemoryManager::InFlightAlloc; 147 using FinalizedAlloc = JITLinkMemoryManager::FinalizedAlloc; 148 149 virtual Expected<SimpleSegmentAlloc> finalizeWorkingMemory() = 0; 150 151 JITLinkMemoryManager &MemMgr; 152 const JITLinkDylib *JD = nullptr; 153 154 private: 155 ExecutionSession &ES; 156 DebugObjectFlags Flags; 157 FinalizedAlloc Alloc; 158 }; 159 160 // Finalize working memory and take ownership of the resulting allocation. Start 161 // copying memory over to the target and pass on the result once we're done. 162 // Ownership of the allocation remains with us for the rest of our lifetime. 163 void DebugObject::finalizeAsync(FinalizeContinuation OnFinalize) { 164 assert(!Alloc && "Cannot finalize more than once"); 165 166 if (auto SimpleSegAlloc = finalizeWorkingMemory()) { 167 auto ROSeg = SimpleSegAlloc->getSegInfo(MemProt::Read); 168 ExecutorAddrRange DebugObjRange(ExecutorAddr(ROSeg.Addr), 169 ExecutorAddrDiff(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 // TODO: Add support for other architectures. 269 uint16_t TargetMachineArch = ObjRef->getHeader().e_machine; 270 if (TargetMachineArch != ELF::EM_X86_64) 271 return nullptr; 272 273 Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections(); 274 if (!Sections) 275 return Sections.takeError(); 276 277 bool HasDwarfSection = false; 278 for (const SectionHeader &Header : *Sections) { 279 Expected<StringRef> Name = ObjRef->getSectionName(Header); 280 if (!Name) 281 return Name.takeError(); 282 if (Name->empty()) 283 continue; 284 HasDwarfSection |= isDwarfSection(*Name); 285 286 // Only record text and data sections (i.e. no bss, comments, rel, etc.) 287 if (Header.sh_type != ELF::SHT_PROGBITS && 288 Header.sh_type != ELF::SHT_X86_64_UNWIND) 289 continue; 290 if (!(Header.sh_flags & ELF::SHF_ALLOC)) 291 continue; 292 293 auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header); 294 if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped))) 295 return std::move(Err); 296 } 297 298 if (!HasDwarfSection) { 299 LLVM_DEBUG(dbgs() << "Aborting debug registration for LinkGraph \"" 300 << DebugObj->Buffer->getBufferIdentifier() 301 << "\": input object contains no debug info\n"); 302 return nullptr; 303 } 304 305 return std::move(DebugObj); 306 } 307 308 Expected<std::unique_ptr<DebugObject>> 309 ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, 310 ExecutionSession &ES) { 311 unsigned char Class, Endian; 312 std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer()); 313 314 if (Class == ELF::ELFCLASS32) { 315 if (Endian == ELF::ELFDATA2LSB) 316 return CreateArchType<ELF32LE>(Buffer, Ctx.getMemoryManager(), 317 Ctx.getJITLinkDylib(), ES); 318 if (Endian == ELF::ELFDATA2MSB) 319 return CreateArchType<ELF32BE>(Buffer, Ctx.getMemoryManager(), 320 Ctx.getJITLinkDylib(), ES); 321 return nullptr; 322 } 323 if (Class == ELF::ELFCLASS64) { 324 if (Endian == ELF::ELFDATA2LSB) 325 return CreateArchType<ELF64LE>(Buffer, Ctx.getMemoryManager(), 326 Ctx.getJITLinkDylib(), ES); 327 if (Endian == ELF::ELFDATA2MSB) 328 return CreateArchType<ELF64BE>(Buffer, Ctx.getMemoryManager(), 329 Ctx.getJITLinkDylib(), ES); 330 return nullptr; 331 } 332 return nullptr; 333 } 334 335 Expected<SimpleSegmentAlloc> ELFDebugObject::finalizeWorkingMemory() { 336 LLVM_DEBUG({ 337 dbgs() << "Section load-addresses in debug object for \"" 338 << Buffer->getBufferIdentifier() << "\":\n"; 339 for (const auto &KV : Sections) 340 KV.second->dump(dbgs(), KV.first()); 341 }); 342 343 // TODO: This works, but what actual alignment requirements do we have? 344 unsigned PageSize = sys::Process::getPageSizeEstimate(); 345 size_t Size = Buffer->getBufferSize(); 346 347 // Allocate working memory for debug object in read-only segment. 348 auto Alloc = SimpleSegmentAlloc::Create( 349 MemMgr, JD, {{MemProt::Read, {Size, Align(PageSize)}}}); 350 if (!Alloc) 351 return Alloc; 352 353 // Initialize working memory with a copy of our object buffer. 354 auto SegInfo = Alloc->getSegInfo(MemProt::Read); 355 memcpy(SegInfo.WorkingMem.data(), Buffer->getBufferStart(), Size); 356 Buffer.reset(); 357 358 return Alloc; 359 } 360 361 void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name, 362 SectionRange TargetMem) { 363 if (auto *DebugObjSection = getSection(Name)) 364 DebugObjSection->setTargetMemoryRange(TargetMem); 365 } 366 367 template <typename ELFT> 368 Error ELFDebugObject::recordSection( 369 StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) { 370 if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data())) 371 return Err; 372 auto ItInserted = Sections.try_emplace(Name, std::move(Section)); 373 LLVM_DEBUG({ 374 if (!ItInserted.second) 375 dbgs() << "Skipping debug registration for section '" << Name << "' " 376 << "in object " << Buffer->getBufferIdentifier() 377 << " (duplicate name)\n"; 378 }); 379 return Error::success(); 380 } 381 382 DebugObjectSection *ELFDebugObject::getSection(StringRef Name) { 383 auto It = Sections.find(Name); 384 return It == Sections.end() ? nullptr : It->second.get(); 385 } 386 387 /// Creates a debug object based on the input object file from 388 /// ObjectLinkingLayerJITLinkContext. 389 /// 390 static Expected<std::unique_ptr<DebugObject>> 391 createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G, 392 JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) { 393 switch (G.getTargetTriple().getObjectFormat()) { 394 case Triple::ELF: 395 return ELFDebugObject::Create(ObjBuffer, Ctx, ES); 396 397 default: 398 // TODO: Once we add support for other formats, we might want to split this 399 // into multiple files. 400 return nullptr; 401 } 402 } 403 404 DebugObjectManagerPlugin::DebugObjectManagerPlugin( 405 ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target) 406 : ES(ES), Target(std::move(Target)) {} 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 PendingObjs[&MR] = std::move(*DebugObj); 422 } else { 423 ES.reportError(DebugObj.takeError()); 424 } 425 } 426 427 void DebugObjectManagerPlugin::modifyPassConfig( 428 MaterializationResponsibility &MR, LinkGraph &G, 429 PassConfiguration &PassConfig) { 430 // Not all link artifacts have associated debug objects. 431 std::lock_guard<std::mutex> Lock(PendingObjsLock); 432 auto It = PendingObjs.find(&MR); 433 if (It == PendingObjs.end()) 434 return; 435 436 DebugObject &DebugObj = *It->second; 437 if (DebugObj.hasFlags(ReportFinalSectionLoadAddresses)) { 438 PassConfig.PostAllocationPasses.push_back( 439 [&DebugObj](LinkGraph &Graph) -> Error { 440 for (const Section &GraphSection : Graph.sections()) 441 DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(), 442 SectionRange(GraphSection)); 443 return Error::success(); 444 }); 445 } 446 } 447 448 Error DebugObjectManagerPlugin::notifyEmitted( 449 MaterializationResponsibility &MR) { 450 std::lock_guard<std::mutex> Lock(PendingObjsLock); 451 auto It = PendingObjs.find(&MR); 452 if (It == PendingObjs.end()) 453 return Error::success(); 454 455 // During finalization the debug object is registered with the target. 456 // Materialization must wait for this process to finish. Otherwise we might 457 // start running code before the debugger processed the corresponding debug 458 // info. 459 std::promise<MSVCPError> FinalizePromise; 460 std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future(); 461 462 It->second->finalizeAsync( 463 [this, &FinalizePromise, &MR](Expected<ExecutorAddrRange> TargetMem) { 464 // Any failure here will fail materialization. 465 if (!TargetMem) { 466 FinalizePromise.set_value(TargetMem.takeError()); 467 return; 468 } 469 if (Error Err = Target->registerDebugObject(*TargetMem)) { 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