[llvm] [DebugLine] Correct debug line emittion (PR #157529)
Peter Rong via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 8 11:37:02 PDT 2025
https://github.com/DataCorrupted created https://github.com/llvm/llvm-project/pull/157529
### Context
#99710 introduced `.loc_label` so we can terminate a line sequence. However, it did not advance PC properly. This is problematic for 1-instruction functions as it will have zero-length sequence. The test checked in that PR shows the problem:
```
# CHECK-LINE-TABLE: Address Line Column File ISA Discriminator OpIndex Flags
# CHECK-LINE-TABLE-NEXT: ------------------ ------ ------ ------ --- ------------- ------- -------------
# CHECK-LINE-TABLE-NEXT: 0x00000028: 05 DW_LNS_set_column (1)
# CHECK-LINE-TABLE-NEXT: 0x0000002a: 00 DW_LNE_set_address (0x0000000000000000)
# CHECK-LINE-TABLE-NEXT: 0x00000035: 01 DW_LNS_copy
# CHECK-LINE-TABLE-NEXT: 0x0000000000000000 1 1 1 0 0 0 is_stmt
# CHECK-LINE-TABLE-NEXT: 0x00000036: 00 DW_LNE_end_sequence
# CHECK-LINE-TABLE-NEXT: 0x0000000000000000 1 1 1 0 0 0 is_stmt end_sequence
```
Both rows having PC 0x0 is incorrect, and parsers won't be able to parse them. See more explanation why this is wrong in #154851.
### Fix
This PR attempts to fix this by advancing the PC to the next available Label, and advance to the end of the section if no Label is available.
### Impl
- `emitDwarfLineEndEntry` will advance PC to the `CurrLabel`
- If `CurrLabel` is null, its probably a fake LineEntry we introduced in #110192. In that case look for the next Label
- If still not label can be found, use `null` and `emitDwarfLineEndEntry` is smart enough to advance PC to the end of the section
- Rename `LastLabel` to `PrevLabel`, "last" can mean "previous" or "final", this is ambigous.
- Updated the tests to emit a correct label.
### Note
This fix should render #154986 and #154851 obsolete, they were temporary fixes and don't resolve the root cause.
>From a33d2b2e892a3f9a66b11c7dd6773df2e75e65b9 Mon Sep 17 00:00:00 2001
From: Peter Rong <PeterRong at meta.com>
Date: Mon, 8 Sep 2025 11:25:14 -0700
Subject: [PATCH] [DebugLine] Correct debug line emittion
Signed-off-by: Peter Rong <PeterRong at meta.com>
---
llvm/lib/MC/MCDwarf.cpp | 30 ++++++----
.../X86/DW_AT_LLVM_stmt_seq_sec_offset.ll | 59 ++++++++++---------
llvm/test/MC/ELF/debug-loc-label.s | 54 +++++++++--------
3 files changed, 79 insertions(+), 64 deletions(-)
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index e7c0d37e8f99b..e8f000a584839 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -181,7 +181,7 @@ void MCDwarfLineTable::emitOne(
unsigned FileNum, LastLine, Column, Flags, Isa, Discriminator;
bool IsAtStartSeq;
- MCSymbol *LastLabel;
+ MCSymbol *PrevLabel;
auto init = [&]() {
FileNum = 1;
LastLine = 1;
@@ -189,21 +189,31 @@ void MCDwarfLineTable::emitOne(
Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
Isa = 0;
Discriminator = 0;
- LastLabel = nullptr;
+ PrevLabel = nullptr;
IsAtStartSeq = true;
};
init();
// Loop through each MCDwarfLineEntry and encode the dwarf line number table.
bool EndEntryEmitted = false;
- for (const MCDwarfLineEntry &LineEntry : LineEntries) {
- MCSymbol *Label = LineEntry.getLabel();
+ for (auto It = LineEntries.begin(); It != LineEntries.end(); ++It) {
+ auto LineEntry = *It;
+ MCSymbol *CurrLabel = LineEntry.getLabel();
const MCAsmInfo *asmInfo = MCOS->getContext().getAsmInfo();
if (LineEntry.LineStreamLabel) {
if (!IsAtStartSeq) {
- MCOS->emitDwarfLineEndEntry(Section, LastLabel,
- /*EndLabel =*/LastLabel);
+ auto *Label = CurrLabel;
+ auto NextIt = It + 1;
+ // LineEntry with a null Label is probably a fake LineEntry we added
+ // when `-emit-func-debug-line-table-offsets` in order to terminate the
+ // sequence. Look for the next Label if possible, otherwise we will set
+ // the PC to the end of the section.
+ if (!Label && NextIt != LineEntries.end()) {
+ Label = NextIt->getLabel();
+ }
+ MCOS->emitDwarfLineEndEntry(Section, PrevLabel,
+ /*EndLabel =*/Label);
init();
}
MCOS->emitLabel(LineEntry.LineStreamLabel, LineEntry.StreamLabelDefLoc);
@@ -211,7 +221,7 @@ void MCDwarfLineTable::emitOne(
}
if (LineEntry.IsEndEntry) {
- MCOS->emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, Label,
+ MCOS->emitDwarfAdvanceLineAddr(INT64_MAX, PrevLabel, CurrLabel,
asmInfo->getCodePointerSize());
init();
EndEntryEmitted = true;
@@ -258,12 +268,12 @@ void MCDwarfLineTable::emitOne(
// At this point we want to emit/create the sequence to encode the delta in
// line numbers and the increment of the address from the previous Label
// and the current Label.
- MCOS->emitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label,
+ MCOS->emitDwarfAdvanceLineAddr(LineDelta, PrevLabel, CurrLabel,
asmInfo->getCodePointerSize());
Discriminator = 0;
LastLine = LineEntry.getLine();
- LastLabel = Label;
+ PrevLabel = CurrLabel;
IsAtStartSeq = false;
}
@@ -273,7 +283,7 @@ void MCDwarfLineTable::emitOne(
// does not track ranges nor terminate the line table. In that case,
// conservatively use the section end symbol to end the line table.
if (!EndEntryEmitted && !IsAtStartSeq)
- MCOS->emitDwarfLineEndEntry(Section, LastLabel);
+ MCOS->emitDwarfLineEndEntry(Section, PrevLabel);
}
void MCDwarfLineTable::endCurrentSeqAndEmitLineStreamLabel(MCStreamer *MCOS,
diff --git a/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll
index 58f6495924b90..10059b7b30c20 100644
--- a/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll
+++ b/llvm/test/DebugInfo/X86/DW_AT_LLVM_stmt_seq_sec_offset.ll
@@ -14,38 +14,39 @@
; STMT_SEQ: DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset] (0x00000043)
; STMT_SEQ: DW_AT_name {{.*}}func01
; STMT_SEQ: DW_TAG_subprogram [[[ABBREV_CODE2]]]
-; STMT_SEQ: DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset] (0x00000056)
+; STMT_SEQ: DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset] (0x00000058)
; STMT_SEQ: DW_AT_name {{.*}}main
;; Check the entire line sequence to see that it's correct
-; STMT_SEQ: Address Line Column File ISA Discriminator OpIndex Flags
-; STMT_SEQ-NEXT: ------------------ ------ ------ ------ --- ------------- ------- -------------
-; STMT_SEQ-NEXT: 0x00000043: 04 DW_LNS_set_file (0)
-; STMT_SEQ-NEXT: 0x00000045: 05 DW_LNS_set_column (9)
-; STMT_SEQ-NEXT: 0x00000047: 0a DW_LNS_set_prologue_end
-; STMT_SEQ-NEXT: 0x00000048: 00 DW_LNE_set_address (0x00000000)
-; STMT_SEQ-NEXT: 0x0000004f: 16 address += 0, line += 4, op-index += 0
-; STMT_SEQ-NEXT: 0x0000000000000000 5 9 0 0 0 0 is_stmt prologue_end
-; STMT_SEQ-NEXT: 0x00000050: 05 DW_LNS_set_column (3)
-; STMT_SEQ-NEXT: 0x00000052: 67 address += 6, line += 1, op-index += 0
-; STMT_SEQ-NEXT: 0x0000000000000006 6 3 0 0 0 0 is_stmt
-; STMT_SEQ-NEXT: 0x00000053: 00 DW_LNE_end_sequence
-; STMT_SEQ-NEXT: 0x0000000000000006 6 3 0 0 0 0 is_stmt end_sequence
-; STMT_SEQ-NEXT: 0x00000056: 04 DW_LNS_set_file (0)
-; STMT_SEQ-NEXT: 0x00000058: 00 DW_LNE_set_address (0x00000008)
-; STMT_SEQ-NEXT: 0x0000005f: 03 DW_LNS_advance_line (10)
-; STMT_SEQ-NEXT: 0x00000061: 01 DW_LNS_copy
-; STMT_SEQ-NEXT: 0x0000000000000008 10 0 0 0 0 0 is_stmt
-; STMT_SEQ-NEXT: 0x00000062: 05 DW_LNS_set_column (10)
-; STMT_SEQ-NEXT: 0x00000064: 0a DW_LNS_set_prologue_end
-; STMT_SEQ-NEXT: 0x00000065: 83 address += 8, line += 1, op-index += 0
-; STMT_SEQ-NEXT: 0x0000000000000010 11 10 0 0 0 0 is_stmt prologue_end
-; STMT_SEQ-NEXT: 0x00000066: 05 DW_LNS_set_column (3)
-; STMT_SEQ-NEXT: 0x00000068: 9f address += 10, line += 1, op-index += 0
-; STMT_SEQ-NEXT: 0x000000000000001a 12 3 0 0 0 0 is_stmt
-; STMT_SEQ-NEXT: 0x00000069: 02 DW_LNS_advance_pc (addr += 5, op-index += 0)
-; STMT_SEQ-NEXT: 0x0000006b: 00 DW_LNE_end_sequence
-; STMT_SEQ-NEXT: 0x000000000000001f 12 3 0 0 0 0 is_stmt end_sequence
+; STMT_SEQ: Address Line Column File ISA Discriminator OpIndex Flags
+; STMT_SEQ-NEXT: ------------------ ------ ------ ------ --- ------------- ------- -------------
+; STMT_SEQ-NEXT: 0x00000043: 04 DW_LNS_set_file (0)
+; STMT_SEQ-NEXT: 0x00000045: 05 DW_LNS_set_column (9)
+; STMT_SEQ-NEXT: 0x00000047: 0a DW_LNS_set_prologue_end
+; STMT_SEQ-NEXT: 0x00000048: 00 DW_LNE_set_address (0x00000000)
+; STMT_SEQ-NEXT: 0x0000004f: 16 address += 0, line += 4, op-index += 0
+; STMT_SEQ-NEXT: 0x0000000000000000 5 9 0 0 0 0 is_stmt prologue_end
+; STMT_SEQ-NEXT: 0x00000050: 05 DW_LNS_set_column (3)
+; STMT_SEQ-NEXT: 0x00000052: 67 address += 6, line += 1, op-index += 0
+; STMT_SEQ-NEXT: 0x0000000000000006 6 3 0 0 0 0 is_stmt
+; STMT_SEQ-NEXT: 0x00000053: 02 DW_LNS_advance_pc (addr += 2, op-index += 0)
+; STMT_SEQ-NEXT: 0x00000055: 00 DW_LNE_end_sequence
+; STMT_SEQ-NEXT: 0x0000000000000008 6 3 0 0 0 0 is_stmt end_sequence
+; STMT_SEQ-NEXT: 0x00000058: 04 DW_LNS_set_file (0)
+; STMT_SEQ-NEXT: 0x0000005a: 00 DW_LNE_set_address (0x00000008)
+; STMT_SEQ-NEXT: 0x00000061: 03 DW_LNS_advance_line (10)
+; STMT_SEQ-NEXT: 0x00000063: 01 DW_LNS_copy
+; STMT_SEQ-NEXT: 0x0000000000000008 10 0 0 0 0 0 is_stmt
+; STMT_SEQ-NEXT: 0x00000064: 05 DW_LNS_set_column (10)
+; STMT_SEQ-NEXT: 0x00000066: 0a DW_LNS_set_prologue_end
+; STMT_SEQ-NEXT: 0x00000067: 83 address += 8, line += 1, op-index += 0
+; STMT_SEQ-NEXT: 0x0000000000000010 11 10 0 0 0 0 is_stmt prologue_end
+; STMT_SEQ-NEXT: 0x00000068: 05 DW_LNS_set_column (3)
+; STMT_SEQ-NEXT: 0x0000006a: 9f address += 10, line += 1, op-index += 0
+; STMT_SEQ-NEXT: 0x000000000000001a 12 3 0 0 0 0 is_stmt
+; STMT_SEQ-NEXT: 0x0000006b: 02 DW_LNS_advance_pc (addr += 5, op-index += 0)
+; STMT_SEQ-NEXT: 0x0000006d: 00 DW_LNE_end_sequence
+; STMT_SEQ-NEXT: 0x000000000000001f 12 3 0 0 0 0 is_stmt end_sequence
; generated from:
; clang -Oz -g -S -emit-llvm test.c -o test.ll
diff --git a/llvm/test/MC/ELF/debug-loc-label.s b/llvm/test/MC/ELF/debug-loc-label.s
index 6b5d04777bef4..4200b1192107b 100644
--- a/llvm/test/MC/ELF/debug-loc-label.s
+++ b/llvm/test/MC/ELF/debug-loc-label.s
@@ -17,43 +17,47 @@
# CHECK-LINE-TABLE-NEXT: 0x0000002a: 00 DW_LNE_set_address (0x0000000000000000)
# CHECK-LINE-TABLE-NEXT: 0x00000035: 01 DW_LNS_copy
# CHECK-LINE-TABLE-NEXT: 0x0000000000000000 1 1 1 0 0 0 is_stmt
-# CHECK-LINE-TABLE-NEXT: 0x00000036: 00 DW_LNE_end_sequence
-# CHECK-LINE-TABLE-NEXT: 0x0000000000000000 1 1 1 0 0 0 is_stmt end_sequence
-# CHECK-LINE-TABLE-NEXT: 0x00000039: 05 DW_LNS_set_column (2)
-# CHECK-LINE-TABLE-NEXT: 0x0000003b: 00 DW_LNE_set_address (0x0000000000000008)
-# CHECK-LINE-TABLE-NEXT: 0x00000046: 01 DW_LNS_copy
+# CHECK-LINE-TABLE-NEXT: 0x00000036: 02 DW_LNS_advance_pc (addr += 8, op-index += 0)
+# CHECK-LINE-TABLE-NEXT: 0x00000038: 00 DW_LNE_end_sequence
+# CHECK-LINE-TABLE-NEXT: 0x0000000000000008 1 1 1 0 0 0 is_stmt end_sequence
+# CHECK-LINE-TABLE-NEXT: 0x0000003b: 05 DW_LNS_set_column (2)
+# CHECK-LINE-TABLE-NEXT: 0x0000003d: 00 DW_LNE_set_address (0x0000000000000008)
+# CHECK-LINE-TABLE-NEXT: 0x00000048: 01 DW_LNS_copy
# CHECK-LINE-TABLE-NEXT: 0x0000000000000008 1 2 1 0 0 0 is_stmt
-# CHECK-LINE-TABLE-NEXT: 0x00000047: 00 DW_LNE_end_sequence
-# CHECK-LINE-TABLE-NEXT: 0x0000000000000008 1 2 1 0 0 0 is_stmt end_sequence
-# CHECK-LINE-TABLE-NEXT: 0x0000004a: 05 DW_LNS_set_column (3)
-# CHECK-LINE-TABLE-NEXT: 0x0000004c: 00 DW_LNE_set_address (0x0000000000000010)
-# CHECK-LINE-TABLE-NEXT: 0x00000057: 01 DW_LNS_copy
+# CHECK-LINE-TABLE-NEXT: 0x00000049: 02 DW_LNS_advance_pc (addr += 8, op-index += 0)
+# CHECK-LINE-TABLE-NEXT: 0x0000004b: 00 DW_LNE_end_sequence
+# CHECK-LINE-TABLE-NEXT: 0x0000000000000010 1 2 1 0 0 0 is_stmt end_sequence
+# CHECK-LINE-TABLE-NEXT: 0x0000004e: 05 DW_LNS_set_column (3)
+# CHECK-LINE-TABLE-NEXT: 0x00000050: 00 DW_LNE_set_address (0x0000000000000010)
+# CHECK-LINE-TABLE-NEXT: 0x0000005b: 01 DW_LNS_copy
# CHECK-LINE-TABLE-NEXT: 0x0000000000000010 1 3 1 0 0 0 is_stmt
-# CHECK-LINE-TABLE-NEXT: 0x00000058: 00 DW_LNE_end_sequence
-# CHECK-LINE-TABLE-NEXT: 0x0000000000000010 1 3 1 0 0 0 is_stmt end_sequence
-# CHECK-LINE-TABLE-NEXT: 0x0000005b: 05 DW_LNS_set_column (4)
-# CHECK-LINE-TABLE-NEXT: 0x0000005d: 00 DW_LNE_set_address (0x0000000000000018)
-# CHECK-LINE-TABLE-NEXT: 0x00000068: 01 DW_LNS_copy
+# CHECK-LINE-TABLE-NEXT: 0x0000005c: 02 DW_LNS_advance_pc (addr += 8, op-index += 0)
+# CHECK-LINE-TABLE-NEXT: 0x0000005e: 00 DW_LNE_end_sequence
+# CHECK-LINE-TABLE-NEXT: 0x0000000000000018 1 3 1 0 0 0 is_stmt end_sequence
+# CHECK-LINE-TABLE-NEXT: 0x00000061: 05 DW_LNS_set_column (4)
+# CHECK-LINE-TABLE-NEXT: 0x00000063: 00 DW_LNE_set_address (0x0000000000000018)
+# CHECK-LINE-TABLE-NEXT: 0x0000006e: 01 DW_LNS_copy
# CHECK-LINE-TABLE-NEXT: 0x0000000000000018 1 4 1 0 0 0 is_stmt
-# CHECK-LINE-TABLE-NEXT: 0x00000069: 05 DW_LNS_set_column (5)
-# CHECK-LINE-TABLE-NEXT: 0x0000006b: 01 DW_LNS_copy
+# CHECK-LINE-TABLE-NEXT: 0x0000006f: 05 DW_LNS_set_column (5)
+# CHECK-LINE-TABLE-NEXT: 0x00000071: 01 DW_LNS_copy
# CHECK-LINE-TABLE-NEXT: 0x0000000000000018 1 5 1 0 0 0 is_stmt
-# CHECK-LINE-TABLE-NEXT: 0x0000006c: 00 DW_LNE_end_sequence
-# CHECK-LINE-TABLE-NEXT: 0x0000000000000018 1 5 1 0 0 0 is_stmt end_sequence
+# CHECK-LINE-TABLE-NEXT: 0x00000072: 02 DW_LNS_advance_pc (addr += 8, op-index += 0)
+# CHECK-LINE-TABLE-NEXT: 0x00000074: 00 DW_LNE_end_sequence
+# CHECK-LINE-TABLE-NEXT: 0x0000000000000020 1 5 1 0 0 0 is_stmt end_sequence
# CHECK-SYM: Symbol table '.symtab' contains 9 entries:
# CHECK-SYM-NEXT: Num: Value Size Type Bind Vis Ndx Name
# CHECK-SYM-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
# CHECK-SYM-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS test.c
# CHECK-SYM-NEXT: 2: 0000000000000000 0 SECTION LOCAL DEFAULT 2 .text
-# CHECK-SYM-NEXT: 3: 0000000000000039 0 NOTYPE LOCAL DEFAULT 3 my_label_02
-# CHECK-SYM-NEXT: 4: 000000000000004a 0 NOTYPE LOCAL DEFAULT 3 my_label_03
-# CHECK-SYM-NEXT: 5: 000000000000005b 0 NOTYPE LOCAL DEFAULT 3 my_label_04
-# CHECK-SYM-NEXT: 6: 000000000000004a 0 NOTYPE LOCAL DEFAULT 3 my_label_03.1
-# CHECK-SYM-NEXT: 7: 000000000000006f 0 NOTYPE LOCAL DEFAULT 3 my_label_05
+# CHECK-SYM-NEXT: 3: 000000000000003b 0 NOTYPE LOCAL DEFAULT 3 my_label_02
+# CHECK-SYM-NEXT: 4: 000000000000004e 0 NOTYPE LOCAL DEFAULT 3 my_label_03
+# CHECK-SYM-NEXT: 5: 0000000000000061 0 NOTYPE LOCAL DEFAULT 3 my_label_04
+# CHECK-SYM-NEXT: 6: 000000000000004e 0 NOTYPE LOCAL DEFAULT 3 my_label_03.1
+# CHECK-SYM-NEXT: 7: 0000000000000077 0 NOTYPE LOCAL DEFAULT 3 my_label_05
# CHECK-SYM-NEXT: 8: 0000000000000000 0 FUNC GLOBAL DEFAULT 2 foo
-# CHECK-OFFSETS: 0000 39000000 4a000000 5b000000
+# CHECK-OFFSETS: 0000 3b000000 4e000000 61000000
.text
.file "test.c"
More information about the llvm-commits
mailing list