180814287SRaphael Isemann //===-- LineTable.cpp -----------------------------------------------------===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner 
9b9c1b51eSKate Stone #include "lldb/Symbol/LineTable.h"
1030fdc8d8SChris Lattner #include "lldb/Core/Address.h"
119422dd64SGreg Clayton #include "lldb/Core/Module.h"
1230fdc8d8SChris Lattner #include "lldb/Core/Section.h"
1330fdc8d8SChris Lattner #include "lldb/Symbol/CompileUnit.h"
14bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
1548862d45SEli Friedman #include <algorithm>
1630fdc8d8SChris Lattner 
1730fdc8d8SChris Lattner using namespace lldb;
1830fdc8d8SChris Lattner using namespace lldb_private;
1930fdc8d8SChris Lattner 
2030fdc8d8SChris Lattner // LineTable constructor
LineTable(CompileUnit * comp_unit)21b9c1b51eSKate Stone LineTable::LineTable(CompileUnit *comp_unit)
22b9c1b51eSKate Stone     : m_comp_unit(comp_unit), m_entries() {}
2330fdc8d8SChris Lattner 
LineTable(CompileUnit * comp_unit,std::vector<std::unique_ptr<LineSequence>> && sequences)2418a96fd5SPavel Labath LineTable::LineTable(CompileUnit *comp_unit,
2518a96fd5SPavel Labath                      std::vector<std::unique_ptr<LineSequence>> &&sequences)
2639f13354SUnnar Freyr Erlendsson     : m_comp_unit(comp_unit), m_entries() {
2739f13354SUnnar Freyr Erlendsson   LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
283f9b6b27SPavel Labath   llvm::stable_sort(sequences, less_than_bp);
2918a96fd5SPavel Labath   for (const auto &sequence : sequences) {
3018a96fd5SPavel Labath     LineSequenceImpl *seq = static_cast<LineSequenceImpl *>(sequence.get());
3139f13354SUnnar Freyr Erlendsson     m_entries.insert(m_entries.end(), seq->m_entries.begin(),
3239f13354SUnnar Freyr Erlendsson                      seq->m_entries.end());
3339f13354SUnnar Freyr Erlendsson   }
3439f13354SUnnar Freyr Erlendsson }
3539f13354SUnnar Freyr Erlendsson 
3630fdc8d8SChris Lattner // Destructor
37*fd2433e1SJonas Devlieghere LineTable::~LineTable() = default;
3830fdc8d8SChris Lattner 
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)39b9c1b51eSKate Stone void LineTable::InsertLineEntry(lldb::addr_t file_addr, uint32_t line,
40b9c1b51eSKate Stone                                 uint16_t column, uint16_t file_idx,
4130fdc8d8SChris Lattner                                 bool is_start_of_statement,
4230fdc8d8SChris Lattner                                 bool is_start_of_basic_block,
43b9c1b51eSKate Stone                                 bool is_prologue_end, bool is_epilogue_begin,
44b9c1b51eSKate Stone                                 bool is_terminal_entry) {
45b9c1b51eSKate Stone   Entry entry(file_addr, line, column, file_idx, is_start_of_statement,
46b9c1b51eSKate Stone               is_start_of_basic_block, is_prologue_end, is_epilogue_begin,
47b9c1b51eSKate Stone               is_terminal_entry);
4830fdc8d8SChris Lattner 
4930fdc8d8SChris Lattner   LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
50b9c1b51eSKate Stone   entry_collection::iterator pos =
51159641d7SPavel Labath       llvm::upper_bound(m_entries, entry, less_than_bp);
5230fdc8d8SChris Lattner 
5330fdc8d8SChris Lattner   //  Stream s(stdout);
5430fdc8d8SChris Lattner   //  s << "\n\nBefore:\n";
5530fdc8d8SChris Lattner   //  Dump (&s, Address::DumpStyleFileAddress);
5630fdc8d8SChris Lattner   m_entries.insert(pos, entry);
5730fdc8d8SChris Lattner   //  s << "After:\n";
5830fdc8d8SChris Lattner   //  Dump (&s, Address::DumpStyleFileAddress);
5930fdc8d8SChris Lattner }
6030fdc8d8SChris Lattner 
61*fd2433e1SJonas Devlieghere LineSequence::LineSequence() = default;
62c740150fSAndrew Kaylor 
Clear()63b9c1b51eSKate Stone void LineTable::LineSequenceImpl::Clear() { m_entries.clear(); }
64c740150fSAndrew Kaylor 
CreateLineSequenceContainer()6518a96fd5SPavel Labath std::unique_ptr<LineSequence> LineTable::CreateLineSequenceContainer() {
6618a96fd5SPavel Labath   return std::make_unique<LineTable::LineSequenceImpl>();
67c740150fSAndrew Kaylor }
68c740150fSAndrew Kaylor 
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)69b9c1b51eSKate Stone void LineTable::AppendLineEntryToSequence(
70b9c1b51eSKate Stone     LineSequence *sequence, lldb::addr_t file_addr, uint32_t line,
71b9c1b51eSKate Stone     uint16_t column, uint16_t file_idx, bool is_start_of_statement,
72b9c1b51eSKate Stone     bool is_start_of_basic_block, bool is_prologue_end, bool is_epilogue_begin,
73b9c1b51eSKate Stone     bool is_terminal_entry) {
74d4612ad0SEd Maste   assert(sequence != nullptr);
75c740150fSAndrew Kaylor   LineSequenceImpl *seq = reinterpret_cast<LineSequenceImpl *>(sequence);
76b9c1b51eSKate Stone   Entry entry(file_addr, line, column, file_idx, is_start_of_statement,
77b9c1b51eSKate Stone               is_start_of_basic_block, is_prologue_end, is_epilogue_begin,
78b9c1b51eSKate Stone               is_terminal_entry);
799e42e92eSGreg Clayton   entry_collection &entries = seq->m_entries;
80b9c1b51eSKate Stone   // Replace the last entry if the address is the same, otherwise append it. If
8105097246SAdrian Prantl   // we have multiple line entries at the same address, this indicates illegal
8205097246SAdrian Prantl   // DWARF so this "fixes" the line table to be correct. If not fixed this can
8305097246SAdrian Prantl   // cause a line entry's address that when resolved back to a symbol context,
8405097246SAdrian Prantl   // could resolve to a different line entry. We really want a
85b9c1b51eSKate Stone   // 1 to 1 mapping
8605097246SAdrian Prantl   // here to avoid these kinds of inconsistencies. We will need tor revisit
8705097246SAdrian Prantl   // this if the DWARF line tables are updated to allow multiple entries at the
8805097246SAdrian Prantl   // same address legally.
89b9c1b51eSKate Stone   if (!entries.empty() && entries.back().file_addr == file_addr) {
90b9c1b51eSKate Stone     // GCC don't use the is_prologue_end flag to mark the first instruction
91b9c1b51eSKate Stone     // after the prologue.
92b9c1b51eSKate Stone     // Instead of it it is issuing a line table entry for the first instruction
9305097246SAdrian Prantl     // of the prologue and one for the first instruction after the prologue. If
9405097246SAdrian Prantl     // the size of the prologue is 0 instruction then the 2 line entry will
9505097246SAdrian Prantl     // have the same file address. Removing it will remove our ability to
9605097246SAdrian Prantl     // properly detect the location of the end of prologe so we set the
9705097246SAdrian Prantl     // prologue_end flag to preserve this information (setting the prologue_end
9805097246SAdrian Prantl     // flag for an entry what is after the prologue end don't have any effect)
996127f033STamas Berghammer     entry.is_prologue_end = entry.file_idx == entries.back().file_idx;
1009e42e92eSGreg Clayton     entries.back() = entry;
101b9c1b51eSKate Stone   } else
1029e42e92eSGreg Clayton     entries.push_back(entry);
103c740150fSAndrew Kaylor }
104c740150fSAndrew Kaylor 
InsertSequence(LineSequence * sequence)105b9c1b51eSKate Stone void LineTable::InsertSequence(LineSequence *sequence) {
106d4612ad0SEd Maste   assert(sequence != nullptr);
107c740150fSAndrew Kaylor   LineSequenceImpl *seq = reinterpret_cast<LineSequenceImpl *>(sequence);
1089422dd64SGreg Clayton   if (seq->m_entries.empty())
109c740150fSAndrew Kaylor     return;
1109422dd64SGreg Clayton   Entry &entry = seq->m_entries.front();
111c740150fSAndrew Kaylor 
112c740150fSAndrew Kaylor   // If the first entry address in this sequence is greater than or equal to
113c740150fSAndrew Kaylor   // the address of the last item in our entry collection, just append.
114b9c1b51eSKate Stone   if (m_entries.empty() ||
115b9c1b51eSKate Stone       !Entry::EntryAddressLessThan(entry, m_entries.back())) {
116b9c1b51eSKate Stone     m_entries.insert(m_entries.end(), seq->m_entries.begin(),
1179422dd64SGreg Clayton                      seq->m_entries.end());
118c740150fSAndrew Kaylor     return;
119c740150fSAndrew Kaylor   }
120c740150fSAndrew Kaylor 
121c740150fSAndrew Kaylor   // Otherwise, find where this belongs in the collection
122c740150fSAndrew Kaylor   entry_collection::iterator begin_pos = m_entries.begin();
123c740150fSAndrew Kaylor   entry_collection::iterator end_pos = m_entries.end();
124c740150fSAndrew Kaylor   LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
125b9c1b51eSKate Stone   entry_collection::iterator pos =
126b9c1b51eSKate Stone       upper_bound(begin_pos, end_pos, entry, less_than_bp);
127506ecac0SStephane Sezer 
128506ecac0SStephane Sezer   // We should never insert a sequence in the middle of another sequence
129506ecac0SStephane Sezer   if (pos != begin_pos) {
130506ecac0SStephane Sezer     while (pos < end_pos && !((pos - 1)->is_terminal_entry))
131506ecac0SStephane Sezer       pos++;
132506ecac0SStephane Sezer   }
133506ecac0SStephane Sezer 
13428f7466fSAdrian Prantl #ifndef NDEBUG
135c740150fSAndrew Kaylor   // If we aren't inserting at the beginning, the previous entry should
136c740150fSAndrew Kaylor   // terminate a sequence.
137b9c1b51eSKate Stone   if (pos != begin_pos) {
138c740150fSAndrew Kaylor     entry_collection::iterator prev_pos = pos - 1;
139c740150fSAndrew Kaylor     assert(prev_pos->is_terminal_entry);
140c740150fSAndrew Kaylor   }
141c740150fSAndrew Kaylor #endif
1429422dd64SGreg Clayton   m_entries.insert(pos, seq->m_entries.begin(), seq->m_entries.end());
143c740150fSAndrew Kaylor }
144c740150fSAndrew Kaylor 
LessThanBinaryPredicate(LineTable * line_table)145b9c1b51eSKate Stone LineTable::Entry::LessThanBinaryPredicate::LessThanBinaryPredicate(
146b9c1b51eSKate Stone     LineTable *line_table)
147b9c1b51eSKate Stone     : m_line_table(line_table) {}
14830fdc8d8SChris Lattner 
149b9c1b51eSKate Stone bool LineTable::Entry::LessThanBinaryPredicate::
operator ()(const LineTable::Entry & a,const LineTable::Entry & b) const150b9c1b51eSKate Stone operator()(const LineTable::Entry &a, const LineTable::Entry &b) const {
151b9c1b51eSKate Stone #define LT_COMPARE(a, b)                                                       \
152b9c1b51eSKate Stone   if (a != b)                                                                  \
153b9c1b51eSKate Stone   return a < b
1549422dd64SGreg Clayton   LT_COMPARE(a.file_addr, b.file_addr);
155322654a7SGreg Clayton   // b and a reversed on purpose below.
156322654a7SGreg Clayton   LT_COMPARE(b.is_terminal_entry, a.is_terminal_entry);
15730fdc8d8SChris Lattner   LT_COMPARE(a.line, b.line);
15830fdc8d8SChris Lattner   LT_COMPARE(a.column, b.column);
15930fdc8d8SChris Lattner   LT_COMPARE(a.is_start_of_statement, b.is_start_of_statement);
16030fdc8d8SChris Lattner   LT_COMPARE(a.is_start_of_basic_block, b.is_start_of_basic_block);
16130fdc8d8SChris Lattner   // b and a reversed on purpose below.
16230fdc8d8SChris Lattner   LT_COMPARE(b.is_prologue_end, a.is_prologue_end);
16330fdc8d8SChris Lattner   LT_COMPARE(a.is_epilogue_begin, b.is_epilogue_begin);
16430fdc8d8SChris Lattner   LT_COMPARE(a.file_idx, b.file_idx);
16530fdc8d8SChris Lattner   return false;
16648862d45SEli Friedman #undef LT_COMPARE
16730fdc8d8SChris Lattner }
16830fdc8d8SChris Lattner 
16939f13354SUnnar Freyr Erlendsson bool LineTable::Entry::LessThanBinaryPredicate::
operator ()(const std::unique_ptr<LineSequence> & sequence_a,const std::unique_ptr<LineSequence> & sequence_b) const17018a96fd5SPavel Labath operator()(const std::unique_ptr<LineSequence> &sequence_a,
17118a96fd5SPavel Labath            const std::unique_ptr<LineSequence> &sequence_b) const {
17218a96fd5SPavel Labath   auto *seq_a = static_cast<const LineSequenceImpl *>(sequence_a.get());
17318a96fd5SPavel Labath   auto *seq_b = static_cast<const LineSequenceImpl *>(sequence_b.get());
17439f13354SUnnar Freyr Erlendsson   return (*this)(seq_a->m_entries.front(), seq_b->m_entries.front());
17539f13354SUnnar Freyr Erlendsson }
17639f13354SUnnar Freyr Erlendsson 
GetSize() const177b9c1b51eSKate Stone uint32_t LineTable::GetSize() const { return m_entries.size(); }
17830fdc8d8SChris Lattner 
GetLineEntryAtIndex(uint32_t idx,LineEntry & line_entry)179b9c1b51eSKate Stone bool LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry &line_entry) {
180b9c1b51eSKate Stone   if (idx < m_entries.size()) {
18130fdc8d8SChris Lattner     ConvertEntryAtIndexToLineEntry(idx, line_entry);
18230fdc8d8SChris Lattner     return true;
18330fdc8d8SChris Lattner   }
18430fdc8d8SChris Lattner   line_entry.Clear();
18530fdc8d8SChris Lattner   return false;
18630fdc8d8SChris Lattner }
18730fdc8d8SChris Lattner 
FindLineEntryByAddress(const Address & so_addr,LineEntry & line_entry,uint32_t * index_ptr)188b9c1b51eSKate Stone bool LineTable::FindLineEntryByAddress(const Address &so_addr,
189b9c1b51eSKate Stone                                        LineEntry &line_entry,
190b9c1b51eSKate Stone                                        uint32_t *index_ptr) {
191d4612ad0SEd Maste   if (index_ptr != nullptr)
19230fdc8d8SChris Lattner     *index_ptr = UINT32_MAX;
19330fdc8d8SChris Lattner 
19430fdc8d8SChris Lattner   bool success = false;
1959422dd64SGreg Clayton 
196b9c1b51eSKate Stone   if (so_addr.GetModule().get() == m_comp_unit->GetModule().get()) {
19730fdc8d8SChris Lattner     Entry search_entry;
1989422dd64SGreg Clayton     search_entry.file_addr = so_addr.GetFileAddress();
199b9c1b51eSKate Stone     if (search_entry.file_addr != LLDB_INVALID_ADDRESS) {
20030fdc8d8SChris Lattner       entry_collection::const_iterator begin_pos = m_entries.begin();
20130fdc8d8SChris Lattner       entry_collection::const_iterator end_pos = m_entries.end();
202b9c1b51eSKate Stone       entry_collection::const_iterator pos = lower_bound(
203b9c1b51eSKate Stone           begin_pos, end_pos, search_entry, Entry::EntryAddressLessThan);
204b9c1b51eSKate Stone       if (pos != end_pos) {
205b9c1b51eSKate Stone         if (pos != begin_pos) {
2069422dd64SGreg Clayton           if (pos->file_addr != search_entry.file_addr)
20730fdc8d8SChris Lattner             --pos;
208b9c1b51eSKate Stone           else if (pos->file_addr == search_entry.file_addr) {
20905097246SAdrian Prantl             // If this is a termination entry, it shouldn't match since entries
21005097246SAdrian Prantl             // with the "is_terminal_entry" member set to true are termination
21105097246SAdrian Prantl             // entries that define the range for the previous entry.
212b9c1b51eSKate Stone             if (pos->is_terminal_entry) {
21305097246SAdrian Prantl               // The matching entry is a terminal entry, so we skip ahead to
21405097246SAdrian Prantl               // the next entry to see if there is another entry following this
21505097246SAdrian Prantl               // one whose section/offset matches.
216364f1167SGreg Clayton               ++pos;
217b9c1b51eSKate Stone               if (pos != end_pos) {
2189422dd64SGreg Clayton                 if (pos->file_addr != search_entry.file_addr)
219364f1167SGreg Clayton                   pos = end_pos;
220364f1167SGreg Clayton               }
221364f1167SGreg Clayton             }
222364f1167SGreg Clayton 
223b9c1b51eSKate Stone             if (pos != end_pos) {
22405097246SAdrian Prantl               // While in the same section/offset backup to find the first line
22505097246SAdrian Prantl               // entry that matches the address in case there are multiple
226b9c1b51eSKate Stone               while (pos != begin_pos) {
22730fdc8d8SChris Lattner                 entry_collection::const_iterator prev_pos = pos - 1;
2289422dd64SGreg Clayton                 if (prev_pos->file_addr == search_entry.file_addr &&
229364f1167SGreg Clayton                     prev_pos->is_terminal_entry == false)
23030fdc8d8SChris Lattner                   --pos;
23130fdc8d8SChris Lattner                 else
23230fdc8d8SChris Lattner                   break;
23330fdc8d8SChris Lattner               }
23430fdc8d8SChris Lattner             }
235364f1167SGreg Clayton           }
23630fdc8d8SChris Lattner         }
2372dc4a3e9SJim Ingham         else
2382dc4a3e9SJim Ingham         {
23905097246SAdrian Prantl           // There might be code in the containing objfile before the first
24005097246SAdrian Prantl           // line table entry.  Make sure that does not get considered part of
24105097246SAdrian Prantl           // the first line table entry.
2422dc4a3e9SJim Ingham           if (pos->file_addr > so_addr.GetFileAddress())
2432dc4a3e9SJim Ingham             return false;
2442dc4a3e9SJim Ingham         }
245364f1167SGreg Clayton 
246b9c1b51eSKate Stone         // Make sure we have a valid match and that the match isn't a
24705097246SAdrian Prantl         // terminating entry for a previous line...
248b9c1b51eSKate Stone         if (pos != end_pos && pos->is_terminal_entry == false) {
24930fdc8d8SChris Lattner           uint32_t match_idx = std::distance(begin_pos, pos);
25030fdc8d8SChris Lattner           success = ConvertEntryAtIndexToLineEntry(match_idx, line_entry);
251d4612ad0SEd Maste           if (index_ptr != nullptr && success)
25230fdc8d8SChris Lattner             *index_ptr = match_idx;
25330fdc8d8SChris Lattner         }
25430fdc8d8SChris Lattner       }
255364f1167SGreg Clayton     }
2569422dd64SGreg Clayton   }
25730fdc8d8SChris Lattner   return success;
25830fdc8d8SChris Lattner }
25930fdc8d8SChris Lattner 
ConvertEntryAtIndexToLineEntry(uint32_t idx,LineEntry & line_entry)260b9c1b51eSKate Stone bool LineTable::ConvertEntryAtIndexToLineEntry(uint32_t idx,
261b9c1b51eSKate Stone                                                LineEntry &line_entry) {
262a3bdcdf7SPavel Labath   if (idx >= m_entries.size())
263a3bdcdf7SPavel Labath     return false;
264a3bdcdf7SPavel Labath 
26530fdc8d8SChris Lattner   const Entry &entry = m_entries[idx];
2669422dd64SGreg Clayton   ModuleSP module_sp(m_comp_unit->GetModule());
267a3bdcdf7SPavel Labath   if (!module_sp)
268a3bdcdf7SPavel Labath     return false;
269a3bdcdf7SPavel Labath 
270a3bdcdf7SPavel Labath   addr_t file_addr = entry.file_addr;
271a3bdcdf7SPavel Labath 
272a3bdcdf7SPavel Labath   // A terminal entry can point outside of a module or a section. Decrement the
273a3bdcdf7SPavel Labath   // address to ensure it resolves correctly.
274a3bdcdf7SPavel Labath   if (entry.is_terminal_entry)
275a3bdcdf7SPavel Labath     --file_addr;
276a3bdcdf7SPavel Labath 
277a3bdcdf7SPavel Labath   if (!module_sp->ResolveFileAddress(file_addr,
278a3bdcdf7SPavel Labath                                      line_entry.range.GetBaseAddress()))
279a3bdcdf7SPavel Labath     return false;
280a3bdcdf7SPavel Labath 
281a3bdcdf7SPavel Labath   // Now undo the decrement above.
282a3bdcdf7SPavel Labath   if (entry.is_terminal_entry)
283a3bdcdf7SPavel Labath     line_entry.range.GetBaseAddress().Slide(1);
284a3bdcdf7SPavel Labath 
28530fdc8d8SChris Lattner   if (!entry.is_terminal_entry && idx + 1 < m_entries.size())
286b9c1b51eSKate Stone     line_entry.range.SetByteSize(m_entries[idx + 1].file_addr -
287b9c1b51eSKate Stone                                  entry.file_addr);
28830fdc8d8SChris Lattner   else
28930fdc8d8SChris Lattner     line_entry.range.SetByteSize(0);
2909422dd64SGreg Clayton 
291b9c1b51eSKate Stone   line_entry.file =
292b9c1b51eSKate Stone       m_comp_unit->GetSupportFiles().GetFileSpecAtIndex(entry.file_idx);
293b9c1b51eSKate Stone   line_entry.original_file =
294b9c1b51eSKate Stone       m_comp_unit->GetSupportFiles().GetFileSpecAtIndex(entry.file_idx);
29530fdc8d8SChris Lattner   line_entry.line = entry.line;
29630fdc8d8SChris Lattner   line_entry.column = entry.column;
29730fdc8d8SChris Lattner   line_entry.is_start_of_statement = entry.is_start_of_statement;
29830fdc8d8SChris Lattner   line_entry.is_start_of_basic_block = entry.is_start_of_basic_block;
29930fdc8d8SChris Lattner   line_entry.is_prologue_end = entry.is_prologue_end;
30030fdc8d8SChris Lattner   line_entry.is_epilogue_begin = entry.is_epilogue_begin;
30130fdc8d8SChris Lattner   line_entry.is_terminal_entry = entry.is_terminal_entry;
30230fdc8d8SChris Lattner   return true;
30330fdc8d8SChris Lattner }
30430fdc8d8SChris Lattner 
FindLineEntryIndexByFileIndex(uint32_t start_idx,uint32_t file_idx,const SourceLocationSpec & src_location_spec,LineEntry * line_entry_ptr)305b9c1b51eSKate Stone uint32_t LineTable::FindLineEntryIndexByFileIndex(
30635ecfda0SMed Ismail Bennani     uint32_t start_idx, uint32_t file_idx,
3073e2ed744SMed Ismail Bennani     const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr) {
30835ecfda0SMed Ismail Bennani   auto file_idx_matcher = [](uint32_t file_index, uint16_t entry_file_idx) {
30935ecfda0SMed Ismail Bennani     return file_index == entry_file_idx;
31035ecfda0SMed Ismail Bennani   };
31135ecfda0SMed Ismail Bennani   return FindLineEntryIndexByFileIndexImpl<uint32_t>(
312fd269157SGreg Clayton 
31335ecfda0SMed Ismail Bennani       start_idx, file_idx, src_location_spec, line_entry_ptr, file_idx_matcher);
314fd269157SGreg Clayton }
315fd269157SGreg Clayton 
FindLineEntryIndexByFileIndex(uint32_t start_idx,const std::vector<uint32_t> & file_idx,const SourceLocationSpec & src_location_spec,LineEntry * line_entry_ptr)3163e2ed744SMed Ismail Bennani uint32_t LineTable::FindLineEntryIndexByFileIndex(
31735ecfda0SMed Ismail Bennani     uint32_t start_idx, const std::vector<uint32_t> &file_idx,
3183e2ed744SMed Ismail Bennani     const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr) {
31935ecfda0SMed Ismail Bennani   auto file_idx_matcher = [](const std::vector<uint32_t> &file_indexes,
32035ecfda0SMed Ismail Bennani                              uint16_t entry_file_idx) {
32135ecfda0SMed Ismail Bennani     return llvm::is_contained(file_indexes, entry_file_idx);
32235ecfda0SMed Ismail Bennani   };
32330fdc8d8SChris Lattner 
32435ecfda0SMed Ismail Bennani   return FindLineEntryIndexByFileIndexImpl<std::vector<uint32_t>>(
32535ecfda0SMed Ismail Bennani       start_idx, file_idx, src_location_spec, line_entry_ptr, file_idx_matcher);
32630fdc8d8SChris Lattner }
32730fdc8d8SChris Lattner 
FineLineEntriesForFileIndex(uint32_t file_idx,bool append,SymbolContextList & sc_list)328b9c1b51eSKate Stone size_t LineTable::FineLineEntriesForFileIndex(uint32_t file_idx, bool append,
329b9c1b51eSKate Stone                                               SymbolContextList &sc_list) {
330176761e5SGreg Clayton 
331176761e5SGreg Clayton   if (!append)
332176761e5SGreg Clayton     sc_list.Clear();
333176761e5SGreg Clayton 
334176761e5SGreg Clayton   size_t num_added = 0;
335176761e5SGreg Clayton   const size_t count = m_entries.size();
336b9c1b51eSKate Stone   if (count > 0) {
337176761e5SGreg Clayton     SymbolContext sc(m_comp_unit);
338176761e5SGreg Clayton 
339b9c1b51eSKate Stone     for (size_t idx = 0; idx < count; ++idx) {
34005097246SAdrian Prantl       // Skip line table rows that terminate the previous row
34105097246SAdrian Prantl       // (is_terminal_entry is non-zero)
342176761e5SGreg Clayton       if (m_entries[idx].is_terminal_entry)
343176761e5SGreg Clayton         continue;
344176761e5SGreg Clayton 
345b9c1b51eSKate Stone       if (m_entries[idx].file_idx == file_idx) {
346b9c1b51eSKate Stone         if (ConvertEntryAtIndexToLineEntry(idx, sc.line_entry)) {
347176761e5SGreg Clayton           ++num_added;
348176761e5SGreg Clayton           sc_list.Append(sc);
349176761e5SGreg Clayton         }
350176761e5SGreg Clayton       }
351176761e5SGreg Clayton     }
352176761e5SGreg Clayton   }
353176761e5SGreg Clayton   return num_added;
354176761e5SGreg Clayton }
355176761e5SGreg Clayton 
Dump(Stream * s,Target * target,Address::DumpStyle style,Address::DumpStyle fallback_style,bool show_line_ranges)356b9c1b51eSKate Stone void LineTable::Dump(Stream *s, Target *target, Address::DumpStyle style,
357b9c1b51eSKate Stone                      Address::DumpStyle fallback_style, bool show_line_ranges) {
35830fdc8d8SChris Lattner   const size_t count = m_entries.size();
35930fdc8d8SChris Lattner   LineEntry line_entry;
36030fdc8d8SChris Lattner   FileSpec prev_file;
361b9c1b51eSKate Stone   for (size_t idx = 0; idx < count; ++idx) {
36230fdc8d8SChris Lattner     ConvertEntryAtIndexToLineEntry(idx, line_entry);
363b9c1b51eSKate Stone     line_entry.Dump(s, target, prev_file != line_entry.original_file, style,
364b9c1b51eSKate Stone                     fallback_style, show_line_ranges);
36530fdc8d8SChris Lattner     s->EOL();
366911d5784STed Woodward     prev_file = line_entry.original_file;
36730fdc8d8SChris Lattner   }
36830fdc8d8SChris Lattner }
36930fdc8d8SChris Lattner 
GetDescription(Stream * s,Target * target,DescriptionLevel level)370b9c1b51eSKate Stone void LineTable::GetDescription(Stream *s, Target *target,
371b9c1b51eSKate Stone                                DescriptionLevel level) {
37230fdc8d8SChris Lattner   const size_t count = m_entries.size();
37330fdc8d8SChris Lattner   LineEntry line_entry;
374b9c1b51eSKate Stone   for (size_t idx = 0; idx < count; ++idx) {
37530fdc8d8SChris Lattner     ConvertEntryAtIndexToLineEntry(idx, line_entry);
376f5e56de0SGreg Clayton     line_entry.GetDescription(s, level, m_comp_unit, target, true);
37730fdc8d8SChris Lattner     s->EOL();
37830fdc8d8SChris Lattner   }
37930fdc8d8SChris Lattner }
38030fdc8d8SChris Lattner 
GetContiguousFileAddressRanges(FileAddressRanges & file_ranges,bool append)381b9c1b51eSKate Stone size_t LineTable::GetContiguousFileAddressRanges(FileAddressRanges &file_ranges,
382b9c1b51eSKate Stone                                                  bool append) {
3836ab80139SGreg Clayton   if (!append)
3846ab80139SGreg Clayton     file_ranges.Clear();
3856ab80139SGreg Clayton   const size_t initial_count = file_ranges.GetSize();
3866ab80139SGreg Clayton 
3876ab80139SGreg Clayton   const size_t count = m_entries.size();
3886ab80139SGreg Clayton   LineEntry line_entry;
3896ab80139SGreg Clayton   FileAddressRanges::Entry range(LLDB_INVALID_ADDRESS, 0);
390b9c1b51eSKate Stone   for (size_t idx = 0; idx < count; ++idx) {
3916ab80139SGreg Clayton     const Entry &entry = m_entries[idx];
3926ab80139SGreg Clayton 
393b9c1b51eSKate Stone     if (entry.is_terminal_entry) {
394b9c1b51eSKate Stone       if (range.GetRangeBase() != LLDB_INVALID_ADDRESS) {
3959422dd64SGreg Clayton         range.SetRangeEnd(entry.file_addr);
3966ab80139SGreg Clayton         file_ranges.Append(range);
3976ab80139SGreg Clayton         range.Clear(LLDB_INVALID_ADDRESS);
3986ab80139SGreg Clayton       }
399b9c1b51eSKate Stone     } else if (range.GetRangeBase() == LLDB_INVALID_ADDRESS) {
4009422dd64SGreg Clayton       range.SetRangeBase(entry.file_addr);
4016ab80139SGreg Clayton     }
4026ab80139SGreg Clayton   }
4036ab80139SGreg Clayton   return file_ranges.GetSize() - initial_count;
4046ab80139SGreg Clayton }
4056ab80139SGreg Clayton 
LinkLineTable(const FileRangeMap & file_range_map)406b9c1b51eSKate Stone LineTable *LineTable::LinkLineTable(const FileRangeMap &file_range_map) {
407d5b44036SJonas Devlieghere   std::unique_ptr<LineTable> line_table_up(new LineTable(m_comp_unit));
4089422dd64SGreg Clayton   LineSequenceImpl sequence;
4099422dd64SGreg Clayton   const size_t count = m_entries.size();
4109422dd64SGreg Clayton   LineEntry line_entry;
411d4612ad0SEd Maste   const FileRangeMap::Entry *file_range_entry = nullptr;
412d4612ad0SEd Maste   const FileRangeMap::Entry *prev_file_range_entry = nullptr;
4139422dd64SGreg Clayton   lldb::addr_t prev_file_addr = LLDB_INVALID_ADDRESS;
4149422dd64SGreg Clayton   bool prev_entry_was_linked = false;
415084fad6aSGreg Clayton   bool range_changed = false;
416b9c1b51eSKate Stone   for (size_t idx = 0; idx < count; ++idx) {
4179422dd64SGreg Clayton     const Entry &entry = m_entries[idx];
4189422dd64SGreg Clayton 
4199422dd64SGreg Clayton     const bool end_sequence = entry.is_terminal_entry;
420b9c1b51eSKate Stone     const lldb::addr_t lookup_file_addr =
421b9c1b51eSKate Stone         entry.file_addr - (end_sequence ? 1 : 0);
422b9c1b51eSKate Stone     if (file_range_entry == nullptr ||
423b9c1b51eSKate Stone         !file_range_entry->Contains(lookup_file_addr)) {
4249422dd64SGreg Clayton       prev_file_range_entry = file_range_entry;
4259422dd64SGreg Clayton       file_range_entry = file_range_map.FindEntryThatContains(lookup_file_addr);
426084fad6aSGreg Clayton       range_changed = true;
4279422dd64SGreg Clayton     }
4289422dd64SGreg Clayton 
429084fad6aSGreg Clayton     lldb::addr_t prev_end_entry_linked_file_addr = LLDB_INVALID_ADDRESS;
430084fad6aSGreg Clayton     lldb::addr_t entry_linked_file_addr = LLDB_INVALID_ADDRESS;
431084fad6aSGreg Clayton 
432084fad6aSGreg Clayton     bool terminate_previous_entry = false;
433b9c1b51eSKate Stone     if (file_range_entry) {
434b9c1b51eSKate Stone       entry_linked_file_addr = entry.file_addr -
435b9c1b51eSKate Stone                                file_range_entry->GetRangeBase() +
436b9c1b51eSKate Stone                                file_range_entry->data;
437084fad6aSGreg Clayton       // Determine if we need to terminate the previous entry when the previous
438e171da5cSBruce Mitchener       // entry was not contiguous with this one after being linked.
439b9c1b51eSKate Stone       if (range_changed && prev_file_range_entry) {
440b9c1b51eSKate Stone         prev_end_entry_linked_file_addr =
441b9c1b51eSKate Stone             std::min<lldb::addr_t>(entry.file_addr,
442b9c1b51eSKate Stone                                    prev_file_range_entry->GetRangeEnd()) -
443b9c1b51eSKate Stone             prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
444084fad6aSGreg Clayton         if (prev_end_entry_linked_file_addr != entry_linked_file_addr)
445617995c0SGreg Clayton           terminate_previous_entry = prev_entry_was_linked;
446084fad6aSGreg Clayton       }
447b9c1b51eSKate Stone     } else if (prev_entry_was_linked) {
44805097246SAdrian Prantl       // This entry doesn't have a remapping and it needs to be removed. Watch
44905097246SAdrian Prantl       // out in case we need to terminate a previous entry needs to be
45005097246SAdrian Prantl       // terminated now that one line entry in a sequence is not longer valid.
451cc8913ccSGreg Clayton       if (!sequence.m_entries.empty() &&
452b9c1b51eSKate Stone           !sequence.m_entries.back().is_terminal_entry) {
453084fad6aSGreg Clayton         terminate_previous_entry = true;
454084fad6aSGreg Clayton       }
455084fad6aSGreg Clayton     }
456084fad6aSGreg Clayton 
457b9c1b51eSKate Stone     if (terminate_previous_entry && !sequence.m_entries.empty()) {
4589422dd64SGreg Clayton       assert(prev_file_addr != LLDB_INVALID_ADDRESS);
459b1554311SHafiz Abid Qadeer       UNUSED_IF_ASSERT_DISABLED(prev_file_addr);
4609422dd64SGreg Clayton       sequence.m_entries.push_back(sequence.m_entries.back());
461084fad6aSGreg Clayton       if (prev_end_entry_linked_file_addr == LLDB_INVALID_ADDRESS)
462b9c1b51eSKate Stone         prev_end_entry_linked_file_addr =
463b9c1b51eSKate Stone             std::min<lldb::addr_t>(entry.file_addr,
464b9c1b51eSKate Stone                                    prev_file_range_entry->GetRangeEnd()) -
465b9c1b51eSKate Stone             prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
466084fad6aSGreg Clayton       sequence.m_entries.back().file_addr = prev_end_entry_linked_file_addr;
4679422dd64SGreg Clayton       sequence.m_entries.back().is_terminal_entry = true;
468084fad6aSGreg Clayton 
469084fad6aSGreg Clayton       // Append the sequence since we just terminated the previous one
470d5b44036SJonas Devlieghere       line_table_up->InsertSequence(&sequence);
471084fad6aSGreg Clayton       sequence.Clear();
4729422dd64SGreg Clayton     }
473084fad6aSGreg Clayton 
474084fad6aSGreg Clayton     // Now link the current entry
475b9c1b51eSKate Stone     if (file_range_entry) {
476b9c1b51eSKate Stone       // This entry has an address remapping and it needs to have its address
477b9c1b51eSKate Stone       // relinked
478084fad6aSGreg Clayton       sequence.m_entries.push_back(entry);
479084fad6aSGreg Clayton       sequence.m_entries.back().file_addr = entry_linked_file_addr;
4809422dd64SGreg Clayton     }
4819422dd64SGreg Clayton 
4829422dd64SGreg Clayton     // If we have items in the sequence and the last entry is a terminal entry,
4839422dd64SGreg Clayton     // insert this sequence into our new line table.
484b9c1b51eSKate Stone     if (!sequence.m_entries.empty() &&
485b9c1b51eSKate Stone         sequence.m_entries.back().is_terminal_entry) {
486d5b44036SJonas Devlieghere       line_table_up->InsertSequence(&sequence);
4879422dd64SGreg Clayton       sequence.Clear();
4889422dd64SGreg Clayton       prev_entry_was_linked = false;
489b9c1b51eSKate Stone     } else {
490d4612ad0SEd Maste       prev_entry_was_linked = file_range_entry != nullptr;
4919422dd64SGreg Clayton     }
492084fad6aSGreg Clayton     prev_file_addr = entry.file_addr;
493084fad6aSGreg Clayton     range_changed = false;
4949422dd64SGreg Clayton   }
495d5b44036SJonas Devlieghere   if (line_table_up->m_entries.empty())
496d4612ad0SEd Maste     return nullptr;
497d5b44036SJonas Devlieghere   return line_table_up.release();
4989422dd64SGreg Clayton }
499