[llvm] [MCDwarf] Fix issue with debug line offsets for empty functions (PR #142253)
via llvm-commits
llvm-commits at lists.llvm.org
Fri May 30 22:33:56 PDT 2025
https://github.com/alx32 created https://github.com/llvm/llvm-project/pull/142253
This patch addresses an issue where an anonymous DWARF line table symbol could be inadvertently defined multiple times, leading to an "symbol '' is already defined" error during assembly or object file emission. This issue happens for empty functions when `-emit-func-debug-line-table-offsets` is enabled.
The root cause is the creation of the "end sequence" entry for a DWARF line table. This entry was sometimes created by copying the last existing line table entry. If this last entry was a special one (created for the purpose of marking the position in the line table stream and having an anonymous symbol attached), the copied end-sequence entry would also incorrectly reference this same anonymous symbol. Consequently, when the line table was finally emitted, the DWARF emission logic would attempt to emit a label for this anonymous symbol twice, triggering the redefinition error.
The fix ensures that when an end-sequence line table entry is created, it does not inherit any special stream label from the entry it might have been based on, thereby preventing the duplicate label emission.
>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] [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)
More information about the llvm-commits
mailing list