1 //===------- DebuggerSupportPlugin.cpp - Utils for debugger support -------===// 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 // 10 //===----------------------------------------------------------------------===// 11 12 #include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.h" 13 #include "llvm/ExecutionEngine/Orc/MachOBuilder.h" 14 15 #include "llvm/ADT/SmallSet.h" 16 #include "llvm/ADT/SmallVector.h" 17 #include "llvm/BinaryFormat/MachO.h" 18 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 19 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" 20 21 #include <chrono> 22 23 #define DEBUG_TYPE "orc" 24 25 using namespace llvm; 26 using namespace llvm::jitlink; 27 using namespace llvm::orc; 28 29 static const char *SynthDebugSectionName = "__jitlink_synth_debug_object"; 30 31 namespace { 32 33 class MachODebugObjectSynthesizerBase 34 : public GDBJITDebugInfoRegistrationPlugin::DebugSectionSynthesizer { 35 public: 36 static bool isDebugSection(Section &Sec) { 37 return Sec.getName().starts_with("__DWARF,"); 38 } 39 40 MachODebugObjectSynthesizerBase(LinkGraph &G, ExecutorAddr RegisterActionAddr) 41 : G(G), RegisterActionAddr(RegisterActionAddr) {} 42 virtual ~MachODebugObjectSynthesizerBase() = default; 43 44 Error preserveDebugSections() { 45 if (G.findSectionByName(SynthDebugSectionName)) { 46 LLVM_DEBUG({ 47 dbgs() << "MachODebugObjectSynthesizer skipping graph " << G.getName() 48 << " which contains an unexpected existing " 49 << SynthDebugSectionName << " section.\n"; 50 }); 51 return Error::success(); 52 } 53 54 LLVM_DEBUG({ 55 dbgs() << "MachODebugObjectSynthesizer visiting graph " << G.getName() 56 << "\n"; 57 }); 58 for (auto &Sec : G.sections()) { 59 if (!isDebugSection(Sec)) 60 continue; 61 // Preserve blocks in this debug section by marking one existing symbol 62 // live for each block, and introducing a new live, anonymous symbol for 63 // each currently unreferenced block. 64 LLVM_DEBUG({ 65 dbgs() << " Preserving debug section " << Sec.getName() << "\n"; 66 }); 67 SmallSet<Block *, 8> PreservedBlocks; 68 for (auto *Sym : Sec.symbols()) { 69 bool NewPreservedBlock = 70 PreservedBlocks.insert(&Sym->getBlock()).second; 71 if (NewPreservedBlock) 72 Sym->setLive(true); 73 } 74 for (auto *B : Sec.blocks()) 75 if (!PreservedBlocks.count(B)) 76 G.addAnonymousSymbol(*B, 0, 0, false, true); 77 } 78 79 return Error::success(); 80 } 81 82 protected: 83 LinkGraph &G; 84 ExecutorAddr RegisterActionAddr; 85 }; 86 87 template <typename MachOTraits> 88 class MachODebugObjectSynthesizer : public MachODebugObjectSynthesizerBase { 89 public: 90 MachODebugObjectSynthesizer(ExecutionSession &ES, LinkGraph &G, 91 ExecutorAddr RegisterActionAddr) 92 : MachODebugObjectSynthesizerBase(G, RegisterActionAddr), 93 Builder(ES.getPageSize()) {} 94 95 using MachODebugObjectSynthesizerBase::MachODebugObjectSynthesizerBase; 96 97 Error startSynthesis() override { 98 LLVM_DEBUG({ 99 dbgs() << "Creating " << SynthDebugSectionName << " for " << G.getName() 100 << "\n"; 101 }); 102 103 for (auto &Sec : G.sections()) { 104 if (Sec.blocks().empty()) 105 continue; 106 107 // Skip sections whose name's don't fit the MachO standard. 108 if (Sec.getName().empty() || Sec.getName().size() > 33 || 109 Sec.getName().find(',') > 16) 110 continue; 111 112 if (isDebugSection(Sec)) 113 DebugSections.push_back({&Sec, nullptr}); 114 else if (Sec.getMemLifetime() != MemLifetime::NoAlloc) 115 NonDebugSections.push_back({&Sec, nullptr}); 116 } 117 118 // Bail out early if no debug sections. 119 if (DebugSections.empty()) 120 return Error::success(); 121 122 // Write MachO header and debug section load commands. 123 Builder.Header.filetype = MachO::MH_OBJECT; 124 switch (G.getTargetTriple().getArch()) { 125 case Triple::x86_64: 126 Builder.Header.cputype = MachO::CPU_TYPE_X86_64; 127 Builder.Header.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL; 128 break; 129 case Triple::aarch64: 130 Builder.Header.cputype = MachO::CPU_TYPE_ARM64; 131 Builder.Header.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL; 132 break; 133 default: 134 llvm_unreachable("Unsupported architecture"); 135 } 136 137 Seg = &Builder.addSegment(""); 138 139 StringMap<std::unique_ptr<MemoryBuffer>> DebugSectionMap; 140 StringRef DebugLineSectionData; 141 for (auto &DSec : DebugSections) { 142 auto [SegName, SecName] = DSec.GraphSec->getName().split(','); 143 DSec.BuilderSec = &Seg->addSection(SecName, SegName); 144 145 SectionRange SR(*DSec.GraphSec); 146 DSec.BuilderSec->Content.Size = SR.getSize(); 147 if (!SR.empty()) { 148 DSec.BuilderSec->align = Log2_64(SR.getFirstBlock()->getAlignment()); 149 StringRef SectionData(SR.getFirstBlock()->getContent().data(), 150 SR.getFirstBlock()->getSize()); 151 DebugSectionMap[SecName] = 152 MemoryBuffer::getMemBuffer(SectionData, G.getName(), false); 153 if (SecName == "__debug_line") 154 DebugLineSectionData = SectionData; 155 } 156 } 157 158 std::optional<StringRef> FileName; 159 if (!DebugLineSectionData.empty()) { 160 assert((G.getEndianness() == llvm::endianness::big || 161 G.getEndianness() == llvm::endianness::little) && 162 "G.getEndianness() must be either big or little"); 163 auto DWARFCtx = 164 DWARFContext::create(DebugSectionMap, G.getPointerSize(), 165 G.getEndianness() == llvm::endianness::little); 166 DWARFDataExtractor DebugLineData( 167 DebugLineSectionData, G.getEndianness() == llvm::endianness::little, 168 G.getPointerSize()); 169 uint64_t Offset = 0; 170 DWARFDebugLine::LineTable LineTable; 171 172 // Try to parse line data. Consume error on failure. 173 if (auto Err = LineTable.parse(DebugLineData, &Offset, *DWARFCtx, nullptr, 174 consumeError)) { 175 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { 176 LLVM_DEBUG({ 177 dbgs() << "Cannot parse line table for \"" << G.getName() << "\": "; 178 EIB.log(dbgs()); 179 dbgs() << "\n"; 180 }); 181 }); 182 } else { 183 if (!LineTable.Prologue.FileNames.empty()) 184 FileName = *dwarf::toString(LineTable.Prologue.FileNames[0].Name); 185 } 186 } 187 188 // If no line table (or unable to use) then use graph name. 189 // FIXME: There are probably other debug sections we should look in first. 190 if (!FileName) 191 FileName = StringRef(G.getName()); 192 193 Builder.addSymbol("", MachO::N_SO, 0, 0, 0); 194 Builder.addSymbol(*FileName, MachO::N_SO, 0, 0, 0); 195 auto TimeStamp = std::chrono::duration_cast<std::chrono::seconds>( 196 std::chrono::system_clock::now().time_since_epoch()) 197 .count(); 198 Builder.addSymbol("", MachO::N_OSO, 3, 1, TimeStamp); 199 200 for (auto &NDSP : NonDebugSections) { 201 auto [SegName, SecName] = NDSP.GraphSec->getName().split(','); 202 NDSP.BuilderSec = &Seg->addSection(SecName, SegName); 203 SectionRange SR(*NDSP.GraphSec); 204 if (!SR.empty()) 205 NDSP.BuilderSec->align = Log2_64(SR.getFirstBlock()->getAlignment()); 206 207 // Add stabs. 208 for (auto *Sym : NDSP.GraphSec->symbols()) { 209 // Skip anonymous symbols. 210 if (!Sym->hasName()) 211 continue; 212 213 uint8_t SymType = Sym->isCallable() ? MachO::N_FUN : MachO::N_GSYM; 214 215 Builder.addSymbol("", MachO::N_BNSYM, 1, 0, 0); 216 StabSymbols.push_back( 217 {*Sym, Builder.addSymbol(Sym->getName(), SymType, 1, 0, 0), 218 Builder.addSymbol(Sym->getName(), SymType, 0, 0, 0)}); 219 Builder.addSymbol("", MachO::N_ENSYM, 1, 0, 0); 220 } 221 } 222 223 Builder.addSymbol("", MachO::N_SO, 1, 0, 0); 224 225 // Lay out the debug object, create a section and block for it. 226 size_t DebugObjectSize = Builder.layout(); 227 228 auto &SDOSec = G.createSection(SynthDebugSectionName, MemProt::Read); 229 MachOContainerBlock = &G.createMutableContentBlock( 230 SDOSec, G.allocateBuffer(DebugObjectSize), orc::ExecutorAddr(), 8, 0); 231 232 return Error::success(); 233 } 234 235 Error completeSynthesisAndRegister() override { 236 if (!MachOContainerBlock) { 237 LLVM_DEBUG({ 238 dbgs() << "Not writing MachO debug object header for " << G.getName() 239 << " since createDebugSection failed\n"; 240 }); 241 242 return Error::success(); 243 } 244 ExecutorAddr MaxAddr; 245 for (auto &NDSec : NonDebugSections) { 246 SectionRange SR(*NDSec.GraphSec); 247 NDSec.BuilderSec->addr = SR.getStart().getValue(); 248 NDSec.BuilderSec->size = SR.getSize(); 249 NDSec.BuilderSec->offset = SR.getStart().getValue(); 250 if (SR.getEnd() > MaxAddr) 251 MaxAddr = SR.getEnd(); 252 } 253 254 for (auto &DSec : DebugSections) { 255 if (DSec.GraphSec->blocks_size() != 1) 256 return make_error<StringError>( 257 "Unexpected number of blocks in debug info section", 258 inconvertibleErrorCode()); 259 260 if (ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size > MaxAddr) 261 MaxAddr = ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size; 262 263 auto &B = **DSec.GraphSec->blocks().begin(); 264 DSec.BuilderSec->Content.Data = B.getContent().data(); 265 DSec.BuilderSec->Content.Size = B.getContent().size(); 266 DSec.BuilderSec->flags |= MachO::S_ATTR_DEBUG; 267 } 268 269 LLVM_DEBUG({ 270 dbgs() << "Writing MachO debug object header for " << G.getName() << "\n"; 271 }); 272 273 // Update stab symbol addresses. 274 for (auto &SS : StabSymbols) { 275 SS.StartStab.nlist().n_value = SS.Sym.getAddress().getValue(); 276 SS.EndStab.nlist().n_value = SS.Sym.getSize(); 277 } 278 279 Builder.write(MachOContainerBlock->getAlreadyMutableContent()); 280 281 static constexpr bool AutoRegisterCode = true; 282 SectionRange R(MachOContainerBlock->getSection()); 283 G.allocActions().push_back( 284 {cantFail(shared::WrapperFunctionCall::Create< 285 shared::SPSArgList<shared::SPSExecutorAddrRange, bool>>( 286 RegisterActionAddr, R.getRange(), AutoRegisterCode)), 287 {}}); 288 289 return Error::success(); 290 } 291 292 private: 293 struct SectionPair { 294 Section *GraphSec = nullptr; 295 typename MachOBuilder<MachOTraits>::Section *BuilderSec = nullptr; 296 }; 297 298 struct StabSymbolsEntry { 299 using RelocTarget = typename MachOBuilder<MachOTraits>::RelocTarget; 300 301 StabSymbolsEntry(Symbol &Sym, RelocTarget StartStab, RelocTarget EndStab) 302 : Sym(Sym), StartStab(StartStab), EndStab(EndStab) {} 303 304 Symbol &Sym; 305 RelocTarget StartStab, EndStab; 306 }; 307 308 using BuilderType = MachOBuilder<MachOTraits>; 309 310 Block *MachOContainerBlock = nullptr; 311 MachOBuilder<MachOTraits> Builder; 312 typename MachOBuilder<MachOTraits>::Segment *Seg = nullptr; 313 std::vector<StabSymbolsEntry> StabSymbols; 314 SmallVector<SectionPair, 16> DebugSections; 315 SmallVector<SectionPair, 16> NonDebugSections; 316 }; 317 318 } // end anonymous namespace 319 320 namespace llvm { 321 namespace orc { 322 323 Expected<std::unique_ptr<GDBJITDebugInfoRegistrationPlugin>> 324 GDBJITDebugInfoRegistrationPlugin::Create(ExecutionSession &ES, 325 JITDylib &ProcessJD, 326 const Triple &TT) { 327 auto RegisterActionAddr = 328 TT.isOSBinFormatMachO() 329 ? ES.intern("_llvm_orc_registerJITLoaderGDBAllocAction") 330 : ES.intern("llvm_orc_registerJITLoaderGDBAllocAction"); 331 332 if (auto RegisterSym = ES.lookup({&ProcessJD}, RegisterActionAddr)) 333 return std::make_unique<GDBJITDebugInfoRegistrationPlugin>( 334 RegisterSym->getAddress()); 335 else 336 return RegisterSym.takeError(); 337 } 338 339 Error GDBJITDebugInfoRegistrationPlugin::notifyFailed( 340 MaterializationResponsibility &MR) { 341 return Error::success(); 342 } 343 344 Error GDBJITDebugInfoRegistrationPlugin::notifyRemovingResources( 345 JITDylib &JD, ResourceKey K) { 346 return Error::success(); 347 } 348 349 void GDBJITDebugInfoRegistrationPlugin::notifyTransferringResources( 350 JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) {} 351 352 void GDBJITDebugInfoRegistrationPlugin::modifyPassConfig( 353 MaterializationResponsibility &MR, LinkGraph &LG, 354 PassConfiguration &PassConfig) { 355 356 if (LG.getTargetTriple().getObjectFormat() == Triple::MachO) 357 modifyPassConfigForMachO(MR, LG, PassConfig); 358 else { 359 LLVM_DEBUG({ 360 dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unspported graph " 361 << LG.getName() << "(triple = " << LG.getTargetTriple().str() 362 << "\n"; 363 }); 364 } 365 } 366 367 void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO( 368 MaterializationResponsibility &MR, jitlink::LinkGraph &LG, 369 jitlink::PassConfiguration &PassConfig) { 370 371 switch (LG.getTargetTriple().getArch()) { 372 case Triple::x86_64: 373 case Triple::aarch64: 374 // Supported, continue. 375 assert(LG.getPointerSize() == 8 && "Graph has incorrect pointer size"); 376 assert(LG.getEndianness() == llvm::endianness::little && 377 "Graph has incorrect endianness"); 378 break; 379 default: 380 // Unsupported. 381 LLVM_DEBUG({ 382 dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unsupported " 383 << "MachO graph " << LG.getName() 384 << "(triple = " << LG.getTargetTriple().str() 385 << ", pointer size = " << LG.getPointerSize() << ", endianness = " 386 << (LG.getEndianness() == llvm::endianness::big ? "big" : "little") 387 << ")\n"; 388 }); 389 return; 390 } 391 392 // Scan for debug sections. If we find one then install passes. 393 bool HasDebugSections = false; 394 for (auto &Sec : LG.sections()) 395 if (MachODebugObjectSynthesizerBase::isDebugSection(Sec)) { 396 HasDebugSections = true; 397 break; 398 } 399 400 if (HasDebugSections) { 401 LLVM_DEBUG({ 402 dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName() 403 << " contains debug info. Installing debugger support passes.\n"; 404 }); 405 406 auto MDOS = std::make_shared<MachODebugObjectSynthesizer<MachO64LE>>( 407 MR.getTargetJITDylib().getExecutionSession(), LG, RegisterActionAddr); 408 PassConfig.PrePrunePasses.push_back( 409 [=](LinkGraph &G) { return MDOS->preserveDebugSections(); }); 410 PassConfig.PostPrunePasses.push_back( 411 [=](LinkGraph &G) { return MDOS->startSynthesis(); }); 412 PassConfig.PostFixupPasses.push_back( 413 [=](LinkGraph &G) { return MDOS->completeSynthesisAndRegister(); }); 414 } else { 415 LLVM_DEBUG({ 416 dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName() 417 << " contains no debug info. Skipping.\n"; 418 }); 419 } 420 } 421 422 } // namespace orc 423 } // namespace llvm 424