summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYonghong Song <yhs@fb.com>2022-02-16 11:54:38 -0800
committerTom Stellard <tstellar@redhat.com>2022-03-01 14:30:33 -0800
commit19149538e9a9fce91bcdf70b69dc6defc9e8a533 (patch)
tree566dea058cf31887ebcdfa144ba84bac3290aff8
parentda33d400682a8cf93062fe61a9f0b6ec1d60c8ad (diff)
[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
-rw-r--r--llvm/lib/Target/BPF/BTFDebug.cpp30
-rw-r--r--llvm/test/CodeGen/BPF/BTF/pruning-multi-derived-type.ll87
2 files changed, 110 insertions, 7 deletions
diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp
index d536aed1d211..166b62bd6226 100644
--- a/llvm/lib/Target/BPF/BTFDebug.cpp
+++ b/llvm/lib/Target/BPF/BTFDebug.cpp
@@ -773,15 +773,31 @@ void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId,
// already defined, we should keep moving to eventually
// bring in types for "struct t". Otherwise, the "struct s2"
// definition won't be correct.
+ //
+ // In the above, we have following debuginfo:
+ // {ptr, struct_member} -> typedef -> struct
+ // and BTF type for 'typedef' is generated while 'struct' may
+ // be in FixUp. But let us generalize the above to handle
+ // {different types} -> [various derived types]+ -> another type.
+ // For example,
+ // {func_param, struct_member} -> const -> ptr -> volatile -> struct
+ // We will traverse const/ptr/volatile which already have corresponding
+ // BTF types and generate type for 'struct' which might be in Fixup
+ // state.
if (Ty && (!CheckPointer || !SeenPointer)) {
if (const auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
- unsigned Tag = DTy->getTag();
- if (Tag == dwarf::DW_TAG_typedef || Tag == dwarf::DW_TAG_const_type ||
- Tag == dwarf::DW_TAG_volatile_type ||
- Tag == dwarf::DW_TAG_restrict_type) {
- uint32_t TmpTypeId;
- visitTypeEntry(DTy->getBaseType(), TmpTypeId, CheckPointer,
- SeenPointer);
+ while (DTy) {
+ const DIType *BaseTy = DTy->getBaseType();
+ if (!BaseTy)
+ break;
+
+ if (DIToIdMap.find(BaseTy) != DIToIdMap.end()) {
+ DTy = dyn_cast<DIDerivedType>(BaseTy);
+ } else {
+ uint32_t TmpTypeId;
+ visitTypeEntry(BaseTy, TmpTypeId, CheckPointer, SeenPointer);
+ break;
+ }
}
}
}
diff --git a/llvm/test/CodeGen/BPF/BTF/pruning-multi-derived-type.ll b/llvm/test/CodeGen/BPF/BTF/pruning-multi-derived-type.ll
new file mode 100644
index 000000000000..63c864fd0e3a
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/BTF/pruning-multi-derived-type.ll
@@ -0,0 +1,87 @@
+; 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:
+; struct t1 {
+; int a;
+; };
+; struct t2 {
+; const struct t1 * const a;
+; };
+; int foo(struct t2 *arg) { return 0; }
+; int bar(const struct t1 * const arg) { return 0; }
+; Compilation flags:
+; clang -target bpf -O2 -g -S -emit-llvm t.c
+
+%struct.t2 = type { %struct.t1* }
+%struct.t1 = type { i32 }
+
+; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
+define dso_local i32 @foo(%struct.t2* nocapture noundef readnone %arg) local_unnamed_addr #0 !dbg !7 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.t2* %arg, metadata !22, metadata !DIExpression()), !dbg !23
+ ret i32 0, !dbg !24
+}
+
+; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
+define dso_local i32 @bar(%struct.t1* nocapture noundef readnone %arg) local_unnamed_addr #0 !dbg !25 {
+entry:
+ call void @llvm.dbg.value(metadata %struct.t1* %arg, metadata !29, metadata !DIExpression()), !dbg !30
+ ret i32 0, !dbg !31
+}
+
+; CHECK: .long 10 # BTF_KIND_INT(id = 7)
+; CHECK-NEXT: .long 16777216 # 0x1000000
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 16777248 # 0x1000020
+
+; CHECK: .long 69 # BTF_KIND_STRUCT(id = 9)
+; CHECK-NEXT: .long 67108865 # 0x4000001
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long 7
+
+; CHECK: .byte 97 # string offset=4
+; CHECK: .ascii "t1" # string offset=69
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+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" }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5}
+!llvm.ident = !{!6}
+
+!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)
+!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_ptr", checksumkind: CSK_MD5, checksum: "d43a0541e830263021772349589e47a5")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 7, !"frame-pointer", i32 2}
+!6 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git c34c8afcb85ae9142d0f783bb899c464e8bd2356)"}
+!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)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !11}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
+!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", file: !1, line: 4, size: 64, elements: !13)
+!13 = !{!14}
+!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 5, baseType: !15, size: 64)
+!15 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !16)
+!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64)
+!17 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !18)
+!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !1, line: 1, size: 32, elements: !19)
+!19 = !{!20}
+!20 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !18, file: !1, line: 2, baseType: !10, size: 32)
+!21 = !{!22}
+!22 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 7, type: !11)
+!23 = !DILocation(line: 0, scope: !7)
+!24 = !DILocation(line: 7, column: 27, scope: !7)
+!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)
+!26 = !DISubroutineType(types: !27)
+!27 = !{!10, !15}
+!28 = !{!29}
+!29 = !DILocalVariable(name: "arg", arg: 1, scope: !25, file: !1, line: 8, type: !15)
+!30 = !DILocation(line: 0, scope: !25)
+!31 = !DILocation(line: 8, column: 40, scope: !25)