[llvm] Improve DWARFDebugLine::LineTable::lookupAddressRangeImpl(...) to act as exptected. (PR #226625)
Greg Clayton via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 26 05:19:33 PDT 2026
https://github.com/clayborg updated https://github.com/llvm/llvm-project/pull/226625
>From 531f11649ede13e3f98b25137881d5cba37fe03b Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Fri, 25 Sep 2026 18:56:07 -0700
Subject: [PATCH 1/2] Modify DWARFDebugLine::LineTable::lookupAddressRangeImpl
to not return merged function line entries.
The current DWARFDebugLine::LineTable::lookupAddressRangeImpl(...) function returns all line entries for an address range in the current line table. This creates a problem for tools looking to get the line entries for a given address range when there is no DW_AT_LLVM_stmt_sequence attribute on a DW_TAG_subprogram, or if the attribute value has been set to UINT32_MAX (invalid). This change will grab all unique line entries for a given address range. If there are multiple line tables for merged functions in the same line table, only the first will be returned. Prior to this, you could get N copies of the line table returned and there is no way to tell from the returned rows if they came from different sequences, so they look like a line table, but they violate the DWARF line table rules where the rows don't monotonically increase.
There are a few solutions to this:
- return a std::vector<std::vector<uint32_t>> where each vector of uint32_t values come from different sequences. This would work well for a compile unit with merged functions (multiple copies of the same line table) but not very well for line tables where two sequences describe the lines for a function with a discontiguous range.
- return what is done here where we track the address ranges that are already covered by previous sequences and don't add more rows from the same ranges. This allows line tables with discontiguous function ranges to get a full set of rows if the line table is split into multiple sequences and also handles merged functions correctly by grabbing the first line entries for a given range.
Since we don't include the rows with row.EndSequence == true, we can't reason about multiple sequences. One option would be to include the rows with EndSequence set to true if it matches the Address + Size, but only if the are end sequences. I didn't do that because it changes the expected result from this function call.
I ran into cases where llvm-gsymutil was trying to get the line table rows for merged functions, but it got back rows with repeating line tables which causes errors to be emitted for multiple copies of line tables or for line tables with non-monotonically increasing values.
---
llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp | 48 ++++++++++++++-----
.../DebugInfo/DWARF/DWARFDebugLineTest.cpp | 7 ++-
2 files changed, 40 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 2cdbe64f4ce0c..4731bf154a83d 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/ADT/AddressRanges.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -1423,20 +1424,26 @@ bool DWARFDebugLine::LineTable::lookupAddressRangeImpl(
return false;
}
- // If the start sequence doesn't contain the address, nothing to do
- if (!SeqPos->containsPC(Address))
- return false;
-
- SequenceIter StartPos = SeqPos;
+ // Keep track of range sequences to ensure that we don't process the same
+ // sequence multiple times. If there is no StmtSequenceOffset we might have
+ // multiple sequences map to the same address range (merged functions), so we
+ // need to pick one of the ranges and not return a series of duplicated
+ // sequences.
+ AddressRanges RowRanges;
// Process sequences that overlap with the desired range
while (SeqPos != LastSeq && SeqPos->LowPC < EndAddr) {
+ // As soon as an address isn't contained in a sequence, we can stop
+ // searching.
+ if (!SeqPos->containsPC(Address))
+ break;
+
const DWARFDebugLine::Sequence &CurSeq = *SeqPos;
- // For the first sequence, we need to find which row in the sequence is the
- // first in our range.
- uint32_t FirstRowIndex = CurSeq.FirstRowIndex;
- if (SeqPos == StartPos)
- FirstRowIndex = findRowInSeq(CurSeq, Address);
+ // Always find the first row in the sequence that matches the address. We
+ // have seen merged functions create multiple sequences that contain the
+ // same address range, but also have ranges that contain these same
+ // addresses in the middle.
+ uint32_t FirstRowIndex = findRowInSeq(CurSeq, Address);
// Figure out the last row in the range.
uint32_t LastRowIndex =
@@ -1446,6 +1453,25 @@ bool DWARFDebugLine::LineTable::lookupAddressRangeImpl(
assert(FirstRowIndex != UnknownRowIndex);
assert(LastRowIndex != UnknownRowIndex);
+ // The matching row range should end at the next row's address, unless the
+ // last row is the last row in the sequence. If we don't do this and we have
+ // outlined functions, we can end up with a range that is empty.
+ uint64_t MatchingRangeHighPC = Rows[LastRowIndex].EndSequence ?
+ Rows[LastRowIndex].Address.Address :
+ Rows[LastRowIndex + 1].Address.Address;
+ AddressRange MatchingRowRange(Rows[FirstRowIndex].Address.Address,
+ MatchingRangeHighPC);
+ if (RowRanges.contains(MatchingRowRange)) {
+ // We've already processed this range, so skip it. This can happen when
+ // merged functions have multiple sequences that represent the same
+ // address range. We don't want to append any rows that we've already
+ // added to the result as it will return an rows that are not
+ // monotonically increasing.
+ ++SeqPos;
+ continue;
+ } else {
+ RowRanges.insert(MatchingRowRange);
+ }
for (uint32_t I = FirstRowIndex; I <= LastRowIndex; ++I) {
Result.push_back(I);
@@ -1454,7 +1480,7 @@ bool DWARFDebugLine::LineTable::lookupAddressRangeImpl(
++SeqPos;
}
- return true;
+ return !Result.empty();
}
std::optional<StringRef>
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
index b2156bf1772dc..ca57302e7dea8 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
@@ -2154,18 +2154,17 @@ TEST_F(DebugLineBasicFixture, LookupAddressRangeWithStmtSequenceOffset) {
}
// 4) Look up with no statement-sequence offset specified.
- // We should get rows from both sequences for address 0x1000.
+ // We should get row from the first sequence for address 0x1000.
{
std::vector<uint32_t> Rows;
bool Found = Table->lookupAddressRange(
{0x1000, object::SectionedAddress::UndefSection}, /*Size=*/1, Rows,
std::nullopt /* no filter */);
EXPECT_TRUE(Found);
- // The first sequence's row is #0, second's row is #2, so both should
+ // The first sequence's row is #0, second's row is #2, but only one should
// appear.
- ASSERT_EQ(Rows.size(), 2u);
+ ASSERT_EQ(Rows.size(), 1u);
EXPECT_EQ(Rows[0], 0u);
- EXPECT_EQ(Rows[1], 3u);
}
}
} // end anonymous namespace
>From e17df1a5d221aff3b74181fdbb215c0df3e1c20e Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Sat, 26 Sep 2026 05:18:59 -0700
Subject: [PATCH 2/2] Run clang format.
---
llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 4731bf154a83d..eefd781204d29 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -1456,9 +1456,9 @@ bool DWARFDebugLine::LineTable::lookupAddressRangeImpl(
// The matching row range should end at the next row's address, unless the
// last row is the last row in the sequence. If we don't do this and we have
// outlined functions, we can end up with a range that is empty.
- uint64_t MatchingRangeHighPC = Rows[LastRowIndex].EndSequence ?
- Rows[LastRowIndex].Address.Address :
- Rows[LastRowIndex + 1].Address.Address;
+ uint64_t MatchingRangeHighPC = Rows[LastRowIndex].EndSequence
+ ? Rows[LastRowIndex].Address.Address
+ : Rows[LastRowIndex + 1].Address.Address;
AddressRange MatchingRowRange(Rows[FirstRowIndex].Address.Address,
MatchingRangeHighPC);
if (RowRanges.contains(MatchingRowRange)) {
More information about the llvm-commits
mailing list