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