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) : Ctx(Ctx) {} 127 virtual ~DebugObject() = default; 128 129 void set(Requirement Req) { Reqs.insert(Req); } 130 bool has(Requirement Req) const { return Reqs.count(Req) > 0; } 131 132 using FinalizeContinuation = std::function<void(Expected<sys::MemoryBlock>)>; 133 void finalizeAsync(FinalizeContinuation OnFinalize); 134 135 Error deallocate() { 136 if (Alloc) 137 return Alloc->deallocate(); 138 return Error::success(); 139 } 140 141 virtual void reportSectionTargetMemoryRange(StringRef Name, 142 SectionRange TargetMem) {} 143 144 protected: 145 using Allocation = JITLinkMemoryManager::Allocation; 146 147 virtual Expected<std::unique_ptr<Allocation>> 148 finalizeWorkingMemory(JITLinkContext &Ctx) = 0; 149 150 private: 151 JITLinkContext &Ctx; 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>> Create(MemoryBufferRef Buffer, 185 JITLinkContext &Ctx); 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 206 static std::unique_ptr<WritableMemoryBuffer> 207 CopyBuffer(MemoryBufferRef Buffer, Error &Err); 208 209 ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer, 210 JITLinkContext &Ctx) 211 : DebugObject(Ctx), Buffer(std::move(Buffer)) { 212 set(Requirement::ReportFinalSectionLoadAddresses); 213 } 214 215 std::unique_ptr<WritableMemoryBuffer> Buffer; 216 StringMap<std::unique_ptr<DebugObjectSection>> Sections; 217 }; 218 219 static const std::set<StringRef> DwarfSectionNames = { 220 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \ 221 ELF_NAME, 222 #include "llvm/BinaryFormat/Dwarf.def" 223 #undef HANDLE_DWARF_SECTION 224 }; 225 226 static bool isDwarfSection(StringRef SectionName) { 227 return DwarfSectionNames.count(SectionName) == 1; 228 } 229 230 std::unique_ptr<WritableMemoryBuffer> 231 ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer, Error &Err) { 232 ErrorAsOutParameter _(&Err); 233 size_t Size = Buffer.getBufferSize(); 234 StringRef Name = Buffer.getBufferIdentifier(); 235 if (auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(Size, Name)) { 236 memcpy(Copy->getBufferStart(), Buffer.getBufferStart(), Size); 237 return Copy; 238 } 239 240 Err = errorCodeToError(make_error_code(errc::not_enough_memory)); 241 return nullptr; 242 } 243 244 template <typename ELFT> 245 Expected<std::unique_ptr<ELFDebugObject>> 246 ELFDebugObject::CreateArchType(MemoryBufferRef Buffer, JITLinkContext &Ctx) { 247 using SectionHeader = typename ELFT::Shdr; 248 249 Error Err = Error::success(); 250 std::unique_ptr<ELFDebugObject> DebugObj( 251 new ELFDebugObject(CopyBuffer(Buffer, Err), Ctx)); 252 if (Err) 253 return std::move(Err); 254 255 Expected<ELFFile<ELFT>> ObjRef = ELFFile<ELFT>::create(DebugObj->getBuffer()); 256 if (!ObjRef) 257 return ObjRef.takeError(); 258 259 // TODO: Add support for other architectures. 260 uint16_t TargetMachineArch = ObjRef->getHeader().e_machine; 261 if (TargetMachineArch != ELF::EM_X86_64) 262 return nullptr; 263 264 Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections(); 265 if (!Sections) 266 return Sections.takeError(); 267 268 bool HasDwarfSection = false; 269 for (const SectionHeader &Header : *Sections) { 270 Expected<StringRef> Name = ObjRef->getSectionName(Header); 271 if (!Name) 272 return Name.takeError(); 273 if (Name->empty()) 274 continue; 275 HasDwarfSection |= isDwarfSection(*Name); 276 277 auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header); 278 if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped))) 279 return std::move(Err); 280 } 281 282 if (!HasDwarfSection) { 283 LLVM_DEBUG(dbgs() << "Aborting debug registration for LinkGraph \"" 284 << DebugObj->Buffer->getBufferIdentifier() 285 << "\": input object contains no debug info\n"); 286 return nullptr; 287 } 288 289 return std::move(DebugObj); 290 } 291 292 Expected<std::unique_ptr<DebugObject>> 293 ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx) { 294 unsigned char Class, Endian; 295 std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer()); 296 297 if (Class == ELF::ELFCLASS32) { 298 if (Endian == ELF::ELFDATA2LSB) 299 return CreateArchType<ELF32LE>(Buffer, Ctx); 300 if (Endian == ELF::ELFDATA2MSB) 301 return CreateArchType<ELF32BE>(Buffer, Ctx); 302 return nullptr; 303 } 304 if (Class == ELF::ELFCLASS64) { 305 if (Endian == ELF::ELFDATA2LSB) 306 return CreateArchType<ELF64LE>(Buffer, Ctx); 307 if (Endian == ELF::ELFDATA2MSB) 308 return CreateArchType<ELF64BE>(Buffer, Ctx); 309 return nullptr; 310 } 311 return nullptr; 312 } 313 314 Expected<std::unique_ptr<DebugObject::Allocation>> 315 ELFDebugObject::finalizeWorkingMemory(JITLinkContext &Ctx) { 316 LLVM_DEBUG({ 317 dbgs() << "Section load-addresses in debug object for \"" 318 << Buffer->getBufferIdentifier() << "\":\n"; 319 for (const auto &KV : Sections) 320 KV.second->dump(dbgs(), KV.first()); 321 }); 322 323 // TODO: This works, but what actual alignment requirements do we have? 324 unsigned Alignment = sys::Process::getPageSizeEstimate(); 325 JITLinkMemoryManager &MemMgr = Ctx.getMemoryManager(); 326 const JITLinkDylib *JD = Ctx.getJITLinkDylib(); 327 size_t Size = Buffer->getBufferSize(); 328 329 // Allocate working memory for debug object in read-only segment. 330 JITLinkMemoryManager::SegmentsRequestMap SingleReadOnlySegment; 331 SingleReadOnlySegment[ReadOnly] = 332 JITLinkMemoryManager::SegmentRequest(Alignment, Size, 0); 333 334 auto AllocOrErr = MemMgr.allocate(JD, SingleReadOnlySegment); 335 if (!AllocOrErr) 336 return AllocOrErr.takeError(); 337 338 // Initialize working memory with a copy of our object buffer. 339 // TODO: Use our buffer as working memory directly. 340 std::unique_ptr<Allocation> Alloc = std::move(*AllocOrErr); 341 MutableArrayRef<char> WorkingMem = Alloc->getWorkingMemory(ReadOnly); 342 memcpy(WorkingMem.data(), Buffer->getBufferStart(), Size); 343 Buffer.reset(); 344 345 return std::move(Alloc); 346 } 347 348 void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name, 349 SectionRange TargetMem) { 350 if (auto *DebugObjSection = getSection(Name)) 351 DebugObjSection->setTargetMemoryRange(TargetMem); 352 } 353 354 template <typename ELFT> 355 Error ELFDebugObject::recordSection( 356 StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) { 357 if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data())) 358 return Err; 359 auto ItInserted = Sections.try_emplace(Name, std::move(Section)); 360 if (!ItInserted.second) 361 return make_error<StringError>("Duplicate section", 362 inconvertibleErrorCode()); 363 return Error::success(); 364 } 365 366 DebugObjectSection *ELFDebugObject::getSection(StringRef Name) { 367 auto It = Sections.find(Name); 368 return It == Sections.end() ? nullptr : It->second.get(); 369 } 370 371 static ResourceKey getResourceKey(MaterializationResponsibility &MR) { 372 ResourceKey Key; 373 if (auto Err = MR.withResourceKeyDo([&](ResourceKey K) { Key = K; })) { 374 MR.getExecutionSession().reportError(std::move(Err)); 375 return ResourceKey{}; 376 } 377 assert(Key && "Invalid key"); 378 return Key; 379 } 380 381 /// Creates a debug object based on the input object file from 382 /// ObjectLinkingLayerJITLinkContext. 383 /// 384 static Expected<std::unique_ptr<DebugObject>> 385 createDebugObjectFromBuffer(LinkGraph &G, JITLinkContext &Ctx, 386 MemoryBufferRef ObjBuffer) { 387 switch (G.getTargetTriple().getObjectFormat()) { 388 case Triple::ELF: 389 return ELFDebugObject::Create(ObjBuffer, Ctx); 390 391 default: 392 // TODO: Once we add support for other formats, we might want to split this 393 // into multiple files. 394 return nullptr; 395 } 396 } 397 398 DebugObjectManagerPlugin::DebugObjectManagerPlugin( 399 ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target) 400 : ES(ES), Target(std::move(Target)) {} 401 402 DebugObjectManagerPlugin::~DebugObjectManagerPlugin() { 403 for (auto &KV : PendingObjs) { 404 std::unique_ptr<DebugObject> &DebugObj = KV.second; 405 if (Error Err = DebugObj->deallocate()) 406 ES.reportError(std::move(Err)); 407 } 408 for (auto &KV : RegisteredObjs) { 409 for (std::unique_ptr<DebugObject> &DebugObj : KV.second) 410 if (Error Err = DebugObj->deallocate()) 411 ES.reportError(std::move(Err)); 412 } 413 } 414 415 void DebugObjectManagerPlugin::notifyMaterializing( 416 MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx, 417 MemoryBufferRef ObjBuffer) { 418 assert(PendingObjs.count(getResourceKey(MR)) == 0 && 419 "Cannot have more than one pending debug object per " 420 "MaterializationResponsibility"); 421 422 std::lock_guard<std::mutex> Lock(PendingObjsLock); 423 if (auto DebugObj = createDebugObjectFromBuffer(G, Ctx, ObjBuffer)) { 424 // Not all link artifacts allow debugging. 425 if (*DebugObj != nullptr) { 426 ResourceKey Key = getResourceKey(MR); 427 PendingObjs[Key] = std::move(*DebugObj); 428 } 429 } else { 430 ES.reportError(DebugObj.takeError()); 431 } 432 } 433 434 void DebugObjectManagerPlugin::modifyPassConfig( 435 MaterializationResponsibility &MR, const Triple &TT, 436 PassConfiguration &PassConfig) { 437 // Not all link artifacts have associated debug objects. 438 std::lock_guard<std::mutex> Lock(PendingObjsLock); 439 auto It = PendingObjs.find(getResourceKey(MR)); 440 if (It == PendingObjs.end()) 441 return; 442 443 DebugObject &DebugObj = *It->second; 444 if (DebugObj.has(Requirement::ReportFinalSectionLoadAddresses)) { 445 PassConfig.PostAllocationPasses.push_back( 446 [&DebugObj](LinkGraph &Graph) -> Error { 447 for (const Section &GraphSection : Graph.sections()) 448 DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(), 449 SectionRange(GraphSection)); 450 return Error::success(); 451 }); 452 } 453 } 454 455 Error DebugObjectManagerPlugin::notifyEmitted( 456 MaterializationResponsibility &MR) { 457 ResourceKey Key = getResourceKey(MR); 458 459 std::lock_guard<std::mutex> Lock(PendingObjsLock); 460 auto It = PendingObjs.find(Key); 461 if (It == PendingObjs.end()) 462 return Error::success(); 463 464 DebugObject *UnownedDebugObj = It->second.release(); 465 PendingObjs.erase(It); 466 467 // During finalization the debug object is registered with the target. 468 // Materialization must wait for this process to finish. Otherwise we might 469 // start running code before the debugger processed the corresponding debug 470 // info. 471 std::promise<MSVCPError> FinalizePromise; 472 std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future(); 473 474 // FIXME: We released ownership of the DebugObject, so we can easily capture 475 // the raw pointer in the continuation function, which re-owns it immediately. 476 if (UnownedDebugObj) 477 UnownedDebugObj->finalizeAsync( 478 [this, Key, UnownedDebugObj, 479 &FinalizePromise](Expected<sys::MemoryBlock> TargetMem) { 480 std::unique_ptr<DebugObject> ReownedDebugObj(UnownedDebugObj); 481 if (!TargetMem) { 482 FinalizePromise.set_value(TargetMem.takeError()); 483 return; 484 } 485 if (Error Err = Target->registerDebugObject(*TargetMem)) { 486 FinalizePromise.set_value(std::move(Err)); 487 return; 488 } 489 490 // Registration successful, notifyEmitted() can return now and 491 // materialization can finish. 492 FinalizePromise.set_value(Error::success()); 493 494 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 495 RegisteredObjs[Key].push_back(std::move(ReownedDebugObj)); 496 }); 497 498 return FinalizeErr.get(); 499 } 500 501 Error DebugObjectManagerPlugin::notifyFailed( 502 MaterializationResponsibility &MR) { 503 std::lock_guard<std::mutex> Lock(PendingObjsLock); 504 PendingObjs.erase(getResourceKey(MR)); 505 return Error::success(); 506 } 507 508 void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey, 509 ResourceKey SrcKey) { 510 { 511 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 512 auto SrcIt = RegisteredObjs.find(SrcKey); 513 if (SrcIt != RegisteredObjs.end()) { 514 // Resources from distinct MaterializationResponsibilitys can get merged 515 // after emission, so we can have multiple debug objects per resource key. 516 for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second) 517 RegisteredObjs[DstKey].push_back(std::move(DebugObj)); 518 RegisteredObjs.erase(SrcIt); 519 } 520 } 521 { 522 std::lock_guard<std::mutex> Lock(PendingObjsLock); 523 auto SrcIt = PendingObjs.find(SrcKey); 524 if (SrcIt != PendingObjs.end()) { 525 assert(PendingObjs.count(DstKey) == 0 && 526 "Cannot have more than one pending debug object per " 527 "MaterializationResponsibility"); 528 PendingObjs[DstKey] = std::move(SrcIt->second); 529 PendingObjs.erase(SrcIt); 530 } 531 } 532 } 533 534 Error DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey K) { 535 { 536 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 537 RegisteredObjs.erase(K); 538 // TODO: Implement unregister notifications. 539 } 540 std::lock_guard<std::mutex> Lock(PendingObjsLock); 541 PendingObjs.erase(K); 542 543 return Error::success(); 544 } 545 546 } // namespace orc 547 } // namespace llvm 548