Skip to content

Commit 1914953

Browse files
yonghong-songtstellar
authored andcommitted
[BPF] Fix a BTF type pruning bug
In BPF backend, BTF type generation may skip some debuginfo types if they are the pointee type of a struct member. For example, struct task_struct { ... struct mm_struct *mm; ... }; BPF backend may generate a forward decl for 'struct mm_struct' instead of full type if there are no other usage of 'struct mm_struct'. The reason is to avoid bringing too much unneeded types in BTF. Alexei found a pruning bug where we may miss some full type generation. The following is an illustrating example: struct t1 { ... } struct t2 { struct t1 *p; }; struct t2 g; void foo(struct t1 *arg) { ... } In the above case, we will have partial debuginfo chain like below: struct t2 -> member p \ -> ptr -> struct t1 / foo -> argument arg During traversing struct t2 -> member p -> ptr -> struct t1 The corresponding BTF types are generated except 'struct t1' which will be in FixUp stage. Later, when traversing foo -> argument arg -> ptr -> struct t1 The 'ptr' BTF type has been generated and currently implementation ignores 'pointer' type hence 'struct t1' is not generated. This patch fixed the issue not just for the above case, but for general case with multiple derived types, e.g., struct t2 -> member p \ -> const -> ptr -> volatile -> struct t1 / foo -> argument arg Differential Revision: https://reviews.llvm.org/D119986
1 parent da33d40 commit 1914953

File tree

2 files changed

+110
-7
lines changed

2 files changed

+110
-7
lines changed

llvm/lib/Target/BPF/BTFDebug.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -773,15 +773,31 @@ void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId,
773773
// already defined, we should keep moving to eventually
774774
// bring in types for "struct t". Otherwise, the "struct s2"
775775
// definition won't be correct.
776+
//
777+
// In the above, we have following debuginfo:
778+
// {ptr, struct_member} -> typedef -> struct
779+
// and BTF type for 'typedef' is generated while 'struct' may
780+
// be in FixUp. But let us generalize the above to handle
781+
// {different types} -> [various derived types]+ -> another type.
782+
// For example,
783+
// {func_param, struct_member} -> const -> ptr -> volatile -> struct
784+
// We will traverse const/ptr/volatile which already have corresponding
785+
// BTF types and generate type for 'struct' which might be in Fixup
786+
// state.
776787
if (Ty && (!CheckPointer || !SeenPointer)) {
777788
if (const auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
778-
unsigned Tag = DTy->getTag();
779-
if (Tag == dwarf::DW_TAG_typedef || Tag == dwarf::DW_TAG_const_type ||
780-
Tag == dwarf::DW_TAG_volatile_type ||
781-
Tag == dwarf::DW_TAG_restrict_type) {
782-
uint32_t TmpTypeId;
783-
visitTypeEntry(DTy->getBaseType(), TmpTypeId, CheckPointer,
784-
SeenPointer);
789+
while (DTy) {
790+
const DIType *BaseTy = DTy->getBaseType();
791+
if (!BaseTy)
792+
break;
793+
794+
if (DIToIdMap.find(BaseTy) != DIToIdMap.end()) {
795+
DTy = dyn_cast<DIDerivedType>(BaseTy);
796+
} else {
797+
uint32_t TmpTypeId;
798+
visitTypeEntry(BaseTy, TmpTypeId, CheckPointer, SeenPointer);
799+
break;
800+
}
785801
}
786802
}
787803
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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 t1 {
5+
; int a;
6+
; };
7+
; struct t2 {
8+
; const struct t1 * const a;
9+
; };
10+
; int foo(struct t2 *arg) { return 0; }
11+
; int bar(const struct t1 * const arg) { return 0; }
12+
; Compilation flags:
13+
; clang -target bpf -O2 -g -S -emit-llvm t.c
14+
15+
%struct.t2 = type { %struct.t1* }
16+
%struct.t1 = type { i32 }
17+
18+
; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
19+
define dso_local i32 @foo(%struct.t2* nocapture noundef readnone %arg) local_unnamed_addr #0 !dbg !7 {
20+
entry:
21+
call void @llvm.dbg.value(metadata %struct.t2* %arg, metadata !22, metadata !DIExpression()), !dbg !23
22+
ret i32 0, !dbg !24
23+
}
24+
25+
; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
26+
define dso_local i32 @bar(%struct.t1* nocapture noundef readnone %arg) local_unnamed_addr #0 !dbg !25 {
27+
entry:
28+
call void @llvm.dbg.value(metadata %struct.t1* %arg, metadata !29, metadata !DIExpression()), !dbg !30
29+
ret i32 0, !dbg !31
30+
}
31+
32+
; CHECK: .long 10 # BTF_KIND_INT(id = 7)
33+
; CHECK-NEXT: .long 16777216 # 0x1000000
34+
; CHECK-NEXT: .long 4
35+
; CHECK-NEXT: .long 16777248 # 0x1000020
36+
37+
; CHECK: .long 69 # BTF_KIND_STRUCT(id = 9)
38+
; CHECK-NEXT: .long 67108865 # 0x4000001
39+
; CHECK-NEXT: .long 4
40+
; CHECK-NEXT: .long 4
41+
; CHECK-NEXT: .long 7
42+
43+
; CHECK: .byte 97 # string offset=4
44+
; CHECK: .ascii "t1" # string offset=69
45+
46+
; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
47+
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
48+
49+
attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
50+
attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
51+
52+
!llvm.dbg.cu = !{!0}
53+
!llvm.module.flags = !{!2, !3, !4, !5}
54+
!llvm.ident = !{!6}
55+
56+
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git c34c8afcb85ae9142d0f783bb899c464e8bd2356)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
57+
!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_ptr", checksumkind: CSK_MD5, checksum: "d43a0541e830263021772349589e47a5")
58+
!2 = !{i32 7, !"Dwarf Version", i32 5}
59+
!3 = !{i32 2, !"Debug Info Version", i32 3}
60+
!4 = !{i32 1, !"wchar_size", i32 4}
61+
!5 = !{i32 7, !"frame-pointer", i32 2}
62+
!6 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git c34c8afcb85ae9142d0f783bb899c464e8bd2356)"}
63+
!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 7, type: !8, scopeLine: 7, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !21)
64+
!8 = !DISubroutineType(types: !9)
65+
!9 = !{!10, !11}
66+
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
67+
!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
68+
!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", file: !1, line: 4, size: 64, elements: !13)
69+
!13 = !{!14}
70+
!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 5, baseType: !15, size: 64)
71+
!15 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !16)
72+
!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64)
73+
!17 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !18)
74+
!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !1, line: 1, size: 32, elements: !19)
75+
!19 = !{!20}
76+
!20 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !18, file: !1, line: 2, baseType: !10, size: 32)
77+
!21 = !{!22}
78+
!22 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 7, type: !11)
79+
!23 = !DILocation(line: 0, scope: !7)
80+
!24 = !DILocation(line: 7, column: 27, scope: !7)
81+
!25 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 8, type: !26, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !28)
82+
!26 = !DISubroutineType(types: !27)
83+
!27 = !{!10, !15}
84+
!28 = !{!29}
85+
!29 = !DILocalVariable(name: "arg", arg: 1, scope: !25, file: !1, line: 8, type: !15)
86+
!30 = !DILocation(line: 0, scope: !25)
87+
!31 = !DILocation(line: 8, column: 40, scope: !25)

0 commit comments

Comments
 (0)