brintos

brintos / llvm-project-archived public Read only

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