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