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 if (auto CPUType = MachO::getCPUType(G.getTargetTriple())) 125 Builder.Header.cputype = *CPUType; 126 else 127 return CPUType.takeError(); 128 if (auto CPUSubType = MachO::getCPUSubType(G.getTargetTriple())) 129 Builder.Header.cpusubtype = *CPUSubType; 130 else 131 return CPUSubType.takeError(); 132 133 Seg = &Builder.addSegment(""); 134 135 StringMap<std::unique_ptr<MemoryBuffer>> DebugSectionMap; 136 StringRef DebugLineSectionData; 137 for (auto &DSec : DebugSections) { 138 auto [SegName, SecName] = DSec.GraphSec->getName().split(','); 139 DSec.BuilderSec = &Seg->addSection(SecName, SegName); 140 141 SectionRange SR(*DSec.GraphSec); 142 DSec.BuilderSec->Content.Size = SR.getSize(); 143 if (!SR.empty()) { 144 DSec.BuilderSec->align = Log2_64(SR.getFirstBlock()->getAlignment()); 145 StringRef SectionData(SR.getFirstBlock()->getContent().data(), 146 SR.getFirstBlock()->getSize()); 147 DebugSectionMap[SecName.drop_front(2)] = // drop "__" prefix. 148 MemoryBuffer::getMemBuffer(SectionData, G.getName(), false); 149 if (SecName == "__debug_line") 150 DebugLineSectionData = SectionData; 151 } 152 } 153 154 std::optional<StringRef> FileName; 155 if (!DebugLineSectionData.empty()) { 156 assert((G.getEndianness() == llvm::endianness::big || 157 G.getEndianness() == llvm::endianness::little) && 158 "G.getEndianness() must be either big or little"); 159 auto DWARFCtx = 160 DWARFContext::create(DebugSectionMap, G.getPointerSize(), 161 G.getEndianness() == llvm::endianness::little); 162 DWARFDataExtractor DebugLineData( 163 DebugLineSectionData, G.getEndianness() == llvm::endianness::little, 164 G.getPointerSize()); 165 uint64_t Offset = 0; 166 DWARFDebugLine::Prologue P; 167 168 // Try to parse line data. Consume error on failure. 169 if (auto Err = P.parse(DebugLineData, &Offset, consumeError, *DWARFCtx)) { 170 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { 171 LLVM_DEBUG({ 172 dbgs() << "Cannot parse line table for \"" << G.getName() << "\": "; 173 EIB.log(dbgs()); 174 dbgs() << "\n"; 175 }); 176 }); 177 } else { 178 for (auto &FN : P.FileNames) 179 if ((FileName = dwarf::toString(FN.Name))) { 180 LLVM_DEBUG({ 181 dbgs() << "Using FileName = \"" << *FileName 182 << "\" from DWARF line table\n"; 183 }); 184 break; 185 } 186 } 187 } 188 189 // If no line table (or unable to use) then use graph name. 190 // FIXME: There are probably other debug sections we should look in first. 191 if (!FileName) { 192 LLVM_DEBUG({ 193 dbgs() << "Could not find source name from DWARF line table. " 194 "Using FileName = \"\"\n"; 195 }); 196 FileName = ""; 197 } 198 199 Builder.addSymbol("", MachO::N_SO, 0, 0, 0); 200 Builder.addSymbol(*FileName, MachO::N_SO, 0, 0, 0); 201 auto TimeStamp = std::chrono::duration_cast<std::chrono::seconds>( 202 std::chrono::system_clock::now().time_since_epoch()) 203 .count(); 204 Builder.addSymbol("", MachO::N_OSO, 3, 1, TimeStamp); 205 206 for (auto &NDSP : NonDebugSections) { 207 auto [SegName, SecName] = NDSP.GraphSec->getName().split(','); 208 NDSP.BuilderSec = &Seg->addSection(SecName, SegName); 209 SectionRange SR(*NDSP.GraphSec); 210 if (!SR.empty()) 211 NDSP.BuilderSec->align = Log2_64(SR.getFirstBlock()->getAlignment()); 212 213 // Add stabs. 214 for (auto *Sym : NDSP.GraphSec->symbols()) { 215 // Skip anonymous symbols. 216 if (!Sym->hasName()) 217 continue; 218 219 uint8_t SymType = Sym->isCallable() ? MachO::N_FUN : MachO::N_GSYM; 220 221 Builder.addSymbol("", MachO::N_BNSYM, 1, 0, 0); 222 StabSymbols.push_back( 223 {*Sym, Builder.addSymbol(*Sym->getName(), SymType, 1, 0, 0), 224 Builder.addSymbol(*Sym->getName(), SymType, 0, 0, 0)}); 225 Builder.addSymbol("", MachO::N_ENSYM, 1, 0, 0); 226 } 227 } 228 229 Builder.addSymbol("", MachO::N_SO, 1, 0, 0); 230 231 // Lay out the debug object, create a section and block for it. 232 size_t DebugObjectSize = Builder.layout(); 233 234 auto &SDOSec = G.createSection(SynthDebugSectionName, MemProt::Read); 235 MachOContainerBlock = &G.createMutableContentBlock( 236 SDOSec, G.allocateBuffer(DebugObjectSize), orc::ExecutorAddr(), 8, 0); 237 238 return Error::success(); 239 } 240 241 Error completeSynthesisAndRegister() override { 242 if (!MachOContainerBlock) { 243 LLVM_DEBUG({ 244 dbgs() << "Not writing MachO debug object header for " << G.getName() 245 << " since createDebugSection failed\n"; 246 }); 247 248 return Error::success(); 249 } 250 ExecutorAddr MaxAddr; 251 for (auto &NDSec : NonDebugSections) { 252 SectionRange SR(*NDSec.GraphSec); 253 NDSec.BuilderSec->addr = SR.getStart().getValue(); 254 NDSec.BuilderSec->size = SR.getSize(); 255 NDSec.BuilderSec->offset = SR.getStart().getValue(); 256 if (SR.getEnd() > MaxAddr) 257 MaxAddr = SR.getEnd(); 258 } 259 260 for (auto &DSec : DebugSections) { 261 if (DSec.GraphSec->blocks_size() != 1) 262 return make_error<StringError>( 263 "Unexpected number of blocks in debug info section", 264 inconvertibleErrorCode()); 265 266 if (ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size > MaxAddr) 267 MaxAddr = ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size; 268 269 auto &B = **DSec.GraphSec->blocks().begin(); 270 DSec.BuilderSec->Content.Data = B.getContent().data(); 271 DSec.BuilderSec->Content.Size = B.getContent().size(); 272 DSec.BuilderSec->flags |= MachO::S_ATTR_DEBUG; 273 } 274 275 LLVM_DEBUG({ 276 dbgs() << "Writing MachO debug object header for " << G.getName() << "\n"; 277 }); 278 279 // Update stab symbol addresses. 280 for (auto &SS : StabSymbols) { 281 SS.StartStab.nlist().n_value = SS.Sym.getAddress().getValue(); 282 SS.EndStab.nlist().n_value = SS.Sym.getSize(); 283 } 284 285 Builder.write(MachOContainerBlock->getAlreadyMutableContent()); 286 287 static constexpr bool AutoRegisterCode = true; 288 SectionRange R(MachOContainerBlock->getSection()); 289 G.allocActions().push_back( 290 {cantFail(shared::WrapperFunctionCall::Create< 291 shared::SPSArgList<shared::SPSExecutorAddrRange, bool>>( 292 RegisterActionAddr, R.getRange(), AutoRegisterCode)), 293 {}}); 294 295 return Error::success(); 296 } 297 298 private: 299 struct SectionPair { 300 Section *GraphSec = nullptr; 301 typename MachOBuilder<MachOTraits>::Section *BuilderSec = nullptr; 302 }; 303 304 struct StabSymbolsEntry { 305 using RelocTarget = typename MachOBuilder<MachOTraits>::RelocTarget; 306 307 StabSymbolsEntry(Symbol &Sym, RelocTarget StartStab, RelocTarget EndStab) 308 : Sym(Sym), StartStab(StartStab), EndStab(EndStab) {} 309 310 Symbol &Sym; 311 RelocTarget StartStab, EndStab; 312 }; 313 314 using BuilderType = MachOBuilder<MachOTraits>; 315 316 Block *MachOContainerBlock = nullptr; 317 MachOBuilder<MachOTraits> Builder; 318 typename MachOBuilder<MachOTraits>::Segment *Seg = nullptr; 319 std::vector<StabSymbolsEntry> StabSymbols; 320 SmallVector<SectionPair, 16> DebugSections; 321 SmallVector<SectionPair, 16> NonDebugSections; 322 }; 323 324 } // end anonymous namespace 325 326 namespace llvm { 327 namespace orc { 328 329 Expected<std::unique_ptr<GDBJITDebugInfoRegistrationPlugin>> 330 GDBJITDebugInfoRegistrationPlugin::Create(ExecutionSession &ES, 331 JITDylib &ProcessJD, 332 const Triple &TT) { 333 auto RegisterActionAddr = 334 TT.isOSBinFormatMachO() 335 ? ES.intern("_llvm_orc_registerJITLoaderGDBAllocAction") 336 : ES.intern("llvm_orc_registerJITLoaderGDBAllocAction"); 337 338 if (auto RegisterSym = ES.lookup({&ProcessJD}, RegisterActionAddr)) 339 return std::make_unique<GDBJITDebugInfoRegistrationPlugin>( 340 RegisterSym->getAddress()); 341 else 342 return RegisterSym.takeError(); 343 } 344 345 Error GDBJITDebugInfoRegistrationPlugin::notifyFailed( 346 MaterializationResponsibility &MR) { 347 return Error::success(); 348 } 349 350 Error GDBJITDebugInfoRegistrationPlugin::notifyRemovingResources( 351 JITDylib &JD, ResourceKey K) { 352 return Error::success(); 353 } 354 355 void GDBJITDebugInfoRegistrationPlugin::notifyTransferringResources( 356 JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) {} 357 358 void GDBJITDebugInfoRegistrationPlugin::modifyPassConfig( 359 MaterializationResponsibility &MR, LinkGraph &LG, 360 PassConfiguration &PassConfig) { 361 362 if (LG.getTargetTriple().getObjectFormat() == Triple::MachO) 363 modifyPassConfigForMachO(MR, LG, PassConfig); 364 else { 365 LLVM_DEBUG({ 366 dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unspported graph " 367 << LG.getName() << "(triple = " << LG.getTargetTriple().str() 368 << "\n"; 369 }); 370 } 371 } 372 373 void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO( 374 MaterializationResponsibility &MR, jitlink::LinkGraph &LG, 375 jitlink::PassConfiguration &PassConfig) { 376 377 switch (LG.getTargetTriple().getArch()) { 378 case Triple::x86_64: 379 case Triple::aarch64: 380 // Supported, continue. 381 assert(LG.getPointerSize() == 8 && "Graph has incorrect pointer size"); 382 assert(LG.getEndianness() == llvm::endianness::little && 383 "Graph has incorrect endianness"); 384 break; 385 default: 386 // Unsupported. 387 LLVM_DEBUG({ 388 dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unsupported " 389 << "MachO graph " << LG.getName() 390 << "(triple = " << LG.getTargetTriple().str() 391 << ", pointer size = " << LG.getPointerSize() << ", endianness = " 392 << (LG.getEndianness() == llvm::endianness::big ? "big" : "little") 393 << ")\n"; 394 }); 395 return; 396 } 397 398 // Scan for debug sections. If we find one then install passes. 399 bool HasDebugSections = false; 400 for (auto &Sec : LG.sections()) 401 if (MachODebugObjectSynthesizerBase::isDebugSection(Sec)) { 402 HasDebugSections = true; 403 break; 404 } 405 406 if (HasDebugSections) { 407 LLVM_DEBUG({ 408 dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName() 409 << " contains debug info. Installing debugger support passes.\n"; 410 }); 411 412 auto MDOS = std::make_shared<MachODebugObjectSynthesizer<MachO64LE>>( 413 MR.getTargetJITDylib().getExecutionSession(), LG, RegisterActionAddr); 414 PassConfig.PrePrunePasses.push_back( 415 [=](LinkGraph &G) { return MDOS->preserveDebugSections(); }); 416 PassConfig.PostPrunePasses.push_back( 417 [=](LinkGraph &G) { return MDOS->startSynthesis(); }); 418 PassConfig.PostFixupPasses.push_back( 419 [=](LinkGraph &G) { return MDOS->completeSynthesisAndRegister(); }); 420 } else { 421 LLVM_DEBUG({ 422 dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName() 423 << " contains no debug info. Skipping.\n"; 424 }); 425 } 426 } 427 428 } // namespace orc 429 } // namespace llvm 430