1cfca06d7SDimitry Andric //===-- LineTable.cpp -----------------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
914f1b3e8SDimitry Andric #include "lldb/Symbol/LineTable.h"
10f034231aSEd Maste #include "lldb/Core/Address.h"
11f034231aSEd Maste #include "lldb/Core/Module.h"
12f034231aSEd Maste #include "lldb/Core/Section.h"
13f034231aSEd Maste #include "lldb/Symbol/CompileUnit.h"
1474a628f7SDimitry Andric #include "lldb/Utility/Stream.h"
15f034231aSEd Maste #include <algorithm>
16f034231aSEd Maste
17f034231aSEd Maste using namespace lldb;
18f034231aSEd Maste using namespace lldb_private;
19f034231aSEd Maste
20f034231aSEd Maste // LineTable constructor
LineTable(CompileUnit * comp_unit)2114f1b3e8SDimitry Andric LineTable::LineTable(CompileUnit *comp_unit)
2214f1b3e8SDimitry Andric : m_comp_unit(comp_unit), m_entries() {}
23f034231aSEd Maste
LineTable(CompileUnit * comp_unit,std::vector<std::unique_ptr<LineSequence>> && sequences)24cfca06d7SDimitry Andric LineTable::LineTable(CompileUnit *comp_unit,
25cfca06d7SDimitry Andric std::vector<std::unique_ptr<LineSequence>> &&sequences)
26cfca06d7SDimitry Andric : m_comp_unit(comp_unit), m_entries() {
27cfca06d7SDimitry Andric LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
28cfca06d7SDimitry Andric llvm::stable_sort(sequences, less_than_bp);
29cfca06d7SDimitry Andric for (const auto &sequence : sequences) {
30cfca06d7SDimitry Andric LineSequenceImpl *seq = static_cast<LineSequenceImpl *>(sequence.get());
31cfca06d7SDimitry Andric m_entries.insert(m_entries.end(), seq->m_entries.begin(),
32cfca06d7SDimitry Andric seq->m_entries.end());
33cfca06d7SDimitry Andric }
34cfca06d7SDimitry Andric }
35cfca06d7SDimitry Andric
36f034231aSEd Maste // Destructor
37344a3780SDimitry Andric LineTable::~LineTable() = default;
38f034231aSEd Maste
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)3914f1b3e8SDimitry Andric void LineTable::InsertLineEntry(lldb::addr_t file_addr, uint32_t line,
4014f1b3e8SDimitry Andric uint16_t column, uint16_t file_idx,
41f034231aSEd Maste bool is_start_of_statement,
42f034231aSEd Maste bool is_start_of_basic_block,
4314f1b3e8SDimitry Andric bool is_prologue_end, bool is_epilogue_begin,
4414f1b3e8SDimitry Andric bool is_terminal_entry) {
4514f1b3e8SDimitry Andric Entry entry(file_addr, line, column, file_idx, is_start_of_statement,
4614f1b3e8SDimitry Andric is_start_of_basic_block, is_prologue_end, is_epilogue_begin,
4714f1b3e8SDimitry Andric is_terminal_entry);
48f034231aSEd Maste
49f034231aSEd Maste LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
5014f1b3e8SDimitry Andric entry_collection::iterator pos =
51706b4fc4SDimitry Andric llvm::upper_bound(m_entries, entry, less_than_bp);
52f034231aSEd Maste
53f034231aSEd Maste // Stream s(stdout);
54f034231aSEd Maste // s << "\n\nBefore:\n";
55f034231aSEd Maste // Dump (&s, Address::DumpStyleFileAddress);
56f034231aSEd Maste m_entries.insert(pos, entry);
57f034231aSEd Maste // s << "After:\n";
58f034231aSEd Maste // Dump (&s, Address::DumpStyleFileAddress);
59f034231aSEd Maste }
60f034231aSEd Maste
61344a3780SDimitry Andric LineSequence::LineSequence() = default;
62f034231aSEd Maste
Clear()6314f1b3e8SDimitry Andric void LineTable::LineSequenceImpl::Clear() { m_entries.clear(); }
64f034231aSEd Maste
CreateLineSequenceContainer()65cfca06d7SDimitry Andric std::unique_ptr<LineSequence> LineTable::CreateLineSequenceContainer() {
66cfca06d7SDimitry Andric return std::make_unique<LineTable::LineSequenceImpl>();
67f034231aSEd Maste }
68f034231aSEd Maste
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)6914f1b3e8SDimitry Andric void LineTable::AppendLineEntryToSequence(
7014f1b3e8SDimitry Andric LineSequence *sequence, lldb::addr_t file_addr, uint32_t line,
7114f1b3e8SDimitry Andric uint16_t column, uint16_t file_idx, bool is_start_of_statement,
7214f1b3e8SDimitry Andric bool is_start_of_basic_block, bool is_prologue_end, bool is_epilogue_begin,
7314f1b3e8SDimitry Andric bool is_terminal_entry) {
740cac4ca3SEd Maste assert(sequence != nullptr);
75f034231aSEd Maste LineSequenceImpl *seq = reinterpret_cast<LineSequenceImpl *>(sequence);
7614f1b3e8SDimitry Andric Entry entry(file_addr, line, column, file_idx, is_start_of_statement,
7714f1b3e8SDimitry Andric is_start_of_basic_block, is_prologue_end, is_epilogue_begin,
7814f1b3e8SDimitry Andric is_terminal_entry);
790cac4ca3SEd Maste entry_collection &entries = seq->m_entries;
8014f1b3e8SDimitry Andric // Replace the last entry if the address is the same, otherwise append it. If
81f73363f1SDimitry Andric // we have multiple line entries at the same address, this indicates illegal
82f73363f1SDimitry Andric // DWARF so this "fixes" the line table to be correct. If not fixed this can
83f73363f1SDimitry Andric // cause a line entry's address that when resolved back to a symbol context,
84f73363f1SDimitry Andric // could resolve to a different line entry. We really want a
8514f1b3e8SDimitry Andric // 1 to 1 mapping
86f73363f1SDimitry Andric // here to avoid these kinds of inconsistencies. We will need tor revisit
87f73363f1SDimitry Andric // this if the DWARF line tables are updated to allow multiple entries at the
88f73363f1SDimitry Andric // same address legally.
8914f1b3e8SDimitry Andric if (!entries.empty() && entries.back().file_addr == file_addr) {
9014f1b3e8SDimitry Andric // GCC don't use the is_prologue_end flag to mark the first instruction
9114f1b3e8SDimitry Andric // after the prologue.
92b1c73532SDimitry Andric // Instead of it is issuing a line table entry for the first instruction
93f73363f1SDimitry Andric // of the prologue and one for the first instruction after the prologue. If
94f73363f1SDimitry Andric // the size of the prologue is 0 instruction then the 2 line entry will
95f73363f1SDimitry Andric // have the same file address. Removing it will remove our ability to
96f73363f1SDimitry Andric // properly detect the location of the end of prologe so we set the
97f73363f1SDimitry Andric // prologue_end flag to preserve this information (setting the prologue_end
98f73363f1SDimitry Andric // flag for an entry what is after the prologue end don't have any effect)
99e81d9d49SDimitry Andric entry.is_prologue_end = entry.file_idx == entries.back().file_idx;
1000cac4ca3SEd Maste entries.back() = entry;
10114f1b3e8SDimitry Andric } else
1020cac4ca3SEd Maste entries.push_back(entry);
103f034231aSEd Maste }
104f034231aSEd Maste
InsertSequence(LineSequence * sequence)10514f1b3e8SDimitry Andric void LineTable::InsertSequence(LineSequence *sequence) {
1060cac4ca3SEd Maste assert(sequence != nullptr);
107f034231aSEd Maste LineSequenceImpl *seq = reinterpret_cast<LineSequenceImpl *>(sequence);
108f034231aSEd Maste if (seq->m_entries.empty())
109f034231aSEd Maste return;
110f034231aSEd Maste Entry &entry = seq->m_entries.front();
111f034231aSEd Maste
112f034231aSEd Maste // If the first entry address in this sequence is greater than or equal to
113f034231aSEd Maste // the address of the last item in our entry collection, just append.
11414f1b3e8SDimitry Andric if (m_entries.empty() ||
11514f1b3e8SDimitry Andric !Entry::EntryAddressLessThan(entry, m_entries.back())) {
11614f1b3e8SDimitry Andric m_entries.insert(m_entries.end(), seq->m_entries.begin(),
117f034231aSEd Maste seq->m_entries.end());
118f034231aSEd Maste return;
119f034231aSEd Maste }
120f034231aSEd Maste
121f034231aSEd Maste // Otherwise, find where this belongs in the collection
122f034231aSEd Maste entry_collection::iterator begin_pos = m_entries.begin();
123f034231aSEd Maste entry_collection::iterator end_pos = m_entries.end();
124f034231aSEd Maste LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
12514f1b3e8SDimitry Andric entry_collection::iterator pos =
12614f1b3e8SDimitry Andric upper_bound(begin_pos, end_pos, entry, less_than_bp);
1277fed546dSDimitry Andric
1287fed546dSDimitry Andric // We should never insert a sequence in the middle of another sequence
1297fed546dSDimitry Andric if (pos != begin_pos) {
1307fed546dSDimitry Andric while (pos < end_pos && !((pos - 1)->is_terminal_entry))
1317fed546dSDimitry Andric pos++;
1327fed546dSDimitry Andric }
1337fed546dSDimitry Andric
1345f29bb8aSDimitry Andric #ifndef NDEBUG
135f034231aSEd Maste // If we aren't inserting at the beginning, the previous entry should
136f034231aSEd Maste // terminate a sequence.
13714f1b3e8SDimitry Andric if (pos != begin_pos) {
138f034231aSEd Maste entry_collection::iterator prev_pos = pos - 1;
139f034231aSEd Maste assert(prev_pos->is_terminal_entry);
140f034231aSEd Maste }
141f034231aSEd Maste #endif
142f034231aSEd Maste m_entries.insert(pos, seq->m_entries.begin(), seq->m_entries.end());
143f034231aSEd Maste }
144f034231aSEd Maste
LessThanBinaryPredicate(LineTable * line_table)14514f1b3e8SDimitry Andric LineTable::Entry::LessThanBinaryPredicate::LessThanBinaryPredicate(
14614f1b3e8SDimitry Andric LineTable *line_table)
14714f1b3e8SDimitry Andric : m_line_table(line_table) {}
148f034231aSEd Maste
14914f1b3e8SDimitry Andric bool LineTable::Entry::LessThanBinaryPredicate::
operator ()(const LineTable::Entry & a,const LineTable::Entry & b) const15014f1b3e8SDimitry Andric operator()(const LineTable::Entry &a, const LineTable::Entry &b) const {
15114f1b3e8SDimitry Andric #define LT_COMPARE(a, b) \
15214f1b3e8SDimitry Andric if (a != b) \
15314f1b3e8SDimitry Andric return a < b
154f034231aSEd Maste LT_COMPARE(a.file_addr, b.file_addr);
155f034231aSEd Maste // b and a reversed on purpose below.
156f034231aSEd Maste LT_COMPARE(b.is_terminal_entry, a.is_terminal_entry);
157f034231aSEd Maste LT_COMPARE(a.line, b.line);
158f034231aSEd Maste LT_COMPARE(a.column, b.column);
159f034231aSEd Maste LT_COMPARE(a.is_start_of_statement, b.is_start_of_statement);
160f034231aSEd Maste LT_COMPARE(a.is_start_of_basic_block, b.is_start_of_basic_block);
161f034231aSEd Maste // b and a reversed on purpose below.
162f034231aSEd Maste LT_COMPARE(b.is_prologue_end, a.is_prologue_end);
163f034231aSEd Maste LT_COMPARE(a.is_epilogue_begin, b.is_epilogue_begin);
164f034231aSEd Maste LT_COMPARE(a.file_idx, b.file_idx);
165f034231aSEd Maste return false;
166f034231aSEd Maste #undef LT_COMPARE
167f034231aSEd Maste }
168f034231aSEd Maste
169cfca06d7SDimitry Andric bool LineTable::Entry::LessThanBinaryPredicate::
operator ()(const std::unique_ptr<LineSequence> & sequence_a,const std::unique_ptr<LineSequence> & sequence_b) const170cfca06d7SDimitry Andric operator()(const std::unique_ptr<LineSequence> &sequence_a,
171cfca06d7SDimitry Andric const std::unique_ptr<LineSequence> &sequence_b) const {
172cfca06d7SDimitry Andric auto *seq_a = static_cast<const LineSequenceImpl *>(sequence_a.get());
173cfca06d7SDimitry Andric auto *seq_b = static_cast<const LineSequenceImpl *>(sequence_b.get());
174cfca06d7SDimitry Andric return (*this)(seq_a->m_entries.front(), seq_b->m_entries.front());
175cfca06d7SDimitry Andric }
176cfca06d7SDimitry Andric
GetSize() const17714f1b3e8SDimitry Andric uint32_t LineTable::GetSize() const { return m_entries.size(); }
178f034231aSEd Maste
GetLineEntryAtIndex(uint32_t idx,LineEntry & line_entry)17914f1b3e8SDimitry Andric bool LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry &line_entry) {
18014f1b3e8SDimitry Andric if (idx < m_entries.size()) {
181f034231aSEd Maste ConvertEntryAtIndexToLineEntry(idx, line_entry);
182f034231aSEd Maste return true;
183f034231aSEd Maste }
184f034231aSEd Maste line_entry.Clear();
185f034231aSEd Maste return false;
186f034231aSEd Maste }
187f034231aSEd Maste
FindLineEntryByAddress(const Address & so_addr,LineEntry & line_entry,uint32_t * index_ptr)18814f1b3e8SDimitry Andric bool LineTable::FindLineEntryByAddress(const Address &so_addr,
18914f1b3e8SDimitry Andric LineEntry &line_entry,
19014f1b3e8SDimitry Andric uint32_t *index_ptr) {
1910cac4ca3SEd Maste if (index_ptr != nullptr)
192f034231aSEd Maste *index_ptr = UINT32_MAX;
193f034231aSEd Maste
194f034231aSEd Maste bool success = false;
195f034231aSEd Maste
19614f1b3e8SDimitry Andric if (so_addr.GetModule().get() == m_comp_unit->GetModule().get()) {
197f034231aSEd Maste Entry search_entry;
198f034231aSEd Maste search_entry.file_addr = so_addr.GetFileAddress();
19914f1b3e8SDimitry Andric if (search_entry.file_addr != LLDB_INVALID_ADDRESS) {
200f034231aSEd Maste entry_collection::const_iterator begin_pos = m_entries.begin();
201f034231aSEd Maste entry_collection::const_iterator end_pos = m_entries.end();
20214f1b3e8SDimitry Andric entry_collection::const_iterator pos = lower_bound(
20314f1b3e8SDimitry Andric begin_pos, end_pos, search_entry, Entry::EntryAddressLessThan);
20414f1b3e8SDimitry Andric if (pos != end_pos) {
20514f1b3e8SDimitry Andric if (pos != begin_pos) {
206f034231aSEd Maste if (pos->file_addr != search_entry.file_addr)
207f034231aSEd Maste --pos;
20814f1b3e8SDimitry Andric else if (pos->file_addr == search_entry.file_addr) {
209f73363f1SDimitry Andric // If this is a termination entry, it shouldn't match since entries
210f73363f1SDimitry Andric // with the "is_terminal_entry" member set to true are termination
211f73363f1SDimitry Andric // entries that define the range for the previous entry.
21214f1b3e8SDimitry Andric if (pos->is_terminal_entry) {
213f73363f1SDimitry Andric // The matching entry is a terminal entry, so we skip ahead to
214f73363f1SDimitry Andric // the next entry to see if there is another entry following this
215f73363f1SDimitry Andric // one whose section/offset matches.
216f034231aSEd Maste ++pos;
21714f1b3e8SDimitry Andric if (pos != end_pos) {
218f034231aSEd Maste if (pos->file_addr != search_entry.file_addr)
219f034231aSEd Maste pos = end_pos;
220f034231aSEd Maste }
221f034231aSEd Maste }
222f034231aSEd Maste
22314f1b3e8SDimitry Andric if (pos != end_pos) {
224f73363f1SDimitry Andric // While in the same section/offset backup to find the first line
225f73363f1SDimitry Andric // entry that matches the address in case there are multiple
22614f1b3e8SDimitry Andric while (pos != begin_pos) {
227f034231aSEd Maste entry_collection::const_iterator prev_pos = pos - 1;
228f034231aSEd Maste if (prev_pos->file_addr == search_entry.file_addr &&
229f034231aSEd Maste prev_pos->is_terminal_entry == false)
230f034231aSEd Maste --pos;
231f034231aSEd Maste else
232f034231aSEd Maste break;
233f034231aSEd Maste }
234f034231aSEd Maste }
235f034231aSEd Maste }
236f034231aSEd Maste }
23774a628f7SDimitry Andric else
23874a628f7SDimitry Andric {
239f73363f1SDimitry Andric // There might be code in the containing objfile before the first
240f73363f1SDimitry Andric // line table entry. Make sure that does not get considered part of
241f73363f1SDimitry Andric // the first line table entry.
24274a628f7SDimitry Andric if (pos->file_addr > so_addr.GetFileAddress())
24374a628f7SDimitry Andric return false;
24474a628f7SDimitry Andric }
245f034231aSEd Maste
24614f1b3e8SDimitry Andric // Make sure we have a valid match and that the match isn't a
247f73363f1SDimitry Andric // terminating entry for a previous line...
24814f1b3e8SDimitry Andric if (pos != end_pos && pos->is_terminal_entry == false) {
249f034231aSEd Maste uint32_t match_idx = std::distance(begin_pos, pos);
250f034231aSEd Maste success = ConvertEntryAtIndexToLineEntry(match_idx, line_entry);
2510cac4ca3SEd Maste if (index_ptr != nullptr && success)
252f034231aSEd Maste *index_ptr = match_idx;
253f034231aSEd Maste }
254f034231aSEd Maste }
255f034231aSEd Maste }
256f034231aSEd Maste }
257f034231aSEd Maste return success;
258f034231aSEd Maste }
259f034231aSEd Maste
ConvertEntryAtIndexToLineEntry(uint32_t idx,LineEntry & line_entry)26014f1b3e8SDimitry Andric bool LineTable::ConvertEntryAtIndexToLineEntry(uint32_t idx,
26114f1b3e8SDimitry Andric LineEntry &line_entry) {
262ead24645SDimitry Andric if (idx >= m_entries.size())
263ead24645SDimitry Andric return false;
264ead24645SDimitry Andric
265f034231aSEd Maste const Entry &entry = m_entries[idx];
266f034231aSEd Maste ModuleSP module_sp(m_comp_unit->GetModule());
267ead24645SDimitry Andric if (!module_sp)
268ead24645SDimitry Andric return false;
269ead24645SDimitry Andric
270ead24645SDimitry Andric addr_t file_addr = entry.file_addr;
271ead24645SDimitry Andric
272ead24645SDimitry Andric // A terminal entry can point outside of a module or a section. Decrement the
273ead24645SDimitry Andric // address to ensure it resolves correctly.
274ead24645SDimitry Andric if (entry.is_terminal_entry)
275ead24645SDimitry Andric --file_addr;
276ead24645SDimitry Andric
277ead24645SDimitry Andric if (!module_sp->ResolveFileAddress(file_addr,
278ead24645SDimitry Andric line_entry.range.GetBaseAddress()))
279ead24645SDimitry Andric return false;
280ead24645SDimitry Andric
281ead24645SDimitry Andric // Now undo the decrement above.
282ead24645SDimitry Andric if (entry.is_terminal_entry)
283ead24645SDimitry Andric line_entry.range.GetBaseAddress().Slide(1);
284ead24645SDimitry Andric
285f034231aSEd Maste if (!entry.is_terminal_entry && idx + 1 < m_entries.size())
28614f1b3e8SDimitry Andric line_entry.range.SetByteSize(m_entries[idx + 1].file_addr -
28714f1b3e8SDimitry Andric entry.file_addr);
288f034231aSEd Maste else
289f034231aSEd Maste line_entry.range.SetByteSize(0);
290f034231aSEd Maste
291ac9a064cSDimitry Andric line_entry.file_sp = std::make_shared<SupportFile>(
292ac9a064cSDimitry Andric m_comp_unit->GetSupportFiles().GetFileSpecAtIndex(entry.file_idx));
2934df029ccSDimitry Andric line_entry.original_file_sp =
2944df029ccSDimitry Andric m_comp_unit->GetSupportFiles().GetSupportFileAtIndex(entry.file_idx);
295f034231aSEd Maste line_entry.line = entry.line;
296f034231aSEd Maste line_entry.column = entry.column;
297f034231aSEd Maste line_entry.is_start_of_statement = entry.is_start_of_statement;
298f034231aSEd Maste line_entry.is_start_of_basic_block = entry.is_start_of_basic_block;
299f034231aSEd Maste line_entry.is_prologue_end = entry.is_prologue_end;
300f034231aSEd Maste line_entry.is_epilogue_begin = entry.is_epilogue_begin;
301f034231aSEd Maste line_entry.is_terminal_entry = entry.is_terminal_entry;
302f034231aSEd Maste return true;
303f034231aSEd Maste }
304f034231aSEd Maste
FindLineEntryIndexByFileIndex(uint32_t start_idx,uint32_t file_idx,const SourceLocationSpec & src_location_spec,LineEntry * line_entry_ptr)30514f1b3e8SDimitry Andric uint32_t LineTable::FindLineEntryIndexByFileIndex(
306344a3780SDimitry Andric uint32_t start_idx, uint32_t file_idx,
307344a3780SDimitry Andric const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr) {
308344a3780SDimitry Andric auto file_idx_matcher = [](uint32_t file_index, uint16_t entry_file_idx) {
309344a3780SDimitry Andric return file_index == entry_file_idx;
310344a3780SDimitry Andric };
311344a3780SDimitry Andric return FindLineEntryIndexByFileIndexImpl<uint32_t>(
312f034231aSEd Maste
313344a3780SDimitry Andric start_idx, file_idx, src_location_spec, line_entry_ptr, file_idx_matcher);
314f034231aSEd Maste }
315f034231aSEd Maste
FindLineEntryIndexByFileIndex(uint32_t start_idx,const std::vector<uint32_t> & file_idx,const SourceLocationSpec & src_location_spec,LineEntry * line_entry_ptr)316344a3780SDimitry Andric uint32_t LineTable::FindLineEntryIndexByFileIndex(
317344a3780SDimitry Andric uint32_t start_idx, const std::vector<uint32_t> &file_idx,
318344a3780SDimitry Andric const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr) {
319344a3780SDimitry Andric auto file_idx_matcher = [](const std::vector<uint32_t> &file_indexes,
320344a3780SDimitry Andric uint16_t entry_file_idx) {
321344a3780SDimitry Andric return llvm::is_contained(file_indexes, entry_file_idx);
322344a3780SDimitry Andric };
323f034231aSEd Maste
324344a3780SDimitry Andric return FindLineEntryIndexByFileIndexImpl<std::vector<uint32_t>>(
325344a3780SDimitry Andric start_idx, file_idx, src_location_spec, line_entry_ptr, file_idx_matcher);
326f034231aSEd Maste }
327f034231aSEd Maste
FindLineEntriesForFileIndex(uint32_t file_idx,bool append,SymbolContextList & sc_list)3287fa27ce4SDimitry Andric size_t LineTable::FindLineEntriesForFileIndex(uint32_t file_idx, bool append,
32914f1b3e8SDimitry Andric SymbolContextList &sc_list) {
330f034231aSEd Maste
331f034231aSEd Maste if (!append)
332f034231aSEd Maste sc_list.Clear();
333f034231aSEd Maste
334f034231aSEd Maste size_t num_added = 0;
335f034231aSEd Maste const size_t count = m_entries.size();
33614f1b3e8SDimitry Andric if (count > 0) {
337f034231aSEd Maste SymbolContext sc(m_comp_unit);
338f034231aSEd Maste
33914f1b3e8SDimitry Andric for (size_t idx = 0; idx < count; ++idx) {
340f73363f1SDimitry Andric // Skip line table rows that terminate the previous row
341f73363f1SDimitry Andric // (is_terminal_entry is non-zero)
342f034231aSEd Maste if (m_entries[idx].is_terminal_entry)
343f034231aSEd Maste continue;
344f034231aSEd Maste
34514f1b3e8SDimitry Andric if (m_entries[idx].file_idx == file_idx) {
34614f1b3e8SDimitry Andric if (ConvertEntryAtIndexToLineEntry(idx, sc.line_entry)) {
347f034231aSEd Maste ++num_added;
348f034231aSEd Maste sc_list.Append(sc);
349f034231aSEd Maste }
350f034231aSEd Maste }
351f034231aSEd Maste }
352f034231aSEd Maste }
353f034231aSEd Maste return num_added;
354f034231aSEd Maste }
355f034231aSEd Maste
Dump(Stream * s,Target * target,Address::DumpStyle style,Address::DumpStyle fallback_style,bool show_line_ranges)35614f1b3e8SDimitry Andric void LineTable::Dump(Stream *s, Target *target, Address::DumpStyle style,
35714f1b3e8SDimitry Andric Address::DumpStyle fallback_style, bool show_line_ranges) {
358f034231aSEd Maste const size_t count = m_entries.size();
359f034231aSEd Maste LineEntry line_entry;
3604df029ccSDimitry Andric SupportFileSP prev_file;
36114f1b3e8SDimitry Andric for (size_t idx = 0; idx < count; ++idx) {
362f034231aSEd Maste ConvertEntryAtIndexToLineEntry(idx, line_entry);
363ac9a064cSDimitry Andric line_entry.Dump(s, target, !prev_file->Equal(*line_entry.original_file_sp),
3644df029ccSDimitry Andric style, fallback_style, show_line_ranges);
365f034231aSEd Maste s->EOL();
3664df029ccSDimitry Andric prev_file = line_entry.original_file_sp;
367f034231aSEd Maste }
368f034231aSEd Maste }
369f034231aSEd Maste
GetDescription(Stream * s,Target * target,DescriptionLevel level)37014f1b3e8SDimitry Andric void LineTable::GetDescription(Stream *s, Target *target,
37114f1b3e8SDimitry Andric DescriptionLevel level) {
372f034231aSEd Maste const size_t count = m_entries.size();
373f034231aSEd Maste LineEntry line_entry;
37414f1b3e8SDimitry Andric for (size_t idx = 0; idx < count; ++idx) {
375f034231aSEd Maste ConvertEntryAtIndexToLineEntry(idx, line_entry);
376f034231aSEd Maste line_entry.GetDescription(s, level, m_comp_unit, target, true);
377f034231aSEd Maste s->EOL();
378f034231aSEd Maste }
379f034231aSEd Maste }
380f034231aSEd Maste
GetContiguousFileAddressRanges(FileAddressRanges & file_ranges,bool append)38114f1b3e8SDimitry Andric size_t LineTable::GetContiguousFileAddressRanges(FileAddressRanges &file_ranges,
38214f1b3e8SDimitry Andric bool append) {
383f034231aSEd Maste if (!append)
384f034231aSEd Maste file_ranges.Clear();
385f034231aSEd Maste const size_t initial_count = file_ranges.GetSize();
386f034231aSEd Maste
387f034231aSEd Maste const size_t count = m_entries.size();
388f034231aSEd Maste LineEntry line_entry;
389f034231aSEd Maste FileAddressRanges::Entry range(LLDB_INVALID_ADDRESS, 0);
39014f1b3e8SDimitry Andric for (size_t idx = 0; idx < count; ++idx) {
391f034231aSEd Maste const Entry &entry = m_entries[idx];
392f034231aSEd Maste
39314f1b3e8SDimitry Andric if (entry.is_terminal_entry) {
39414f1b3e8SDimitry Andric if (range.GetRangeBase() != LLDB_INVALID_ADDRESS) {
395f034231aSEd Maste range.SetRangeEnd(entry.file_addr);
396f034231aSEd Maste file_ranges.Append(range);
397f034231aSEd Maste range.Clear(LLDB_INVALID_ADDRESS);
398f034231aSEd Maste }
39914f1b3e8SDimitry Andric } else if (range.GetRangeBase() == LLDB_INVALID_ADDRESS) {
400f034231aSEd Maste range.SetRangeBase(entry.file_addr);
401f034231aSEd Maste }
402f034231aSEd Maste }
403f034231aSEd Maste return file_ranges.GetSize() - initial_count;
404f034231aSEd Maste }
405f034231aSEd Maste
LinkLineTable(const FileRangeMap & file_range_map)40614f1b3e8SDimitry Andric LineTable *LineTable::LinkLineTable(const FileRangeMap &file_range_map) {
4075f29bb8aSDimitry Andric std::unique_ptr<LineTable> line_table_up(new LineTable(m_comp_unit));
408f034231aSEd Maste LineSequenceImpl sequence;
409f034231aSEd Maste const size_t count = m_entries.size();
410f034231aSEd Maste LineEntry line_entry;
4110cac4ca3SEd Maste const FileRangeMap::Entry *file_range_entry = nullptr;
4120cac4ca3SEd Maste const FileRangeMap::Entry *prev_file_range_entry = nullptr;
413f034231aSEd Maste lldb::addr_t prev_file_addr = LLDB_INVALID_ADDRESS;
414f034231aSEd Maste bool prev_entry_was_linked = false;
415f034231aSEd Maste bool range_changed = false;
41614f1b3e8SDimitry Andric for (size_t idx = 0; idx < count; ++idx) {
417f034231aSEd Maste const Entry &entry = m_entries[idx];
418f034231aSEd Maste
419f034231aSEd Maste const bool end_sequence = entry.is_terminal_entry;
42014f1b3e8SDimitry Andric const lldb::addr_t lookup_file_addr =
42114f1b3e8SDimitry Andric entry.file_addr - (end_sequence ? 1 : 0);
42214f1b3e8SDimitry Andric if (file_range_entry == nullptr ||
42314f1b3e8SDimitry Andric !file_range_entry->Contains(lookup_file_addr)) {
424f034231aSEd Maste prev_file_range_entry = file_range_entry;
425f034231aSEd Maste file_range_entry = file_range_map.FindEntryThatContains(lookup_file_addr);
426f034231aSEd Maste range_changed = true;
427f034231aSEd Maste }
428f034231aSEd Maste
429f034231aSEd Maste lldb::addr_t prev_end_entry_linked_file_addr = LLDB_INVALID_ADDRESS;
430f034231aSEd Maste lldb::addr_t entry_linked_file_addr = LLDB_INVALID_ADDRESS;
431f034231aSEd Maste
432f034231aSEd Maste bool terminate_previous_entry = false;
43314f1b3e8SDimitry Andric if (file_range_entry) {
43414f1b3e8SDimitry Andric entry_linked_file_addr = entry.file_addr -
43514f1b3e8SDimitry Andric file_range_entry->GetRangeBase() +
43614f1b3e8SDimitry Andric file_range_entry->data;
437f034231aSEd Maste // Determine if we need to terminate the previous entry when the previous
438e81d9d49SDimitry Andric // entry was not contiguous with this one after being linked.
43914f1b3e8SDimitry Andric if (range_changed && prev_file_range_entry) {
44014f1b3e8SDimitry Andric prev_end_entry_linked_file_addr =
44114f1b3e8SDimitry Andric std::min<lldb::addr_t>(entry.file_addr,
44214f1b3e8SDimitry Andric prev_file_range_entry->GetRangeEnd()) -
44314f1b3e8SDimitry Andric prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
444f034231aSEd Maste if (prev_end_entry_linked_file_addr != entry_linked_file_addr)
445f034231aSEd Maste terminate_previous_entry = prev_entry_was_linked;
446f034231aSEd Maste }
44714f1b3e8SDimitry Andric } else if (prev_entry_was_linked) {
448f73363f1SDimitry Andric // This entry doesn't have a remapping and it needs to be removed. Watch
449f73363f1SDimitry Andric // out in case we need to terminate a previous entry needs to be
450f73363f1SDimitry Andric // terminated now that one line entry in a sequence is not longer valid.
4515e95aa85SEd Maste if (!sequence.m_entries.empty() &&
45214f1b3e8SDimitry Andric !sequence.m_entries.back().is_terminal_entry) {
453f034231aSEd Maste terminate_previous_entry = true;
454f034231aSEd Maste }
455f034231aSEd Maste }
456f034231aSEd Maste
45714f1b3e8SDimitry Andric if (terminate_previous_entry && !sequence.m_entries.empty()) {
458f034231aSEd Maste assert(prev_file_addr != LLDB_INVALID_ADDRESS);
45974a628f7SDimitry Andric UNUSED_IF_ASSERT_DISABLED(prev_file_addr);
460f034231aSEd Maste sequence.m_entries.push_back(sequence.m_entries.back());
461f034231aSEd Maste if (prev_end_entry_linked_file_addr == LLDB_INVALID_ADDRESS)
46214f1b3e8SDimitry Andric prev_end_entry_linked_file_addr =
46314f1b3e8SDimitry Andric std::min<lldb::addr_t>(entry.file_addr,
46414f1b3e8SDimitry Andric prev_file_range_entry->GetRangeEnd()) -
46514f1b3e8SDimitry Andric prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
466f034231aSEd Maste sequence.m_entries.back().file_addr = prev_end_entry_linked_file_addr;
467f034231aSEd Maste sequence.m_entries.back().is_terminal_entry = true;
468f034231aSEd Maste
469f034231aSEd Maste // Append the sequence since we just terminated the previous one
4705f29bb8aSDimitry Andric line_table_up->InsertSequence(&sequence);
471f034231aSEd Maste sequence.Clear();
472f034231aSEd Maste }
473f034231aSEd Maste
474f034231aSEd Maste // Now link the current entry
47514f1b3e8SDimitry Andric if (file_range_entry) {
47614f1b3e8SDimitry Andric // This entry has an address remapping and it needs to have its address
47714f1b3e8SDimitry Andric // relinked
478f034231aSEd Maste sequence.m_entries.push_back(entry);
479f034231aSEd Maste sequence.m_entries.back().file_addr = entry_linked_file_addr;
480f034231aSEd Maste }
481f034231aSEd Maste
482f034231aSEd Maste // If we have items in the sequence and the last entry is a terminal entry,
483f034231aSEd Maste // insert this sequence into our new line table.
48414f1b3e8SDimitry Andric if (!sequence.m_entries.empty() &&
48514f1b3e8SDimitry Andric sequence.m_entries.back().is_terminal_entry) {
4865f29bb8aSDimitry Andric line_table_up->InsertSequence(&sequence);
487f034231aSEd Maste sequence.Clear();
488f034231aSEd Maste prev_entry_was_linked = false;
48914f1b3e8SDimitry Andric } else {
4900cac4ca3SEd Maste prev_entry_was_linked = file_range_entry != nullptr;
491f034231aSEd Maste }
492f034231aSEd Maste prev_file_addr = entry.file_addr;
493f034231aSEd Maste range_changed = false;
494f034231aSEd Maste }
4955f29bb8aSDimitry Andric if (line_table_up->m_entries.empty())
4960cac4ca3SEd Maste return nullptr;
4975f29bb8aSDimitry Andric return line_table_up.release();
498f034231aSEd Maste }
499