-
Notifications
You must be signed in to change notification settings - Fork 12k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BPF] Fix linking issues in static map initializers #91310
[BPF] Fix linking issues in static map initializers #91310
Conversation
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write If you have received no comments on your PR for a week, you can request a review If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-clang-codegen Author: Nick Zavaritsky (mejedi) ChangesWhen BPF object files are linked with bpftool, every symbol must be accompanied by BTF info. Ensure that extern functions referenced by global variable initializers are included in BTF. The primary motivation is "static" initialization of PROG maps: extern int elsewhere(struct xdp_md *); struct { Full diff: https://github.com/llvm/llvm-project/pull/91310.diff 5 Files Affected:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 94962091116af..945f2e222b23f 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1950,8 +1950,22 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
if (D->hasAttr<WeakRefAttr>())
return CGM.GetWeakRefReference(D).getPointer();
- if (auto FD = dyn_cast<FunctionDecl>(D))
- return CGM.GetAddrOfFunction(FD);
+ if (auto FD = dyn_cast<FunctionDecl>(D)) {
+ auto *C = CGM.GetAddrOfFunction(FD);
+
+ // we don't normally emit debug info for extern fns referenced via
+ // variable initialisers; BPF needs it since it generates BTF from
+ // debug info and bpftool demands BTF for every symbol linked
+ if (CGM.getTarget().getTriple().isBPF() && FD->getStorageClass() == SC_Extern) {
+ if (CGDebugInfo *DI = CGM.getModuleDebugInfo()) {
+ auto *Fn = dyn_cast<llvm::Function>(C);
+ if (Fn && !Fn->getSubprogram())
+ DI->EmitFunctionDecl(FD, FD->getLocation(), D->getType(), Fn);
+ }
+ }
+
+ return C;
+ }
if (auto VD = dyn_cast<VarDecl>(D)) {
// We can never refer to a variable with local storage.
diff --git a/clang/test/bpf-debug-info-extern-func.c b/clang/test/bpf-debug-info-extern-func.c
new file mode 100644
index 0000000000000..da324630a314d
--- /dev/null
+++ b/clang/test/bpf-debug-info-extern-func.c
@@ -0,0 +1,9 @@
+// RUN: %clang -g -O2 -target bpf -S -emit-llvm %s -o - | FileCheck %s
+//
+// When linking BPF object files via bpftool, BTF info is required for
+// every symbol. BTF is generated from debug info. Ensure that debug info
+// is emitted for extern functions referenced via variable initializers.
+//
+// CHECK: !DISubprogram(name: "fn"
+extern void fn(void);
+void (*pfn) (void) = &fn;
diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp
index b6d3b460005c9..7d64f2e04bc26 100644
--- a/llvm/lib/Target/BPF/BTFDebug.cpp
+++ b/llvm/lib/Target/BPF/BTFDebug.cpp
@@ -1494,6 +1494,29 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) {
DataSecEntries[std::string(SecName)]->addDataSecEntry(VarId,
Asm->getSymbol(&Global), Size);
+
+ if (Global.hasInitializer())
+ processGlobalInitializer(Global.getInitializer());
+ }
+}
+
+/// Process global variable initializer in pursuit for function
+/// pointers. Add discovered (extern) functions to BTF. Some (extern)
+/// functions might have been missed otherwise. Every symbol needs BTF
+/// info when linking with bpftool. Primary use case: "static"
+/// initialization of BPF maps.
+///
+/// struct {
+/// __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
+/// ...
+/// } prog_map SEC(".maps") = { .values = { extern_func } };
+///
+void BTFDebug::processGlobalInitializer(const Constant *C) {
+ if (auto *Fn = dyn_cast<Function>(C))
+ processFuncPrototypes(Fn);
+ if (auto *CA = dyn_cast<ConstantAggregate>(C)) {
+ for (unsigned I = 0, N = CA->getNumOperands(); I < N; ++I)
+ processGlobalInitializer(CA->getOperand(I));
}
}
diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h
index 11a0c59ba6c90..02181d3013be9 100644
--- a/llvm/lib/Target/BPF/BTFDebug.h
+++ b/llvm/lib/Target/BPF/BTFDebug.h
@@ -352,6 +352,10 @@ class BTFDebug : public DebugHandlerBase {
/// Generate types and variables for globals.
void processGlobals(bool ProcessingMapDef);
+ /// Process global variable initializer in pursuit for function
+ /// pointers.
+ void processGlobalInitializer(const Constant *C);
+
/// Generate types for function prototypes.
void processFuncPrototypes(const Function *);
diff --git a/llvm/test/CodeGen/BPF/BTF/extern-var-func2.ll b/llvm/test/CodeGen/BPF/BTF/extern-var-func2.ll
new file mode 100644
index 0000000000000..700486d9f3515
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/BTF/extern-var-func2.ll
@@ -0,0 +1,54 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+;
+; Source code:
+; extern int elsewhere(void);
+; struct {
+; void *values[];
+; } prog_map = { .values = { elsewhere } };
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+; ModuleID = 'b.c'
+
+@prog_map = dso_local local_unnamed_addr global { [1 x ptr] } { [1 x ptr] [ptr @elsewhere] }, align 8, !dbg !0
+
+declare !dbg !17 dso_local i32 @elsewhere() #0
+
+; CHECK: .long 0 # BTF_KIND_FUNC_PROTO(id = 6)
+; CHECK-NEXT: .long 218103808 # 0xd000000
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 37 # BTF_KIND_INT(id = 7)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 41 # BTF_KIND_FUNC(id = 8)
+; CHECK-NEXT: .long 201326594 # 0xc000002
+; CHECK-NEXT: .long 6
+
+attributes #0 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13, !14, !15}
+!llvm.ident = !{!16}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "prog_map", scope: !2, file: !3, line: 4, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 19.0.0git (git@github.com:llvm/llvm-project.git 0390a6803608e3a5314315b73740c2d3f5a5723f)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "b.c", directory: "/home/nickz/llvm-project.git", checksumkind: CSK_MD5, checksum: "41cc17375f1261a0e072590833492553")
+!4 = !{!0}
+!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 2, elements: !6)
+!6 = !{!7}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "values", scope: !5, file: !3, line: 3, baseType: !8)
+!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, elements: !10)
+!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!10 = !{!11}
+!11 = !DISubrange(count: -1)
+!12 = !{i32 7, !"Dwarf Version", i32 5}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!14 = !{i32 1, !"wchar_size", i32 4}
+!15 = !{i32 7, !"frame-pointer", i32 2}
+!16 = !{!"clang version 19.0.0git (git@github.com:llvm/llvm-project.git 0390a6803608e3a5314315b73740c2d3f5a5723f)"}
+!17 = !DISubprogram(name: "elsewhere", scope: !3, file: !3, line: 1, type: !18, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!20}
+!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
@llvm/pr-subscribers-clang Author: Nick Zavaritsky (mejedi) ChangesWhen BPF object files are linked with bpftool, every symbol must be accompanied by BTF info. Ensure that extern functions referenced by global variable initializers are included in BTF. The primary motivation is "static" initialization of PROG maps: extern int elsewhere(struct xdp_md *); struct { Full diff: https://github.com/llvm/llvm-project/pull/91310.diff 5 Files Affected:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 94962091116a..945f2e222b23 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1950,8 +1950,22 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
if (D->hasAttr<WeakRefAttr>())
return CGM.GetWeakRefReference(D).getPointer();
- if (auto FD = dyn_cast<FunctionDecl>(D))
- return CGM.GetAddrOfFunction(FD);
+ if (auto FD = dyn_cast<FunctionDecl>(D)) {
+ auto *C = CGM.GetAddrOfFunction(FD);
+
+ // we don't normally emit debug info for extern fns referenced via
+ // variable initialisers; BPF needs it since it generates BTF from
+ // debug info and bpftool demands BTF for every symbol linked
+ if (CGM.getTarget().getTriple().isBPF() && FD->getStorageClass() == SC_Extern) {
+ if (CGDebugInfo *DI = CGM.getModuleDebugInfo()) {
+ auto *Fn = dyn_cast<llvm::Function>(C);
+ if (Fn && !Fn->getSubprogram())
+ DI->EmitFunctionDecl(FD, FD->getLocation(), D->getType(), Fn);
+ }
+ }
+
+ return C;
+ }
if (auto VD = dyn_cast<VarDecl>(D)) {
// We can never refer to a variable with local storage.
diff --git a/clang/test/bpf-debug-info-extern-func.c b/clang/test/bpf-debug-info-extern-func.c
new file mode 100644
index 000000000000..da324630a314
--- /dev/null
+++ b/clang/test/bpf-debug-info-extern-func.c
@@ -0,0 +1,9 @@
+// RUN: %clang -g -O2 -target bpf -S -emit-llvm %s -o - | FileCheck %s
+//
+// When linking BPF object files via bpftool, BTF info is required for
+// every symbol. BTF is generated from debug info. Ensure that debug info
+// is emitted for extern functions referenced via variable initializers.
+//
+// CHECK: !DISubprogram(name: "fn"
+extern void fn(void);
+void (*pfn) (void) = &fn;
diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp
index b6d3b460005c..7d64f2e04bc2 100644
--- a/llvm/lib/Target/BPF/BTFDebug.cpp
+++ b/llvm/lib/Target/BPF/BTFDebug.cpp
@@ -1494,6 +1494,29 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) {
DataSecEntries[std::string(SecName)]->addDataSecEntry(VarId,
Asm->getSymbol(&Global), Size);
+
+ if (Global.hasInitializer())
+ processGlobalInitializer(Global.getInitializer());
+ }
+}
+
+/// Process global variable initializer in pursuit for function
+/// pointers. Add discovered (extern) functions to BTF. Some (extern)
+/// functions might have been missed otherwise. Every symbol needs BTF
+/// info when linking with bpftool. Primary use case: "static"
+/// initialization of BPF maps.
+///
+/// struct {
+/// __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
+/// ...
+/// } prog_map SEC(".maps") = { .values = { extern_func } };
+///
+void BTFDebug::processGlobalInitializer(const Constant *C) {
+ if (auto *Fn = dyn_cast<Function>(C))
+ processFuncPrototypes(Fn);
+ if (auto *CA = dyn_cast<ConstantAggregate>(C)) {
+ for (unsigned I = 0, N = CA->getNumOperands(); I < N; ++I)
+ processGlobalInitializer(CA->getOperand(I));
}
}
diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h
index 11a0c59ba6c9..02181d3013be 100644
--- a/llvm/lib/Target/BPF/BTFDebug.h
+++ b/llvm/lib/Target/BPF/BTFDebug.h
@@ -352,6 +352,10 @@ class BTFDebug : public DebugHandlerBase {
/// Generate types and variables for globals.
void processGlobals(bool ProcessingMapDef);
+ /// Process global variable initializer in pursuit for function
+ /// pointers.
+ void processGlobalInitializer(const Constant *C);
+
/// Generate types for function prototypes.
void processFuncPrototypes(const Function *);
diff --git a/llvm/test/CodeGen/BPF/BTF/extern-var-func2.ll b/llvm/test/CodeGen/BPF/BTF/extern-var-func2.ll
new file mode 100644
index 000000000000..700486d9f351
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/BTF/extern-var-func2.ll
@@ -0,0 +1,54 @@
+; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
+;
+; Source code:
+; extern int elsewhere(void);
+; struct {
+; void *values[];
+; } prog_map = { .values = { elsewhere } };
+; Compilation flag:
+; clang -target bpf -O2 -g -S -emit-llvm test.c
+; ModuleID = 'b.c'
+
+@prog_map = dso_local local_unnamed_addr global { [1 x ptr] } { [1 x ptr] [ptr @elsewhere] }, align 8, !dbg !0
+
+declare !dbg !17 dso_local i32 @elsewhere() #0
+
+; CHECK: .long 0 # BTF_KIND_FUNC_PROTO(id = 6)
+; CHECK-NEXT: .long 218103808 # 0xd000000
+; CHECK-NEXT: .long 7
+; CHECK-NEXT: .long 37 # BTF_KIND_INT(id = 7)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+; CHECK-NEXT: .long 41 # BTF_KIND_FUNC(id = 8)
+; CHECK-NEXT: .long 201326594 # 0xc000002
+; CHECK-NEXT: .long 6
+
+attributes #0 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!12, !13, !14, !15}
+!llvm.ident = !{!16}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "prog_map", scope: !2, file: !3, line: 4, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 19.0.0git (git@github.com:llvm/llvm-project.git 0390a6803608e3a5314315b73740c2d3f5a5723f)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "b.c", directory: "/home/nickz/llvm-project.git", checksumkind: CSK_MD5, checksum: "41cc17375f1261a0e072590833492553")
+!4 = !{!0}
+!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 2, elements: !6)
+!6 = !{!7}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "values", scope: !5, file: !3, line: 3, baseType: !8)
+!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, elements: !10)
+!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!10 = !{!11}
+!11 = !DISubrange(count: -1)
+!12 = !{i32 7, !"Dwarf Version", i32 5}
+!13 = !{i32 2, !"Debug Info Version", i32 3}
+!14 = !{i32 1, !"wchar_size", i32 4}
+!15 = !{i32 7, !"frame-pointer", i32 2}
+!16 = !{!"clang version 19.0.0git (git@github.com:llvm/llvm-project.git 0390a6803608e3a5314315b73740c2d3f5a5723f)"}
+!17 = !DISubprogram(name: "elsewhere", scope: !3, file: !3, line: 1, type: !18, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!20}
+!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
6fb034e
to
e518bdf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible you could put this code into CompleteExternalDeclaration(), instead of writing it out in every place that can refer to the address of a function?
clang/lib/CodeGen/CGExprConstant.cpp
Outdated
// we don't normally emit debug info for extern fns referenced via | ||
// variable initialisers; BPF needs it since it generates BTF from | ||
// debug info and bpftool demands BTF for every symbol linked | ||
if (CGM.getTarget().getTriple().isBPF() && FD->getStorageClass() == SC_Extern) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an existing hook allowDebugInfoForExternalRef() for which targets want this.
You almost never want getStorageClass(); if you care about linkage, we have different methods for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@efriedma-quic Thank you for insightful comments! As a newbie, I need more guidance.
It is pretty much clear that allowDebugInfoForExternalRef
is a preferred way to check whether we should emit additional debug info. It is currently only overriden by BPF target and is being used for exact same purpose we have here.
I need help getting up to speed irt. CompleteExternalDeclaration
proposal. Having grepped through the code, I can see that BPF faced the same challenge with extern
variables. At the moment, there's a vector of VariableDecl
s populated in SemaDecl.cpp
and later used to attach debug info to variables.
A different mechanism is applied to discovering extern
functions in need for debug info (prior to my patch, extern
functions referenced through code were handled). This is accomplished by code in CGExpr.cpp
. I am proposing a similar extension in CGExprConstant.cpp
.
Would you like to have functions on ExternalDeclarations
list instead?
What would be a good spot to get ahold of FunctionDecl
to put it on ExternalDeclarations
list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the code again, I guess the ultimate question is whether we want to emit debug info for all external functions/variables, or only functions/variables that are actually referenced.
If we want all functions/variables, we want to extend ExternalDeclarations to include them. Maybe put the code in Sema::ActOnFunctionDeclarator, or something like that.
If you just want referenced functions/variables, probably the code should be in GetAddrOfFunction() (and something similar for variables).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mejedi @efriedma-quic Yes, we only want referenced functions/variables. The support for external variable has been implemented here d77ae15. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@efriedma-quic @yonghong-song I ended up generalising ExternalDeclarations
to include both VarDecl
s and FunctionDecl
s.
Since GetAddrOfFunction
is invoked in so many different contexts, I found it difficult to emit debug info only for the subset of calls we care about.
Personally, I find it cleaner to collect external declarations on a list and handle them separately rather than plugging directly into codegen. Please let me know if I am missing something.
Concerning referenced/all debacle -
Sema::ActOnEndOfTranslationUnit
checks whether a declaration is used (does it mean referenced?) before callingConsumer.CompleteExternalDeclaration
;- plugging into codegen ensures that we notice any reference that made it into llvm bitcode BUT they could be removed by the optimiser later;
- BPF backend ensures that only referenced entities make it to BTF.
It looks like both approaches are quite similar?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @mejedi I think we do not need to worry about cases where external functions are in the code but removed by optimizer later as this should not that frequent. Your patch looks good to me, which follows what we did for VarDecl so adding FunctionDecl is a natural addition. BPF side of the change looks good to me too. @efriedma-quic could you take a look as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current approach seems fine.
Sema::ActOnEndOfTranslationUnit checks whether a declaration is used (does it mean referenced?)
"Used" in this context corresponds to odr-used in the C++ standard... which is stuff that Sema thinks the code generator might need to emit. In some cases we manage to skip actually emitting some declarations due to optimizations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @efriedma-quic if the clang believes the declaration might not be necessary due to optimizaiton, it is okay to remove it as in that case kernel/bpf does not need it either.
cc @anakryiko |
✅ With the latest revision this PR passed the C/C++ code formatter. |
e518bdf
to
440f62d
Compare
440f62d
to
88f895c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sema.h
changes look good to me.
Ping. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there some test coverage that shows that unreferenced variables/functions aren't included in the output?
@mejedi Please add a test case for this. |
88f895c
to
defe9d0
Compare
|
ping |
happy with the test coverage, but I'm probably not the right person to review th ecode in more detail |
@yonghong-song @efriedma-quic Any chance we could get it merged? |
When BPF object files are linked with bpftool, every symbol must be accompanied by BTF info. Ensure that extern functions referenced by global variable initializers are included in BTF. The primary motivation is "static" initialization of PROG maps: extern int elsewhere(struct xdp_md *); struct { __uint(type, BPF_MAP_TYPE_PROG_ARRAY); __uint(max_entries, 1); __type(key, int); __type(value, int); __array(values, int (struct xdp_md *)); } prog_map SEC(".maps") = { .values = { elsewhere } }; BPF backend needs debug info to produce BTF. Debug info is not normally generated for external variables and functions. Previously, it was solved differently for variables (collecting variable declarations in ExternalDeclarations vector) and functions (logic invoked during codegen in CGExpr.cpp). This patch generalises ExternalDefclarations to include both function and variable declarations. This change ensures that function references are not missed no matter the context. Previously external functions referenced in constant expressions lacked debug info.
defe9d0
to
a9682a1
Compare
@mejedi Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested Please check whether problems have been caused by your change specifically, as How to do this, and the rest of the post-merge process, is covered in detail here. If your change does cause a problem, it may be reverted, or you can revert it yourself. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! |
When BPF object files are linked with bpftool, every symbol must be accompanied by BTF info. Ensure that extern functions referenced by global variable initializers are included in BTF. The primary motivation is "static" initialization of PROG maps: ```c extern int elsewhere(struct xdp_md *); struct { __uint(type, BPF_MAP_TYPE_PROG_ARRAY); __uint(max_entries, 1); __type(key, int); __type(value, int); __array(values, int (struct xdp_md *)); } prog_map SEC(".maps") = { .values = { elsewhere } }; ``` BPF backend needs debug info to produce BTF. Debug info is not normally generated for external variables and functions. Previously, it was solved differently for variables (collecting variable declarations in ExternalDeclarations vector) and functions (logic invoked during codegen in CGExpr.cpp). This patch generalises ExternalDefclarations to include both function and variable declarations. This change ensures that function references are not missed no matter the context. Previously external functions referenced in constant expressions lacked debug info.
When BPF object files are linked with bpftool, every symbol must be accompanied by BTF info. Ensure that extern functions referenced by global variable initializers are included in BTF.
The primary motivation is "static" initialization of PROG maps:
BPF backend needs debug info to produce BTF. Debug info is not
normally generated for external variables and functions. Previously, it
was solved differently for variables (collecting variable declarations
in ExternalDeclarations vector) and functions (logic invoked during
codegen in CGExpr.cpp).
This patch generalises ExternalDefclarations to include both function
and variable declarations. This change ensures that function references
are not missed no matter the context. Previously external functions
referenced in constant expressions lacked debug info.