Skip to content

Commit 7ddf7d8

Browse files
pchintalapudilhames
authored andcommitted
[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
1 parent 2f3b7d3 commit 7ddf7d8

File tree

8 files changed

+246
-29
lines changed

8 files changed

+246
-29
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//===--- DebugInfoSupport.h ---- Utils for debug info support ---*- C++ -*-===//
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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Utilities to preserve and parse debug info from LinkGraphs.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_ORC_DEBUGINFOSUPPORT_H
14+
#define LLVM_EXECUTIONENGINE_ORC_DEBUGINFOSUPPORT_H
15+
16+
#include "llvm/ExecutionEngine/Orc/Core.h"
17+
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
18+
19+
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
20+
21+
namespace llvm {
22+
23+
namespace orc {
24+
25+
Error preserveDebugSections(jitlink::LinkGraph &G);
26+
// The backing stringmap is also returned, for memory liftime management.
27+
Expected<std::pair<std::unique_ptr<DWARFContext>,
28+
StringMap<std::unique_ptr<MemoryBuffer>>>>
29+
createDWARFContext(jitlink::LinkGraph &G);
30+
31+
// Thin wrapper around preserveDebugSections to be used as a standalone plugin.
32+
class DebugInfoPreservationPlugin : public ObjectLinkingLayer::Plugin {
33+
public:
34+
void modifyPassConfig(MaterializationResponsibility &MR,
35+
jitlink::LinkGraph &LG,
36+
jitlink::PassConfiguration &PassConfig) override {
37+
PassConfig.PrePrunePasses.push_back(preserveDebugSections);
38+
}
39+
40+
Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
41+
// Do nothing.
42+
return Error::success();
43+
}
44+
Error notifyFailed(MaterializationResponsibility &MR) override {
45+
// Do nothing.
46+
return Error::success();
47+
}
48+
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
49+
ResourceKey SrcKey) override {
50+
// Do nothing.
51+
}
52+
53+
static Expected<std::unique_ptr<DebugInfoPreservationPlugin>> Create() {
54+
return std::make_unique<DebugInfoPreservationPlugin>();
55+
}
56+
};
57+
58+
} // namespace orc
59+
60+
} // namespace llvm
61+
62+
#endif

llvm/include/llvm/ExecutionEngine/Orc/PerfSupportPlugin.h renamed to llvm/include/llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class PerfSupportPlugin : public ObjectLinkingLayer::Plugin {
2929
PerfSupportPlugin(ExecutorProcessControl &EPC,
3030
ExecutorAddr RegisterPerfStartAddr,
3131
ExecutorAddr RegisterPerfEndAddr,
32-
ExecutorAddr RegisterPerfImplAddr, bool EmitUnwindInfo);
32+
ExecutorAddr RegisterPerfImplAddr, bool EmitDebugInfo,
33+
bool EmitUnwindInfo);
3334
~PerfSupportPlugin();
3435

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

5051
static Expected<std::unique_ptr<PerfSupportPlugin>>
51-
Create(ExecutorProcessControl &EPC, JITDylib &JD, bool EmitUnwindInfo);
52+
Create(ExecutorProcessControl &EPC, JITDylib &JD, bool EmitDebugInfo,
53+
bool EmitUnwindInfo);
5254

5355
private:
5456
ExecutorProcessControl &EPC;
5557
ExecutorAddr RegisterPerfStartAddr;
5658
ExecutorAddr RegisterPerfEndAddr;
5759
ExecutorAddr RegisterPerfImplAddr;
5860
std::atomic<uint64_t> CodeIndex;
61+
bool EmitDebugInfo;
5962
bool EmitUnwindInfo;
6063
};
6164

llvm/lib/ExecutionEngine/Orc/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ add_llvm_component_library(LLVMOrcJIT
4242
ObjectTransformLayer.cpp
4343
OrcABISupport.cpp
4444
OrcV2CBindings.cpp
45-
PerfSupportPlugin.cpp
4645
RTDyldObjectLinkingLayer.cpp
4746
SimpleRemoteEPC.cpp
4847
Speculation.cpp
@@ -78,6 +77,7 @@ add_llvm_component_library(LLVMOrcJIT
7877
TransformUtils
7978
)
8079

80+
add_subdirectory(Debugging)
8181
add_subdirectory(Shared)
8282
add_subdirectory(TargetProcess)
8383

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
if( CMAKE_HOST_UNIX AND HAVE_LIBRT )
2+
set(rt_lib rt)
3+
endif()
4+
5+
add_llvm_component_library(LLVMOrcDebugging
6+
DebugInfoSupport.cpp
7+
PerfSupportPlugin.cpp
8+
9+
ADDITIONAL_HEADER_DIRS
10+
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc/Debugging/
11+
12+
LINK_LIBS
13+
${LLVM_PTHREAD_LIB}
14+
${rt_lib}
15+
16+
LINK_COMPONENTS
17+
DebugInfoDWARF
18+
OrcJIT
19+
OrcShared
20+
Support
21+
TargetParser
22+
)
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//===--- DebugInfoSupport.cpp -- Utils for debug info support ---*- C++ -*-===//
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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Utilities to preserve and parse debug info from LinkGraphs.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
14+
15+
#include "llvm/Support/SmallVectorMemoryBuffer.h"
16+
17+
#define DEBUG_TYPE "orc"
18+
19+
using namespace llvm;
20+
using namespace llvm::orc;
21+
using namespace llvm::jitlink;
22+
23+
namespace {
24+
static DenseSet<StringRef> DWARFSectionNames = {
25+
#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \
26+
StringRef(ELF_NAME),
27+
#include "llvm/BinaryFormat/Dwarf.def"
28+
#undef HANDLE_DWARF_SECTION
29+
};
30+
31+
// We might be able to drop relocations to symbols that do end up
32+
// being pruned by the linker, but for now we just preserve all
33+
static void preserveDWARFSection(LinkGraph &G, Section &Sec) {
34+
DenseMap<Block *, Symbol *> Preserved;
35+
for (auto Sym : Sec.symbols()) {
36+
if (Sym->isLive())
37+
Preserved[&Sym->getBlock()] = Sym;
38+
else if (!Preserved.count(&Sym->getBlock()))
39+
Preserved[&Sym->getBlock()] = Sym;
40+
}
41+
for (auto Block : Sec.blocks()) {
42+
auto &PSym = Preserved[Block];
43+
if (!PSym)
44+
PSym = &G.addAnonymousSymbol(*Block, 0, 0, false, true);
45+
else if (!PSym->isLive())
46+
PSym->setLive(true);
47+
}
48+
}
49+
50+
static SmallVector<char, 0> getSectionData(Section &Sec) {
51+
SmallVector<char, 0> SecData;
52+
SmallVector<Block *, 8> SecBlocks(Sec.blocks().begin(), Sec.blocks().end());
53+
std::sort(SecBlocks.begin(), SecBlocks.end(), [](Block *LHS, Block *RHS) {
54+
return LHS->getAddress() < RHS->getAddress();
55+
});
56+
// Convert back to what object file would have, one blob of section content
57+
// Assumes all zerofill
58+
// TODO handle alignment?
59+
// TODO handle alignment offset?
60+
for (auto *Block : SecBlocks) {
61+
if (Block->isZeroFill())
62+
SecData.resize(SecData.size() + Block->getSize(), 0);
63+
else
64+
SecData.append(Block->getContent().begin(), Block->getContent().end());
65+
}
66+
return SecData;
67+
}
68+
69+
static void dumpDWARFContext(DWARFContext &DC) {
70+
auto options = llvm::DIDumpOptions();
71+
options.DumpType &= ~DIDT_UUID;
72+
options.DumpType &= ~(1 << DIDT_ID_DebugFrame);
73+
LLVM_DEBUG(DC.dump(dbgs(), options));
74+
}
75+
76+
} // namespace
77+
78+
Error llvm::orc::preserveDebugSections(LinkGraph &G) {
79+
if (!G.getTargetTriple().isOSBinFormatELF()) {
80+
return make_error<StringError>(
81+
"preserveDebugSections only supports ELF LinkGraphs!",
82+
inconvertibleErrorCode());
83+
}
84+
for (auto &Sec : G.sections()) {
85+
if (DWARFSectionNames.count(Sec.getName())) {
86+
LLVM_DEBUG(dbgs() << "Preserving DWARF section " << Sec.getName()
87+
<< "\n");
88+
preserveDWARFSection(G, Sec);
89+
}
90+
}
91+
return Error::success();
92+
}
93+
94+
Expected<std::pair<std::unique_ptr<DWARFContext>,
95+
StringMap<std::unique_ptr<MemoryBuffer>>>>
96+
llvm::orc::createDWARFContext(LinkGraph &G) {
97+
if (!G.getTargetTriple().isOSBinFormatELF()) {
98+
return make_error<StringError>(
99+
"createDWARFContext only supports ELF LinkGraphs!",
100+
inconvertibleErrorCode());
101+
}
102+
StringMap<std::unique_ptr<MemoryBuffer>> DWARFSectionData;
103+
for (auto &Sec : G.sections()) {
104+
if (DWARFSectionNames.count(Sec.getName())) {
105+
auto SecData = getSectionData(Sec);
106+
auto Name = Sec.getName();
107+
// DWARFContext expects the section name to not start with a dot
108+
if (Name.startswith("."))
109+
Name = Name.drop_front();
110+
LLVM_DEBUG(dbgs() << "Creating DWARFContext section " << Name
111+
<< " with size " << SecData.size() << "\n");
112+
DWARFSectionData[Name] =
113+
std::make_unique<SmallVectorMemoryBuffer>(std::move(SecData));
114+
}
115+
}
116+
auto Ctx = DWARFContext::create(DWARFSectionData, G.getPointerSize(),
117+
G.getEndianness() == support::little);
118+
dumpDWARFContext(*Ctx);
119+
return std::make_pair(std::move(Ctx), std::move(DWARFSectionData));
120+
}

llvm/lib/ExecutionEngine/Orc/PerfSupportPlugin.cpp renamed to llvm/lib/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.cpp

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "llvm/ExecutionEngine/Orc/PerfSupportPlugin.h"
13+
#include "llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h"
1414

15-
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
16-
17-
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
1815
#include "llvm/ExecutionEngine/JITLink/x86_64.h"
16+
#include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
1917
#include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
18+
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
2019

2120
#define DEBUG_TYPE "orc"
2221

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

116115
static std::optional<PerfJITDebugInfoRecord>
117-
getDebugInfoRecord(const Symbol &Sym, DWARFContext *DC) {
118-
if (!DC) {
119-
LLVM_DEBUG(dbgs() << "No debug info available\n");
120-
return std::nullopt;
121-
}
116+
getDebugInfoRecord(const Symbol &Sym, DWARFContext &DC) {
122117
auto &Section = Sym.getBlock().getSection();
123118
auto Addr = Sym.getAddress();
124119
auto Size = Sym.getSize();
@@ -127,7 +122,7 @@ getDebugInfoRecord(const Symbol &Sym, DWARFContext *DC) {
127122
<< " at address " << Addr.getValue() << " with size "
128123
<< Size << "\n"
129124
<< "Section ordinal: " << Section.getOrdinal() << "\n");
130-
auto LInfo = DC->getLineInfoForAddressRange(
125+
auto LInfo = DC.getLineInfoForAddressRange(
131126
SAddr, Size, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
132127
if (LInfo.empty()) {
133128
// No line info available
@@ -218,16 +213,29 @@ getUnwindingRecord(LinkGraph &G) {
218213
}
219214

220215
static PerfJITRecordBatch getRecords(ExecutionSession &ES, LinkGraph &G,
221-
DWARFContext *DC,
222216
std::atomic<uint64_t> &CodeIndex,
223-
bool EmitUnwindInfo) {
217+
bool EmitDebugInfo, bool EmitUnwindInfo) {
218+
std::unique_ptr<DWARFContext> DC;
219+
StringMap<std::unique_ptr<MemoryBuffer>> DCBacking;
220+
if (EmitDebugInfo) {
221+
auto EDC = createDWARFContext(G);
222+
if (!EDC) {
223+
ES.reportError(EDC.takeError());
224+
EmitDebugInfo = false;
225+
} else {
226+
DC = std::move(EDC->first);
227+
DCBacking = std::move(EDC->second);
228+
}
229+
}
224230
PerfJITRecordBatch Batch;
225231
for (auto Sym : G.defined_symbols()) {
226232
if (!Sym->hasName() || !Sym->isCallable())
227233
continue;
228-
auto DebugInfo = getDebugInfoRecord(*Sym, DC);
229-
if (DebugInfo)
230-
Batch.DebugInfoRecords.push_back(std::move(*DebugInfo));
234+
if (EmitDebugInfo) {
235+
auto DebugInfo = getDebugInfoRecord(*Sym, *DC);
236+
if (DebugInfo)
237+
Batch.DebugInfoRecords.push_back(std::move(*DebugInfo));
238+
}
231239
Batch.CodeLoadRecords.push_back(getCodeLoadRecord(*Sym, CodeIndex));
232240
}
233241
if (EmitUnwindInfo) {
@@ -248,11 +256,11 @@ PerfSupportPlugin::PerfSupportPlugin(ExecutorProcessControl &EPC,
248256
ExecutorAddr RegisterPerfStartAddr,
249257
ExecutorAddr RegisterPerfEndAddr,
250258
ExecutorAddr RegisterPerfImplAddr,
251-
bool EmitUnwindInfo)
259+
bool EmitDebugInfo, bool EmitUnwindInfo)
252260
: EPC(EPC), RegisterPerfStartAddr(RegisterPerfStartAddr),
253261
RegisterPerfEndAddr(RegisterPerfEndAddr),
254262
RegisterPerfImplAddr(RegisterPerfImplAddr), CodeIndex(0),
255-
EmitUnwindInfo(EmitUnwindInfo) {
263+
EmitDebugInfo(EmitDebugInfo), EmitUnwindInfo(EmitUnwindInfo) {
256264
cantFail(EPC.callSPSWrapper<void()>(RegisterPerfStartAddr));
257265
}
258266
PerfSupportPlugin::~PerfSupportPlugin() {
@@ -263,10 +271,8 @@ void PerfSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
263271
LinkGraph &G,
264272
PassConfiguration &Config) {
265273
Config.PostFixupPasses.push_back([this](LinkGraph &G) {
266-
// TODO get an actual DWARFContext for line info
267-
DWARFContext *DWC = nullptr;
268-
auto Batch = getRecords(EPC.getExecutionSession(), G, DWC, CodeIndex,
269-
EmitUnwindInfo);
274+
auto Batch = getRecords(EPC.getExecutionSession(), G, CodeIndex,
275+
EmitDebugInfo, EmitUnwindInfo);
270276
G.allocActions().push_back(
271277
{cantFail(shared::WrapperFunctionCall::Create<
272278
shared::SPSArgList<shared::SPSPerfJITRecordBatch>>(
@@ -278,7 +284,7 @@ void PerfSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
278284

279285
Expected<std::unique_ptr<PerfSupportPlugin>>
280286
PerfSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
281-
bool EmitUnwindInfo) {
287+
bool EmitDebugInfo, bool EmitUnwindInfo) {
282288
if (!EPC.getTargetTriple().isOSBinFormatELF()) {
283289
return make_error<StringError>(
284290
"Perf support only available for ELF LinkGraphs!",
@@ -293,5 +299,5 @@ PerfSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
293299
{ES.intern(RegisterPerfImplSymbolName), &ImplAddr}}))
294300
return std::move(Err);
295301
return std::make_unique<PerfSupportPlugin>(EPC, StartAddr, EndAddr, ImplAddr,
296-
EmitUnwindInfo);
302+
EmitDebugInfo, EmitUnwindInfo);
297303
}

llvm/tools/llvm-jitlink/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ set(LLVM_LINK_COMPONENTS
1111
JITLink
1212
MC
1313
Object
14+
OrcDebugging
1415
OrcJIT
1516
OrcShared
1617
OrcTargetProcess

0 commit comments

Comments
 (0)