Skip to content

Commit 2c022e3

Browse files
authored
[lldb] Replace LineTable::upper_bound with GetLineEntryIndexRange (#127806)
After (too) much deliberation, I came to the conclusion that this isn't the right abstraction, as it doesn't behave completely like the standard upper_bound method. What I really wanted was to get the range of line entries for a given address range -- so I implement just that. lower_bound is still useful as a primitive for building other kinds of lookups.
1 parent 62d77fc commit 2c022e3

File tree

3 files changed

+73
-48
lines changed

3 files changed

+73
-48
lines changed

lldb/include/lldb/Symbol/LineTable.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,19 @@ class LineTable {
102102

103103
void GetDescription(Stream *s, Target *target, lldb::DescriptionLevel level);
104104

105-
/// Helper function for line table iteration. \c lower_bound returns the index
106-
/// of the first line entry which ends after the given address (i.e., the
107-
/// first entry which contains the given address or it comes after it).
108-
/// \c upper_bound returns the index of the first line entry which begins on
109-
/// or after the given address (i.e., the entry which would come after the
110-
/// entry containing the given address, if such an entry exists). Functions
111-
/// return <tt>GetSize()</tt> if there is no such entry. The functions are
112-
/// most useful in combination: iterating from <tt>lower_bound(a)</tt> to
113-
/// <tt>upper_bound(b) returns all line tables which intersect the half-open
114-
/// range <tt>[a,b)</tt>.
105+
/// Returns the index of the first line entry which ends after the given
106+
/// address (i.e., the first entry which contains the given address or it
107+
/// comes after it). Returns <tt>GetSize()</tt> if there is no such entry.
115108
uint32_t lower_bound(const Address &so_addr) const;
116-
uint32_t upper_bound(const Address &so_addr) const;
109+
110+
/// Returns the (half-open) range of line entry indexes which overlap the
111+
/// given address range. Line entries partially overlapping the range (on
112+
/// either side) are included as well. Returns an empty range
113+
/// (<tt>first==second</tt>) pointing to the "right" place in the list if
114+
/// there are no such line entries. Empty input ranges always result in an
115+
/// empty output range.
116+
std::pair<uint32_t, uint32_t>
117+
GetLineEntryIndexRange(const AddressRange &range) const;
117118

118119
/// Find a line entry that contains the section offset address \a so_addr.
119120
///

lldb/source/Symbol/LineTable.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -206,25 +206,27 @@ uint32_t LineTable::lower_bound(const Address &so_addr) const {
206206
return std::distance(m_entries.begin(), pos);
207207
}
208208

209-
uint32_t LineTable::upper_bound(const Address &so_addr) const {
210-
if (so_addr.GetModule() != m_comp_unit->GetModule())
211-
return GetSize();
209+
std::pair<uint32_t, uint32_t>
210+
LineTable::GetLineEntryIndexRange(const AddressRange &range) const {
211+
uint32_t first = lower_bound(range.GetBaseAddress());
212+
if (first >= GetSize() || range.GetByteSize() == 0)
213+
return {first, first};
212214

213215
Entry search_entry;
214-
search_entry.file_addr = so_addr.GetFileAddress();
215-
if (search_entry.file_addr == LLDB_INVALID_ADDRESS)
216-
return GetSize();
216+
search_entry.file_addr =
217+
range.GetBaseAddress().GetFileAddress() + range.GetByteSize();
217218

218-
// This is not a typo. lower_bound returns the first entry which starts on or
219-
// after the given address, which is exactly what we want -- *except* if the
220-
// entry is a termination entry (in that case, we want the one after it).
219+
// lower_bound returns the first entry which starts on or after the given
220+
// address, which is exactly what we want -- *except* if the entry is a
221+
// termination entry (in that case, we want the one after it).
221222
auto pos =
222-
llvm::lower_bound(m_entries, search_entry, Entry::EntryAddressLessThan);
223+
std::lower_bound(std::next(m_entries.begin(), first), m_entries.end(),
224+
search_entry, Entry::EntryAddressLessThan);
223225
if (pos != m_entries.end() && pos->file_addr == search_entry.file_addr &&
224226
pos->is_terminal_entry)
225227
++pos;
226228

227-
return std::distance(m_entries.begin(), pos);
229+
return {first, std::distance(m_entries.begin(), pos)};
228230
}
229231

230232
bool LineTable::FindLineEntryByAddress(const Address &so_addr,

lldb/unittests/Symbol/LineTableTest.cpp

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ CreateFakeModule(std::vector<std::unique_ptr<LineSequence>> line_sequences) {
194194
std::move(text_sp), line_table};
195195
}
196196

197-
TEST_F(LineTableTest, LowerAndUpperBound) {
197+
TEST_F(LineTableTest, lower_bound) {
198198
LineSequenceBuilder builder;
199199
builder.Entry(0);
200200
builder.Entry(10);
@@ -211,41 +211,63 @@ TEST_F(LineTableTest, LowerAndUpperBound) {
211211

212212
auto make_addr = [&](addr_t addr) { return Address(fixture->text_sp, addr); };
213213

214-
// Both functions return the same value for boundary values. This way the
215-
// index range for e.g. [0,10) is [0,1).
216214
EXPECT_EQ(table->lower_bound(make_addr(0)), 0u);
217-
EXPECT_EQ(table->upper_bound(make_addr(0)), 0u);
215+
EXPECT_EQ(table->lower_bound(make_addr(9)), 0u);
218216
EXPECT_EQ(table->lower_bound(make_addr(10)), 1u);
219-
EXPECT_EQ(table->upper_bound(make_addr(10)), 1u);
217+
EXPECT_EQ(table->lower_bound(make_addr(19)), 1u);
218+
219+
// Skips over the terminal entry.
220220
EXPECT_EQ(table->lower_bound(make_addr(20)), 3u);
221-
EXPECT_EQ(table->upper_bound(make_addr(20)), 3u);
221+
EXPECT_EQ(table->lower_bound(make_addr(29)), 3u);
222222

223-
// In case there's no "real" entry at this address, they return the first real
224-
// entry.
223+
// In case there's no "real" entry at this address, the function returns the
224+
// first real entry.
225225
EXPECT_EQ(table->lower_bound(make_addr(30)), 5u);
226-
EXPECT_EQ(table->upper_bound(make_addr(30)), 5u);
227-
228226
EXPECT_EQ(table->lower_bound(make_addr(40)), 5u);
229-
EXPECT_EQ(table->upper_bound(make_addr(40)), 5u);
230-
231-
// For in-between values, their result differs by one. [9,19) maps to [0,2)
232-
// because the first two entries contain a part of that range.
233-
EXPECT_EQ(table->lower_bound(make_addr(9)), 0u);
234-
EXPECT_EQ(table->upper_bound(make_addr(9)), 1u);
235-
EXPECT_EQ(table->lower_bound(make_addr(19)), 1u);
236-
EXPECT_EQ(table->upper_bound(make_addr(19)), 2u);
237-
EXPECT_EQ(table->lower_bound(make_addr(29)), 3u);
238-
EXPECT_EQ(table->upper_bound(make_addr(29)), 4u);
239227

240-
// In a gap, they both return the first entry after the gap.
241-
EXPECT_EQ(table->upper_bound(make_addr(39)), 5u);
242-
EXPECT_EQ(table->upper_bound(make_addr(39)), 5u);
228+
// In a gap, return the first entry after the gap.
229+
EXPECT_EQ(table->lower_bound(make_addr(39)), 5u);
243230

244-
// And if there's no such entry, they return the size of the list.
231+
// And if there's no such entry, return the size of the list.
245232
EXPECT_EQ(table->lower_bound(make_addr(50)), table->GetSize());
246-
EXPECT_EQ(table->upper_bound(make_addr(50)), table->GetSize());
247233
EXPECT_EQ(table->lower_bound(make_addr(59)), table->GetSize());
248-
EXPECT_EQ(table->upper_bound(make_addr(59)), table->GetSize());
234+
}
235+
236+
TEST_F(LineTableTest, GetLineEntryIndexRange) {
237+
LineSequenceBuilder builder;
238+
builder.Entry(0);
239+
builder.Entry(10);
240+
builder.Entry(20, LineSequenceBuilder::Terminal);
241+
242+
llvm::Expected<FakeModuleFixture> fixture = CreateFakeModule(builder.Build());
243+
ASSERT_THAT_EXPECTED(fixture, llvm::Succeeded());
244+
245+
LineTable *table = fixture->line_table;
246+
247+
auto make_range = [&](addr_t addr, addr_t size) {
248+
return AddressRange(fixture->text_sp, addr, size);
249+
};
250+
251+
EXPECT_THAT(table->GetLineEntryIndexRange(make_range(0, 10)),
252+
testing::Pair(0, 1));
253+
EXPECT_THAT(table->GetLineEntryIndexRange(make_range(0, 20)),
254+
testing::Pair(0, 3)); // Includes the terminal entry.
255+
// Partial overlap on one side.
256+
EXPECT_THAT(table->GetLineEntryIndexRange(make_range(3, 7)),
257+
testing::Pair(0, 1));
258+
// On the other side
259+
EXPECT_THAT(table->GetLineEntryIndexRange(make_range(0, 15)),
260+
testing::Pair(0, 2));
261+
// On both sides
262+
EXPECT_THAT(table->GetLineEntryIndexRange(make_range(2, 3)),
263+
testing::Pair(0, 1));
264+
// Empty ranges
265+
EXPECT_THAT(table->GetLineEntryIndexRange(make_range(0, 0)),
266+
testing::Pair(0, 0));
267+
EXPECT_THAT(table->GetLineEntryIndexRange(make_range(5, 0)),
268+
testing::Pair(0, 0));
269+
EXPECT_THAT(table->GetLineEntryIndexRange(make_range(10, 0)),
270+
testing::Pair(1, 1));
249271
}
250272

251273
TEST_F(LineTableTest, FindLineEntryByAddress) {

0 commit comments

Comments
 (0)