[ORC] Add DWARFContext generation from LinkGraphs, use in perf support.
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
This commit is contained in:
committed by
Lang Hames
parent
2f3b7d33f4
commit
7ddf7d8783
@@ -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
|
||||
@@ -29,7 +29,8 @@ public:
|
||||
PerfSupportPlugin(ExecutorProcessControl &EPC,
|
||||
ExecutorAddr RegisterPerfStartAddr,
|
||||
ExecutorAddr RegisterPerfEndAddr,
|
||||
ExecutorAddr RegisterPerfImplAddr, bool EmitUnwindInfo);
|
||||
ExecutorAddr RegisterPerfImplAddr, bool EmitDebugInfo,
|
||||
bool EmitUnwindInfo);
|
||||
~PerfSupportPlugin();
|
||||
|
||||
void modifyPassConfig(MaterializationResponsibility &MR,
|
||||
@@ -48,7 +49,8 @@ public:
|
||||
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;
|
||||
@@ -56,6 +58,7 @@ private:
|
||||
ExecutorAddr RegisterPerfEndAddr;
|
||||
ExecutorAddr RegisterPerfImplAddr;
|
||||
std::atomic<uint64_t> CodeIndex;
|
||||
bool EmitDebugInfo;
|
||||
bool EmitUnwindInfo;
|
||||
};
|
||||
|
||||
@@ -42,7 +42,6 @@ add_llvm_component_library(LLVMOrcJIT
|
||||
ObjectTransformLayer.cpp
|
||||
OrcABISupport.cpp
|
||||
OrcV2CBindings.cpp
|
||||
PerfSupportPlugin.cpp
|
||||
RTDyldObjectLinkingLayer.cpp
|
||||
SimpleRemoteEPC.cpp
|
||||
Speculation.cpp
|
||||
@@ -78,6 +77,7 @@ add_llvm_component_library(LLVMOrcJIT
|
||||
TransformUtils
|
||||
)
|
||||
|
||||
add_subdirectory(Debugging)
|
||||
add_subdirectory(Shared)
|
||||
add_subdirectory(TargetProcess)
|
||||
|
||||
|
||||
22
llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
Normal file
22
llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
Normal file
@@ -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
llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp
Normal file
120
llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp
Normal file
@@ -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));
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
@@ -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
|
||||
@@ -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) {
|
||||
@@ -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() {
|
||||
@@ -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>>(
|
||||
@@ -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!",
|
||||
@@ -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);
|
||||
}
|
||||
@@ -11,6 +11,7 @@ set(LLVM_LINK_COMPONENTS
|
||||
JITLink
|
||||
MC
|
||||
Object
|
||||
OrcDebugging
|
||||
OrcJIT
|
||||
OrcShared
|
||||
OrcTargetProcess
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "llvm/ExecutionEngine/Orc/COFFVCRuntimeSupport.h"
|
||||
#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
|
||||
#include "llvm/ExecutionEngine/Orc/DebuggerSupportPlugin.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"
|
||||
#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
|
||||
#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
|
||||
@@ -28,7 +30,6 @@
|
||||
#include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
|
||||
#include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h"
|
||||
#include "llvm/ExecutionEngine/Orc/PerfSupportPlugin.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderPerf.h"
|
||||
@@ -990,9 +991,11 @@ Session::Session(std::unique_ptr<ExecutorProcessControl> EPC, Error &Err)
|
||||
ObjLayer.addPlugin(ExitOnErr(
|
||||
GDBJITDebugInfoRegistrationPlugin::Create(this->ES, *MainJD, TT)));
|
||||
|
||||
if (PerfSupport && TT.isOSBinFormatELF())
|
||||
if (PerfSupport && TT.isOSBinFormatELF()) {
|
||||
ObjLayer.addPlugin(ExitOnErr(DebugInfoPreservationPlugin::Create()));
|
||||
ObjLayer.addPlugin(ExitOnErr(PerfSupportPlugin::Create(
|
||||
this->ES.getExecutorProcessControl(), *MainJD, true)));
|
||||
this->ES.getExecutorProcessControl(), *MainJD, true, true)));
|
||||
}
|
||||
|
||||
// Set up the platform.
|
||||
if (TT.isOSBinFormatMachO() && !OrcRuntime.empty()) {
|
||||
|
||||
Reference in New Issue
Block a user