Skip to content

Commit 035d961

Browse files
author
Yonghong Song
committed
[LLVM] Emit dwarf data for changed-signature and new functions
Add a new pass EmitChangedFuncDebugInfo which will add dwarf for additional functions including functions with signature change and new functions. The previous approach in [1] tries to add debuginfo for those optimization passes which cause signature changes. Based on discussion in [1], it is preferred to have a specific pass to add debuginfo and later on dwarf generation can include those new debuginfo. The ultimate goal is to add new information to dwarf like below: DW_TAG_compile_unit ... // New functions with suffix DW_TAG_inlined_subroutine DW_AT_name ("foo.1") DW_AT_type (0x0000000000000091 "int") DW_AT_artificial (true) DW_AT_specificiation (original DW_TAG_subprogram) DW_TAG_formal_parameter DW_AT_name ("b") DW_AT_type (0x0000000000000091 "int") DW_TAG_formal_parameter DW_AT_name ("c") DW_AT_type (0x0000000000000095 "long") ... // Functions with changed signatures DW_TAG_inlined_subroutine DW_AT_name ("bar") DW_AT_type (0x0000000000000091 "int") DW_AT_artificial (true) DW_AT_specificiation (original DW_TAG_subprogram) DW_TAG_formal_parameter DW_AT_name ("c") DW_AT_type (0x0000000000000095 "unsigned int") The new functions will not include those functions whose return value is a struct/union or the function has variable arguments. In rare cases, if DIExpression is complex and not handled by this pull request, the following dwarf entry will be issued: // The DW_CC_nocall presence indicates such cases. DW_TAG_inlined_subroutine DW_AT_name ("bar" or "bar.1") DW_AT_calling_convention (DW_CC_nocall) DW_AT_artificial (true) DW_AT_specificiation (original DW_TAG_subprogram) The parent tag of above DW_TAG_inlined_subroutine is DW_TAG_compile_unit. This is a new feature for dwarf so it won't cause issues with existing dwarf related tools. Total three patterns are introduced as the above. . New functions with suffix, e.g., 'foo.1' or 'foo.llvm.<hash>'. . Functions with changed signature due to ArgumentPromotion or DeadArgumentElimination. . Functions the current implementation cannot get proper signature in which case, DW_CC_nocall is set to indicate signature is lost. A special CompileUnit with file name "<artificial>" is created to hold special DISubprograms for the above three kinds of functions. During actual dwarf generation, these special DISubprograms will turn to above to proper DW_TAG_inlined_subroutine tags. The below are some discussions with not handled cases and some other alternative things: (1) Current implementation only supports C language and only supports 64bit architecture as this particularly needed for linux kernel. (2) Currently, I am using a special CompileUnit "<artificial>" to hold newly created DISubprograms. But there is an alternative. For example, "llvm.dbg.cu" metadata is used to hold all CompileUnits. We could introduce "llvm.dbg.sp.extra" to hold all new DISubprograms instead of a new CompileUnit. I have tested this patch set by building latest bpf-next linux kernel. For no-lto case: 65341 original number of functions 1082 new functions with this patch For thin-lto case: 65595 original number of functions 2484 new functions with this patch For a particular linux kernel with bpf-next tree, There are no new functions with DW_CC_nocall. That is, all new functions have proper signatures. The following are some examples with thinlto with generated dwarf: ... 0x0001707f: DW_TAG_inlined_subroutine DW_AT_name ("msr_build_context") DW_AT_type (0x00004163 "int") DW_AT_artificial (true) DW_AT_specification (0x0000440b "msr_build_context") 0x0001708b: DW_TAG_formal_parameter DW_AT_name ("msr_id") DW_AT_type (0x0000e55c "const u32 *") 0x00017093: NULL ... 0x004225e5: DW_TAG_inlined_subroutine DW_AT_name ("__die_body.llvm.14794269134614576759") DW_AT_type (0x00418a14 "int") DW_AT_artificial (true) DW_AT_specification (0x00422348 "__die_body") 0x004225f1: DW_TAG_formal_parameter DW_AT_name ("") DW_AT_type (0x004181f3 "const char *") 0x004225f9: DW_TAG_formal_parameter DW_AT_name ("") DW_AT_type (0x00419118 "pt_regs *") 0x00422601: DW_TAG_formal_parameter DW_AT_name ("") DW_AT_type (0x0041af2f "long") 0x00422609: NULL ... [1] #127855
1 parent 9f187bf commit 035d961

File tree

12 files changed

+524
-2
lines changed

12 files changed

+524
-2
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===- EmitChangedFuncDebugInfo.h - Emit Additional Debug Info -*- 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+
/// \file
10+
/// Emit debug info for changed or new funcs.
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H
14+
#define LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H
15+
16+
#include "llvm/IR/PassManager.h"
17+
18+
namespace llvm {
19+
20+
class Module;
21+
22+
// Pass that emits late dwarf.
23+
class EmitChangedFuncDebugInfoPass
24+
: public PassInfoMixin<EmitChangedFuncDebugInfoPass> {
25+
public:
26+
EmitChangedFuncDebugInfoPass() = default;
27+
28+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
29+
};
30+
31+
} // end namespace llvm
32+
33+
#endif // LLVM_TRANSFORMS_UTILS_EMITCHANGEDFUNCDEBUGINFO_H

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,11 +1267,76 @@ void DwarfDebug::finishSubprogramDefinitions() {
12671267
}
12681268
}
12691269

1270+
void DwarfDebug::addChangedSubprograms() {
1271+
// Generate additional dwarf for functions with signature changed.
1272+
DICompileUnit *ExtraCU = nullptr;
1273+
for (DICompileUnit *CUNode : MMI->getModule()->debug_compile_units()) {
1274+
if (CUNode->getFile()->getFilename() == "<artificial>") {
1275+
ExtraCU = CUNode;
1276+
break;
1277+
}
1278+
}
1279+
if (!ExtraCU)
1280+
return;
1281+
1282+
llvm::DebugInfoFinder DIF;
1283+
DIF.processModule(*MMI->getModule());
1284+
for (auto *ExtraSP : DIF.subprograms()) {
1285+
if (ExtraSP->getUnit() != ExtraCU)
1286+
continue;
1287+
1288+
DISubprogram *SP = cast<DISubprogram>(ExtraSP->getScope());
1289+
DwarfCompileUnit &Cu = getOrCreateDwarfCompileUnit(SP->getUnit());
1290+
DIE *ScopeDIE =
1291+
DIE::get(DIEValueAllocator, dwarf::DW_TAG_inlined_subroutine);
1292+
Cu.getUnitDie().addChild(ScopeDIE);
1293+
1294+
Cu.addString(*ScopeDIE, dwarf::DW_AT_name, ExtraSP->getName());
1295+
1296+
DITypeRefArray Args = ExtraSP->getType()->getTypeArray();
1297+
1298+
if (Args[0])
1299+
Cu.addType(*ScopeDIE, Args[0]);
1300+
1301+
if (ExtraSP->getType()->getCC() == llvm::dwarf::DW_CC_nocall) {
1302+
Cu.addUInt(*ScopeDIE, dwarf::DW_AT_calling_convention,
1303+
dwarf::DW_FORM_data1, llvm::dwarf::DW_CC_nocall);
1304+
}
1305+
1306+
Cu.addFlag(*ScopeDIE, dwarf::DW_AT_artificial);
1307+
1308+
// dereference the DIE* for DIEEntry
1309+
DIE *OriginDIE = Cu.getOrCreateSubprogramDIE(SP, nullptr);
1310+
Cu.addDIEEntry(*ScopeDIE, dwarf::DW_AT_specification, DIEEntry(*OriginDIE));
1311+
1312+
SmallVector<const DILocalVariable *> ArgVars(Args.size());
1313+
for (const DINode *DN : ExtraSP->getRetainedNodes()) {
1314+
if (const auto *DV = dyn_cast<DILocalVariable>(DN)) {
1315+
uint32_t Arg = DV->getArg();
1316+
if (Arg)
1317+
ArgVars[Arg - 1] = DV;
1318+
}
1319+
}
1320+
1321+
// The func does not have variant arguments.
1322+
for (unsigned i = 1, N = Args.size(); i < N; ++i) {
1323+
const DIType *Ty = Args[i];
1324+
DIE &Arg = Cu.createAndAddDIE(dwarf::DW_TAG_formal_parameter, *ScopeDIE);
1325+
const DILocalVariable *DV = ArgVars[i - 1];
1326+
if (DV)
1327+
Cu.addString(Arg, dwarf::DW_AT_name, DV->getName());
1328+
Cu.addType(Arg, Ty);
1329+
}
1330+
}
1331+
}
1332+
12701333
void DwarfDebug::finalizeModuleInfo() {
12711334
const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
12721335

12731336
finishSubprogramDefinitions();
12741337

1338+
addChangedSubprograms();
1339+
12751340
finishEntityDefinitions();
12761341

12771342
bool HasEmittedSplitCU = false;

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,8 @@ class DwarfDebug : public DebugHandlerBase {
565565

566566
void finishSubprogramDefinitions();
567567

568+
void addChangedSubprograms();
569+
568570
/// Finish off debug information after all functions have been
569571
/// processed.
570572
void finalizeModuleInfo();

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@
348348
#include "llvm/Transforms/Utils/DXILUpgrade.h"
349349
#include "llvm/Transforms/Utils/Debugify.h"
350350
#include "llvm/Transforms/Utils/DeclareRuntimeLibcalls.h"
351+
#include "llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h"
351352
#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
352353
#include "llvm/Transforms/Utils/FixIrreducible.h"
353354
#include "llvm/Transforms/Utils/HelloWorld.h"

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
136136
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
137137
#include "llvm/Transforms/Utils/CountVisits.h"
138+
#include "llvm/Transforms/Utils/EmitChangedFuncDebugInfo.h"
138139
#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
139140
#include "llvm/Transforms/Utils/ExtraPassManager.h"
140141
#include "llvm/Transforms/Utils/InjectTLIMappings.h"
@@ -1640,9 +1641,12 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
16401641
if (PTO.CallGraphProfile && !LTOPreLink)
16411642
MPM.addPass(CGProfilePass(isLTOPostLink(LTOPhase)));
16421643

1643-
// RelLookupTableConverterPass runs later in LTO post-link pipeline.
1644-
if (!LTOPreLink)
1644+
// RelLookupTableConverterPass and EmitChangedFuncDebugInfoPass run later in
1645+
// LTO post-link pipeline.
1646+
if (!LTOPreLink) {
16451647
MPM.addPass(RelLookupTableConverterPass());
1648+
MPM.addPass(EmitChangedFuncDebugInfoPass());
1649+
}
16461650

16471651
return MPM;
16481652
}

llvm/lib/Passes/PassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ MODULE_PASS("debugify", NewPMDebugifyPass())
7373
MODULE_PASS("declare-runtime-libcalls", DeclareRuntimeLibcallsPass())
7474
MODULE_PASS("dfsan", DataFlowSanitizerPass())
7575
MODULE_PASS("dot-callgraph", CallGraphDOTPrinterPass())
76+
MODULE_PASS("dwarf-emit-late", EmitChangedFuncDebugInfoPass())
7677
MODULE_PASS("dxil-upgrade", DXILUpgradePass())
7778
MODULE_PASS("elim-avail-extern", EliminateAvailableExternallyPass())
7879
MODULE_PASS("extract-blocks", BlockExtractorPass({}, false))

llvm/lib/Transforms/Utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ add_llvm_component_library(LLVMTransformUtils
2323
DebugSSAUpdater.cpp
2424
DeclareRuntimeLibcalls.cpp
2525
DemoteRegToStack.cpp
26+
EmitChangedFuncDebugInfo.cpp
2627
DXILUpgrade.cpp
2728
EntryExitInstrumenter.cpp
2829
EscapeEnumerator.cpp

0 commit comments

Comments
 (0)