Skip to content

[LLVM][DWARF] Fix accelerator table switching between CU and TU #77511

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 12, 2024

Conversation

ayermolo
Copy link
Contributor

@ayermolo ayermolo commented Jan 9, 2024

Bug 1 is triggered when a TU is already created, and we process the same
DICompositeType at a top level. We would switch to TU accelerator table, but
would not switch back on early exit. As the result we would add CU entries to the TU
accelerator table. When we try to write out TUs and normalize entries, the
offsets for DIEs that are part of a CU would not have been computed, and it
would assert on getOffset().

Bug 2 is triggered when processing nested TUs. When we exit from addDwarfTypeUnitType we switched back to CU accelerator table. If we were processing nested TUs, the rest of the entries from TUs would be added to CU accelerator table. When we write out TUs, all the DIE pointers will become invalid. Eventually it will assert during normalization step after CU is processed.

This bug is triggered when a TU is already created, and we process the same
DICompositeType at a top level. We would switch to TU accelerator table, but
would not switch back on early exit. As the result we would add CU entries to the TU
accelerator table. When we try to write out TUs and normalize entries, the
offsets for DIEs that are part of a CU would not have been computed, and it
would assert on getOffset().
@llvmbot llvmbot added clang Clang issues not falling into any other category debuginfo labels Jan 9, 2024
@llvmbot
Copy link
Member

llvmbot commented Jan 9, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-debuginfo

Author: Alexander Yermolovich (ayermolo)

Changes

This bug is triggered when a TU is already created, and we process the same
DICompositeType at a top level. We would switch to TU accelerator table, but
would not switch back on early exit. As the result we would add CU entries to the TU
accelerator table. When we try to write out TUs and normalize entries, the
offsets for DIEs that are part of a CU would not have been computed, and it
would assert on getOffset().


Full diff: https://github.com/llvm/llvm-project/pull/77511.diff

3 Files Affected:

  • (added) clang/test/CodeGen/thinlto-debug-names-tu-reuse.ll (+58)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (+9-1)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h (+2)
diff --git a/clang/test/CodeGen/thinlto-debug-names-tu-reuse.ll b/clang/test/CodeGen/thinlto-debug-names-tu-reuse.ll
new file mode 100644
index 00000000000000..53aec43a050f8b
--- /dev/null
+++ b/clang/test/CodeGen/thinlto-debug-names-tu-reuse.ll
@@ -0,0 +1,58 @@
+; REQUIRES: asserts
+
+;; Tests that accelerator table switches correctly from TU to CU when a top level TU is re-used.
+;; Assert is not triggered.
+;; File1
+;; struct Foo {
+;;   char fChar;
+;; };
+;; Foo fGlobal;
+;; FIle2
+;; struct Foo {
+;;   char fChar;
+;; };
+;; Foo fGlobal2;
+;; clang++ <file>.cpp -O0 -g2 -fdebug-types-section -gpubnames -S -emit-llvm -o <file>.ll
+;; llvm-link file1.ll file2.ll -S -o thinlto-debug-names-tu-reuse.ll
+
+; RUN: llc -O0 -dwarf-version=5 -generate-type-units -filetype=obj < %s -o %t.o
+; RUN: llvm-readelf --sections %t.o | FileCheck --check-prefix=OBJ %s
+
+; OBJ: debug_names
+
+; ModuleID = 'llvm-link'
+source_filename = "llvm-link"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.Foo = type { i8 }
+
+@fGlobal = dso_local global %struct.Foo zeroinitializer, align 1, !dbg !0
+@fGlobal2 = dso_local global %struct.Foo zeroinitializer, align 1, !dbg !9
+
+!llvm.dbg.cu = !{!2, !11}
+!llvm.ident = !{!14, !14}
+!llvm.module.flags = !{!15, !16, !17, !18, !19, !20, !21}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "fGlobal", scope: !2, file: !3, line: 5, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 18.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false)
+!3 = !DIFile(filename: "main.cpp", directory: "/smallTUReuse", checksumkind: CSK_MD5, checksum: "4f1831504f0948b03880356fae49cb58")
+!4 = !{!0}
+!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !3, line: 2, size: 8, flags: DIFlagTypePassByValue, elements: !6, identifier: "_ZTS3Foo")
+!6 = !{!7}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "fChar", scope: !5, file: !3, line: 3, baseType: !8, size: 8)
+!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression())
+!10 = distinct !DIGlobalVariable(name: "fGlobal2", scope: !11, file: !12, line: 5, type: !5, isLocal: false, isDefinition: true)
+!11 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !12, producer: "clang version 18.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !13, splitDebugInlining: false)
+!12 = !DIFile(filename: "helper.cpp", directory: "/smallTUReuse", checksumkind: CSK_MD5, checksum: "014145d46991fd1eb6a2192d382feb75")
+!13 = !{!9}
+!14 = !{!"clang version 18.0.0git"}
+!15 = !{i32 7, !"Dwarf Version", i32 5}
+!16 = !{i32 2, !"Debug Info Version", i32 3}
+!17 = !{i32 1, !"wchar_size", i32 4}
+!18 = !{i32 8, !"PIC Level", i32 2}
+!19 = !{i32 7, !"PIE Level", i32 2}
+!20 = !{i32 7, !"uwtable", i32 2}
+!21 = !{i32 7, !"frame-pointer", i32 2}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 41afbea4561433..0a922fcd54a061 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -3448,7 +3448,6 @@ uint64_t DwarfDebug::makeTypeSignature(StringRef Identifier) {
 void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU,
                                       StringRef Identifier, DIE &RefDie,
                                       const DICompositeType *CTy) {
-  setCurrentDWARF5AccelTable(DWARF5AccelTableKind::TU);
   // Fast path if we're building some type units and one has already used the
   // address pool we know we're going to throw away all this work anyway, so
   // don't bother building dependent types.
@@ -3461,6 +3460,7 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU,
     return;
   }
 
+  setCurrentDWARF5AccelTable(DWARF5AccelTableKind::TU);
   bool TopLevelType = TypeUnitsUnderConstruction.empty();
   AddrPool.resetUsedFlag();
 
@@ -3580,6 +3580,14 @@ void DwarfDebug::addAccelNameImpl(
     break;
   case AccelTableKind::Dwarf: {
     DWARF5AccelTable &Current = getCurrentDWARF5AccelTable();
+    assert((CurrentKind == DWARF5AccelTableKind::TU) ||
+           ((CurrentKind == DWARF5AccelTableKind::CU) &&
+            (Unit.getUnitDie().getTag() != dwarf::DW_TAG_type_unit)) &&
+               "Kind is CU but TU is being processed.");
+    assert((CurrentKind == DWARF5AccelTableKind::CU) ||
+           ((CurrentKind == DWARF5AccelTableKind::TU) &&
+            (Unit.getUnitDie().getTag() == dwarf::DW_TAG_type_unit)) &&
+               "Kind is TU but CU is being processed.");
     // The type unit can be discarded, so need to add references to final
     // acceleration table once we know it's complete and we emit it.
     Current.addName(Ref, Die, Unit.getUniqueID());
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 452485b632c45f..09e9ca07624f83 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -509,6 +509,7 @@ class DwarfDebug : public DebugHandlerBase {
   DWARF5AccelTable AccelTypeUnitsDebugNames;
   /// Used to hide which DWARF5AccelTable we are using now.
   DWARF5AccelTable *CurrentDebugNames = &AccelDebugNames;
+  DWARF5AccelTableKind CurrentKind = DWARF5AccelTableKind::CU;
   AccelTable<AppleAccelTableOffsetData> AccelNames;
   AccelTable<AppleAccelTableOffsetData> AccelObjC;
   AccelTable<AppleAccelTableOffsetData> AccelNamespace;
@@ -925,6 +926,7 @@ class DwarfDebug : public DebugHandlerBase {
 
   /// Sets the current DWARF5AccelTable to use.
   void setCurrentDWARF5AccelTable(const DWARF5AccelTableKind Kind) {
+    CurrentKind = Kind;
     switch (Kind) {
     case DWARF5AccelTableKind::CU:
       CurrentDebugNames = &AccelDebugNames;

@ayermolo
Copy link
Contributor Author

ayermolo commented Jan 9, 2024

There is another bug on when we exit from addDwarfTypeUnitType. I need to construct a small repro for it.

@ayermolo ayermolo requested a review from dwblaikie January 9, 2024 19:03
@ayermolo ayermolo changed the title [LLVM][DWARF] Fix accelerator swtiching with TU re-use [LLVM][DWARF] Fix accelerator table switching between CU and TU Jan 9, 2024
Copy link
Collaborator

@dwblaikie dwblaikie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks OK but please skip the extra assert-only CurrentKind variable in favor of testing the CurrentDebugNames value.

@ayermolo ayermolo merged commit d199ab4 into llvm:main Jan 12, 2024
@ayermolo ayermolo deleted the debugNamesTUReuseBug branch January 12, 2024 15:01
@vitalybuka
Copy link
Collaborator

Could this be caused by the patch https://lab.llvm.org/buildbot/#/builders/236/builds/8673 ?

@ayermolo
Copy link
Contributor Author

Could this be caused by the patch https://lab.llvm.org/buildbot/#/builders/236/builds/8673 ?

Passes for me locally. Also patch impacts .debug_names for DWARF. So highly unlikely it would cause this test to fail.

@rorth
Copy link
Collaborator

rorth commented Jan 12, 2024

However, the patch broke the Solaris/sparcv9 buildbot:

llc: error: unable to get target for 'x86_64-unknown-linux-gnu', see --version and --triple.

The bot is configured to do a Sparc-only build.

@ayermolo
Copy link
Contributor Author

ayermolo commented Jan 12, 2024

However, the patch broke the Solaris/sparcv9 buildbot:

llc: error: unable to get target for 'x86_64-unknown-linux-gnu', see --version and --triple.

The bot is configured to do a Sparc-only build.

oh. I think
; REQUIRES: x86-registered-target is missing. Let me add it

EDIT: Looks like it's already added 6f55c13

justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
…#77511)

Bug 1 is triggered when a TU is already created, and we process the same
DICompositeType at a top level. We would switch to TU accelerator table,
but
would not switch back on early exit. As the result we would add CU
entries to the TU
accelerator table. When we try to write out TUs and normalize entries,
the
offsets for DIEs that are part of a CU would not have been computed, and
it
would assert on getOffset().

Bug 2 is triggered when processing nested TUs. When we exit from
addDwarfTypeUnitType we switched back to CU accelerator table. If we
were processing nested TUs, the rest of the entries from TUs would be
added to CU accelerator table. When we write out TUs, all the DIE
pointers will become invalid. Eventually it will assert during
normalization step after CU is processed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category debuginfo
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants