Skip to content

Commit a2a3ca8

Browse files
committed
BPF: emit debuginfo for Function of DeclRefExpr if requested
Commit e3d8ee3 ("reland "[DebugInfo] Support to emit debugInfo for extern variables"") added support to emit debugInfo for extern variables if requested by the target. Currently, only BPF target enables this feature by default. As BPF ecosystem grows, callback function started to get support, e.g., recently bpf_for_each_map_elem() is introduced (https://lwn.net/Articles/846504/) with a callback function as an argument. In the future we may have something like below as a demonstration of use case : extern int do_work(int); long bpf_helper(void *callback_fn, void *callback_ctx, ...); long prog_main() { struct { ... } ctx = { ... }; return bpf_helper(&do_work, &ctx, ...); } Basically bpf helper may have a callback function and the callback function is defined in another file or in the kernel. In this case, we would like to know the debuginfo types for do_work(), so the verifier can proper verify the safety of bpf_helper() call. For the following example, extern int do_work(int); long bpf_helper(void *callback_fn); long prog() { return bpf_helper(&do_work); } Currently, there is no debuginfo generated for extern function do_work(). In the IR, we have, ... define dso_local i64 @prog() local_unnamed_addr #0 !dbg !7 { entry: %call = tail call i64 @bpf_helper(i8* bitcast (i32 (i32)* @do_work to i8*)) rust-lang#2, !dbg !11 ret i64 %call, !dbg !12 } ... declare dso_local i32 @do_work(i32) #1 ... This patch added support for the above callback function use case, and the generated IR looks like below: ... declare !dbg !17 dso_local i32 @do_work(i32) #1 ... !17 = !DISubprogram(name: "do_work", scope: !1, file: !1, line: 1, type: !18, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) !18 = !DISubroutineType(types: !19) !19 = !{!20, !20} !20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) The TargetInfo.allowDebugInfoForExternalVar is renamed to TargetInfo.allowDebugInfoForExternalRef as now it guards both extern variable and extern function debuginfo generation. Differential Revision: https://reviews.llvm.org/D100567
1 parent 30bb5be commit a2a3ca8

File tree

5 files changed

+41
-6
lines changed

5 files changed

+41
-6
lines changed

clang/include/clang/Basic/TargetInfo.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,8 +1538,8 @@ class TargetInfo : public virtual TransferrableTargetInfo,
15381538

15391539
virtual void setAuxTarget(const TargetInfo *Aux) {}
15401540

1541-
/// Whether target allows debuginfo types for decl only variables.
1542-
virtual bool allowDebugInfoForExternalVar() const { return false; }
1541+
/// Whether target allows debuginfo types for decl only variables/functions.
1542+
virtual bool allowDebugInfoForExternalRef() const { return false; }
15431543

15441544
protected:
15451545
/// Copy type and layout related info.

clang/lib/Basic/Targets/BPF.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo {
7676
return None;
7777
}
7878

79-
bool allowDebugInfoForExternalVar() const override { return true; }
79+
bool allowDebugInfoForExternalRef() const override { return true; }
8080

8181
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
8282
switch (CC) {

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2832,8 +2832,21 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
28322832
return LV;
28332833
}
28342834

2835-
if (const auto *FD = dyn_cast<FunctionDecl>(ND))
2836-
return EmitFunctionDeclLValue(*this, E, FD);
2835+
if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
2836+
LValue LV = EmitFunctionDeclLValue(*this, E, FD);
2837+
2838+
// Emit debuginfo for the function declaration if the target wants to.
2839+
if (getContext().getTargetInfo().allowDebugInfoForExternalRef()) {
2840+
if (CGDebugInfo *DI = CGM.getModuleDebugInfo()) {
2841+
auto *Fn =
2842+
cast<llvm::Function>(LV.getPointer(*this)->stripPointerCasts());
2843+
if (!Fn->getSubprogram())
2844+
DI->EmitFunctionDecl(FD, FD->getLocation(), T, Fn);
2845+
}
2846+
}
2847+
2848+
return LV;
2849+
}
28372850

28382851
// FIXME: While we're emitting a binding from an enclosing scope, all other
28392852
// DeclRefExprs we see should be implicitly treated as if they also refer to

clang/lib/Sema/SemaDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12688,7 +12688,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
1268812688
Diag(Var->getLocation(), diag::note_private_extern);
1268912689
}
1269012690

12691-
if (Context.getTargetInfo().allowDebugInfoForExternalVar() &&
12691+
if (Context.getTargetInfo().allowDebugInfoForExternalRef() &&
1269212692
!Var->isInvalidDecl() && !getLangOpts().CPlusPlus)
1269312693
ExternalDeclarations.push_back(Var);
1269412694

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -x c -debug-info-kind=limited -triple bpf-linux-gnu -emit-llvm %s -o - | FileCheck %s
2+
3+
extern int do_work1(int);
4+
long bpf_helper1(void *callback_fn);
5+
long prog1() {
6+
return bpf_helper1(&do_work1);
7+
}
8+
9+
extern int do_work2();
10+
long prog2_1() {
11+
return (long)&do_work2;
12+
}
13+
int do_work2() { return 0; }
14+
long prog2_2() {
15+
return (long)&do_work2;
16+
}
17+
18+
// CHECK: declare !dbg ![[FUNC1:[0-9]+]] i32 @do_work1
19+
// CHECK: define dso_local i32 @do_work2() #{{[0-9]+}} !dbg ![[FUNC2:[0-9]+]]
20+
21+
// CHECK: ![[FUNC1]] = !DISubprogram(name: "do_work1"
22+
// CHECK: ![[FUNC2]] = distinct !DISubprogram(name: "do_work2"

0 commit comments

Comments
 (0)