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 auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header); 293 if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped))) 294 return std::move(Err); 295 } 296 297 if (!HasDwarfSection) { 298 LLVM_DEBUG(dbgs() << "Aborting debug registration for LinkGraph \"" 299 << DebugObj->Buffer->getBufferIdentifier() 300 << "\": input object contains no debug info\n"); 301 return nullptr; 302 } 303 304 return std::move(DebugObj); 305 } 306 307 Expected<std::unique_ptr<DebugObject>> 308 ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, 309 ExecutionSession &ES) { 310 unsigned char Class, Endian; 311 std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer()); 312 313 if (Class == ELF::ELFCLASS32) { 314 if (Endian == ELF::ELFDATA2LSB) 315 return CreateArchType<ELF32LE>(Buffer, Ctx.getMemoryManager(), 316 Ctx.getJITLinkDylib(), ES); 317 if (Endian == ELF::ELFDATA2MSB) 318 return CreateArchType<ELF32BE>(Buffer, Ctx.getMemoryManager(), 319 Ctx.getJITLinkDylib(), ES); 320 return nullptr; 321 } 322 if (Class == ELF::ELFCLASS64) { 323 if (Endian == ELF::ELFDATA2LSB) 324 return CreateArchType<ELF64LE>(Buffer, Ctx.getMemoryManager(), 325 Ctx.getJITLinkDylib(), ES); 326 if (Endian == ELF::ELFDATA2MSB) 327 return CreateArchType<ELF64BE>(Buffer, Ctx.getMemoryManager(), 328 Ctx.getJITLinkDylib(), ES); 329 return nullptr; 330 } 331 return nullptr; 332 } 333 334 Expected<SimpleSegmentAlloc> ELFDebugObject::finalizeWorkingMemory() { 335 LLVM_DEBUG({ 336 dbgs() << "Section load-addresses in debug object for \"" 337 << Buffer->getBufferIdentifier() << "\":\n"; 338 for (const auto &KV : Sections) 339 KV.second->dump(dbgs(), KV.first()); 340 }); 341 342 // TODO: This works, but what actual alignment requirements do we have? 343 unsigned PageSize = sys::Process::getPageSizeEstimate(); 344 size_t Size = Buffer->getBufferSize(); 345 346 // Allocate working memory for debug object in read-only segment. 347 auto Alloc = SimpleSegmentAlloc::Create( 348 MemMgr, JD, {{MemProt::Read, {Size, Align(PageSize)}}}); 349 if (!Alloc) 350 return Alloc; 351 352 // Initialize working memory with a copy of our object buffer. 353 auto SegInfo = Alloc->getSegInfo(MemProt::Read); 354 memcpy(SegInfo.WorkingMem.data(), Buffer->getBufferStart(), Size); 355 Buffer.reset(); 356 357 return Alloc; 358 } 359 360 void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name, 361 SectionRange TargetMem) { 362 if (auto *DebugObjSection = getSection(Name)) 363 DebugObjSection->setTargetMemoryRange(TargetMem); 364 } 365 366 template <typename ELFT> 367 Error ELFDebugObject::recordSection( 368 StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) { 369 if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data())) 370 return Err; 371 auto ItInserted = Sections.try_emplace(Name, std::move(Section)); 372 if (!ItInserted.second) 373 return make_error<StringError>("Duplicate section", 374 inconvertibleErrorCode()); 375 return Error::success(); 376 } 377 378 DebugObjectSection *ELFDebugObject::getSection(StringRef Name) { 379 auto It = Sections.find(Name); 380 return It == Sections.end() ? nullptr : It->second.get(); 381 } 382 383 /// Creates a debug object based on the input object file from 384 /// ObjectLinkingLayerJITLinkContext. 385 /// 386 static Expected<std::unique_ptr<DebugObject>> 387 createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G, 388 JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) { 389 switch (G.getTargetTriple().getObjectFormat()) { 390 case Triple::ELF: 391 return ELFDebugObject::Create(ObjBuffer, Ctx, ES); 392 393 default: 394 // TODO: Once we add support for other formats, we might want to split this 395 // into multiple files. 396 return nullptr; 397 } 398 } 399 400 DebugObjectManagerPlugin::DebugObjectManagerPlugin( 401 ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target) 402 : ES(ES), Target(std::move(Target)) {} 403 404 DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default; 405 406 void DebugObjectManagerPlugin::notifyMaterializing( 407 MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx, 408 MemoryBufferRef ObjBuffer) { 409 std::lock_guard<std::mutex> Lock(PendingObjsLock); 410 assert(PendingObjs.count(&MR) == 0 && 411 "Cannot have more than one pending debug object per " 412 "MaterializationResponsibility"); 413 414 if (auto DebugObj = createDebugObjectFromBuffer(ES, G, Ctx, ObjBuffer)) { 415 // Not all link artifacts allow debugging. 416 if (*DebugObj != nullptr) 417 PendingObjs[&MR] = std::move(*DebugObj); 418 } else { 419 ES.reportError(DebugObj.takeError()); 420 } 421 } 422 423 void DebugObjectManagerPlugin::modifyPassConfig( 424 MaterializationResponsibility &MR, LinkGraph &G, 425 PassConfiguration &PassConfig) { 426 // Not all link artifacts have associated debug objects. 427 std::lock_guard<std::mutex> Lock(PendingObjsLock); 428 auto It = PendingObjs.find(&MR); 429 if (It == PendingObjs.end()) 430 return; 431 432 DebugObject &DebugObj = *It->second; 433 if (DebugObj.has(Requirement::ReportFinalSectionLoadAddresses)) { 434 PassConfig.PostAllocationPasses.push_back( 435 [&DebugObj](LinkGraph &Graph) -> Error { 436 for (const Section &GraphSection : Graph.sections()) 437 DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(), 438 SectionRange(GraphSection)); 439 return Error::success(); 440 }); 441 } 442 } 443 444 Error DebugObjectManagerPlugin::notifyEmitted( 445 MaterializationResponsibility &MR) { 446 std::lock_guard<std::mutex> Lock(PendingObjsLock); 447 auto It = PendingObjs.find(&MR); 448 if (It == PendingObjs.end()) 449 return Error::success(); 450 451 // During finalization the debug object is registered with the target. 452 // Materialization must wait for this process to finish. Otherwise we might 453 // start running code before the debugger processed the corresponding debug 454 // info. 455 std::promise<MSVCPError> FinalizePromise; 456 std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future(); 457 458 It->second->finalizeAsync( 459 [this, &FinalizePromise, &MR](Expected<ExecutorAddrRange> TargetMem) { 460 // Any failure here will fail materialization. 461 if (!TargetMem) { 462 FinalizePromise.set_value(TargetMem.takeError()); 463 return; 464 } 465 if (Error Err = Target->registerDebugObject(*TargetMem)) { 466 FinalizePromise.set_value(std::move(Err)); 467 return; 468 } 469 470 // Once our tracking info is updated, notifyEmitted() can return and 471 // finish materialization. 472 FinalizePromise.set_value(MR.withResourceKeyDo([&](ResourceKey K) { 473 assert(PendingObjs.count(&MR) && "We still hold PendingObjsLock"); 474 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 475 RegisteredObjs[K].push_back(std::move(PendingObjs[&MR])); 476 PendingObjs.erase(&MR); 477 })); 478 }); 479 480 return FinalizeErr.get(); 481 } 482 483 Error DebugObjectManagerPlugin::notifyFailed( 484 MaterializationResponsibility &MR) { 485 std::lock_guard<std::mutex> Lock(PendingObjsLock); 486 PendingObjs.erase(&MR); 487 return Error::success(); 488 } 489 490 void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey, 491 ResourceKey SrcKey) { 492 // Debug objects are stored by ResourceKey only after registration. 493 // Thus, pending objects don't need to be updated here. 494 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 495 auto SrcIt = RegisteredObjs.find(SrcKey); 496 if (SrcIt != RegisteredObjs.end()) { 497 // Resources from distinct MaterializationResponsibilitys can get merged 498 // after emission, so we can have multiple debug objects per resource key. 499 for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second) 500 RegisteredObjs[DstKey].push_back(std::move(DebugObj)); 501 RegisteredObjs.erase(SrcIt); 502 } 503 } 504 505 Error DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey Key) { 506 // Removing the resource for a pending object fails materialization, so they 507 // get cleaned up in the notifyFailed() handler. 508 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 509 RegisteredObjs.erase(Key); 510 511 // TODO: Implement unregister notifications. 512 return Error::success(); 513 } 514 515 } // namespace orc 516 } // namespace llvm 517