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 35using namespace llvm::jitlink; 36using namespace llvm::object; 37 38namespace llvm { 39namespace orc { 40 41class DebugObjectSection { 42public: 43 virtual void setTargetMemoryRange(SectionRange Range) = 0; 44 virtual void dump(raw_ostream &OS, StringRef Name) {} 45 virtual ~DebugObjectSection() = default; 46}; 47 48template <typename ELFT> 49class ELFDebugObjectSection : public DebugObjectSection { 50public: 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 61private: 62 typename ELFT::Shdr *Header; 63 64 bool isTextOrDataSection() const; 65}; 66 67template <typename ELFT> 68void 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 75template <typename ELFT> 76bool 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 85template <typename ELFT> 86Error 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 107template <typename ELFT> 108void 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 116enum 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/// 126class DebugObject { 127public: 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 151protected: 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 160private: 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. 169void 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/// 194class ELFDebugObject : public DebugObject { 195public: 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 204protected: 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 212private: 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 232static 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 239static bool isDwarfSection(StringRef SectionName) { 240 return DwarfSectionNames.count(SectionName) == 1; 241} 242 243std::unique_ptr<WritableMemoryBuffer> 244ELFDebugObject::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 257template <typename ELFT> 258Expected<std::unique_ptr<ELFDebugObject>> 259ELFDebugObject::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 310Expected<std::unique_ptr<DebugObject>> 311ELFDebugObject::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 337Expected<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 363void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name, 364 SectionRange TargetMem) { 365 if (auto *DebugObjSection = getSection(Name)) 366 DebugObjSection->setTargetMemoryRange(TargetMem); 367} 368 369template <typename ELFT> 370Error 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 383DebugObjectSection *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/// 391static Expected<std::unique_ptr<DebugObject>> 392createDebugObjectFromBuffer(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 405DebugObjectManagerPlugin::DebugObjectManagerPlugin( 406 ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target) 407 : ES(ES), Target(std::move(Target)) {} 408 409DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default; 410 411void 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 428void 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 449Error 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 488Error DebugObjectManagerPlugin::notifyFailed( 489 MaterializationResponsibility &MR) { 490 std::lock_guard<std::mutex> Lock(PendingObjsLock); 491 PendingObjs.erase(&MR); 492 return Error::success(); 493} 494 495void 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 511Error 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