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 /// Creates a debug object based on the input object file from 375 /// ObjectLinkingLayerJITLinkContext. 376 /// 377 static Expected<std::unique_ptr<DebugObject>> 378 createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G, 379 JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) { 380 switch (G.getTargetTriple().getObjectFormat()) { 381 case Triple::ELF: 382 return ELFDebugObject::Create(ObjBuffer, Ctx, ES); 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() = default; 396 397 void DebugObjectManagerPlugin::notifyMaterializing( 398 MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx, 399 MemoryBufferRef ObjBuffer) { 400 std::lock_guard<std::mutex> Lock(PendingObjsLock); 401 assert(PendingObjs.count(&MR) == 0 && 402 "Cannot have more than one pending debug object per " 403 "MaterializationResponsibility"); 404 405 if (auto DebugObj = createDebugObjectFromBuffer(ES, G, Ctx, ObjBuffer)) { 406 // Not all link artifacts allow debugging. 407 if (*DebugObj != nullptr) 408 PendingObjs[&MR] = std::move(*DebugObj); 409 } else { 410 ES.reportError(DebugObj.takeError()); 411 } 412 } 413 414 void DebugObjectManagerPlugin::modifyPassConfig( 415 MaterializationResponsibility &MR, LinkGraph &G, 416 PassConfiguration &PassConfig) { 417 // Not all link artifacts have associated debug objects. 418 std::lock_guard<std::mutex> Lock(PendingObjsLock); 419 auto It = PendingObjs.find(&MR); 420 if (It == PendingObjs.end()) 421 return; 422 423 DebugObject &DebugObj = *It->second; 424 if (DebugObj.has(Requirement::ReportFinalSectionLoadAddresses)) { 425 PassConfig.PostAllocationPasses.push_back( 426 [&DebugObj](LinkGraph &Graph) -> Error { 427 for (const Section &GraphSection : Graph.sections()) 428 DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(), 429 SectionRange(GraphSection)); 430 return Error::success(); 431 }); 432 } 433 } 434 435 Error DebugObjectManagerPlugin::notifyEmitted( 436 MaterializationResponsibility &MR) { 437 std::lock_guard<std::mutex> Lock(PendingObjsLock); 438 auto It = PendingObjs.find(&MR); 439 if (It == PendingObjs.end()) 440 return Error::success(); 441 442 // During finalization the debug object is registered with the target. 443 // Materialization must wait for this process to finish. Otherwise we might 444 // start running code before the debugger processed the corresponding debug 445 // info. 446 std::promise<MSVCPError> FinalizePromise; 447 std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future(); 448 449 It->second->finalizeAsync( 450 [this, &FinalizePromise, &MR](Expected<sys::MemoryBlock> TargetMem) { 451 // Any failure here will fail materialization. 452 if (!TargetMem) { 453 FinalizePromise.set_value(TargetMem.takeError()); 454 return; 455 } 456 if (Error Err = Target->registerDebugObject(*TargetMem)) { 457 FinalizePromise.set_value(std::move(Err)); 458 return; 459 } 460 461 // Once our tracking info is updated, notifyEmitted() can return and 462 // finish materialization. 463 FinalizePromise.set_value(MR.withResourceKeyDo([&](ResourceKey K) { 464 assert(PendingObjs.count(&MR) && "We still hold PendingObjsLock"); 465 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 466 RegisteredObjs[K].push_back(std::move(PendingObjs[&MR])); 467 PendingObjs.erase(&MR); 468 })); 469 }); 470 471 return FinalizeErr.get(); 472 } 473 474 Error DebugObjectManagerPlugin::notifyFailed( 475 MaterializationResponsibility &MR) { 476 std::lock_guard<std::mutex> Lock(PendingObjsLock); 477 PendingObjs.erase(&MR); 478 return Error::success(); 479 } 480 481 void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey, 482 ResourceKey SrcKey) { 483 // Debug objects are stored by ResourceKey only after registration. 484 // Thus, pending objects don't need to be updated here. 485 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 486 auto SrcIt = RegisteredObjs.find(SrcKey); 487 if (SrcIt != RegisteredObjs.end()) { 488 // Resources from distinct MaterializationResponsibilitys can get merged 489 // after emission, so we can have multiple debug objects per resource key. 490 for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second) 491 RegisteredObjs[DstKey].push_back(std::move(DebugObj)); 492 RegisteredObjs.erase(SrcIt); 493 } 494 } 495 496 Error DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey Key) { 497 // Removing the resource for a pending object fails materialization, so they 498 // get cleaned up in the notifyFailed() handler. 499 std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 500 RegisteredObjs.erase(Key); 501 502 // TODO: Implement unregister notifications. 503 return Error::success(); 504 } 505 506 } // namespace orc 507 } // namespace llvm 508