Skip to content

Commit c69ed62

Browse files
yonghong-songtstellar
authored andcommitted
[BPF] fix a bug for BTF pointee type pruning
In BTF, pointee type pruning is used to reduce cluttering too many unused types into prog BTF. For example, struct task_struct { ... struct mm_struct *mm; ... } If bpf program does not access members of "struct mm_struct", there is no need to bring types for "struct mm_struct" to BTF. This patch fixed a bug where an incorrect pruning happened. The test case like below: struct t; typedef struct t _t; struct s1 { _t *c; }; int test1(struct s1 *arg) { ... } struct t { int a; int b; }; struct s2 { _t c; } int test2(struct s2 *arg) { ... } After processing test1(), among others, BPF backend generates BTF types for "struct s1", "_t" and a placeholder for "struct t". Note that "struct t" is not really generated. If later a direct access to "struct t" member happened, "struct t" BTF type will be generated properly. During processing test2(), when processing member type "_t c", BPF backend sees type "_t" already generated, so returned. This caused the problem that "struct t" BTF type is never generated and eventually causing incorrect type definition for "struct s2". To fix the issue, during DebugInfo type traversal, even if a typedef/const/volatile/restrict derived type has been recorded in BTF, if it is not a type pruning candidate, type traversal of its base type continues. Differential Revision: https://reviews.llvm.org/D82041 (cherry picked from commit 89648eb)
1 parent 177a9ac commit c69ed62

File tree

3 files changed

+280
-0
lines changed

3 files changed

+280
-0
lines changed

llvm/lib/Target/BPF/BTFDebug.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,38 @@ void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId,
600600
bool CheckPointer, bool SeenPointer) {
601601
if (!Ty || DIToIdMap.find(Ty) != DIToIdMap.end()) {
602602
TypeId = DIToIdMap[Ty];
603+
604+
// To handle the case like the following:
605+
// struct t;
606+
// typedef struct t _t;
607+
// struct s1 { _t *c; };
608+
// int test1(struct s1 *arg) { ... }
609+
//
610+
// struct t { int a; int b; };
611+
// struct s2 { _t c; }
612+
// int test2(struct s2 *arg) { ... }
613+
//
614+
// During traversing test1() argument, "_t" is recorded
615+
// in DIToIdMap and a forward declaration fixup is created
616+
// for "struct t" to avoid pointee type traversal.
617+
//
618+
// During traversing test2() argument, even if we see "_t" is
619+
// already defined, we should keep moving to eventually
620+
// bring in types for "struct t". Otherwise, the "struct s2"
621+
// definition won't be correct.
622+
if (Ty && (!CheckPointer || !SeenPointer)) {
623+
if (const auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
624+
unsigned Tag = DTy->getTag();
625+
if (Tag == dwarf::DW_TAG_typedef || Tag == dwarf::DW_TAG_const_type ||
626+
Tag == dwarf::DW_TAG_volatile_type ||
627+
Tag == dwarf::DW_TAG_restrict_type) {
628+
uint32_t TmpTypeId;
629+
visitTypeEntry(DTy->getBaseType(), TmpTypeId, CheckPointer,
630+
SeenPointer);
631+
}
632+
}
633+
}
634+
603635
return;
604636
}
605637

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
2+
; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
3+
; Source:
4+
; struct tt;
5+
; struct s1 { const struct tt *mp; };
6+
; int test1(struct s1 *arg)
7+
; {
8+
; return 0;
9+
; }
10+
;
11+
; struct tt { int m1; int m2; };
12+
; struct s2 { const struct tt m3; };
13+
; int test2(struct s2 *arg)
14+
; {
15+
; return arg->m3.m1;
16+
; }
17+
; Compilation flags:
18+
; clang -target bpf -O2 -g -S -emit-llvm t.c
19+
20+
%struct.s1 = type { %struct.tt* }
21+
%struct.tt = type { i32, i32 }
22+
%struct.s2 = type { %struct.tt }
23+
24+
; Function Attrs: norecurse nounwind readnone
25+
define dso_local i32 @test1(%struct.s1* nocapture readnone %arg) local_unnamed_addr #0 !dbg !7 {
26+
entry:
27+
call void @llvm.dbg.value(metadata %struct.s1* %arg, metadata !22, metadata !DIExpression()), !dbg !23
28+
ret i32 0, !dbg !24
29+
}
30+
31+
; Function Attrs: norecurse nounwind readonly
32+
define dso_local i32 @test2(%struct.s2* nocapture readonly %arg) local_unnamed_addr #1 !dbg !25 {
33+
entry:
34+
call void @llvm.dbg.value(metadata %struct.s2* %arg, metadata !33, metadata !DIExpression()), !dbg !34
35+
%m1 = getelementptr inbounds %struct.s2, %struct.s2* %arg, i64 0, i32 0, i32 0, !dbg !35
36+
%0 = load i32, i32* %m1, align 4, !dbg !35, !tbaa !36
37+
ret i32 %0, !dbg !42
38+
}
39+
40+
; CHECK: .long 0 # BTF_KIND_CONST(id = 4)
41+
; CHECK-NEXT: .long 167772160 # 0xa000000
42+
; CHECK-NEXT: .long 10
43+
44+
; CHECK: .long 60 # BTF_KIND_STRUCT(id = 9)
45+
; CHECK-NEXT: .long 67108865 # 0x4000001
46+
; CHECK-NEXT: .long 8
47+
; CHECK-NEXT: .long 63
48+
; CHECK-NEXT: .long 4
49+
; CHECK-NEXT: .long 0 # 0x0
50+
51+
; CHECK: .long 66 # BTF_KIND_STRUCT(id = 10)
52+
; CHECK-NEXT: .long 67108866 # 0x4000002
53+
; CHECK-NEXT: .long 8
54+
; CHECK-NEXT: .long 69
55+
; CHECK-NEXT: .long 6
56+
; CHECK-NEXT: .long 0 # 0x0
57+
; CHECK-NEXT: .long 72
58+
; CHECK-NEXT: .long 6
59+
; CHECK-NEXT: .long 32 # 0x20
60+
61+
; CHECK: .ascii "s2" # string offset=60
62+
; CHECK: .ascii "m3" # string offset=63
63+
; CHECK: .ascii "tt" # string offset=66
64+
; CHECK: .ascii "m1" # string offset=69
65+
; CHECK: .ascii "m2" # string offset=72
66+
67+
; Function Attrs: nounwind readnone speculatable willreturn
68+
declare void @llvm.dbg.value(metadata, metadata, metadata) #2
69+
70+
attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
71+
attributes #1 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
72+
attributes #2 = { nounwind readnone speculatable willreturn }
73+
74+
!llvm.dbg.cu = !{!0}
75+
!llvm.module.flags = !{!3, !4, !5}
76+
!llvm.ident = !{!6}
77+
78+
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 7cfd267c518aba226b34b7fbfe8db70000b22053)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
79+
!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/btf")
80+
!2 = !{}
81+
!3 = !{i32 7, !"Dwarf Version", i32 4}
82+
!4 = !{i32 2, !"Debug Info Version", i32 3}
83+
!5 = !{i32 1, !"wchar_size", i32 4}
84+
!6 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 7cfd267c518aba226b34b7fbfe8db70000b22053)"}
85+
!7 = distinct !DISubprogram(name: "test1", scope: !1, file: !1, line: 3, type: !8, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !21)
86+
!8 = !DISubroutineType(types: !9)
87+
!9 = !{!10, !11}
88+
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
89+
!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
90+
!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 64, elements: !13)
91+
!13 = !{!14}
92+
!14 = !DIDerivedType(tag: DW_TAG_member, name: "mp", scope: !12, file: !1, line: 2, baseType: !15, size: 64)
93+
!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
94+
!16 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !17)
95+
!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "tt", file: !1, line: 8, size: 64, elements: !18)
96+
!18 = !{!19, !20}
97+
!19 = !DIDerivedType(tag: DW_TAG_member, name: "m1", scope: !17, file: !1, line: 8, baseType: !10, size: 32)
98+
!20 = !DIDerivedType(tag: DW_TAG_member, name: "m2", scope: !17, file: !1, line: 8, baseType: !10, size: 32, offset: 32)
99+
!21 = !{!22}
100+
!22 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 3, type: !11)
101+
!23 = !DILocation(line: 0, scope: !7)
102+
!24 = !DILocation(line: 5, column: 3, scope: !7)
103+
!25 = distinct !DISubprogram(name: "test2", scope: !1, file: !1, line: 10, type: !26, scopeLine: 11, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !32)
104+
!26 = !DISubroutineType(types: !27)
105+
!27 = !{!10, !28}
106+
!28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !29, size: 64)
107+
!29 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s2", file: !1, line: 9, size: 64, elements: !30)
108+
!30 = !{!31}
109+
!31 = !DIDerivedType(tag: DW_TAG_member, name: "m3", scope: !29, file: !1, line: 9, baseType: !16, size: 64)
110+
!32 = !{!33}
111+
!33 = !DILocalVariable(name: "arg", arg: 1, scope: !25, file: !1, line: 10, type: !28)
112+
!34 = !DILocation(line: 0, scope: !25)
113+
!35 = !DILocation(line: 12, column: 18, scope: !25)
114+
!36 = !{!37, !39, i64 0}
115+
!37 = !{!"s2", !38, i64 0}
116+
!38 = !{!"tt", !39, i64 0, !39, i64 4}
117+
!39 = !{!"int", !40, i64 0}
118+
!40 = !{!"omnipotent char", !41, i64 0}
119+
!41 = !{!"Simple C/C++ TBAA"}
120+
!42 = !DILocation(line: 12, column: 3, scope: !25)
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
2+
; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s
3+
; Source:
4+
; struct tt;
5+
; typedef struct tt _tt;
6+
; typedef _tt __tt;
7+
; struct s1 { __tt *mp; };
8+
; int test1(struct s1 *arg)
9+
; {
10+
; return 0;
11+
; }
12+
;
13+
; struct tt { int m1; int m2; };
14+
; struct s2 { __tt m3; };
15+
; int test2(struct s2 *arg)
16+
; {
17+
; return arg->m3.m1;
18+
; }
19+
; Compilation flags:
20+
; clang -target bpf -O2 -g -S -emit-llvm t.c
21+
22+
%struct.s1 = type { %struct.tt* }
23+
%struct.tt = type { i32, i32 }
24+
%struct.s2 = type { %struct.tt }
25+
26+
; Function Attrs: norecurse nounwind readnone
27+
define dso_local i32 @test1(%struct.s1* nocapture readnone %arg) local_unnamed_addr #0 !dbg !7 {
28+
entry:
29+
call void @llvm.dbg.value(metadata %struct.s1* %arg, metadata !23, metadata !DIExpression()), !dbg !24
30+
ret i32 0, !dbg !25
31+
}
32+
33+
; Function Attrs: norecurse nounwind readonly
34+
define dso_local i32 @test2(%struct.s2* nocapture readonly %arg) local_unnamed_addr #1 !dbg !26 {
35+
entry:
36+
call void @llvm.dbg.value(metadata %struct.s2* %arg, metadata !34, metadata !DIExpression()), !dbg !35
37+
%m1 = getelementptr inbounds %struct.s2, %struct.s2* %arg, i64 0, i32 0, i32 0, !dbg !36
38+
%0 = load i32, i32* %m1, align 4, !dbg !36, !tbaa !37
39+
ret i32 %0, !dbg !43
40+
}
41+
42+
; CHECK: .long 7 # BTF_KIND_TYPEDEF(id = 4)
43+
; CHECK-NEXT: .long 134217728 # 0x8000000
44+
; CHECK-NEXT: .long 5
45+
; CHECK-NEXT: .long 12 # BTF_KIND_TYPEDEF(id = 5)
46+
; CHECK-NEXT: .long 134217728 # 0x8000000
47+
; CHECK-NEXT: .long 11
48+
49+
; CHECK: .long 69 # BTF_KIND_STRUCT(id = 10)
50+
; CHECK-NEXT: .long 67108865 # 0x4000001
51+
; CHECK-NEXT: .long 8
52+
; CHECK-NEXT: .long 72
53+
; CHECK-NEXT: .long 4
54+
; CHECK-NEXT: .long 0 # 0x0
55+
56+
; CHECK: .long 75 # BTF_KIND_STRUCT(id = 11)
57+
; CHECK-NEXT: .long 67108866 # 0x4000002
58+
; CHECK-NEXT: .long 8
59+
; CHECK-NEXT: .long 78
60+
; CHECK-NEXT: .long 7
61+
; CHECK-NEXT: .long 0 # 0x0
62+
; CHECK-NEXT: .long 81
63+
; CHECK-NEXT: .long 7
64+
; CHECK-NEXT: .long 32 # 0x20
65+
66+
; CHECK: .ascii "__tt" # string offset=7
67+
; CHECK: .ascii "_tt" # string offset=12
68+
; CHECK: .ascii "s2" # string offset=69
69+
; CHECK: .ascii "m3" # string offset=72
70+
; CHECK: .ascii "tt" # string offset=75
71+
; CHECK: .ascii "m1" # string offset=78
72+
; CHECK: .ascii "m2" # string offset=81
73+
74+
; Function Attrs: nounwind readnone speculatable willreturn
75+
declare void @llvm.dbg.value(metadata, metadata, metadata) #2
76+
77+
attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
78+
attributes #1 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
79+
attributes #2 = { nounwind readnone speculatable willreturn }
80+
81+
!llvm.dbg.cu = !{!0}
82+
!llvm.module.flags = !{!3, !4, !5}
83+
!llvm.ident = !{!6}
84+
85+
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 7cfd267c518aba226b34b7fbfe8db70000b22053)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
86+
!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/btf")
87+
!2 = !{}
88+
!3 = !{i32 7, !"Dwarf Version", i32 4}
89+
!4 = !{i32 2, !"Debug Info Version", i32 3}
90+
!5 = !{i32 1, !"wchar_size", i32 4}
91+
!6 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 7cfd267c518aba226b34b7fbfe8db70000b22053)"}
92+
!7 = distinct !DISubprogram(name: "test1", scope: !1, file: !1, line: 5, type: !8, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !22)
93+
!8 = !DISubroutineType(types: !9)
94+
!9 = !{!10, !11}
95+
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
96+
!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
97+
!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 4, size: 64, elements: !13)
98+
!13 = !{!14}
99+
!14 = !DIDerivedType(tag: DW_TAG_member, name: "mp", scope: !12, file: !1, line: 4, baseType: !15, size: 64)
100+
!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
101+
!16 = !DIDerivedType(tag: DW_TAG_typedef, name: "__tt", file: !1, line: 3, baseType: !17)
102+
!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "_tt", file: !1, line: 2, baseType: !18)
103+
!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "tt", file: !1, line: 10, size: 64, elements: !19)
104+
!19 = !{!20, !21}
105+
!20 = !DIDerivedType(tag: DW_TAG_member, name: "m1", scope: !18, file: !1, line: 10, baseType: !10, size: 32)
106+
!21 = !DIDerivedType(tag: DW_TAG_member, name: "m2", scope: !18, file: !1, line: 10, baseType: !10, size: 32, offset: 32)
107+
!22 = !{!23}
108+
!23 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 5, type: !11)
109+
!24 = !DILocation(line: 0, scope: !7)
110+
!25 = !DILocation(line: 7, column: 3, scope: !7)
111+
!26 = distinct !DISubprogram(name: "test2", scope: !1, file: !1, line: 12, type: !27, scopeLine: 13, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !33)
112+
!27 = !DISubroutineType(types: !28)
113+
!28 = !{!10, !29}
114+
!29 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64)
115+
!30 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s2", file: !1, line: 11, size: 64, elements: !31)
116+
!31 = !{!32}
117+
!32 = !DIDerivedType(tag: DW_TAG_member, name: "m3", scope: !30, file: !1, line: 11, baseType: !16, size: 64)
118+
!33 = !{!34}
119+
!34 = !DILocalVariable(name: "arg", arg: 1, scope: !26, file: !1, line: 12, type: !29)
120+
!35 = !DILocation(line: 0, scope: !26)
121+
!36 = !DILocation(line: 14, column: 18, scope: !26)
122+
!37 = !{!38, !40, i64 0}
123+
!38 = !{!"s2", !39, i64 0}
124+
!39 = !{!"tt", !40, i64 0, !40, i64 4}
125+
!40 = !{!"int", !41, i64 0}
126+
!41 = !{!"omnipotent char", !42, i64 0}
127+
!42 = !{!"Simple C/C++ TBAA"}
128+
!43 = !DILocation(line: 14, column: 3, scope: !26)

0 commit comments

Comments
 (0)