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