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