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