Skip to content

Commit cf56b53

Browse files
[BPF] Allow struct pointee member btf generation with annotations (#141719)
Currently, to avoid generating too much BTF types, for a struct type like ``` struct foo { int val; struct bar *ptr; }; ``` if the BTF generation reaches 'struct foo', it will not generate actual type for 'struct bar' and instead a forward decl is generated. The 'struct bar' is actual generated in BTF unless it is reached through a non-struct pointer member. Such a limitation forces bpf developer to hack and workaround this problem. See [1] and [2]. For example in [1], we have ``` struct map_value { struct prog_test_ref_kfunc *not_kptr; struct prog_test_ref_kfunc __kptr *val; struct node_data __kptr *node; }; ``` The BTF type for 'struct node_data' is not generated. Note that we have a '__kptr' annotation. Similar problem for [2] with a '__uptr' annotation. Note that the issue in [1] has been resolved later but the hack in [2] is still needed. This patch relaxed the struct type (with struct pointer member) BTF generation if the struct pointer has a btf_type_tag annotation. [1] https://lore.kernel.org/r/[email protected] [2] https://lore.kernel.org/r/[email protected]
1 parent 9553514 commit cf56b53

File tree

3 files changed

+111
-61
lines changed

3 files changed

+111
-61
lines changed

llvm/lib/Target/BPF/BTFDebug.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId,
816816
/// Try to avoid chasing pointees, esp. structure pointees which may
817817
/// unnecessary bring in a lot of types.
818818
if (CheckPointer && !SeenPointer) {
819-
SeenPointer = Tag == dwarf::DW_TAG_pointer_type;
819+
SeenPointer = Tag == dwarf::DW_TAG_pointer_type && !DTy->getAnnotations();
820820
}
821821

822822
if (CheckPointer && SeenPointer) {
@@ -916,7 +916,8 @@ void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId,
916916
if (DIToIdMap.find(BaseTy) != DIToIdMap.end()) {
917917
DTy = dyn_cast<DIDerivedType>(BaseTy);
918918
} else {
919-
if (CheckPointer && DTy->getTag() == dwarf::DW_TAG_pointer_type) {
919+
if (CheckPointer && DTy->getTag() == dwarf::DW_TAG_pointer_type &&
920+
!DTy->getAnnotations()) {
920921
SeenPointer = true;
921922
if (IsForwardDeclCandidate(BaseTy))
922923
break;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
; RUN: llc -mtriple=bpfel -mcpu=v3 -filetype=obj -o %t1 %s
2+
; RUN: llvm-objcopy --dump-section='.BTF'=%t2 %t1
3+
; RUN: %python %p/print_btf.py %t2 | FileCheck -check-prefixes=CHECK-BTF %s
4+
; Source:
5+
; #define __tag1 __attribute__((btf_type_tag("tag1")))
6+
;
7+
; struct t1 {
8+
; int a;
9+
; };
10+
; struct t2 {
11+
; struct t1 *p1;
12+
; struct t1 __tag1 *p2;
13+
; int b;
14+
; };
15+
; int foo(struct t2 *arg) {
16+
; return arg->b;
17+
; }
18+
; Compilation flags:
19+
; clang -target bpf -O2 -g -S -emit-llvm t.c
20+
21+
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
22+
define dso_local i32 @foo(ptr nocapture noundef readonly %0) local_unnamed_addr #0 !dbg !8 {
23+
#dbg_value(ptr %0, !26, !DIExpression(), !27)
24+
%2 = getelementptr inbounds nuw i8, ptr %0, i64 16, !dbg !28
25+
%3 = load i32, ptr %2, align 8, !dbg !28, !tbaa !29
26+
ret i32 %3, !dbg !36
27+
}
28+
29+
; CHECK-BTF: [1] PTR '(anon)' type_id=2
30+
; CHECK-BTF: [2] STRUCT 't2' size=24 vlen=3
31+
; CHECK-BTF: 'p1' type_id=3 bits_offset=0
32+
; CHECK-BTF: 'p2' type_id=5 bits_offset=64
33+
; CHECK-BTF: 'b' type_id=7 bits_offset=128
34+
; CHECK-BTF: [3] PTR '(anon)' type_id=6
35+
; CHECK-BTF: [4] TYPE_TAG 'tag1' type_id=6
36+
; CHECK-BTF: [5] PTR '(anon)' type_id=4
37+
; CHECK-BTF: [6] STRUCT 't1' size=4 vlen=1
38+
; CHECK-BTF: 'a' type_id=7 bits_offset=0
39+
; CHECK-BTF: [7] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
40+
; CHECK-BTF: [8] FUNC_PROTO '(anon)' ret_type_id=7 vlen=1
41+
; CHECK-BTF: 'arg' type_id=1
42+
; CHECK-BTF: [9] FUNC 'foo' type_id=8 linkage=global
43+
44+
attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
45+
46+
!llvm.dbg.cu = !{!0}
47+
!llvm.module.flags = !{!2, !3, !4, !5, !6}
48+
!llvm.ident = !{!7}
49+
50+
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 20.1.6 (https://github.com/llvm/llvm-project.git aa804fd3e624cb92c6e7665182504c6049387f35)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
51+
!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/tmp3/tests", checksumkind: CSK_MD5, checksum: "73ef5b93654cc4e2667f383d5c3a9cd3")
52+
!2 = !{i32 7, !"Dwarf Version", i32 5}
53+
!3 = !{i32 2, !"Debug Info Version", i32 3}
54+
!4 = !{i32 1, !"wchar_size", i32 4}
55+
!5 = !{i32 7, !"frame-pointer", i32 2}
56+
!6 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
57+
!7 = !{!"clang version 20.1.6 (https://github.com/llvm/llvm-project.git aa804fd3e624cb92c6e7665182504c6049387f35)"}
58+
!8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 11, type: !9, scopeLine: 11, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !25)
59+
!9 = !DISubroutineType(types: !10)
60+
!10 = !{!11, !12}
61+
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
62+
!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64)
63+
!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", file: !1, line: 6, size: 192, elements: !14)
64+
!14 = !{!15, !20, !24}
65+
!15 = !DIDerivedType(tag: DW_TAG_member, name: "p1", scope: !13, file: !1, line: 7, baseType: !16, size: 64)
66+
!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64)
67+
!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !1, line: 3, size: 32, elements: !18)
68+
!18 = !{!19}
69+
!19 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !17, file: !1, line: 4, baseType: !11, size: 32)
70+
!20 = !DIDerivedType(tag: DW_TAG_member, name: "p2", scope: !13, file: !1, line: 8, baseType: !21, size: 64, offset: 64)
71+
!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64, annotations: !22)
72+
!22 = !{!23}
73+
!23 = !{!"btf_type_tag", !"tag1"}
74+
!24 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !13, file: !1, line: 9, baseType: !11, size: 32, offset: 128)
75+
!25 = !{!26}
76+
!26 = !DILocalVariable(name: "arg", arg: 1, scope: !8, file: !1, line: 11, type: !12)
77+
!27 = !DILocation(line: 0, scope: !8)
78+
!28 = !DILocation(line: 12, column: 15, scope: !8)
79+
!29 = !{!30, !35, i64 16}
80+
!30 = !{!"t2", !31, i64 0, !31, i64 8, !35, i64 16}
81+
!31 = !{!"p1 _ZTS2t1", !32, i64 0}
82+
!32 = !{!"any pointer", !33, i64 0}
83+
!33 = !{!"omnipotent char", !34, i64 0}
84+
!34 = !{!"Simple C/C++ TBAA"}
85+
!35 = !{!"int", !33, i64 0}
86+
!36 = !DILocation(line: 12, column: 3, scope: !8)

llvm/test/CodeGen/BPF/BTF/type-tag-fixup-resolved.ll

Lines changed: 22 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
; RUN: llc -mtriple=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
2-
; RUN: llc -mtriple=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
1+
; RUN: llc -mtriple=bpfel -filetype=obj -o %t1 %s
2+
; RUN: llvm-objcopy --dump-section='.BTF'=%t2 %t1
3+
; RUN: %python %p/print_btf.py %t2 | FileCheck -check-prefixes=CHECK-BTF %s
4+
; RUN: llc -mtriple=bpfeb -filetype=obj -o %t1 %s
5+
; RUN: llvm-objcopy --dump-section='.BTF'=%t2 %t1
6+
; RUN: %python %p/print_btf.py %t2 | FileCheck -check-prefixes=CHECK-BTF %s
37
;
48
; Source:
59
; #define __tag1 __attribute__((btf_type_tag("tag1")))
@@ -37,63 +41,22 @@ entry:
3741
ret void, !dbg !26
3842
}
3943

40-
; CHECK: .long 0 # BTF_KIND_FUNC_PROTO(id = 1)
41-
; CHECK-NEXT: .long 218103808 # 0xd000000
42-
; CHECK-NEXT: .long 0
43-
; CHECK-NEXT: .long 1 # BTF_KIND_FUNC(id = 2)
44-
; CHECK-NEXT: .long 201326593 # 0xc000001
45-
; CHECK-NEXT: .long 1
46-
; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 3)
47-
; CHECK-NEXT: .long 218103810 # 0xd000002
48-
; CHECK-NEXT: .long 0
49-
; CHECK-NEXT: .long 0
50-
; CHECK-NEXT: .long 4
51-
; CHECK-NEXT: .long 0
52-
; CHECK-NEXT: .long 7
53-
; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4)
54-
; CHECK-NEXT: .long 33554432 # 0x2000000
55-
; CHECK-NEXT: .long 5
56-
; CHECK-NEXT: .long 63 # BTF_KIND_STRUCT(id = 5)
57-
; CHECK-NEXT: .long 67108865 # 0x4000001
58-
; CHECK-NEXT: .long 8
59-
; CHECK-NEXT: .long 73
60-
; CHECK-NEXT: .long 6
61-
; CHECK-NEXT: .long 0 # 0x0
62-
; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 6)
63-
; CHECK-NEXT: .long 33554432 # 0x2000000
64-
; CHECK-NEXT: .long 12
65-
; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 7)
66-
; CHECK-NEXT: .long 33554432 # 0x2000000
67-
; CHECK-NEXT: .long 8
68-
; CHECK-NEXT: .long 77 # BTF_KIND_STRUCT(id = 8)
69-
; CHECK-NEXT: .long 67108865 # 0x4000001
70-
; CHECK-NEXT: .long 4
71-
; CHECK-NEXT: .long 81
72-
; CHECK-NEXT: .long 9
73-
; CHECK-NEXT: .long 0 # 0x0
74-
; CHECK-NEXT: .long 83 # BTF_KIND_INT(id = 9)
75-
; CHECK-NEXT: .long 16777216 # 0x1000000
76-
; CHECK-NEXT: .long 4
77-
; CHECK-NEXT: .long 16777248 # 0x1000020
78-
; CHECK-NEXT: .long 87 # BTF_KIND_FUNC(id = 10)
79-
; CHECK-NEXT: .long 201326594 # 0xc000002
80-
; CHECK-NEXT: .long 3
81-
; CHECK-NEXT: .long 92 # BTF_KIND_TYPE_TAG(id = 11)
82-
; CHECK-NEXT: .long 301989888 # 0x12000000
83-
; CHECK-NEXT: .long 8
84-
; CHECK-NEXT: .long 97 # BTF_KIND_TYPE_TAG(id = 12)
85-
; CHECK-NEXT: .long 301989888 # 0x12000000
86-
; CHECK-NEXT: .long 11
87-
88-
; CHECK: .ascii "test" # string offset=1
89-
; CHECK: .ascii "map_value" # string offset=63
90-
; CHECK: .ascii "ptr" # string offset=73
91-
; CHECK: .ascii "foo" # string offset=77
92-
; CHECK: .byte 105 # string offset=81
93-
; CHECK: .ascii "int" # string offset=83
94-
; CHECK: .ascii "func" # string offset=87
95-
; CHECK: .ascii "tag2" # string offset=92
96-
; CHECK: .ascii "tag1" # string offset=97
44+
; CHECK-BTF: [1] FUNC_PROTO '(anon)' ret_type_id=0 vlen=0
45+
; CHECK-BTF: [2] FUNC 'test' type_id=1 linkage=global
46+
; CHECK-BTF: [3] FUNC_PROTO '(anon)' ret_type_id=0 vlen=2
47+
; CHECK-BTF: '(anon)' type_id=4
48+
; CHECK-BTF: '(anon)' type_id=11
49+
; CHECK-BTF: [4] PTR '(anon)' type_id=5
50+
; CHECK-BTF: [5] STRUCT 'map_value' size=8 vlen=1
51+
; CHECK-BTF: 'ptr' type_id=8 bits_offset=0
52+
; CHECK-BTF: [6] TYPE_TAG 'tag2' type_id=9
53+
; CHECK-BTF: [7] TYPE_TAG 'tag1' type_id=6
54+
; CHECK-BTF: [8] PTR '(anon)' type_id=7
55+
; CHECK-BTF: [9] STRUCT 'foo' size=4 vlen=1
56+
; CHECK-BTF: 'i' type_id=10 bits_offset=0
57+
; CHECK-BTF: [10] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
58+
; CHECK-BTF: [11] PTR '(anon)' type_id=9
59+
; CHECK-BTF: [12] FUNC 'func' type_id=3 linkage=extern
9760

9861
; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
9962
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1

0 commit comments

Comments
 (0)