From 4ed5195712fd1f3f43e23678d8f666c47d1aa7d5 Mon Sep 17 00:00:00 2001 From: Scott Linder Date: Fri, 30 Nov 2018 19:13:38 +0000 Subject: [PATCH] [DWARFv5] Verify all-or-nothing constraint on DIFile source Update IR verifier to check the constraint that DIFile source is present on all files or no files. Differential Revision: https://reviews.llvm.org/D54953 llvm-svn: 348022 --- llvm/lib/IR/Verifier.cpp | 18 ++++++++ .../Assembler/debug-info-source-invalid.ll | 27 ++++++++++++ llvm/test/Assembler/debug-info-source.ll | 41 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 llvm/test/Assembler/debug-info-source-invalid.ll create mode 100644 llvm/test/Assembler/debug-info-source.ll diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 17fa472b7236..40f73c9f1a4e 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -281,6 +281,9 @@ class Verifier : public InstVisitor, VerifierSupport { /// Whether the current function has a DISubprogram attached to it. bool HasDebugInfo = false; + /// Whether source was present on the first DIFile encountered in each CU. + DenseMap HasSourceDebugInfo; + /// Stores the count of how many objects were passed to llvm.localescape for a /// given function and the largest index passed to llvm.localrecover. DenseMap> FrameEscapeInfo; @@ -519,6 +522,9 @@ private: /// Module-level verification that all @llvm.experimental.deoptimize /// declarations share the same calling convention. void verifyDeoptimizeCallingConvs(); + + /// Verify all-or-nothing property of DIFile source attribute within a CU. + void verifySourceDebugInfo(const DICompileUnit &U, const DIFile &F); }; } // end anonymous namespace @@ -1032,6 +1038,8 @@ void Verifier::visitDICompileUnit(const DICompileUnit &N) { AssertDI(!N.getFile()->getFilename().empty(), "invalid filename", &N, N.getFile()); + verifySourceDebugInfo(N, *N.getFile()); + AssertDI((N.getEmissionKind() <= DICompileUnit::LastEmissionKind), "invalid emission kind", &N); @@ -1109,6 +1117,8 @@ void Verifier::visitDISubprogram(const DISubprogram &N) { AssertDI(N.isDistinct(), "subprogram definitions must be distinct", &N); AssertDI(Unit, "subprogram definitions must have a compile unit", &N); AssertDI(isa(Unit), "invalid unit type", &N, Unit); + if (N.getFile()) + verifySourceDebugInfo(*N.getUnit(), *N.getFile()); } else { // Subprogram declarations (part of the type hierarchy). AssertDI(!Unit, "subprogram declarations must not have a compile unit", &N); @@ -4744,6 +4754,14 @@ void Verifier::verifyDeoptimizeCallingConvs() { } } +void Verifier::verifySourceDebugInfo(const DICompileUnit &U, const DIFile &F) { + bool HasSource = F.getSource().hasValue(); + if (!HasSourceDebugInfo.count(&U)) + HasSourceDebugInfo[&U] = HasSource; + AssertDI(HasSource == HasSourceDebugInfo[&U], + "inconsistent use of embedded source"); +} + //===----------------------------------------------------------------------===// // Implement the public interfaces to this file... //===----------------------------------------------------------------------===// diff --git a/llvm/test/Assembler/debug-info-source-invalid.ll b/llvm/test/Assembler/debug-info-source-invalid.ll new file mode 100644 index 000000000000..d746e9e25fc3 --- /dev/null +++ b/llvm/test/Assembler/debug-info-source-invalid.ll @@ -0,0 +1,27 @@ +; RUN: llvm-as < %s 2>&1 >/dev/null | FileCheck %s + +; Ensure we reject debug info where the DIFiles of a DICompileUnit mix source +; and no-source. + +define dso_local void @foo() !dbg !5 { + ret void +} + +define dso_local void @bar() !dbg !6 { + ret void +} + +!llvm.dbg.cu = !{!4} +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 2, !"Dwarf Version", i32 5} +!1 = !{i32 2, !"Debug Info Version", i32 3} + +!2 = !DIFile(filename: "foo.c", directory: "dir", source: "void foo() { }\0A") +; CHECK: inconsistent use of embedded source +; CHECK: warning: ignoring invalid debug info +!3 = !DIFile(filename: "bar.h", directory: "dir") + +!4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2) +!5 = distinct !DISubprogram(name: "foo", file: !2, unit: !4) +!6 = distinct !DISubprogram(name: "bar", file: !3, unit: !4) diff --git a/llvm/test/Assembler/debug-info-source.ll b/llvm/test/Assembler/debug-info-source.ll new file mode 100644 index 000000000000..381603ef35c3 --- /dev/null +++ b/llvm/test/Assembler/debug-info-source.ll @@ -0,0 +1,41 @@ +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s +; RUN: verify-uselistorder %s + +; Ensure we accept debug info where DIFiles within a DICompileUnit either all +; have source, or none have source. + +define dso_local void @foo() !dbg !6 { + ret void +} + +define dso_local void @bar() !dbg !7 { + ret void +} + +define dso_local void @baz() !dbg !9 { + ret void +} + +define dso_local void @qux() !dbg !11 { + ret void +} + +!llvm.dbg.cu = !{!0, !2} +!llvm.module.flags = !{!4, !5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1) +; CHECK: !1 = !DIFile(filename: "foo.c", directory: "dir", source: "void foo() { }\0A") +!1 = !DIFile(filename: "foo.c", directory: "dir", source: "void foo() { }\0A") +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3) +; CHECK: !3 = !DIFile(filename: "qux.h", directory: "dir") +!3 = !DIFile(filename: "qux.h", directory: "dir") +!4 = !{i32 2, !"Dwarf Version", i32 5} +!5 = !{i32 2, !"Debug Info Version", i32 3} +!6 = distinct !DISubprogram(name: "foo", file: !1, unit: !0) +!7 = distinct !DISubprogram(name: "bar", file: !8, unit: !0) +; CHECK: !8 = !DIFile(filename: "bar.h", directory: "dir", source: "void bar() { }\0A") +!8 = !DIFile(filename: "bar.h", directory: "dir", source: "void bar() { }\0A") +!9 = distinct !DISubprogram(name: "baz", file: !10, unit: !2) +; CHECK: !10 = !DIFile(filename: "baz.c", directory: "dir") +!10 = !DIFile(filename: "baz.c", directory: "dir") +!11 = distinct !DISubprogram(name: "qux", file: !3, unit: !2)