xref: /freebsd-src/contrib/llvm-project/lldb/source/Symbol/LineTable.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===-- LineTable.cpp -----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Symbol/LineTable.h"
100b57cec5SDimitry Andric #include "lldb/Core/Address.h"
110b57cec5SDimitry Andric #include "lldb/Core/Module.h"
120b57cec5SDimitry Andric #include "lldb/Core/Section.h"
130b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
140b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
150b57cec5SDimitry Andric #include <algorithm>
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric using namespace lldb;
180b57cec5SDimitry Andric using namespace lldb_private;
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric // LineTable constructor
210b57cec5SDimitry Andric LineTable::LineTable(CompileUnit *comp_unit)
220b57cec5SDimitry Andric     : m_comp_unit(comp_unit), m_entries() {}
230b57cec5SDimitry Andric 
245ffd83dbSDimitry Andric LineTable::LineTable(CompileUnit *comp_unit,
255ffd83dbSDimitry Andric                      std::vector<std::unique_ptr<LineSequence>> &&sequences)
265ffd83dbSDimitry Andric     : m_comp_unit(comp_unit), m_entries() {
275ffd83dbSDimitry Andric   LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
285ffd83dbSDimitry Andric   llvm::stable_sort(sequences, less_than_bp);
295ffd83dbSDimitry Andric   for (const auto &sequence : sequences) {
305ffd83dbSDimitry Andric     LineSequenceImpl *seq = static_cast<LineSequenceImpl *>(sequence.get());
315ffd83dbSDimitry Andric     m_entries.insert(m_entries.end(), seq->m_entries.begin(),
325ffd83dbSDimitry Andric                      seq->m_entries.end());
335ffd83dbSDimitry Andric   }
345ffd83dbSDimitry Andric }
355ffd83dbSDimitry Andric 
360b57cec5SDimitry Andric // Destructor
37fe6060f1SDimitry Andric LineTable::~LineTable() = default;
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric void LineTable::InsertLineEntry(lldb::addr_t file_addr, uint32_t line,
400b57cec5SDimitry Andric                                 uint16_t column, uint16_t file_idx,
410b57cec5SDimitry Andric                                 bool is_start_of_statement,
420b57cec5SDimitry Andric                                 bool is_start_of_basic_block,
430b57cec5SDimitry Andric                                 bool is_prologue_end, bool is_epilogue_begin,
440b57cec5SDimitry Andric                                 bool is_terminal_entry) {
450b57cec5SDimitry Andric   Entry entry(file_addr, line, column, file_idx, is_start_of_statement,
460b57cec5SDimitry Andric               is_start_of_basic_block, is_prologue_end, is_epilogue_begin,
470b57cec5SDimitry Andric               is_terminal_entry);
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
500b57cec5SDimitry Andric   entry_collection::iterator pos =
51480093f4SDimitry Andric       llvm::upper_bound(m_entries, entry, less_than_bp);
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   //  Stream s(stdout);
540b57cec5SDimitry Andric   //  s << "\n\nBefore:\n";
550b57cec5SDimitry Andric   //  Dump (&s, Address::DumpStyleFileAddress);
560b57cec5SDimitry Andric   m_entries.insert(pos, entry);
570b57cec5SDimitry Andric   //  s << "After:\n";
580b57cec5SDimitry Andric   //  Dump (&s, Address::DumpStyleFileAddress);
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric 
61fe6060f1SDimitry Andric LineSequence::LineSequence() = default;
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric void LineTable::LineSequenceImpl::Clear() { m_entries.clear(); }
640b57cec5SDimitry Andric 
655ffd83dbSDimitry Andric std::unique_ptr<LineSequence> LineTable::CreateLineSequenceContainer() {
665ffd83dbSDimitry Andric   return std::make_unique<LineTable::LineSequenceImpl>();
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric void LineTable::AppendLineEntryToSequence(
700b57cec5SDimitry Andric     LineSequence *sequence, lldb::addr_t file_addr, uint32_t line,
710b57cec5SDimitry Andric     uint16_t column, uint16_t file_idx, bool is_start_of_statement,
720b57cec5SDimitry Andric     bool is_start_of_basic_block, bool is_prologue_end, bool is_epilogue_begin,
730b57cec5SDimitry Andric     bool is_terminal_entry) {
740b57cec5SDimitry Andric   assert(sequence != nullptr);
750b57cec5SDimitry Andric   LineSequenceImpl *seq = reinterpret_cast<LineSequenceImpl *>(sequence);
760b57cec5SDimitry Andric   Entry entry(file_addr, line, column, file_idx, is_start_of_statement,
770b57cec5SDimitry Andric               is_start_of_basic_block, is_prologue_end, is_epilogue_begin,
780b57cec5SDimitry Andric               is_terminal_entry);
790b57cec5SDimitry Andric   entry_collection &entries = seq->m_entries;
800b57cec5SDimitry Andric   // Replace the last entry if the address is the same, otherwise append it. If
810b57cec5SDimitry Andric   // we have multiple line entries at the same address, this indicates illegal
820b57cec5SDimitry Andric   // DWARF so this "fixes" the line table to be correct. If not fixed this can
830b57cec5SDimitry Andric   // cause a line entry's address that when resolved back to a symbol context,
840b57cec5SDimitry Andric   // could resolve to a different line entry. We really want a
850b57cec5SDimitry Andric   // 1 to 1 mapping
860b57cec5SDimitry Andric   // here to avoid these kinds of inconsistencies. We will need tor revisit
870b57cec5SDimitry Andric   // this if the DWARF line tables are updated to allow multiple entries at the
880b57cec5SDimitry Andric   // same address legally.
890b57cec5SDimitry Andric   if (!entries.empty() && entries.back().file_addr == file_addr) {
900b57cec5SDimitry Andric     // GCC don't use the is_prologue_end flag to mark the first instruction
910b57cec5SDimitry Andric     // after the prologue.
925f757f3fSDimitry Andric     // Instead of it is issuing a line table entry for the first instruction
930b57cec5SDimitry Andric     // of the prologue and one for the first instruction after the prologue. If
940b57cec5SDimitry Andric     // the size of the prologue is 0 instruction then the 2 line entry will
950b57cec5SDimitry Andric     // have the same file address. Removing it will remove our ability to
960b57cec5SDimitry Andric     // properly detect the location of the end of prologe so we set the
970b57cec5SDimitry Andric     // prologue_end flag to preserve this information (setting the prologue_end
980b57cec5SDimitry Andric     // flag for an entry what is after the prologue end don't have any effect)
990b57cec5SDimitry Andric     entry.is_prologue_end = entry.file_idx == entries.back().file_idx;
1000b57cec5SDimitry Andric     entries.back() = entry;
1010b57cec5SDimitry Andric   } else
1020b57cec5SDimitry Andric     entries.push_back(entry);
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric void LineTable::InsertSequence(LineSequence *sequence) {
1060b57cec5SDimitry Andric   assert(sequence != nullptr);
1070b57cec5SDimitry Andric   LineSequenceImpl *seq = reinterpret_cast<LineSequenceImpl *>(sequence);
1080b57cec5SDimitry Andric   if (seq->m_entries.empty())
1090b57cec5SDimitry Andric     return;
1100b57cec5SDimitry Andric   Entry &entry = seq->m_entries.front();
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   // If the first entry address in this sequence is greater than or equal to
1130b57cec5SDimitry Andric   // the address of the last item in our entry collection, just append.
1140b57cec5SDimitry Andric   if (m_entries.empty() ||
1150b57cec5SDimitry Andric       !Entry::EntryAddressLessThan(entry, m_entries.back())) {
1160b57cec5SDimitry Andric     m_entries.insert(m_entries.end(), seq->m_entries.begin(),
1170b57cec5SDimitry Andric                      seq->m_entries.end());
1180b57cec5SDimitry Andric     return;
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   // Otherwise, find where this belongs in the collection
1220b57cec5SDimitry Andric   entry_collection::iterator begin_pos = m_entries.begin();
1230b57cec5SDimitry Andric   entry_collection::iterator end_pos = m_entries.end();
1240b57cec5SDimitry Andric   LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
1250b57cec5SDimitry Andric   entry_collection::iterator pos =
1260b57cec5SDimitry Andric       upper_bound(begin_pos, end_pos, entry, less_than_bp);
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   // We should never insert a sequence in the middle of another sequence
1290b57cec5SDimitry Andric   if (pos != begin_pos) {
1300b57cec5SDimitry Andric     while (pos < end_pos && !((pos - 1)->is_terminal_entry))
1310b57cec5SDimitry Andric       pos++;
1320b57cec5SDimitry Andric   }
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric #ifndef NDEBUG
1350b57cec5SDimitry Andric   // If we aren't inserting at the beginning, the previous entry should
1360b57cec5SDimitry Andric   // terminate a sequence.
1370b57cec5SDimitry Andric   if (pos != begin_pos) {
1380b57cec5SDimitry Andric     entry_collection::iterator prev_pos = pos - 1;
1390b57cec5SDimitry Andric     assert(prev_pos->is_terminal_entry);
1400b57cec5SDimitry Andric   }
1410b57cec5SDimitry Andric #endif
1420b57cec5SDimitry Andric   m_entries.insert(pos, seq->m_entries.begin(), seq->m_entries.end());
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric LineTable::Entry::LessThanBinaryPredicate::LessThanBinaryPredicate(
1460b57cec5SDimitry Andric     LineTable *line_table)
1470b57cec5SDimitry Andric     : m_line_table(line_table) {}
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric bool LineTable::Entry::LessThanBinaryPredicate::
1500b57cec5SDimitry Andric operator()(const LineTable::Entry &a, const LineTable::Entry &b) const {
1510b57cec5SDimitry Andric #define LT_COMPARE(a, b)                                                       \
1520b57cec5SDimitry Andric   if (a != b)                                                                  \
1530b57cec5SDimitry Andric   return a < b
1540b57cec5SDimitry Andric   LT_COMPARE(a.file_addr, b.file_addr);
1550b57cec5SDimitry Andric   // b and a reversed on purpose below.
1560b57cec5SDimitry Andric   LT_COMPARE(b.is_terminal_entry, a.is_terminal_entry);
1570b57cec5SDimitry Andric   LT_COMPARE(a.line, b.line);
1580b57cec5SDimitry Andric   LT_COMPARE(a.column, b.column);
1590b57cec5SDimitry Andric   LT_COMPARE(a.is_start_of_statement, b.is_start_of_statement);
1600b57cec5SDimitry Andric   LT_COMPARE(a.is_start_of_basic_block, b.is_start_of_basic_block);
1610b57cec5SDimitry Andric   // b and a reversed on purpose below.
1620b57cec5SDimitry Andric   LT_COMPARE(b.is_prologue_end, a.is_prologue_end);
1630b57cec5SDimitry Andric   LT_COMPARE(a.is_epilogue_begin, b.is_epilogue_begin);
1640b57cec5SDimitry Andric   LT_COMPARE(a.file_idx, b.file_idx);
1650b57cec5SDimitry Andric   return false;
1660b57cec5SDimitry Andric #undef LT_COMPARE
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric 
1695ffd83dbSDimitry Andric bool LineTable::Entry::LessThanBinaryPredicate::
1705ffd83dbSDimitry Andric operator()(const std::unique_ptr<LineSequence> &sequence_a,
1715ffd83dbSDimitry Andric            const std::unique_ptr<LineSequence> &sequence_b) const {
1725ffd83dbSDimitry Andric   auto *seq_a = static_cast<const LineSequenceImpl *>(sequence_a.get());
1735ffd83dbSDimitry Andric   auto *seq_b = static_cast<const LineSequenceImpl *>(sequence_b.get());
1745ffd83dbSDimitry Andric   return (*this)(seq_a->m_entries.front(), seq_b->m_entries.front());
1755ffd83dbSDimitry Andric }
1765ffd83dbSDimitry Andric 
1770b57cec5SDimitry Andric uint32_t LineTable::GetSize() const { return m_entries.size(); }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric bool LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry &line_entry) {
1800b57cec5SDimitry Andric   if (idx < m_entries.size()) {
1810b57cec5SDimitry Andric     ConvertEntryAtIndexToLineEntry(idx, line_entry);
1820b57cec5SDimitry Andric     return true;
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric   line_entry.Clear();
1850b57cec5SDimitry Andric   return false;
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric bool LineTable::FindLineEntryByAddress(const Address &so_addr,
1890b57cec5SDimitry Andric                                        LineEntry &line_entry,
1900b57cec5SDimitry Andric                                        uint32_t *index_ptr) {
1910b57cec5SDimitry Andric   if (index_ptr != nullptr)
1920b57cec5SDimitry Andric     *index_ptr = UINT32_MAX;
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   bool success = false;
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   if (so_addr.GetModule().get() == m_comp_unit->GetModule().get()) {
1970b57cec5SDimitry Andric     Entry search_entry;
1980b57cec5SDimitry Andric     search_entry.file_addr = so_addr.GetFileAddress();
1990b57cec5SDimitry Andric     if (search_entry.file_addr != LLDB_INVALID_ADDRESS) {
2000b57cec5SDimitry Andric       entry_collection::const_iterator begin_pos = m_entries.begin();
2010b57cec5SDimitry Andric       entry_collection::const_iterator end_pos = m_entries.end();
2020b57cec5SDimitry Andric       entry_collection::const_iterator pos = lower_bound(
2030b57cec5SDimitry Andric           begin_pos, end_pos, search_entry, Entry::EntryAddressLessThan);
2040b57cec5SDimitry Andric       if (pos != end_pos) {
2050b57cec5SDimitry Andric         if (pos != begin_pos) {
2060b57cec5SDimitry Andric           if (pos->file_addr != search_entry.file_addr)
2070b57cec5SDimitry Andric             --pos;
2080b57cec5SDimitry Andric           else if (pos->file_addr == search_entry.file_addr) {
2090b57cec5SDimitry Andric             // If this is a termination entry, it shouldn't match since entries
2100b57cec5SDimitry Andric             // with the "is_terminal_entry" member set to true are termination
2110b57cec5SDimitry Andric             // entries that define the range for the previous entry.
2120b57cec5SDimitry Andric             if (pos->is_terminal_entry) {
2130b57cec5SDimitry Andric               // The matching entry is a terminal entry, so we skip ahead to
2140b57cec5SDimitry Andric               // the next entry to see if there is another entry following this
2150b57cec5SDimitry Andric               // one whose section/offset matches.
2160b57cec5SDimitry Andric               ++pos;
2170b57cec5SDimitry Andric               if (pos != end_pos) {
2180b57cec5SDimitry Andric                 if (pos->file_addr != search_entry.file_addr)
2190b57cec5SDimitry Andric                   pos = end_pos;
2200b57cec5SDimitry Andric               }
2210b57cec5SDimitry Andric             }
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric             if (pos != end_pos) {
2240b57cec5SDimitry Andric               // While in the same section/offset backup to find the first line
2250b57cec5SDimitry Andric               // entry that matches the address in case there are multiple
2260b57cec5SDimitry Andric               while (pos != begin_pos) {
2270b57cec5SDimitry Andric                 entry_collection::const_iterator prev_pos = pos - 1;
2280b57cec5SDimitry Andric                 if (prev_pos->file_addr == search_entry.file_addr &&
2290b57cec5SDimitry Andric                     prev_pos->is_terminal_entry == false)
2300b57cec5SDimitry Andric                   --pos;
2310b57cec5SDimitry Andric                 else
2320b57cec5SDimitry Andric                   break;
2330b57cec5SDimitry Andric               }
2340b57cec5SDimitry Andric             }
2350b57cec5SDimitry Andric           }
2360b57cec5SDimitry Andric         }
2370b57cec5SDimitry Andric         else
2380b57cec5SDimitry Andric         {
2390b57cec5SDimitry Andric           // There might be code in the containing objfile before the first
2400b57cec5SDimitry Andric           // line table entry.  Make sure that does not get considered part of
2410b57cec5SDimitry Andric           // the first line table entry.
2420b57cec5SDimitry Andric           if (pos->file_addr > so_addr.GetFileAddress())
2430b57cec5SDimitry Andric             return false;
2440b57cec5SDimitry Andric         }
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric         // Make sure we have a valid match and that the match isn't a
2470b57cec5SDimitry Andric         // terminating entry for a previous line...
2480b57cec5SDimitry Andric         if (pos != end_pos && pos->is_terminal_entry == false) {
2490b57cec5SDimitry Andric           uint32_t match_idx = std::distance(begin_pos, pos);
2500b57cec5SDimitry Andric           success = ConvertEntryAtIndexToLineEntry(match_idx, line_entry);
2510b57cec5SDimitry Andric           if (index_ptr != nullptr && success)
2520b57cec5SDimitry Andric             *index_ptr = match_idx;
2530b57cec5SDimitry Andric         }
2540b57cec5SDimitry Andric       }
2550b57cec5SDimitry Andric     }
2560b57cec5SDimitry Andric   }
2570b57cec5SDimitry Andric   return success;
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric bool LineTable::ConvertEntryAtIndexToLineEntry(uint32_t idx,
2610b57cec5SDimitry Andric                                                LineEntry &line_entry) {
2629dba64beSDimitry Andric   if (idx >= m_entries.size())
2639dba64beSDimitry Andric     return false;
2649dba64beSDimitry Andric 
2650b57cec5SDimitry Andric   const Entry &entry = m_entries[idx];
2660b57cec5SDimitry Andric   ModuleSP module_sp(m_comp_unit->GetModule());
2679dba64beSDimitry Andric   if (!module_sp)
2689dba64beSDimitry Andric     return false;
2699dba64beSDimitry Andric 
2709dba64beSDimitry Andric   addr_t file_addr = entry.file_addr;
2719dba64beSDimitry Andric 
2729dba64beSDimitry Andric   // A terminal entry can point outside of a module or a section. Decrement the
2739dba64beSDimitry Andric   // address to ensure it resolves correctly.
2749dba64beSDimitry Andric   if (entry.is_terminal_entry)
2759dba64beSDimitry Andric     --file_addr;
2769dba64beSDimitry Andric 
2779dba64beSDimitry Andric   if (!module_sp->ResolveFileAddress(file_addr,
2789dba64beSDimitry Andric                                      line_entry.range.GetBaseAddress()))
2799dba64beSDimitry Andric     return false;
2809dba64beSDimitry Andric 
2819dba64beSDimitry Andric   // Now undo the decrement above.
2829dba64beSDimitry Andric   if (entry.is_terminal_entry)
2839dba64beSDimitry Andric     line_entry.range.GetBaseAddress().Slide(1);
2849dba64beSDimitry Andric 
2850b57cec5SDimitry Andric   if (!entry.is_terminal_entry && idx + 1 < m_entries.size())
2860b57cec5SDimitry Andric     line_entry.range.SetByteSize(m_entries[idx + 1].file_addr -
2870b57cec5SDimitry Andric                                  entry.file_addr);
2880b57cec5SDimitry Andric   else
2890b57cec5SDimitry Andric     line_entry.range.SetByteSize(0);
2900b57cec5SDimitry Andric 
291*0fca6ea1SDimitry Andric   line_entry.file_sp = std::make_shared<SupportFile>(
292*0fca6ea1SDimitry Andric       m_comp_unit->GetSupportFiles().GetFileSpecAtIndex(entry.file_idx));
2937a6dacacSDimitry Andric   line_entry.original_file_sp =
2947a6dacacSDimitry Andric       m_comp_unit->GetSupportFiles().GetSupportFileAtIndex(entry.file_idx);
2950b57cec5SDimitry Andric   line_entry.line = entry.line;
2960b57cec5SDimitry Andric   line_entry.column = entry.column;
2970b57cec5SDimitry Andric   line_entry.is_start_of_statement = entry.is_start_of_statement;
2980b57cec5SDimitry Andric   line_entry.is_start_of_basic_block = entry.is_start_of_basic_block;
2990b57cec5SDimitry Andric   line_entry.is_prologue_end = entry.is_prologue_end;
3000b57cec5SDimitry Andric   line_entry.is_epilogue_begin = entry.is_epilogue_begin;
3010b57cec5SDimitry Andric   line_entry.is_terminal_entry = entry.is_terminal_entry;
3020b57cec5SDimitry Andric   return true;
3030b57cec5SDimitry Andric }
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric uint32_t LineTable::FindLineEntryIndexByFileIndex(
306fe6060f1SDimitry Andric     uint32_t start_idx, uint32_t file_idx,
307fe6060f1SDimitry Andric     const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr) {
308fe6060f1SDimitry Andric   auto file_idx_matcher = [](uint32_t file_index, uint16_t entry_file_idx) {
309fe6060f1SDimitry Andric     return file_index == entry_file_idx;
310fe6060f1SDimitry Andric   };
311fe6060f1SDimitry Andric   return FindLineEntryIndexByFileIndexImpl<uint32_t>(
3120b57cec5SDimitry Andric 
313fe6060f1SDimitry Andric       start_idx, file_idx, src_location_spec, line_entry_ptr, file_idx_matcher);
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric 
316fe6060f1SDimitry Andric uint32_t LineTable::FindLineEntryIndexByFileIndex(
317fe6060f1SDimitry Andric     uint32_t start_idx, const std::vector<uint32_t> &file_idx,
318fe6060f1SDimitry Andric     const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr) {
319fe6060f1SDimitry Andric   auto file_idx_matcher = [](const std::vector<uint32_t> &file_indexes,
320fe6060f1SDimitry Andric                              uint16_t entry_file_idx) {
321fe6060f1SDimitry Andric     return llvm::is_contained(file_indexes, entry_file_idx);
322fe6060f1SDimitry Andric   };
3230b57cec5SDimitry Andric 
324fe6060f1SDimitry Andric   return FindLineEntryIndexByFileIndexImpl<std::vector<uint32_t>>(
325fe6060f1SDimitry Andric       start_idx, file_idx, src_location_spec, line_entry_ptr, file_idx_matcher);
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric 
32806c3fb27SDimitry Andric size_t LineTable::FindLineEntriesForFileIndex(uint32_t file_idx, bool append,
3290b57cec5SDimitry Andric                                               SymbolContextList &sc_list) {
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric   if (!append)
3320b57cec5SDimitry Andric     sc_list.Clear();
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric   size_t num_added = 0;
3350b57cec5SDimitry Andric   const size_t count = m_entries.size();
3360b57cec5SDimitry Andric   if (count > 0) {
3370b57cec5SDimitry Andric     SymbolContext sc(m_comp_unit);
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric     for (size_t idx = 0; idx < count; ++idx) {
3400b57cec5SDimitry Andric       // Skip line table rows that terminate the previous row
3410b57cec5SDimitry Andric       // (is_terminal_entry is non-zero)
3420b57cec5SDimitry Andric       if (m_entries[idx].is_terminal_entry)
3430b57cec5SDimitry Andric         continue;
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric       if (m_entries[idx].file_idx == file_idx) {
3460b57cec5SDimitry Andric         if (ConvertEntryAtIndexToLineEntry(idx, sc.line_entry)) {
3470b57cec5SDimitry Andric           ++num_added;
3480b57cec5SDimitry Andric           sc_list.Append(sc);
3490b57cec5SDimitry Andric         }
3500b57cec5SDimitry Andric       }
3510b57cec5SDimitry Andric     }
3520b57cec5SDimitry Andric   }
3530b57cec5SDimitry Andric   return num_added;
3540b57cec5SDimitry Andric }
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric void LineTable::Dump(Stream *s, Target *target, Address::DumpStyle style,
3570b57cec5SDimitry Andric                      Address::DumpStyle fallback_style, bool show_line_ranges) {
3580b57cec5SDimitry Andric   const size_t count = m_entries.size();
3590b57cec5SDimitry Andric   LineEntry line_entry;
3607a6dacacSDimitry Andric   SupportFileSP prev_file;
3610b57cec5SDimitry Andric   for (size_t idx = 0; idx < count; ++idx) {
3620b57cec5SDimitry Andric     ConvertEntryAtIndexToLineEntry(idx, line_entry);
363*0fca6ea1SDimitry Andric     line_entry.Dump(s, target, !prev_file->Equal(*line_entry.original_file_sp),
3647a6dacacSDimitry Andric                     style, fallback_style, show_line_ranges);
3650b57cec5SDimitry Andric     s->EOL();
3667a6dacacSDimitry Andric     prev_file = line_entry.original_file_sp;
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric void LineTable::GetDescription(Stream *s, Target *target,
3710b57cec5SDimitry Andric                                DescriptionLevel level) {
3720b57cec5SDimitry Andric   const size_t count = m_entries.size();
3730b57cec5SDimitry Andric   LineEntry line_entry;
3740b57cec5SDimitry Andric   for (size_t idx = 0; idx < count; ++idx) {
3750b57cec5SDimitry Andric     ConvertEntryAtIndexToLineEntry(idx, line_entry);
3760b57cec5SDimitry Andric     line_entry.GetDescription(s, level, m_comp_unit, target, true);
3770b57cec5SDimitry Andric     s->EOL();
3780b57cec5SDimitry Andric   }
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric size_t LineTable::GetContiguousFileAddressRanges(FileAddressRanges &file_ranges,
3820b57cec5SDimitry Andric                                                  bool append) {
3830b57cec5SDimitry Andric   if (!append)
3840b57cec5SDimitry Andric     file_ranges.Clear();
3850b57cec5SDimitry Andric   const size_t initial_count = file_ranges.GetSize();
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric   const size_t count = m_entries.size();
3880b57cec5SDimitry Andric   LineEntry line_entry;
3890b57cec5SDimitry Andric   FileAddressRanges::Entry range(LLDB_INVALID_ADDRESS, 0);
3900b57cec5SDimitry Andric   for (size_t idx = 0; idx < count; ++idx) {
3910b57cec5SDimitry Andric     const Entry &entry = m_entries[idx];
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric     if (entry.is_terminal_entry) {
3940b57cec5SDimitry Andric       if (range.GetRangeBase() != LLDB_INVALID_ADDRESS) {
3950b57cec5SDimitry Andric         range.SetRangeEnd(entry.file_addr);
3960b57cec5SDimitry Andric         file_ranges.Append(range);
3970b57cec5SDimitry Andric         range.Clear(LLDB_INVALID_ADDRESS);
3980b57cec5SDimitry Andric       }
3990b57cec5SDimitry Andric     } else if (range.GetRangeBase() == LLDB_INVALID_ADDRESS) {
4000b57cec5SDimitry Andric       range.SetRangeBase(entry.file_addr);
4010b57cec5SDimitry Andric     }
4020b57cec5SDimitry Andric   }
4030b57cec5SDimitry Andric   return file_ranges.GetSize() - initial_count;
4040b57cec5SDimitry Andric }
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric LineTable *LineTable::LinkLineTable(const FileRangeMap &file_range_map) {
4070b57cec5SDimitry Andric   std::unique_ptr<LineTable> line_table_up(new LineTable(m_comp_unit));
4080b57cec5SDimitry Andric   LineSequenceImpl sequence;
4090b57cec5SDimitry Andric   const size_t count = m_entries.size();
4100b57cec5SDimitry Andric   LineEntry line_entry;
4110b57cec5SDimitry Andric   const FileRangeMap::Entry *file_range_entry = nullptr;
4120b57cec5SDimitry Andric   const FileRangeMap::Entry *prev_file_range_entry = nullptr;
4130b57cec5SDimitry Andric   lldb::addr_t prev_file_addr = LLDB_INVALID_ADDRESS;
4140b57cec5SDimitry Andric   bool prev_entry_was_linked = false;
4150b57cec5SDimitry Andric   bool range_changed = false;
4160b57cec5SDimitry Andric   for (size_t idx = 0; idx < count; ++idx) {
4170b57cec5SDimitry Andric     const Entry &entry = m_entries[idx];
4180b57cec5SDimitry Andric 
4190b57cec5SDimitry Andric     const bool end_sequence = entry.is_terminal_entry;
4200b57cec5SDimitry Andric     const lldb::addr_t lookup_file_addr =
4210b57cec5SDimitry Andric         entry.file_addr - (end_sequence ? 1 : 0);
4220b57cec5SDimitry Andric     if (file_range_entry == nullptr ||
4230b57cec5SDimitry Andric         !file_range_entry->Contains(lookup_file_addr)) {
4240b57cec5SDimitry Andric       prev_file_range_entry = file_range_entry;
4250b57cec5SDimitry Andric       file_range_entry = file_range_map.FindEntryThatContains(lookup_file_addr);
4260b57cec5SDimitry Andric       range_changed = true;
4270b57cec5SDimitry Andric     }
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric     lldb::addr_t prev_end_entry_linked_file_addr = LLDB_INVALID_ADDRESS;
4300b57cec5SDimitry Andric     lldb::addr_t entry_linked_file_addr = LLDB_INVALID_ADDRESS;
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric     bool terminate_previous_entry = false;
4330b57cec5SDimitry Andric     if (file_range_entry) {
4340b57cec5SDimitry Andric       entry_linked_file_addr = entry.file_addr -
4350b57cec5SDimitry Andric                                file_range_entry->GetRangeBase() +
4360b57cec5SDimitry Andric                                file_range_entry->data;
4370b57cec5SDimitry Andric       // Determine if we need to terminate the previous entry when the previous
4380b57cec5SDimitry Andric       // entry was not contiguous with this one after being linked.
4390b57cec5SDimitry Andric       if (range_changed && prev_file_range_entry) {
4400b57cec5SDimitry Andric         prev_end_entry_linked_file_addr =
4410b57cec5SDimitry Andric             std::min<lldb::addr_t>(entry.file_addr,
4420b57cec5SDimitry Andric                                    prev_file_range_entry->GetRangeEnd()) -
4430b57cec5SDimitry Andric             prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
4440b57cec5SDimitry Andric         if (prev_end_entry_linked_file_addr != entry_linked_file_addr)
4450b57cec5SDimitry Andric           terminate_previous_entry = prev_entry_was_linked;
4460b57cec5SDimitry Andric       }
4470b57cec5SDimitry Andric     } else if (prev_entry_was_linked) {
4480b57cec5SDimitry Andric       // This entry doesn't have a remapping and it needs to be removed. Watch
4490b57cec5SDimitry Andric       // out in case we need to terminate a previous entry needs to be
4500b57cec5SDimitry Andric       // terminated now that one line entry in a sequence is not longer valid.
4510b57cec5SDimitry Andric       if (!sequence.m_entries.empty() &&
4520b57cec5SDimitry Andric           !sequence.m_entries.back().is_terminal_entry) {
4530b57cec5SDimitry Andric         terminate_previous_entry = true;
4540b57cec5SDimitry Andric       }
4550b57cec5SDimitry Andric     }
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric     if (terminate_previous_entry && !sequence.m_entries.empty()) {
4580b57cec5SDimitry Andric       assert(prev_file_addr != LLDB_INVALID_ADDRESS);
4590b57cec5SDimitry Andric       UNUSED_IF_ASSERT_DISABLED(prev_file_addr);
4600b57cec5SDimitry Andric       sequence.m_entries.push_back(sequence.m_entries.back());
4610b57cec5SDimitry Andric       if (prev_end_entry_linked_file_addr == LLDB_INVALID_ADDRESS)
4620b57cec5SDimitry Andric         prev_end_entry_linked_file_addr =
4630b57cec5SDimitry Andric             std::min<lldb::addr_t>(entry.file_addr,
4640b57cec5SDimitry Andric                                    prev_file_range_entry->GetRangeEnd()) -
4650b57cec5SDimitry Andric             prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
4660b57cec5SDimitry Andric       sequence.m_entries.back().file_addr = prev_end_entry_linked_file_addr;
4670b57cec5SDimitry Andric       sequence.m_entries.back().is_terminal_entry = true;
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric       // Append the sequence since we just terminated the previous one
4700b57cec5SDimitry Andric       line_table_up->InsertSequence(&sequence);
4710b57cec5SDimitry Andric       sequence.Clear();
4720b57cec5SDimitry Andric     }
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric     // Now link the current entry
4750b57cec5SDimitry Andric     if (file_range_entry) {
4760b57cec5SDimitry Andric       // This entry has an address remapping and it needs to have its address
4770b57cec5SDimitry Andric       // relinked
4780b57cec5SDimitry Andric       sequence.m_entries.push_back(entry);
4790b57cec5SDimitry Andric       sequence.m_entries.back().file_addr = entry_linked_file_addr;
4800b57cec5SDimitry Andric     }
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric     // If we have items in the sequence and the last entry is a terminal entry,
4830b57cec5SDimitry Andric     // insert this sequence into our new line table.
4840b57cec5SDimitry Andric     if (!sequence.m_entries.empty() &&
4850b57cec5SDimitry Andric         sequence.m_entries.back().is_terminal_entry) {
4860b57cec5SDimitry Andric       line_table_up->InsertSequence(&sequence);
4870b57cec5SDimitry Andric       sequence.Clear();
4880b57cec5SDimitry Andric       prev_entry_was_linked = false;
4890b57cec5SDimitry Andric     } else {
4900b57cec5SDimitry Andric       prev_entry_was_linked = file_range_entry != nullptr;
4910b57cec5SDimitry Andric     }
4920b57cec5SDimitry Andric     prev_file_addr = entry.file_addr;
4930b57cec5SDimitry Andric     range_changed = false;
4940b57cec5SDimitry Andric   }
4950b57cec5SDimitry Andric   if (line_table_up->m_entries.empty())
4960b57cec5SDimitry Andric     return nullptr;
4970b57cec5SDimitry Andric   return line_table_up.release();
4980b57cec5SDimitry Andric }
499