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