Skip to content

Commit

Permalink
[ORC] Add DWARFContext generation from LinkGraphs, use in perf support.
Browse files Browse the repository at this point in the history
This patch adds line numbers to perf jitdump records emitted by the
PerfSupportPlugin, by parsing and using a DWARFContext from preserved debug
sections.

To avoid making the OrcJIT library depend on DebugInfoDWARF this patch
introduces a new OrcDebugging library.

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D146391
  • Loading branch information
pchintalapudi authored and lhames committed Sep 28, 2023
1 parent 2f3b7d3 commit 7ddf7d8
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 29 deletions.
62 changes: 62 additions & 0 deletions llvm/include/llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h
@@ -0,0 +1,62 @@
//===--- DebugInfoSupport.h ---- Utils for debug info 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
//
//===----------------------------------------------------------------------===//
//
// Utilities to preserve and parse debug info from LinkGraphs.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_EXECUTIONENGINE_ORC_DEBUGINFOSUPPORT_H
#define LLVM_EXECUTIONENGINE_ORC_DEBUGINFOSUPPORT_H

#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"

#include "llvm/DebugInfo/DWARF/DWARFContext.h"

namespace llvm {

namespace orc {

Error preserveDebugSections(jitlink::LinkGraph &G);
// The backing stringmap is also returned, for memory liftime management.
Expected<std::pair<std::unique_ptr<DWARFContext>,
StringMap<std::unique_ptr<MemoryBuffer>>>>
createDWARFContext(jitlink::LinkGraph &G);

// Thin wrapper around preserveDebugSections to be used as a standalone plugin.
class DebugInfoPreservationPlugin : public ObjectLinkingLayer::Plugin {
public:
void modifyPassConfig(MaterializationResponsibility &MR,
jitlink::LinkGraph &LG,
jitlink::PassConfiguration &PassConfig) override {
PassConfig.PrePrunePasses.push_back(preserveDebugSections);
}

Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
// Do nothing.
return Error::success();
}
Error notifyFailed(MaterializationResponsibility &MR) override {
// Do nothing.
return Error::success();
}
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
ResourceKey SrcKey) override {
// Do nothing.
}

static Expected<std::unique_ptr<DebugInfoPreservationPlugin>> Create() {
return std::make_unique<DebugInfoPreservationPlugin>();
}
};

} // namespace orc

} // namespace llvm

#endif
Expand Up @@ -29,7 +29,8 @@ class PerfSupportPlugin : public ObjectLinkingLayer::Plugin {
PerfSupportPlugin(ExecutorProcessControl &EPC,
ExecutorAddr RegisterPerfStartAddr,
ExecutorAddr RegisterPerfEndAddr,
ExecutorAddr RegisterPerfImplAddr, bool EmitUnwindInfo);
ExecutorAddr RegisterPerfImplAddr, bool EmitDebugInfo,
bool EmitUnwindInfo);
~PerfSupportPlugin();

void modifyPassConfig(MaterializationResponsibility &MR,
Expand All @@ -48,14 +49,16 @@ class PerfSupportPlugin : public ObjectLinkingLayer::Plugin {
ResourceKey SrcKey) override {}

static Expected<std::unique_ptr<PerfSupportPlugin>>
Create(ExecutorProcessControl &EPC, JITDylib &JD, bool EmitUnwindInfo);
Create(ExecutorProcessControl &EPC, JITDylib &JD, bool EmitDebugInfo,
bool EmitUnwindInfo);

private:
ExecutorProcessControl &EPC;
ExecutorAddr RegisterPerfStartAddr;
ExecutorAddr RegisterPerfEndAddr;
ExecutorAddr RegisterPerfImplAddr;
std::atomic<uint64_t> CodeIndex;
bool EmitDebugInfo;
bool EmitUnwindInfo;
};

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
Expand Up @@ -42,7 +42,6 @@ add_llvm_component_library(LLVMOrcJIT
ObjectTransformLayer.cpp
OrcABISupport.cpp
OrcV2CBindings.cpp
PerfSupportPlugin.cpp
RTDyldObjectLinkingLayer.cpp
SimpleRemoteEPC.cpp
Speculation.cpp
Expand Down Expand Up @@ -78,6 +77,7 @@ add_llvm_component_library(LLVMOrcJIT
TransformUtils
)

add_subdirectory(Debugging)
add_subdirectory(Shared)
add_subdirectory(TargetProcess)

Expand Down
22 changes: 22 additions & 0 deletions llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
@@ -0,0 +1,22 @@
if( CMAKE_HOST_UNIX AND HAVE_LIBRT )
set(rt_lib rt)
endif()

add_llvm_component_library(LLVMOrcDebugging
DebugInfoSupport.cpp
PerfSupportPlugin.cpp

ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc/Debugging/

LINK_LIBS
${LLVM_PTHREAD_LIB}
${rt_lib}

LINK_COMPONENTS
DebugInfoDWARF
OrcJIT
OrcShared
Support
TargetParser
)
120 changes: 120 additions & 0 deletions llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp
@@ -0,0 +1,120 @@
//===--- DebugInfoSupport.cpp -- Utils for debug info 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
//
//===----------------------------------------------------------------------===//
//
// Utilities to preserve and parse debug info from LinkGraphs.
//
//===----------------------------------------------------------------------===//

#include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"

#include "llvm/Support/SmallVectorMemoryBuffer.h"

#define DEBUG_TYPE "orc"

using namespace llvm;
using namespace llvm::orc;
using namespace llvm::jitlink;

namespace {
static DenseSet<StringRef> DWARFSectionNames = {
#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \
StringRef(ELF_NAME),
#include "llvm/BinaryFormat/Dwarf.def"
#undef HANDLE_DWARF_SECTION
};

// We might be able to drop relocations to symbols that do end up
// being pruned by the linker, but for now we just preserve all
static void preserveDWARFSection(LinkGraph &G, Section &Sec) {
DenseMap<Block *, Symbol *> Preserved;
for (auto Sym : Sec.symbols()) {
if (Sym->isLive())
Preserved[&Sym->getBlock()] = Sym;
else if (!Preserved.count(&Sym->getBlock()))
Preserved[&Sym->getBlock()] = Sym;
}
for (auto Block : Sec.blocks()) {
auto &PSym = Preserved[Block];
if (!PSym)
PSym = &G.addAnonymousSymbol(*Block, 0, 0, false, true);
else if (!PSym->isLive())
PSym->setLive(true);
}
}

static SmallVector<char, 0> getSectionData(Section &Sec) {
SmallVector<char, 0> SecData;
SmallVector<Block *, 8> SecBlocks(Sec.blocks().begin(), Sec.blocks().end());
std::sort(SecBlocks.begin(), SecBlocks.end(), [](Block *LHS, Block *RHS) {
return LHS->getAddress() < RHS->getAddress();
});
// Convert back to what object file would have, one blob of section content
// Assumes all zerofill
// TODO handle alignment?
// TODO handle alignment offset?
for (auto *Block : SecBlocks) {
if (Block->isZeroFill())
SecData.resize(SecData.size() + Block->getSize(), 0);
else
SecData.append(Block->getContent().begin(), Block->getContent().end());
}
return SecData;
}

static void dumpDWARFContext(DWARFContext &DC) {
auto options = llvm::DIDumpOptions();
options.DumpType &= ~DIDT_UUID;
options.DumpType &= ~(1 << DIDT_ID_DebugFrame);
LLVM_DEBUG(DC.dump(dbgs(), options));
}

} // namespace

Error llvm::orc::preserveDebugSections(LinkGraph &G) {
if (!G.getTargetTriple().isOSBinFormatELF()) {
return make_error<StringError>(
"preserveDebugSections only supports ELF LinkGraphs!",
inconvertibleErrorCode());
}
for (auto &Sec : G.sections()) {
if (DWARFSectionNames.count(Sec.getName())) {
LLVM_DEBUG(dbgs() << "Preserving DWARF section " << Sec.getName()
<< "\n");
preserveDWARFSection(G, Sec);
}
}
return Error::success();
}

Expected<std::pair<std::unique_ptr<DWARFContext>,
StringMap<std::unique_ptr<MemoryBuffer>>>>
llvm::orc::createDWARFContext(LinkGraph &G) {
if (!G.getTargetTriple().isOSBinFormatELF()) {
return make_error<StringError>(
"createDWARFContext only supports ELF LinkGraphs!",
inconvertibleErrorCode());
}
StringMap<std::unique_ptr<MemoryBuffer>> DWARFSectionData;
for (auto &Sec : G.sections()) {
if (DWARFSectionNames.count(Sec.getName())) {
auto SecData = getSectionData(Sec);
auto Name = Sec.getName();
// DWARFContext expects the section name to not start with a dot
if (Name.startswith("."))
Name = Name.drop_front();
LLVM_DEBUG(dbgs() << "Creating DWARFContext section " << Name
<< " with size " << SecData.size() << "\n");
DWARFSectionData[Name] =
std::make_unique<SmallVectorMemoryBuffer>(std::move(SecData));
}
}
auto Ctx = DWARFContext::create(DWARFSectionData, G.getPointerSize(),
G.getEndianness() == support::little);
dumpDWARFContext(*Ctx);
return std::make_pair(std::move(Ctx), std::move(DWARFSectionData));
}
Expand Up @@ -10,13 +10,12 @@
//
//===----------------------------------------------------------------------===//

#include "llvm/ExecutionEngine/Orc/PerfSupportPlugin.h"
#include "llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h"

#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"

#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/ExecutionEngine/JITLink/x86_64.h"
#include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
#include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"

#define DEBUG_TYPE "orc"

Expand Down Expand Up @@ -114,11 +113,7 @@ getCodeLoadRecord(const Symbol &Sym, std::atomic<uint64_t> &CodeIndex) {
}

static std::optional<PerfJITDebugInfoRecord>
getDebugInfoRecord(const Symbol &Sym, DWARFContext *DC) {
if (!DC) {
LLVM_DEBUG(dbgs() << "No debug info available\n");
return std::nullopt;
}
getDebugInfoRecord(const Symbol &Sym, DWARFContext &DC) {
auto &Section = Sym.getBlock().getSection();
auto Addr = Sym.getAddress();
auto Size = Sym.getSize();
Expand All @@ -127,7 +122,7 @@ getDebugInfoRecord(const Symbol &Sym, DWARFContext *DC) {
<< " at address " << Addr.getValue() << " with size "
<< Size << "\n"
<< "Section ordinal: " << Section.getOrdinal() << "\n");
auto LInfo = DC->getLineInfoForAddressRange(
auto LInfo = DC.getLineInfoForAddressRange(
SAddr, Size, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
if (LInfo.empty()) {
// No line info available
Expand Down Expand Up @@ -218,16 +213,29 @@ getUnwindingRecord(LinkGraph &G) {
}

static PerfJITRecordBatch getRecords(ExecutionSession &ES, LinkGraph &G,
DWARFContext *DC,
std::atomic<uint64_t> &CodeIndex,
bool EmitUnwindInfo) {
bool EmitDebugInfo, bool EmitUnwindInfo) {
std::unique_ptr<DWARFContext> DC;
StringMap<std::unique_ptr<MemoryBuffer>> DCBacking;
if (EmitDebugInfo) {
auto EDC = createDWARFContext(G);
if (!EDC) {
ES.reportError(EDC.takeError());
EmitDebugInfo = false;
} else {
DC = std::move(EDC->first);
DCBacking = std::move(EDC->second);
}
}
PerfJITRecordBatch Batch;
for (auto Sym : G.defined_symbols()) {
if (!Sym->hasName() || !Sym->isCallable())
continue;
auto DebugInfo = getDebugInfoRecord(*Sym, DC);
if (DebugInfo)
Batch.DebugInfoRecords.push_back(std::move(*DebugInfo));
if (EmitDebugInfo) {
auto DebugInfo = getDebugInfoRecord(*Sym, *DC);
if (DebugInfo)
Batch.DebugInfoRecords.push_back(std::move(*DebugInfo));
}
Batch.CodeLoadRecords.push_back(getCodeLoadRecord(*Sym, CodeIndex));
}
if (EmitUnwindInfo) {
Expand All @@ -248,11 +256,11 @@ PerfSupportPlugin::PerfSupportPlugin(ExecutorProcessControl &EPC,
ExecutorAddr RegisterPerfStartAddr,
ExecutorAddr RegisterPerfEndAddr,
ExecutorAddr RegisterPerfImplAddr,
bool EmitUnwindInfo)
bool EmitDebugInfo, bool EmitUnwindInfo)
: EPC(EPC), RegisterPerfStartAddr(RegisterPerfStartAddr),
RegisterPerfEndAddr(RegisterPerfEndAddr),
RegisterPerfImplAddr(RegisterPerfImplAddr), CodeIndex(0),
EmitUnwindInfo(EmitUnwindInfo) {
EmitDebugInfo(EmitDebugInfo), EmitUnwindInfo(EmitUnwindInfo) {
cantFail(EPC.callSPSWrapper<void()>(RegisterPerfStartAddr));
}
PerfSupportPlugin::~PerfSupportPlugin() {
Expand All @@ -263,10 +271,8 @@ void PerfSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
LinkGraph &G,
PassConfiguration &Config) {
Config.PostFixupPasses.push_back([this](LinkGraph &G) {
// TODO get an actual DWARFContext for line info
DWARFContext *DWC = nullptr;
auto Batch = getRecords(EPC.getExecutionSession(), G, DWC, CodeIndex,
EmitUnwindInfo);
auto Batch = getRecords(EPC.getExecutionSession(), G, CodeIndex,
EmitDebugInfo, EmitUnwindInfo);
G.allocActions().push_back(
{cantFail(shared::WrapperFunctionCall::Create<
shared::SPSArgList<shared::SPSPerfJITRecordBatch>>(
Expand All @@ -278,7 +284,7 @@ void PerfSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,

Expected<std::unique_ptr<PerfSupportPlugin>>
PerfSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
bool EmitUnwindInfo) {
bool EmitDebugInfo, bool EmitUnwindInfo) {
if (!EPC.getTargetTriple().isOSBinFormatELF()) {
return make_error<StringError>(
"Perf support only available for ELF LinkGraphs!",
Expand All @@ -293,5 +299,5 @@ PerfSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
{ES.intern(RegisterPerfImplSymbolName), &ImplAddr}}))
return std::move(Err);
return std::make_unique<PerfSupportPlugin>(EPC, StartAddr, EndAddr, ImplAddr,
EmitUnwindInfo);
EmitDebugInfo, EmitUnwindInfo);
}
1 change: 1 addition & 0 deletions llvm/tools/llvm-jitlink/CMakeLists.txt
Expand Up @@ -11,6 +11,7 @@ set(LLVM_LINK_COMPONENTS
JITLink
MC
Object
OrcDebugging
OrcJIT
OrcShared
OrcTargetProcess
Expand Down

0 comments on commit 7ddf7d8

Please sign in to comment.