1dda28197Spatrick //===-- LineTable.cpp -----------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Symbol/LineTable.h"
10061da546Spatrick #include "lldb/Core/Address.h"
11061da546Spatrick #include "lldb/Core/Module.h"
12061da546Spatrick #include "lldb/Core/Section.h"
13061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
14061da546Spatrick #include "lldb/Utility/Stream.h"
15061da546Spatrick #include <algorithm>
16061da546Spatrick
17061da546Spatrick using namespace lldb;
18061da546Spatrick using namespace lldb_private;
19061da546Spatrick
20061da546Spatrick // LineTable constructor
LineTable(CompileUnit * comp_unit)21061da546Spatrick LineTable::LineTable(CompileUnit *comp_unit)
22061da546Spatrick : m_comp_unit(comp_unit), m_entries() {}
23061da546Spatrick
LineTable(CompileUnit * comp_unit,std::vector<std::unique_ptr<LineSequence>> && sequences)24dda28197Spatrick LineTable::LineTable(CompileUnit *comp_unit,
25dda28197Spatrick std::vector<std::unique_ptr<LineSequence>> &&sequences)
26dda28197Spatrick : m_comp_unit(comp_unit), m_entries() {
27dda28197Spatrick LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
28dda28197Spatrick llvm::stable_sort(sequences, less_than_bp);
29dda28197Spatrick for (const auto &sequence : sequences) {
30dda28197Spatrick LineSequenceImpl *seq = static_cast<LineSequenceImpl *>(sequence.get());
31dda28197Spatrick m_entries.insert(m_entries.end(), seq->m_entries.begin(),
32dda28197Spatrick seq->m_entries.end());
33dda28197Spatrick }
34dda28197Spatrick }
35dda28197Spatrick
36061da546Spatrick // Destructor
37*be691f3bSpatrick LineTable::~LineTable() = default;
38061da546Spatrick
InsertLineEntry(lldb::addr_t file_addr,uint32_t line,uint16_t column,uint16_t file_idx,bool is_start_of_statement,bool is_start_of_basic_block,bool is_prologue_end,bool is_epilogue_begin,bool is_terminal_entry)39061da546Spatrick void LineTable::InsertLineEntry(lldb::addr_t file_addr, uint32_t line,
40061da546Spatrick uint16_t column, uint16_t file_idx,
41061da546Spatrick bool is_start_of_statement,
42061da546Spatrick bool is_start_of_basic_block,
43061da546Spatrick bool is_prologue_end, bool is_epilogue_begin,
44061da546Spatrick bool is_terminal_entry) {
45061da546Spatrick Entry entry(file_addr, line, column, file_idx, is_start_of_statement,
46061da546Spatrick is_start_of_basic_block, is_prologue_end, is_epilogue_begin,
47061da546Spatrick is_terminal_entry);
48061da546Spatrick
49061da546Spatrick LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
50061da546Spatrick entry_collection::iterator pos =
51061da546Spatrick llvm::upper_bound(m_entries, entry, less_than_bp);
52061da546Spatrick
53061da546Spatrick // Stream s(stdout);
54061da546Spatrick // s << "\n\nBefore:\n";
55061da546Spatrick // Dump (&s, Address::DumpStyleFileAddress);
56061da546Spatrick m_entries.insert(pos, entry);
57061da546Spatrick // s << "After:\n";
58061da546Spatrick // Dump (&s, Address::DumpStyleFileAddress);
59061da546Spatrick }
60061da546Spatrick
61*be691f3bSpatrick LineSequence::LineSequence() = default;
62061da546Spatrick
Clear()63061da546Spatrick void LineTable::LineSequenceImpl::Clear() { m_entries.clear(); }
64061da546Spatrick
CreateLineSequenceContainer()65dda28197Spatrick std::unique_ptr<LineSequence> LineTable::CreateLineSequenceContainer() {
66dda28197Spatrick return std::make_unique<LineTable::LineSequenceImpl>();
67061da546Spatrick }
68061da546Spatrick
AppendLineEntryToSequence(LineSequence * sequence,lldb::addr_t file_addr,uint32_t line,uint16_t column,uint16_t file_idx,bool is_start_of_statement,bool is_start_of_basic_block,bool is_prologue_end,bool is_epilogue_begin,bool is_terminal_entry)69061da546Spatrick void LineTable::AppendLineEntryToSequence(
70061da546Spatrick LineSequence *sequence, lldb::addr_t file_addr, uint32_t line,
71061da546Spatrick uint16_t column, uint16_t file_idx, bool is_start_of_statement,
72061da546Spatrick bool is_start_of_basic_block, bool is_prologue_end, bool is_epilogue_begin,
73061da546Spatrick bool is_terminal_entry) {
74061da546Spatrick assert(sequence != nullptr);
75061da546Spatrick LineSequenceImpl *seq = reinterpret_cast<LineSequenceImpl *>(sequence);
76061da546Spatrick Entry entry(file_addr, line, column, file_idx, is_start_of_statement,
77061da546Spatrick is_start_of_basic_block, is_prologue_end, is_epilogue_begin,
78061da546Spatrick is_terminal_entry);
79061da546Spatrick entry_collection &entries = seq->m_entries;
80061da546Spatrick // Replace the last entry if the address is the same, otherwise append it. If
81061da546Spatrick // we have multiple line entries at the same address, this indicates illegal
82061da546Spatrick // DWARF so this "fixes" the line table to be correct. If not fixed this can
83061da546Spatrick // cause a line entry's address that when resolved back to a symbol context,
84061da546Spatrick // could resolve to a different line entry. We really want a
85061da546Spatrick // 1 to 1 mapping
86061da546Spatrick // here to avoid these kinds of inconsistencies. We will need tor revisit
87061da546Spatrick // this if the DWARF line tables are updated to allow multiple entries at the
88061da546Spatrick // same address legally.
89061da546Spatrick if (!entries.empty() && entries.back().file_addr == file_addr) {
90061da546Spatrick // GCC don't use the is_prologue_end flag to mark the first instruction
91061da546Spatrick // after the prologue.
92061da546Spatrick // Instead of it it is issuing a line table entry for the first instruction
93061da546Spatrick // of the prologue and one for the first instruction after the prologue. If
94061da546Spatrick // the size of the prologue is 0 instruction then the 2 line entry will
95061da546Spatrick // have the same file address. Removing it will remove our ability to
96061da546Spatrick // properly detect the location of the end of prologe so we set the
97061da546Spatrick // prologue_end flag to preserve this information (setting the prologue_end
98061da546Spatrick // flag for an entry what is after the prologue end don't have any effect)
99061da546Spatrick entry.is_prologue_end = entry.file_idx == entries.back().file_idx;
100061da546Spatrick entries.back() = entry;
101061da546Spatrick } else
102061da546Spatrick entries.push_back(entry);
103061da546Spatrick }
104061da546Spatrick
InsertSequence(LineSequence * sequence)105061da546Spatrick void LineTable::InsertSequence(LineSequence *sequence) {
106061da546Spatrick assert(sequence != nullptr);
107061da546Spatrick LineSequenceImpl *seq = reinterpret_cast<LineSequenceImpl *>(sequence);
108061da546Spatrick if (seq->m_entries.empty())
109061da546Spatrick return;
110061da546Spatrick Entry &entry = seq->m_entries.front();
111061da546Spatrick
112061da546Spatrick // If the first entry address in this sequence is greater than or equal to
113061da546Spatrick // the address of the last item in our entry collection, just append.
114061da546Spatrick if (m_entries.empty() ||
115061da546Spatrick !Entry::EntryAddressLessThan(entry, m_entries.back())) {
116061da546Spatrick m_entries.insert(m_entries.end(), seq->m_entries.begin(),
117061da546Spatrick seq->m_entries.end());
118061da546Spatrick return;
119061da546Spatrick }
120061da546Spatrick
121061da546Spatrick // Otherwise, find where this belongs in the collection
122061da546Spatrick entry_collection::iterator begin_pos = m_entries.begin();
123061da546Spatrick entry_collection::iterator end_pos = m_entries.end();
124061da546Spatrick LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
125061da546Spatrick entry_collection::iterator pos =
126061da546Spatrick upper_bound(begin_pos, end_pos, entry, less_than_bp);
127061da546Spatrick
128061da546Spatrick // We should never insert a sequence in the middle of another sequence
129061da546Spatrick if (pos != begin_pos) {
130061da546Spatrick while (pos < end_pos && !((pos - 1)->is_terminal_entry))
131061da546Spatrick pos++;
132061da546Spatrick }
133061da546Spatrick
134061da546Spatrick #ifndef NDEBUG
135061da546Spatrick // If we aren't inserting at the beginning, the previous entry should
136061da546Spatrick // terminate a sequence.
137061da546Spatrick if (pos != begin_pos) {
138061da546Spatrick entry_collection::iterator prev_pos = pos - 1;
139061da546Spatrick assert(prev_pos->is_terminal_entry);
140061da546Spatrick }
141061da546Spatrick #endif
142061da546Spatrick m_entries.insert(pos, seq->m_entries.begin(), seq->m_entries.end());
143061da546Spatrick }
144061da546Spatrick
LessThanBinaryPredicate(LineTable * line_table)145061da546Spatrick LineTable::Entry::LessThanBinaryPredicate::LessThanBinaryPredicate(
146061da546Spatrick LineTable *line_table)
147061da546Spatrick : m_line_table(line_table) {}
148061da546Spatrick
149061da546Spatrick bool LineTable::Entry::LessThanBinaryPredicate::
operator ()(const LineTable::Entry & a,const LineTable::Entry & b) const150061da546Spatrick operator()(const LineTable::Entry &a, const LineTable::Entry &b) const {
151061da546Spatrick #define LT_COMPARE(a, b) \
152061da546Spatrick if (a != b) \
153061da546Spatrick return a < b
154061da546Spatrick LT_COMPARE(a.file_addr, b.file_addr);
155061da546Spatrick // b and a reversed on purpose below.
156061da546Spatrick LT_COMPARE(b.is_terminal_entry, a.is_terminal_entry);
157061da546Spatrick LT_COMPARE(a.line, b.line);
158061da546Spatrick LT_COMPARE(a.column, b.column);
159061da546Spatrick LT_COMPARE(a.is_start_of_statement, b.is_start_of_statement);
160061da546Spatrick LT_COMPARE(a.is_start_of_basic_block, b.is_start_of_basic_block);
161061da546Spatrick // b and a reversed on purpose below.
162061da546Spatrick LT_COMPARE(b.is_prologue_end, a.is_prologue_end);
163061da546Spatrick LT_COMPARE(a.is_epilogue_begin, b.is_epilogue_begin);
164061da546Spatrick LT_COMPARE(a.file_idx, b.file_idx);
165061da546Spatrick return false;
166061da546Spatrick #undef LT_COMPARE
167061da546Spatrick }
168061da546Spatrick
169dda28197Spatrick bool LineTable::Entry::LessThanBinaryPredicate::
operator ()(const std::unique_ptr<LineSequence> & sequence_a,const std::unique_ptr<LineSequence> & sequence_b) const170dda28197Spatrick operator()(const std::unique_ptr<LineSequence> &sequence_a,
171dda28197Spatrick const std::unique_ptr<LineSequence> &sequence_b) const {
172dda28197Spatrick auto *seq_a = static_cast<const LineSequenceImpl *>(sequence_a.get());
173dda28197Spatrick auto *seq_b = static_cast<const LineSequenceImpl *>(sequence_b.get());
174dda28197Spatrick return (*this)(seq_a->m_entries.front(), seq_b->m_entries.front());
175dda28197Spatrick }
176dda28197Spatrick
GetSize() const177061da546Spatrick uint32_t LineTable::GetSize() const { return m_entries.size(); }
178061da546Spatrick
GetLineEntryAtIndex(uint32_t idx,LineEntry & line_entry)179061da546Spatrick bool LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry &line_entry) {
180061da546Spatrick if (idx < m_entries.size()) {
181061da546Spatrick ConvertEntryAtIndexToLineEntry(idx, line_entry);
182061da546Spatrick return true;
183061da546Spatrick }
184061da546Spatrick line_entry.Clear();
185061da546Spatrick return false;
186061da546Spatrick }
187061da546Spatrick
FindLineEntryByAddress(const Address & so_addr,LineEntry & line_entry,uint32_t * index_ptr)188061da546Spatrick bool LineTable::FindLineEntryByAddress(const Address &so_addr,
189061da546Spatrick LineEntry &line_entry,
190061da546Spatrick uint32_t *index_ptr) {
191061da546Spatrick if (index_ptr != nullptr)
192061da546Spatrick *index_ptr = UINT32_MAX;
193061da546Spatrick
194061da546Spatrick bool success = false;
195061da546Spatrick
196061da546Spatrick if (so_addr.GetModule().get() == m_comp_unit->GetModule().get()) {
197061da546Spatrick Entry search_entry;
198061da546Spatrick search_entry.file_addr = so_addr.GetFileAddress();
199061da546Spatrick if (search_entry.file_addr != LLDB_INVALID_ADDRESS) {
200061da546Spatrick entry_collection::const_iterator begin_pos = m_entries.begin();
201061da546Spatrick entry_collection::const_iterator end_pos = m_entries.end();
202061da546Spatrick entry_collection::const_iterator pos = lower_bound(
203061da546Spatrick begin_pos, end_pos, search_entry, Entry::EntryAddressLessThan);
204061da546Spatrick if (pos != end_pos) {
205061da546Spatrick if (pos != begin_pos) {
206061da546Spatrick if (pos->file_addr != search_entry.file_addr)
207061da546Spatrick --pos;
208061da546Spatrick else if (pos->file_addr == search_entry.file_addr) {
209061da546Spatrick // If this is a termination entry, it shouldn't match since entries
210061da546Spatrick // with the "is_terminal_entry" member set to true are termination
211061da546Spatrick // entries that define the range for the previous entry.
212061da546Spatrick if (pos->is_terminal_entry) {
213061da546Spatrick // The matching entry is a terminal entry, so we skip ahead to
214061da546Spatrick // the next entry to see if there is another entry following this
215061da546Spatrick // one whose section/offset matches.
216061da546Spatrick ++pos;
217061da546Spatrick if (pos != end_pos) {
218061da546Spatrick if (pos->file_addr != search_entry.file_addr)
219061da546Spatrick pos = end_pos;
220061da546Spatrick }
221061da546Spatrick }
222061da546Spatrick
223061da546Spatrick if (pos != end_pos) {
224061da546Spatrick // While in the same section/offset backup to find the first line
225061da546Spatrick // entry that matches the address in case there are multiple
226061da546Spatrick while (pos != begin_pos) {
227061da546Spatrick entry_collection::const_iterator prev_pos = pos - 1;
228061da546Spatrick if (prev_pos->file_addr == search_entry.file_addr &&
229061da546Spatrick prev_pos->is_terminal_entry == false)
230061da546Spatrick --pos;
231061da546Spatrick else
232061da546Spatrick break;
233061da546Spatrick }
234061da546Spatrick }
235061da546Spatrick }
236061da546Spatrick }
237061da546Spatrick else
238061da546Spatrick {
239061da546Spatrick // There might be code in the containing objfile before the first
240061da546Spatrick // line table entry. Make sure that does not get considered part of
241061da546Spatrick // the first line table entry.
242061da546Spatrick if (pos->file_addr > so_addr.GetFileAddress())
243061da546Spatrick return false;
244061da546Spatrick }
245061da546Spatrick
246061da546Spatrick // Make sure we have a valid match and that the match isn't a
247061da546Spatrick // terminating entry for a previous line...
248061da546Spatrick if (pos != end_pos && pos->is_terminal_entry == false) {
249061da546Spatrick uint32_t match_idx = std::distance(begin_pos, pos);
250061da546Spatrick success = ConvertEntryAtIndexToLineEntry(match_idx, line_entry);
251061da546Spatrick if (index_ptr != nullptr && success)
252061da546Spatrick *index_ptr = match_idx;
253061da546Spatrick }
254061da546Spatrick }
255061da546Spatrick }
256061da546Spatrick }
257061da546Spatrick return success;
258061da546Spatrick }
259061da546Spatrick
ConvertEntryAtIndexToLineEntry(uint32_t idx,LineEntry & line_entry)260061da546Spatrick bool LineTable::ConvertEntryAtIndexToLineEntry(uint32_t idx,
261061da546Spatrick LineEntry &line_entry) {
262061da546Spatrick if (idx >= m_entries.size())
263061da546Spatrick return false;
264061da546Spatrick
265061da546Spatrick const Entry &entry = m_entries[idx];
266061da546Spatrick ModuleSP module_sp(m_comp_unit->GetModule());
267061da546Spatrick if (!module_sp)
268061da546Spatrick return false;
269061da546Spatrick
270061da546Spatrick addr_t file_addr = entry.file_addr;
271061da546Spatrick
272061da546Spatrick // A terminal entry can point outside of a module or a section. Decrement the
273061da546Spatrick // address to ensure it resolves correctly.
274061da546Spatrick if (entry.is_terminal_entry)
275061da546Spatrick --file_addr;
276061da546Spatrick
277061da546Spatrick if (!module_sp->ResolveFileAddress(file_addr,
278061da546Spatrick line_entry.range.GetBaseAddress()))
279061da546Spatrick return false;
280061da546Spatrick
281061da546Spatrick // Now undo the decrement above.
282061da546Spatrick if (entry.is_terminal_entry)
283061da546Spatrick line_entry.range.GetBaseAddress().Slide(1);
284061da546Spatrick
285061da546Spatrick if (!entry.is_terminal_entry && idx + 1 < m_entries.size())
286061da546Spatrick line_entry.range.SetByteSize(m_entries[idx + 1].file_addr -
287061da546Spatrick entry.file_addr);
288061da546Spatrick else
289061da546Spatrick line_entry.range.SetByteSize(0);
290061da546Spatrick
291061da546Spatrick line_entry.file =
292061da546Spatrick m_comp_unit->GetSupportFiles().GetFileSpecAtIndex(entry.file_idx);
293061da546Spatrick line_entry.original_file =
294061da546Spatrick m_comp_unit->GetSupportFiles().GetFileSpecAtIndex(entry.file_idx);
295061da546Spatrick line_entry.line = entry.line;
296061da546Spatrick line_entry.column = entry.column;
297061da546Spatrick line_entry.is_start_of_statement = entry.is_start_of_statement;
298061da546Spatrick line_entry.is_start_of_basic_block = entry.is_start_of_basic_block;
299061da546Spatrick line_entry.is_prologue_end = entry.is_prologue_end;
300061da546Spatrick line_entry.is_epilogue_begin = entry.is_epilogue_begin;
301061da546Spatrick line_entry.is_terminal_entry = entry.is_terminal_entry;
302061da546Spatrick return true;
303061da546Spatrick }
304061da546Spatrick
FindLineEntryIndexByFileIndex(uint32_t start_idx,uint32_t file_idx,const SourceLocationSpec & src_location_spec,LineEntry * line_entry_ptr)305061da546Spatrick uint32_t LineTable::FindLineEntryIndexByFileIndex(
306*be691f3bSpatrick uint32_t start_idx, uint32_t file_idx,
307*be691f3bSpatrick const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr) {
308*be691f3bSpatrick auto file_idx_matcher = [](uint32_t file_index, uint16_t entry_file_idx) {
309*be691f3bSpatrick return file_index == entry_file_idx;
310*be691f3bSpatrick };
311*be691f3bSpatrick return FindLineEntryIndexByFileIndexImpl<uint32_t>(
312061da546Spatrick
313*be691f3bSpatrick start_idx, file_idx, src_location_spec, line_entry_ptr, file_idx_matcher);
314061da546Spatrick }
315061da546Spatrick
FindLineEntryIndexByFileIndex(uint32_t start_idx,const std::vector<uint32_t> & file_idx,const SourceLocationSpec & src_location_spec,LineEntry * line_entry_ptr)316*be691f3bSpatrick uint32_t LineTable::FindLineEntryIndexByFileIndex(
317*be691f3bSpatrick uint32_t start_idx, const std::vector<uint32_t> &file_idx,
318*be691f3bSpatrick const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr) {
319*be691f3bSpatrick auto file_idx_matcher = [](const std::vector<uint32_t> &file_indexes,
320*be691f3bSpatrick uint16_t entry_file_idx) {
321*be691f3bSpatrick return llvm::is_contained(file_indexes, entry_file_idx);
322*be691f3bSpatrick };
323061da546Spatrick
324*be691f3bSpatrick return FindLineEntryIndexByFileIndexImpl<std::vector<uint32_t>>(
325*be691f3bSpatrick start_idx, file_idx, src_location_spec, line_entry_ptr, file_idx_matcher);
326061da546Spatrick }
327061da546Spatrick
FineLineEntriesForFileIndex(uint32_t file_idx,bool append,SymbolContextList & sc_list)328061da546Spatrick size_t LineTable::FineLineEntriesForFileIndex(uint32_t file_idx, bool append,
329061da546Spatrick SymbolContextList &sc_list) {
330061da546Spatrick
331061da546Spatrick if (!append)
332061da546Spatrick sc_list.Clear();
333061da546Spatrick
334061da546Spatrick size_t num_added = 0;
335061da546Spatrick const size_t count = m_entries.size();
336061da546Spatrick if (count > 0) {
337061da546Spatrick SymbolContext sc(m_comp_unit);
338061da546Spatrick
339061da546Spatrick for (size_t idx = 0; idx < count; ++idx) {
340061da546Spatrick // Skip line table rows that terminate the previous row
341061da546Spatrick // (is_terminal_entry is non-zero)
342061da546Spatrick if (m_entries[idx].is_terminal_entry)
343061da546Spatrick continue;
344061da546Spatrick
345061da546Spatrick if (m_entries[idx].file_idx == file_idx) {
346061da546Spatrick if (ConvertEntryAtIndexToLineEntry(idx, sc.line_entry)) {
347061da546Spatrick ++num_added;
348061da546Spatrick sc_list.Append(sc);
349061da546Spatrick }
350061da546Spatrick }
351061da546Spatrick }
352061da546Spatrick }
353061da546Spatrick return num_added;
354061da546Spatrick }
355061da546Spatrick
Dump(Stream * s,Target * target,Address::DumpStyle style,Address::DumpStyle fallback_style,bool show_line_ranges)356061da546Spatrick void LineTable::Dump(Stream *s, Target *target, Address::DumpStyle style,
357061da546Spatrick Address::DumpStyle fallback_style, bool show_line_ranges) {
358061da546Spatrick const size_t count = m_entries.size();
359061da546Spatrick LineEntry line_entry;
360061da546Spatrick FileSpec prev_file;
361061da546Spatrick for (size_t idx = 0; idx < count; ++idx) {
362061da546Spatrick ConvertEntryAtIndexToLineEntry(idx, line_entry);
363061da546Spatrick line_entry.Dump(s, target, prev_file != line_entry.original_file, style,
364061da546Spatrick fallback_style, show_line_ranges);
365061da546Spatrick s->EOL();
366061da546Spatrick prev_file = line_entry.original_file;
367061da546Spatrick }
368061da546Spatrick }
369061da546Spatrick
GetDescription(Stream * s,Target * target,DescriptionLevel level)370061da546Spatrick void LineTable::GetDescription(Stream *s, Target *target,
371061da546Spatrick DescriptionLevel level) {
372061da546Spatrick const size_t count = m_entries.size();
373061da546Spatrick LineEntry line_entry;
374061da546Spatrick for (size_t idx = 0; idx < count; ++idx) {
375061da546Spatrick ConvertEntryAtIndexToLineEntry(idx, line_entry);
376061da546Spatrick line_entry.GetDescription(s, level, m_comp_unit, target, true);
377061da546Spatrick s->EOL();
378061da546Spatrick }
379061da546Spatrick }
380061da546Spatrick
GetContiguousFileAddressRanges(FileAddressRanges & file_ranges,bool append)381061da546Spatrick size_t LineTable::GetContiguousFileAddressRanges(FileAddressRanges &file_ranges,
382061da546Spatrick bool append) {
383061da546Spatrick if (!append)
384061da546Spatrick file_ranges.Clear();
385061da546Spatrick const size_t initial_count = file_ranges.GetSize();
386061da546Spatrick
387061da546Spatrick const size_t count = m_entries.size();
388061da546Spatrick LineEntry line_entry;
389061da546Spatrick FileAddressRanges::Entry range(LLDB_INVALID_ADDRESS, 0);
390061da546Spatrick for (size_t idx = 0; idx < count; ++idx) {
391061da546Spatrick const Entry &entry = m_entries[idx];
392061da546Spatrick
393061da546Spatrick if (entry.is_terminal_entry) {
394061da546Spatrick if (range.GetRangeBase() != LLDB_INVALID_ADDRESS) {
395061da546Spatrick range.SetRangeEnd(entry.file_addr);
396061da546Spatrick file_ranges.Append(range);
397061da546Spatrick range.Clear(LLDB_INVALID_ADDRESS);
398061da546Spatrick }
399061da546Spatrick } else if (range.GetRangeBase() == LLDB_INVALID_ADDRESS) {
400061da546Spatrick range.SetRangeBase(entry.file_addr);
401061da546Spatrick }
402061da546Spatrick }
403061da546Spatrick return file_ranges.GetSize() - initial_count;
404061da546Spatrick }
405061da546Spatrick
LinkLineTable(const FileRangeMap & file_range_map)406061da546Spatrick LineTable *LineTable::LinkLineTable(const FileRangeMap &file_range_map) {
407061da546Spatrick std::unique_ptr<LineTable> line_table_up(new LineTable(m_comp_unit));
408061da546Spatrick LineSequenceImpl sequence;
409061da546Spatrick const size_t count = m_entries.size();
410061da546Spatrick LineEntry line_entry;
411061da546Spatrick const FileRangeMap::Entry *file_range_entry = nullptr;
412061da546Spatrick const FileRangeMap::Entry *prev_file_range_entry = nullptr;
413061da546Spatrick lldb::addr_t prev_file_addr = LLDB_INVALID_ADDRESS;
414061da546Spatrick bool prev_entry_was_linked = false;
415061da546Spatrick bool range_changed = false;
416061da546Spatrick for (size_t idx = 0; idx < count; ++idx) {
417061da546Spatrick const Entry &entry = m_entries[idx];
418061da546Spatrick
419061da546Spatrick const bool end_sequence = entry.is_terminal_entry;
420061da546Spatrick const lldb::addr_t lookup_file_addr =
421061da546Spatrick entry.file_addr - (end_sequence ? 1 : 0);
422061da546Spatrick if (file_range_entry == nullptr ||
423061da546Spatrick !file_range_entry->Contains(lookup_file_addr)) {
424061da546Spatrick prev_file_range_entry = file_range_entry;
425061da546Spatrick file_range_entry = file_range_map.FindEntryThatContains(lookup_file_addr);
426061da546Spatrick range_changed = true;
427061da546Spatrick }
428061da546Spatrick
429061da546Spatrick lldb::addr_t prev_end_entry_linked_file_addr = LLDB_INVALID_ADDRESS;
430061da546Spatrick lldb::addr_t entry_linked_file_addr = LLDB_INVALID_ADDRESS;
431061da546Spatrick
432061da546Spatrick bool terminate_previous_entry = false;
433061da546Spatrick if (file_range_entry) {
434061da546Spatrick entry_linked_file_addr = entry.file_addr -
435061da546Spatrick file_range_entry->GetRangeBase() +
436061da546Spatrick file_range_entry->data;
437061da546Spatrick // Determine if we need to terminate the previous entry when the previous
438061da546Spatrick // entry was not contiguous with this one after being linked.
439061da546Spatrick if (range_changed && prev_file_range_entry) {
440061da546Spatrick prev_end_entry_linked_file_addr =
441061da546Spatrick std::min<lldb::addr_t>(entry.file_addr,
442061da546Spatrick prev_file_range_entry->GetRangeEnd()) -
443061da546Spatrick prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
444061da546Spatrick if (prev_end_entry_linked_file_addr != entry_linked_file_addr)
445061da546Spatrick terminate_previous_entry = prev_entry_was_linked;
446061da546Spatrick }
447061da546Spatrick } else if (prev_entry_was_linked) {
448061da546Spatrick // This entry doesn't have a remapping and it needs to be removed. Watch
449061da546Spatrick // out in case we need to terminate a previous entry needs to be
450061da546Spatrick // terminated now that one line entry in a sequence is not longer valid.
451061da546Spatrick if (!sequence.m_entries.empty() &&
452061da546Spatrick !sequence.m_entries.back().is_terminal_entry) {
453061da546Spatrick terminate_previous_entry = true;
454061da546Spatrick }
455061da546Spatrick }
456061da546Spatrick
457061da546Spatrick if (terminate_previous_entry && !sequence.m_entries.empty()) {
458061da546Spatrick assert(prev_file_addr != LLDB_INVALID_ADDRESS);
459061da546Spatrick UNUSED_IF_ASSERT_DISABLED(prev_file_addr);
460061da546Spatrick sequence.m_entries.push_back(sequence.m_entries.back());
461061da546Spatrick if (prev_end_entry_linked_file_addr == LLDB_INVALID_ADDRESS)
462061da546Spatrick prev_end_entry_linked_file_addr =
463061da546Spatrick std::min<lldb::addr_t>(entry.file_addr,
464061da546Spatrick prev_file_range_entry->GetRangeEnd()) -
465061da546Spatrick prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
466061da546Spatrick sequence.m_entries.back().file_addr = prev_end_entry_linked_file_addr;
467061da546Spatrick sequence.m_entries.back().is_terminal_entry = true;
468061da546Spatrick
469061da546Spatrick // Append the sequence since we just terminated the previous one
470061da546Spatrick line_table_up->InsertSequence(&sequence);
471061da546Spatrick sequence.Clear();
472061da546Spatrick }
473061da546Spatrick
474061da546Spatrick // Now link the current entry
475061da546Spatrick if (file_range_entry) {
476061da546Spatrick // This entry has an address remapping and it needs to have its address
477061da546Spatrick // relinked
478061da546Spatrick sequence.m_entries.push_back(entry);
479061da546Spatrick sequence.m_entries.back().file_addr = entry_linked_file_addr;
480061da546Spatrick }
481061da546Spatrick
482061da546Spatrick // If we have items in the sequence and the last entry is a terminal entry,
483061da546Spatrick // insert this sequence into our new line table.
484061da546Spatrick if (!sequence.m_entries.empty() &&
485061da546Spatrick sequence.m_entries.back().is_terminal_entry) {
486061da546Spatrick line_table_up->InsertSequence(&sequence);
487061da546Spatrick sequence.Clear();
488061da546Spatrick prev_entry_was_linked = false;
489061da546Spatrick } else {
490061da546Spatrick prev_entry_was_linked = file_range_entry != nullptr;
491061da546Spatrick }
492061da546Spatrick prev_file_addr = entry.file_addr;
493061da546Spatrick range_changed = false;
494061da546Spatrick }
495061da546Spatrick if (line_table_up->m_entries.empty())
496061da546Spatrick return nullptr;
497061da546Spatrick return line_table_up.release();
498061da546Spatrick }
499