[llvm] 7ddf7d8 - [ORC] Add DWARFContext generation from LinkGraphs, use in perf support.
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 28 16:14:18 PDT 2023
Author: Prem Chintalapudi
Date: 2023-09-28T16:13:49-07:00
New Revision: 7ddf7d87831a90164fd125589850fcf48d24f33f
URL: https://github.com/llvm/llvm-project/commit/7ddf7d87831a90164fd125589850fcf48d24f33f
DIFF: https://github.com/llvm/llvm-project/commit/7ddf7d87831a90164fd125589850fcf48d24f33f.diff
LOG: [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
Added:
llvm/include/llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h
llvm/include/llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h
llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp
llvm/lib/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.cpp
Modified:
llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
llvm/tools/llvm-jitlink/CMakeLists.txt
llvm/tools/llvm-jitlink/llvm-jitlink.cpp
Removed:
llvm/include/llvm/ExecutionEngine/Orc/PerfSupportPlugin.h
llvm/lib/ExecutionEngine/Orc/PerfSupportPlugin.cpp
################################################################################
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h b/llvm/include/llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h
new file mode 100644
index 000000000000000..011dccbcf6407f2
--- /dev/null
+++ b/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
\ No newline at end of file
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/PerfSupportPlugin.h b/llvm/include/llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h
similarity index 90%
rename from llvm/include/llvm/ExecutionEngine/Orc/PerfSupportPlugin.h
rename to llvm/include/llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h
index c663377b17b652b..8235de861befa25 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/PerfSupportPlugin.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h
@@ -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,
@@ -48,7 +49,8 @@ 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;
@@ -56,6 +58,7 @@ class PerfSupportPlugin : public ObjectLinkingLayer::Plugin {
ExecutorAddr RegisterPerfEndAddr;
ExecutorAddr RegisterPerfImplAddr;
std::atomic<uint64_t> CodeIndex;
+ bool EmitDebugInfo;
bool EmitUnwindInfo;
};
diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
index 5956a898de1256d..49f202244f96c17 100644
--- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
@@ -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)
diff --git a/llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
new file mode 100644
index 000000000000000..216761d8209084c
--- /dev/null
+++ b/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
+ )
diff --git a/llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp b/llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp
new file mode 100644
index 000000000000000..febd2e73aa176e6
--- /dev/null
+++ b/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));
+}
diff --git a/llvm/lib/ExecutionEngine/Orc/PerfSupportPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.cpp
similarity index 89%
rename from llvm/lib/ExecutionEngine/Orc/PerfSupportPlugin.cpp
rename to llvm/lib/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.cpp
index fd7acbd4446c524..1c5b9c6078b7545 100644
--- a/llvm/lib/ExecutionEngine/Orc/PerfSupportPlugin.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.cpp
@@ -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);
}
diff --git a/llvm/tools/llvm-jitlink/CMakeLists.txt b/llvm/tools/llvm-jitlink/CMakeLists.txt
index a9f8bd16e02393b..1480be3f03c6d7c 100644
--- a/llvm/tools/llvm-jitlink/CMakeLists.txt
+++ b/llvm/tools/llvm-jitlink/CMakeLists.txt
@@ -11,6 +11,7 @@ set(LLVM_LINK_COMPONENTS
JITLink
MC
Object
+ OrcDebugging
OrcJIT
OrcShared
OrcTargetProcess
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
index c1354ee96c6ef8d..17aeb3055953efb 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
@@ -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()) {
More information about the llvm-commits
mailing list