xref: /src/contrib/llvm-project/lldb/source/Symbol/LineTable.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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