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 bool Inserted = Sections.try_emplace(Name, std::move(Section)).second; 373 if (!Inserted) 374 LLVM_DEBUG(dbgs() << "Skipping debug registration for section '" << Name 375 << "' in object " << Buffer->getBufferIdentifier() 376 << " (duplicate name)\n"); 377 return Error::success(); 378 } 379 380 DebugObjectSection *ELFDebugObject::getSection(StringRef Name) { 381 auto It = Sections.find(Name); 382 return It == Sections.end() ? nullptr : It->second.get(); 383 } 384 385 /// Creates a debug object based on the input object file from 386 /// ObjectLinkingLayerJITLinkContext. 387 /// 388 static Expected<std::unique_ptr<DebugObject>> 389 createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G, 390 JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) { 391 switch (G.getTargetTriple().getObjectFormat()) { 392 case Triple::ELF: 393 return ELFDebugObject::Create(ObjBuffer, Ctx, ES); 394 395 default: 396 // TODO: Once we add support for other formats, we might want to split this 397 // into multiple files. 398 return nullptr; 399 } 400 } 401 402 DebugObjectManagerPlugin::DebugObjectManagerPlugin( 403 ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target) 404 : ES(ES), Target(std::move(Target)) {} 405 406 DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default; 407 408 void DebugObjectManagerPlugin::notifyMaterializing( 409 MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx, 410 MemoryBufferRef ObjBuffer) { 411 std::lock_guard<std::mutex> Lock(PendingObjsLock); 412 assert(PendingObjs.count(&MR) == 0 && 413 "Cannot have more than one pending debug object per " 414 "MaterializationResponsibility"); 415 416 if (auto DebugObj = createDebugObjectFromBuffer(ES, G, Ctx, ObjBuffer)) { 417 // Not all link artifacts allow debugging. 418 if (*DebugObj != nullptr) 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 = Target->registerDebugObject(*TargetMem)) { 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