[clang] a2a3ca8 - BPF: emit debuginfo for Function of DeclRefExpr if requested

Yonghong Song via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 26 16:57:30 PDT 2021


Author: Yonghong Song
Date: 2021-04-26T16:53:25-07:00
New Revision: a2a3ca8d97962d90443ee758e47877e15d7e3832

URL: https://github.com/llvm/llvm-project/commit/a2a3ca8d97962d90443ee758e47877e15d7e3832
DIFF: https://github.com/llvm/llvm-project/commit/a2a3ca8d97962d90443ee758e47877e15d7e3832.diff

LOG: BPF: emit debuginfo for Function of DeclRefExpr if requested

Commit e3d8ee35e4ad ("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*)) #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

Added: 
    clang/test/CodeGen/debug-info-extern-callback.c

Modified: 
    clang/include/clang/Basic/TargetInfo.h
    clang/lib/Basic/Targets/BPF.h
    clang/lib/CodeGen/CGExpr.cpp
    clang/lib/Sema/SemaDecl.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 449c026639b90..1655f932dad23 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1538,8 +1538,8 @@ class TargetInfo : public virtual TransferrableTargetInfo,
 
   virtual void setAuxTarget(const TargetInfo *Aux) {}
 
-  /// Whether target allows debuginfo types for decl only variables.
-  virtual bool allowDebugInfoForExternalVar() const { return false; }
+  /// Whether target allows debuginfo types for decl only variables/functions.
+  virtual bool allowDebugInfoForExternalRef() const { return false; }
 
 protected:
   /// Copy type and layout related info.

diff  --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h
index 43e55dfbfb2b2..06b451db189af 100644
--- a/clang/lib/Basic/Targets/BPF.h
+++ b/clang/lib/Basic/Targets/BPF.h
@@ -76,7 +76,7 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo {
     return None;
   }
 
-  bool allowDebugInfoForExternalVar() const override { return true; }
+  bool allowDebugInfoForExternalRef() const override { return true; }
 
   CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
     switch (CC) {

diff  --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index b98865971f8bf..2a272bf29e04e 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -2832,8 +2832,21 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
     return LV;
   }
 
-  if (const auto *FD = dyn_cast<FunctionDecl>(ND))
-    return EmitFunctionDeclLValue(*this, E, FD);
+  if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
+    LValue LV = EmitFunctionDeclLValue(*this, E, FD);
+
+    // Emit debuginfo for the function declaration if the target wants to.
+    if (getContext().getTargetInfo().allowDebugInfoForExternalRef()) {
+      if (CGDebugInfo *DI = CGM.getModuleDebugInfo()) {
+        auto *Fn =
+            cast<llvm::Function>(LV.getPointer(*this)->stripPointerCasts());
+        if (!Fn->getSubprogram())
+          DI->EmitFunctionDecl(FD, FD->getLocation(), T, Fn);
+      }
+    }
+
+    return LV;
+  }
 
   // FIXME: While we're emitting a binding from an enclosing scope, all other
   // DeclRefExprs we see should be implicitly treated as if they also refer to

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7f65f16a26f7e..f57e705604c81 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12688,7 +12688,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
         Diag(Var->getLocation(), diag::note_private_extern);
       }
 
-      if (Context.getTargetInfo().allowDebugInfoForExternalVar() &&
+      if (Context.getTargetInfo().allowDebugInfoForExternalRef() &&
           !Var->isInvalidDecl() && !getLangOpts().CPlusPlus)
         ExternalDeclarations.push_back(Var);
 

diff  --git a/clang/test/CodeGen/debug-info-extern-callback.c b/clang/test/CodeGen/debug-info-extern-callback.c
new file mode 100644
index 0000000000000..6a2fe301561e5
--- /dev/null
+++ b/clang/test/CodeGen/debug-info-extern-callback.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -x c -debug-info-kind=limited -triple bpf-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+extern int do_work1(int);
+long bpf_helper1(void *callback_fn);
+long prog1() {
+  return bpf_helper1(&do_work1);
+}
+
+extern int do_work2();
+long prog2_1() {
+  return (long)&do_work2;
+}
+int do_work2() { return 0; }
+long prog2_2() {
+  return (long)&do_work2;
+}
+
+// CHECK: declare !dbg ![[FUNC1:[0-9]+]] i32 @do_work1
+// CHECK: define dso_local i32 @do_work2() #{{[0-9]+}} !dbg ![[FUNC2:[0-9]+]]
+
+// CHECK: ![[FUNC1]] = !DISubprogram(name: "do_work1"
+// CHECK: ![[FUNC2]] = distinct !DISubprogram(name: "do_work2"


        


More information about the cfe-commits mailing list