[ORC] Initial MachO debugging support (via GDB JIT debug registration interface)

This commit adds a new plugin, GDBJITDebugInfoRegistrationPlugin, that checks
for objects containing debug info and registers any debug info found via the
GDB JIT registration API.

To enable this registration without redundantly representing non-debug sections
this plugin synthesizes a new embedded object within a section of the LinkGraph.
An allocation action is used to make the registration call.

Currently MachO only. ELF users can still use the DebugObjectManagerPlugin. The
two are likely to be merged in the near future.
This commit is contained in:
Lang Hames
2021-11-11 15:19:21 -08:00
parent c35e8185d8
commit e1933a0488
10 changed files with 582 additions and 43 deletions

View File

@@ -343,6 +343,12 @@ private:
std::vector<Edge> Edges;
};
// Align a JITTargetAddress to conform with block alignment requirements.
inline JITTargetAddress alignToBlock(JITTargetAddress Addr, Block &B) {
uint64_t Delta = (B.getAlignmentOffset() - Addr) % B.getAlignment();
return Addr + Delta;
}
/// Describes symbol linkage. This can be used to make resolve definition
/// clashes.
enum class Linkage : uint8_t {

View File

@@ -0,0 +1,64 @@
//===--- DebugerSupportPlugin.h -- Utils for debugger support ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Generates debug objects and registers them using the jit-loader-gdb protocol.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_DEBUGGERSUPPORT_H
#define LLVM_EXECUTIONENGINE_ORC_DEBUGGERSUPPORT_H
#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
namespace llvm {
namespace orc {
/// For each object containing debug info, installs JITLink passes to synthesize
/// a debug object and then register it via the GDB JIT-registration interface.
///
/// Currently MachO only. For ELF use DebugObjectManagerPlugin. These two
/// plugins will be merged in the near future.
class GDBJITDebugInfoRegistrationPlugin : public ObjectLinkingLayer::Plugin {
public:
class DebugSectionSynthesizer {
public:
virtual ~DebugSectionSynthesizer() {}
virtual Error startSynthesis() = 0;
virtual Error completeSynthesisAndRegister() = 0;
};
static Expected<std::unique_ptr<GDBJITDebugInfoRegistrationPlugin>>
Create(ExecutionSession &ES, JITDylib &ProcessJD, const Triple &TT);
GDBJITDebugInfoRegistrationPlugin(ExecutorAddr RegisterActionAddr)
: RegisterActionAddr(RegisterActionAddr) {}
Error notifyFailed(MaterializationResponsibility &MR) override;
Error notifyRemovingResources(ResourceKey K) override;
void notifyTransferringResources(ResourceKey DstKey,
ResourceKey SrcKey) override;
void modifyPassConfig(MaterializationResponsibility &MR,
jitlink::LinkGraph &LG,
jitlink::PassConfiguration &PassConfig) override;
private:
void modifyPassConfigForMachO(MaterializationResponsibility &MR,
jitlink::LinkGraph &LG,
jitlink::PassConfiguration &PassConfig);
ExecutorAddr RegisterActionAddr;
};
} // namespace orc
} // namespace llvm
#endif // LLVM_EXECUTIONENGINE_ORC_DEBUGGERSUPPORT_H

View File

@@ -72,12 +72,6 @@ static Error runAllocAction(JITLinkMemoryManager::AllocActionCall &C) {
static_cast<size_t>(C.CtxSize)));
}
// Align a JITTargetAddress to conform with block alignment requirements.
static JITTargetAddress alignToBlock(JITTargetAddress Addr, Block &B) {
uint64_t Delta = (B.getAlignmentOffset() - Addr) % B.getAlignment();
return Addr + Delta;
}
BasicLayout::BasicLayout(LinkGraph &G) : G(G) {
for (auto &Sec : G.sections()) {

View File

@@ -180,17 +180,10 @@ Error MachOLinkGraphBuilder::createNormalizedSections() {
else
Prot = MemProt::Read | MemProt::Write;
if (!isDebugSection(NSec)) {
auto FullyQualifiedName =
G->allocateString(StringRef(NSec.SegName) + "," + NSec.SectName);
NSec.GraphSection = &G->createSection(
StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()),
Prot);
} else
LLVM_DEBUG({
dbgs() << " " << NSec.SegName << "," << NSec.SectName
<< " is a debug section: No graph section will be created.\n";
});
auto FullyQualifiedName =
G->allocateString(StringRef(NSec.SegName) + "," + NSec.SectName);
NSec.GraphSection = &G->createSection(
StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()), Prot);
IndexToSection.insert(std::make_pair(SecIndex, std::move(NSec)));
}

View File

@@ -3,6 +3,7 @@ add_llvm_component_library(LLVMOrcJIT
CompileUtils.cpp
Core.cpp
DebugObjectManagerPlugin.cpp
DebuggerSupportPlugin.cpp
DebugUtils.cpp
EPCDynamicLibrarySearchGenerator.cpp
EPCDebugObjectRegistrar.cpp

View File

@@ -0,0 +1,450 @@
//===------- DebuggerSupportPlugin.cpp - Utils for debugger support -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/Orc/DebuggerSupportPlugin.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/BinaryFormat/MachO.h"
#define DEBUG_TYPE "orc"
using namespace llvm;
using namespace llvm::jitlink;
using namespace llvm::orc;
static const char *SynthDebugSectionName = "__jitlink_synth_debug_object";
namespace {
struct MachO64LE {
using UIntPtr = uint64_t;
using Header = MachO::mach_header_64;
using SegmentLC = MachO::segment_command_64;
using Section = MachO::section_64;
using NList = MachO::nlist_64;
static constexpr support::endianness Endianness = support::little;
static constexpr const uint32_t Magic = MachO::MH_MAGIC_64;
static constexpr const uint32_t SegmentCmd = MachO::LC_SEGMENT_64;
};
class MachODebugObjectSynthesizerBase
: public GDBJITDebugInfoRegistrationPlugin::DebugSectionSynthesizer {
public:
static bool isDebugSection(Section &Sec) {
return Sec.getName().startswith("__DWARF,");
}
MachODebugObjectSynthesizerBase(LinkGraph &G, ExecutorAddr RegisterActionAddr)
: G(G), RegisterActionAddr(RegisterActionAddr) {}
virtual ~MachODebugObjectSynthesizerBase() {}
Error preserveDebugSections() {
if (G.findSectionByName(SynthDebugSectionName)) {
LLVM_DEBUG({
dbgs() << "MachODebugObjectSynthesizer skipping graph " << G.getName()
<< " which contains an unexpected existing "
<< SynthDebugSectionName << " section.\n";
});
return Error::success();
}
LLVM_DEBUG({
dbgs() << "MachODebugObjectSynthesizer visiting graph " << G.getName()
<< "\n";
});
for (auto &Sec : G.sections()) {
if (!isDebugSection(Sec))
continue;
// Preserve blocks in this debug section by marking one existing symbol
// live for each block, and introducing a new live, anonymous symbol for
// each currently unreferenced block.
LLVM_DEBUG({
dbgs() << " Preserving debug section " << Sec.getName() << "\n";
});
SmallSet<Block *, 8> PreservedBlocks;
for (auto *Sym : Sec.symbols()) {
bool NewPreservedBlock =
PreservedBlocks.insert(&Sym->getBlock()).second;
if (NewPreservedBlock)
Sym->setLive(true);
}
for (auto *B : Sec.blocks())
if (!PreservedBlocks.count(B))
G.addAnonymousSymbol(*B, 0, 0, false, true);
}
return Error::success();
}
protected:
LinkGraph &G;
ExecutorAddr RegisterActionAddr;
};
template <typename MachOTraits>
class MachODebugObjectSynthesizer : public MachODebugObjectSynthesizerBase {
private:
class MachOStructWriter {
public:
MachOStructWriter(MutableArrayRef<char> Buffer) : Buffer(Buffer) {}
size_t getOffset() const { return Offset; }
template <typename MachOStruct> void write(MachOStruct S) {
assert(Offset + sizeof(S) <= Buffer.size() &&
"Container block overflow while constructing debug MachO");
if (MachOTraits::Endianness != support::endian::system_endianness())
MachO::swapStruct(S);
memcpy(Buffer.data() + Offset, &S, sizeof(S));
Offset += sizeof(S);
}
private:
MutableArrayRef<char> Buffer;
size_t Offset = 0;
};
public:
using MachODebugObjectSynthesizerBase::MachODebugObjectSynthesizerBase;
Error startSynthesis() override {
LLVM_DEBUG({
dbgs() << "Creating " << SynthDebugSectionName << " for " << G.getName()
<< "\n";
});
auto &SDOSec = G.createSection(SynthDebugSectionName, MemProt::Read);
struct DebugSectionInfo {
Section *Sec = nullptr;
StringRef SegName;
StringRef SecName;
JITTargetAddress Alignment = 0;
JITTargetAddress StartAddr = 0;
uint64_t Size = 0;
};
SmallVector<DebugSectionInfo, 12> DebugSecInfos;
size_t NumSections = 0;
for (auto &Sec : G.sections()) {
if (llvm::empty(Sec.blocks()))
continue;
++NumSections;
if (isDebugSection(Sec)) {
size_t SepPos = Sec.getName().find(',');
if (SepPos > 16 || (Sec.getName().size() - (SepPos + 1) > 16)) {
LLVM_DEBUG({
dbgs() << "Skipping debug object synthesis for graph "
<< G.getName()
<< ": encountered non-standard DWARF section name \""
<< Sec.getName() << "\"\n";
});
return Error::success();
}
DebugSecInfos.push_back({&Sec, Sec.getName().substr(0, SepPos),
Sec.getName().substr(SepPos + 1), 0, 0});
} else
NonDebugSections.push_back(&Sec);
}
// Create container block.
size_t SectionsCmdSize =
sizeof(typename MachOTraits::Section) * NumSections;
size_t SegmentLCSize =
sizeof(typename MachOTraits::SegmentLC) + SectionsCmdSize;
size_t ContainerBlockSize =
sizeof(typename MachOTraits::Header) + SegmentLCSize;
auto ContainerBlockContent = G.allocateBuffer(ContainerBlockSize);
MachOContainerBlock =
&G.createMutableContentBlock(SDOSec, ContainerBlockContent, 0, 8, 0);
// Copy debug section blocks and symbols.
JITTargetAddress NextBlockAddr = MachOContainerBlock->getSize();
for (auto &SI : DebugSecInfos) {
assert(!llvm::empty(SI.Sec->blocks()) && "Empty debug info section?");
// Update addresses in debug section.
LLVM_DEBUG({
dbgs() << " Appending " << SI.Sec->getName() << " ("
<< SI.Sec->blocks_size() << " block(s)) at "
<< formatv("{0:x8}", NextBlockAddr) << "\n";
});
for (auto *B : SI.Sec->blocks()) {
NextBlockAddr = alignToBlock(NextBlockAddr, *B);
B->setAddress(NextBlockAddr);
NextBlockAddr += B->getSize();
}
auto &FirstBlock = **SI.Sec->blocks().begin();
if (FirstBlock.getAlignmentOffset() != 0)
return make_error<StringError>(
"First block in " + SI.Sec->getName() +
" section has non-zero alignment offset",
inconvertibleErrorCode());
if (FirstBlock.getAlignment() > std::numeric_limits<uint32_t>::max())
return make_error<StringError>("First block in " + SI.Sec->getName() +
" has alignment >4Gb",
inconvertibleErrorCode());
SI.Alignment = FirstBlock.getAlignment();
SI.StartAddr = FirstBlock.getAddress();
SI.Size = NextBlockAddr - SI.StartAddr;
G.mergeSections(SDOSec, *SI.Sec);
SI.Sec = nullptr;
}
size_t DebugSectionsSize = NextBlockAddr - MachOContainerBlock->getSize();
// Write MachO header and debug section load commands.
MachOStructWriter Writer(MachOContainerBlock->getAlreadyMutableContent());
typename MachOTraits::Header Hdr;
memset(&Hdr, 0, sizeof(Hdr));
Hdr.magic = MachOTraits::Magic;
switch (G.getTargetTriple().getArch()) {
case Triple::x86_64:
Hdr.cputype = MachO::CPU_TYPE_X86_64;
Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
break;
case Triple::aarch64:
Hdr.cputype = MachO::CPU_TYPE_ARM64;
Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
break;
default:
llvm_unreachable("Unsupported architecture");
}
Hdr.filetype = MachO::MH_OBJECT;
Hdr.ncmds = 1;
Hdr.sizeofcmds = SegmentLCSize;
Hdr.flags = 0;
Writer.write(Hdr);
typename MachOTraits::SegmentLC SegLC;
memset(&SegLC, 0, sizeof(SegLC));
SegLC.cmd = MachOTraits::SegmentCmd;
SegLC.cmdsize = SegmentLCSize;
SegLC.vmaddr = ContainerBlockSize;
SegLC.vmsize = DebugSectionsSize;
SegLC.fileoff = ContainerBlockSize;
SegLC.filesize = DebugSectionsSize;
SegLC.maxprot =
MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
SegLC.initprot =
MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
SegLC.nsects = NumSections;
SegLC.flags = 0;
Writer.write(SegLC);
StringSet<> ExistingLongNames;
for (auto &SI : DebugSecInfos) {
typename MachOTraits::Section Sec;
memset(&Sec, 0, sizeof(Sec));
memcpy(Sec.sectname, SI.SecName.data(), SI.SecName.size());
memcpy(Sec.segname, SI.SegName.data(), SI.SegName.size());
Sec.addr = SI.StartAddr;
Sec.size = SI.Size;
Sec.offset = SI.StartAddr;
Sec.align = SI.Alignment;
Sec.reloff = 0;
Sec.nreloc = 0;
Sec.flags = MachO::S_ATTR_DEBUG;
Writer.write(Sec);
}
// Set MachOContainerBlock to indicate success to
// completeSynthesisAndRegister.
NonDebugSectionsStart = Writer.getOffset();
return Error::success();
}
Error completeSynthesisAndRegister() override {
if (!MachOContainerBlock) {
LLVM_DEBUG({
dbgs() << "Not writing MachO debug object header for " << G.getName()
<< " since createDebugSection failed\n";
});
return Error::success();
}
LLVM_DEBUG({
dbgs() << "Writing MachO debug object header for " << G.getName() << "\n";
});
MachOStructWriter Writer(
MachOContainerBlock->getAlreadyMutableContent().drop_front(
NonDebugSectionsStart));
unsigned LongSectionNameIdx = 0;
for (auto *Sec : NonDebugSections) {
size_t SepPos = Sec->getName().find(',');
StringRef SegName, SecName;
std::string CustomSecName;
if ((SepPos == StringRef::npos && Sec->getName().size() <= 16)) {
// No embedded segment name, short section name.
SegName = "__JITLINK_CUSTOM";
SecName = Sec->getName();
} else if (SepPos < 16 && (Sec->getName().size() - (SepPos + 1) <= 16)) {
// Canonical embedded segment and section name.
SegName = Sec->getName().substr(0, SepPos);
SecName = Sec->getName().substr(SepPos + 1);
} else {
// Long section name that needs to be truncated.
assert(Sec->getName().size() > 16 &&
"Short section name should have been handled above");
SegName = "__JITLINK_CUSTOM";
auto IdxStr = std::to_string(++LongSectionNameIdx);
CustomSecName = Sec->getName().substr(0, 15 - IdxStr.size()).str();
CustomSecName += ".";
CustomSecName += IdxStr;
SecName = StringRef(CustomSecName.data(), 16);
}
SectionRange R(*Sec);
if (R.getFirstBlock()->getAlignmentOffset() != 0)
return make_error<StringError>(
"While building MachO debug object for " + G.getName() +
" first block has non-zero alignment offset",
inconvertibleErrorCode());
typename MachOTraits::Section SecCmd;
memset(&SecCmd, 0, sizeof(SecCmd));
memcpy(SecCmd.sectname, SecName.data(), SecName.size());
memcpy(SecCmd.segname, SegName.data(), SegName.size());
SecCmd.addr = R.getStart();
SecCmd.size = R.getSize();
SecCmd.offset = 0;
SecCmd.align = R.getFirstBlock()->getAlignment();
SecCmd.reloff = 0;
SecCmd.nreloc = 0;
SecCmd.flags = 0;
Writer.write(SecCmd);
}
SectionRange R(MachOContainerBlock->getSection());
G.allocActions().push_back(
{{RegisterActionAddr.getValue(), R.getStart(), R.getSize()}, {}});
return Error::success();
}
private:
Block *MachOContainerBlock = nullptr;
SmallVector<Section *, 16> NonDebugSections;
size_t NonDebugSectionsStart = 0;
};
} // end anonymous namespace
namespace llvm {
namespace orc {
Expected<std::unique_ptr<GDBJITDebugInfoRegistrationPlugin>>
GDBJITDebugInfoRegistrationPlugin::Create(ExecutionSession &ES,
JITDylib &ProcessJD,
const Triple &TT) {
auto RegisterActionAddr =
TT.isOSBinFormatMachO()
? ES.intern("_llvm_orc_registerJITLoaderGDBAllocAction")
: ES.intern("llvm_orc_registerJITLoaderGDBAllocAction");
if (auto Addr = ES.lookup({&ProcessJD}, RegisterActionAddr))
return std::make_unique<GDBJITDebugInfoRegistrationPlugin>(
ExecutorAddr(Addr->getAddress()));
else
return Addr.takeError();
}
Error GDBJITDebugInfoRegistrationPlugin::notifyFailed(
MaterializationResponsibility &MR) {
return Error::success();
}
Error GDBJITDebugInfoRegistrationPlugin::notifyRemovingResources(
ResourceKey K) {
return Error::success();
}
void GDBJITDebugInfoRegistrationPlugin::notifyTransferringResources(
ResourceKey DstKey, ResourceKey SrcKey) {}
void GDBJITDebugInfoRegistrationPlugin::modifyPassConfig(
MaterializationResponsibility &MR, LinkGraph &LG,
PassConfiguration &PassConfig) {
if (LG.getTargetTriple().getObjectFormat() == Triple::MachO)
modifyPassConfigForMachO(MR, LG, PassConfig);
else {
LLVM_DEBUG({
dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unspported graph "
<< LG.getName() << "(triple = " << LG.getTargetTriple().str()
<< "\n";
});
}
}
void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO(
MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
jitlink::PassConfiguration &PassConfig) {
switch (LG.getTargetTriple().getArch()) {
case Triple::x86_64:
case Triple::aarch64:
// Supported, continue.
assert(LG.getPointerSize() == 8 && "Graph has incorrect pointer size");
assert(LG.getEndianness() == support::little &&
"Graph has incorrect endianness");
break;
default:
// Unsupported.
LLVM_DEBUG({
dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unsupported "
<< "MachO graph " << LG.getName()
<< "(triple = " << LG.getTargetTriple().str()
<< ", pointer size = " << LG.getPointerSize() << ", endianness = "
<< (LG.getEndianness() == support::big ? "big" : "little")
<< ")\n";
});
return;
}
// Scan for debug sections. If we find one then install passes.
bool HasDebugSections = false;
for (auto &Sec : LG.sections())
if (MachODebugObjectSynthesizerBase::isDebugSection(Sec)) {
HasDebugSections = true;
break;
}
if (HasDebugSections) {
LLVM_DEBUG({
dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName()
<< " contains debug info. Installing debugger support passes.\n";
});
auto MDOS = std::make_shared<MachODebugObjectSynthesizer<MachO64LE>>(
LG, RegisterActionAddr);
PassConfig.PrePrunePasses.push_back(
[=](LinkGraph &G) { return MDOS->preserveDebugSections(); });
PassConfig.PostPrunePasses.push_back(
[=](LinkGraph &G) { return MDOS->startSynthesis(); });
PassConfig.PreFixupPasses.push_back(
[=](LinkGraph &G) { return MDOS->completeSynthesisAndRegister(); });
} else {
LLVM_DEBUG({
dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName()
<< " contains no debug info. Skipping.\n";
});
}
}
} // namespace orc
} // namespace llvm

View File

@@ -10,6 +10,7 @@
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/ManagedStatic.h"
#include <cstdint>
@@ -70,10 +71,18 @@ using namespace llvm::orc;
ManagedStatic<std::mutex> JITDebugLock;
// Register debug object, return error message or null for success.
static void registerJITLoaderGDBImpl(ExecutorAddrRange DebugObjRange) {
static void registerJITLoaderGDBImpl(const char *ObjAddr, size_t Size) {
LLVM_DEBUG({
dbgs() << "Registering debug object with GDB JIT interface "
<< formatv("([{0:x16} -- {1:x16}])",
reinterpret_cast<uintptr_t>(ObjAddr),
reinterpret_cast<uintptr_t>(ObjAddr + Size))
<< "\n";
});
jit_code_entry *E = new jit_code_entry;
E->symfile_addr = DebugObjRange.Start.toPtr<const char *>();
E->symfile_size = DebugObjRange.size().getValue();
E->symfile_addr = ObjAddr;
E->symfile_size = Size;
E->prev_entry = nullptr;
std::lock_guard<std::mutex> Lock(*JITDebugLock);
@@ -93,10 +102,26 @@ static void registerJITLoaderGDBImpl(ExecutorAddrRange DebugObjRange) {
__jit_debug_register_code();
}
extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_registerJITLoaderGDBAllocAction(const char *Data, size_t Size) {
using namespace orc::shared;
return WrapperFunction<SPSError()>::handle(nullptr, 0,
[=]() -> Error {
registerJITLoaderGDBImpl(Data,
Size);
return Error::success();
})
.release();
}
extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_registerJITLoaderGDBWrapper(const char *Data, uint64_t Size) {
using namespace orc::shared;
return WrapperFunction<void(SPSExecutorAddrRange)>::handle(
Data, Size, registerJITLoaderGDBImpl)
Data, Size,
[](ExecutorAddrRange R) {
registerJITLoaderGDBImpl(R.Start.toPtr<char *>(),
R.size().getValue());
})
.release();
}

View File

@@ -0,0 +1,21 @@
# REQUIRES: asserts
# RUN: llvm-mc -triple=x86_64-apple-macosx10.9 -filetype=obj -o %t %s
# RUN: llvm-jitlink -debug-only=orc -noexec %t 2>&1 | FileCheck %s
#
# Check that presence of a "__DWARF" section triggers the
# GDBJITDebugInfoRegistrationPlugin.
#
# CHECK: Registering debug object with GDB JIT interface
.section __TEXT,__text,regular,pure_instructions
.globl _main
.p2align 4, 0x90
_main:
xorl %eax, %eax
retq
.section __DWARF,__debug_str,regular,debug
Linfo_string:
.asciz "test dwarf string"
.subsections_via_symbols

View File

@@ -1,21 +0,0 @@
# REQUIRES: asserts
# RUN: llvm-mc -triple=x86_64-apple-macosx10.9 -filetype=obj -o %t %s
# RUN: llvm-jitlink -debug-only=jitlink -noexec %t 2>&1 | FileCheck %s
#
# Check that debug sections are not emitted, and consequently that we don't
# error out due to buggy past-the-end anonymous relocations in __debug_ranges.
#
# CHECK: __debug_ranges is a debug section: No graph section will be created.
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 15
.globl _main
.p2align 4, 0x90
_main:
retq
Lpast_the_end:
.section __DWARF,__debug_ranges
.p2align 4
.quad Lpast_the_end
.subsections_via_symbols

View File

@@ -16,6 +16,7 @@
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
#include "llvm/ExecutionEngine/Orc/DebuggerSupportPlugin.h"
#include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"
#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
@@ -987,8 +988,13 @@ Session::Session(std::unique_ptr<ExecutorProcessControl> EPC, Error &Err)
ExitOnErr(loadProcessSymbols(*this));
ExitOnErr(loadDylibs(*this));
// Set up the platform.
auto &TT = ES.getExecutorProcessControl().getTargetTriple();
if (TT.isOSBinFormatMachO())
ObjLayer.addPlugin(ExitOnErr(
GDBJITDebugInfoRegistrationPlugin::Create(this->ES, *MainJD, TT)));
// Set up the platform.
if (TT.isOSBinFormatMachO() && !OrcRuntime.empty()) {
if (auto P =
MachOPlatform::Create(ES, ObjLayer, *MainJD, OrcRuntime.c_str()))