[llvm] aab79c4 - [DebugInfo] Fix issue with debug line table offsets for empty functions (#142253)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 3 07:33:55 PDT 2025
Author: alx32
Date: 2025-06-03T07:33:51-07:00
New Revision: aab79c41b2cc16d542072a5a2fad4ac8855ba9ff
URL: https://github.com/llvm/llvm-project/commit/aab79c41b2cc16d542072a5a2fad4ac8855ba9ff
DIFF: https://github.com/llvm/llvm-project/commit/aab79c41b2cc16d542072a5a2fad4ac8855ba9ff.diff
LOG: [DebugInfo] Fix issue with debug line table offsets for empty functions (#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.
Added:
llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset_empty_func.ll
Modified:
llvm/include/llvm/MC/MCDwarf.h
llvm/lib/MC/MCDwarf.cpp
Removed:
################################################################################
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 2525ff02878e4..bb9bbd0a9e61b 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -144,19 +144,33 @@ 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();
+
+ // 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);
}
//
@@ -1227,7 +1241,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 +1309,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