[llvm] [dsymutil] Fix line table sequence mapping for stmt_sequence attributes (PR #143656)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 10 22:54:42 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-debuginfo

Author: None (alx32)

<details>
<summary>Changes</summary>

This commit resolves an issue in dsymutil where `DW_AT_LLVM_stmt_sequence` attributes were incorrectly patched during the `.debug_line table` rewrite. This led to invalid offsets being written to the DWARF, severing the crucial link between a function's DIE and its specific line entries. 

The root cause was the patching logic's sole reliance on the `DWARFDebugLine::LineTable` parser's `LT->Sequences` output. This parser does not reliably identify every sequence start, as it was not designed for the current DW_AT_LLVM_stmt_sequence model where each function has its own distinct sequence, which may not start with a new address range.

This patch implements a more resilient, hybrid mapping strategy. It first populates a map with the sequences the parser correctly identifies. It then adds to this map by manually reconstructing all sequence boundaries, identifying the start of the table and every row following an end_sequence flag. These boundaries are correlated with a sorted list of all `DW_AT_LLVM_stmt_sequence` attributes, ensuring a complete and accurate mapping from original to new offsets, even with partial matches.

The existing `stmt-seq-macho.test` actually exhibited this issue - so we can just add an additional check to ensure the issue is fixed. 

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


2 Files Affected:

- (modified) llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp (+28-2) 
- (modified) llvm/test/tools/dsymutil/ARM/stmt-seq-macho.test (+6-1) 


``````````diff
diff --git a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
index ae4cc6d85c120..8d8f4bea48d0b 100644
--- a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
@@ -2297,8 +2297,34 @@ void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
 
         // Create a map of stmt sequence offsets to original row indices.
         DenseMap<uint64_t, unsigned> SeqOffToOrigRow;
-        for (const DWARFDebugLine::Sequence &Seq : LT->Sequences)
-          SeqOffToOrigRow[Seq.StmtSeqOffset] = Seq.FirstRowIndex;
+        // The DWARF parser's discovery of sequences can be incomplete. To ensure all
+        // DW_AT_LLVM_stmt_sequence attributes can be patched, we build a map from
+        // both the parser's results and a manual reconstruction.
+        if (!LT->Rows.empty()) {
+          // First, trust the sequences that the DWARF parser did identify.
+          for (const DWARFDebugLine::Sequence &Seq : LT->Sequences)
+            SeqOffToOrigRow.try_emplace(Seq.StmtSeqOffset, Seq.FirstRowIndex);
+
+          // Second, manually find sequence boundaries and match them to the sorted
+          // attributes to handle sequences the parser might have missed.
+          auto StmtAttrs = Unit.getStmtSeqListAttributes();
+          llvm::sort(StmtAttrs, [](const PatchLocation &A,
+                                   const PatchLocation &B) { return A.get() < B.get(); });
+
+          std::vector<size_t> SeqStartRows;
+          SeqStartRows.push_back(0);
+          for (size_t i = 0; i < LT->Rows.size() - 1; ++i)
+            if (LT->Rows[i].EndSequence)
+              SeqStartRows.push_back(i + 1);
+
+          // Correlate the sorted attributes with the reconstructed sequence starts.
+          // This provides a partial mapping if counts are mismatched, maximizing the
+          // number of correctly patched attributes.
+          size_t NumMappings = std::min(StmtAttrs.size(), SeqStartRows.size());
+          for (size_t i = 0; i < NumMappings; ++i) {
+            SeqOffToOrigRow.try_emplace(StmtAttrs[i].get(), SeqStartRows[i]);
+          }
+        }
 
         // Create a map of original row indices to new row indices.
         DenseMap<size_t, size_t> OrigRowToNewRow;
diff --git a/llvm/test/tools/dsymutil/ARM/stmt-seq-macho.test b/llvm/test/tools/dsymutil/ARM/stmt-seq-macho.test
index f2fe794e1b484..b6ad216bc0be3 100644
--- a/llvm/test/tools/dsymutil/ARM/stmt-seq-macho.test
+++ b/llvm/test/tools/dsymutil/ARM/stmt-seq-macho.test
@@ -4,7 +4,12 @@
 # RUN: yaml2obj %t/stmt_seq_macho.exe.yaml -o %t/stmt_seq_macho.exe
 # RUN: yaml2obj %t/stmt_seq_macho.o.yaml   -o %t/stmt_seq_macho.o
 # RUN: dsymutil --flat --verify-dwarf=none -oso-prepend-path %t %t/stmt_seq_macho.exe -o %t/stmt_seq_macho.dSYM
-# RUN: llvm-dwarfdump --debug-info --debug-line -v %t/stmt_seq_macho.dSYM | sort | FileCheck %s -check-prefix=CHECK_DSYM
+# RUN: llvm-dwarfdump --debug-info --debug-line -v %t/stmt_seq_macho.dSYM > %t/stmt_seq_macho.dSYM.txt
+# RUN: cat %t/stmt_seq_macho.dSYM.txt | sort | FileCheck %s -check-prefix=CHECK_DSYM
+# RUN: cat %t/stmt_seq_macho.dSYM.txt | FileCheck %s -check-prefix=CHECK_NO_INVALID_OFFSET
+
+# CHECK_NO_INVALID_OFFSET-NOT: DW_AT_LLVM_stmt_sequence{{.*}}0xffffffff
+
 
 # CHECK_DSYM: DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset] ([[OFFSET1:(0x[0-9a-f]+)]])
 # CHECK_DSYM: DW_AT_LLVM_stmt_sequence [DW_FORM_sec_offset] ([[OFFSET2:(0x[0-9a-f]+)]])

``````````

</details>


https://github.com/llvm/llvm-project/pull/143656


More information about the llvm-commits mailing list