[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:10 PDT 2025
https://github.com/alx32 created https://github.com/llvm/llvm-project/pull/143656
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.
>From 3f6c523f5f210d1d7d81170956eaa61d5bd178e9 Mon Sep 17 00:00:00 2001
From: Alex Borcan <alexborcan at fb.com>
Date: Tue, 10 Jun 2025 22:25:05 -0700
Subject: [PATCH] [dsymutil] Fix line table sequence mapping for stmt_sequence
attributes
---
llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp | 30 +++++++++++++++++--
.../tools/dsymutil/ARM/stmt-seq-macho.test | 7 ++++-
2 files changed, 34 insertions(+), 3 deletions(-)
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]+)]])
More information about the llvm-commits
mailing list