[llvm] [DebugInfo] Fix issue with debug line table offsets for empty functions (PR #142253)

via llvm-commits llvm-commits at lists.llvm.org
Sat May 31 07:41:51 PDT 2025


https://github.com/alx32 updated https://github.com/llvm/llvm-project/pull/142253

>From 72d37611264b2ee14079dbfa17bee477b8266d0c Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Fri, 30 May 2025 20:40:33 -0700
Subject: [PATCH 1/2] [MCDwarf] Fix issue with debug line offsets for empty
 functions

---
 llvm/lib/MC/MCDwarf.cpp                       | 31 +++++++++++-----
 ..._AT_LLVM_stmt_seq_sec_offset_empty_func.ll | 37 +++++++++++++++++++
 2 files changed, 59 insertions(+), 9 deletions(-)
 create mode 100644 llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset_empty_func.ll

diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 2525ff02878e4..8f6f37e5b610a 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -144,19 +144,32 @@ makeStartPlusIntExpr(MCContext &Ctx, const MCSymbol &Start, int IntVal) {
 void MCLineSection::addEndEntry(MCSymbol *EndLabel) {
   auto *Sec = &EndLabel->getSection();
   // The line table may be empty, which we should skip adding an end entry.
-  // There are two cases:
+  // There are three cases:
   // (1) MCAsmStreamer - emitDwarfLocDirective emits a location directive in
   //     place instead of adding a line entry if the target has
   //     usesDwarfFileAndLocDirectives.
   // (2) MCObjectStreamer - if a function has incomplete debug info where
   //     instructions don't have DILocations, the line entries are missing.
+  // (3) It's also possible that there are no prior line entries if the section
+  //     itself is empty before this end label.
   auto I = MCLineDivisions.find(Sec);
-  if (I != MCLineDivisions.end()) {
-    auto &Entries = I->second;
-    auto EndEntry = Entries.back();
-    EndEntry.setEndLabel(EndLabel);
-    Entries.push_back(EndEntry);
-  }
+  if (I == MCLineDivisions.end()) // If section not found, do nothing.
+    return;
+
+  auto &Entries = I->second;
+  // If no entries in this section's list, nothing to base the end entry on.
+  if (Entries.empty())
+    return;
+
+  // Create the end entry based on the last existing entry.
+  MCDwarfLineEntry EndEntry = Entries.back();
+  EndEntry.setEndLabel(EndLabel);
+  // An end entry is just for marking the end of a sequence of code locations.
+  // It should not carry forward a LineStreamLabel from a previous special entry
+  // if Entries.back() happened to be such an entry. So here we clear
+  // LineStreamLabel.
+  EndEntry.LineStreamLabel = nullptr;
+  Entries.push_back(EndEntry);
 }
 
 //
@@ -1227,7 +1240,7 @@ void MCGenDwarfInfo::Emit(MCStreamer *MCOS) {
 // a dwarf label.
 //
 void MCGenDwarfLabelEntry::Make(MCSymbol *Symbol, MCStreamer *MCOS,
-                                     SourceMgr &SrcMgr, SMLoc &Loc) {
+                                SourceMgr &SrcMgr, SMLoc &Loc) {
   // We won't create dwarf labels for temporary symbols.
   if (Symbol->isTemporary())
     return;
@@ -1295,7 +1308,7 @@ static unsigned getSizeForEncoding(MCStreamer &streamer,
 }
 
 static void emitFDESymbol(MCObjectStreamer &streamer, const MCSymbol &symbol,
-                       unsigned symbolEncoding, bool isEH) {
+                          unsigned symbolEncoding, bool isEH) {
   MCContext &context = streamer.getContext();
   const MCAsmInfo *asmInfo = context.getAsmInfo();
   const MCExpr *v = asmInfo->getExprForFDESymbol(&symbol,
diff --git a/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset_empty_func.ll b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset_empty_func.ll
new file mode 100644
index 0000000000000..553a05f12082e
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset_empty_func.ll
@@ -0,0 +1,37 @@
+; RUN: llc -filetype=obj -emit-func-debug-line-table-offsets < %s -o %t_yes_off.o
+; RUN: llc -filetype=obj < %s -o %t_no_off.o
+; RUN: llvm-dwarfdump -v -all %t_no_off.o | FileCheck --check-prefix=CHECK-NO-OFF %s
+; RUN: llvm-dwarfdump -v -all %t_yes_off.o | FileCheck --check-prefix=CHECK-YES-OFF %s
+
+; We don't need a line table for an empty function
+; CHECK-NO-OFF-NOT: DW_LNE_set_address
+
+; CHECK-YES-OFF:                 DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset] ({{.*}})
+; CHECK-YES-OFF:                 Address
+; CHECK-YES-OFF-NEXT:            ------------------
+; CHECK-YES-OFF-NEXT:            DW_LNE_set_address ({{.*}})
+; CHECK-YES-OFF-NEXT:            DW_LNE_end_sequence
+; CHECK-YES-OFF-NEXT:            0x0000000000000000 {{.*}} is_stmt end_sequence
+
+; IR generated by llvm-reduce from LTO repro
+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"
+
+define ptr @_my_test_function() !dbg !4 {
+entry:
+  unreachable
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 21.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2, imports: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "repro_bug.cpp", directory: "/tmp/repro", checksumkind: CSK_MD5, checksum: "74e33e88b3108a4f94403da9fdb362f5")
+!2 = !{}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = distinct !DISubprogram(name: "east", linkageName: "_my_test_function", scope: !6, file: !5, line: 114, type: !8, scopeLine: 114, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, declaration: !9, retainedNodes: !2)
+!5 = !DIFile(filename: "repro_bug.cpp", directory: "/tmp/repro", checksumkind: CSK_MD5, checksum: "74e33e88b3108a4f94403da9fdb362f5")
+!6 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "rectangle", file: !5, line: 103, size: 256, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !2, vtableHolder: !7)
+!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "shape", file: !5, line: 58, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !2, vtableHolder: !7, identifier: "_ZTS5shape")
+!8 = distinct !DISubroutineType(types: !2)
+!9 = !DISubprogram(name: "east", linkageName: "_my_test_function", scope: !6, file: !5, line: 114, type: !8, scopeLine: 114, containingType: !6, virtualIndex: 2, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual | DISPFlagOptimized)

>From 805bb644784f352a3e54aa9457f6307354f634a3 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Sat, 31 May 2025 07:41:37 -0700
Subject: [PATCH 2/2] mend

---
 llvm/include/llvm/MC/MCDwarf.h | 3 +++
 llvm/lib/MC/MCDwarf.cpp        | 3 ++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
index 2fa7d73e1fa25..b33c9f0c8e4d0 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -216,6 +216,9 @@ class MCDwarfLineEntry : public MCDwarfLoc {
 
   // Override the label with the given EndLabel.
   void setEndLabel(MCSymbol *EndLabel) {
+    // If we're setting this to be an end entry, make sure we don't have
+    // LineStreamLabel set.
+    assert(LineStreamLabel == nullptr);
     Label = EndLabel;
     IsEndEntry = true;
   }
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 8f6f37e5b610a..bb9bbd0a9e61b 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -163,12 +163,13 @@ void MCLineSection::addEndEntry(MCSymbol *EndLabel) {
 
   // Create the end entry based on the last existing entry.
   MCDwarfLineEntry EndEntry = Entries.back();
-  EndEntry.setEndLabel(EndLabel);
+
   // An end entry is just for marking the end of a sequence of code locations.
   // It should not carry forward a LineStreamLabel from a previous special entry
   // if Entries.back() happened to be such an entry. So here we clear
   // LineStreamLabel.
   EndEntry.LineStreamLabel = nullptr;
+  EndEntry.setEndLabel(EndLabel);
   Entries.push_back(EndEntry);
 }
 



More information about the llvm-commits mailing list