1 //===-- LineTable.cpp -------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Symbol/LineTable.h"
10 #include "lldb/Core/Address.h"
11 #include "lldb/Core/Module.h"
12 #include "lldb/Core/Section.h"
13 #include "lldb/Symbol/CompileUnit.h"
14 #include "lldb/Utility/Stream.h"
15 #include <algorithm>
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 
20 // LineTable constructor
21 LineTable::LineTable(CompileUnit *comp_unit)
22     : m_comp_unit(comp_unit), m_entries() {}
23 
24 LineTable::LineTable(CompileUnit *comp_unit, std::vector<LineSequence *> &sequences)
25     : m_comp_unit(comp_unit), m_entries() {
26   LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
27   llvm::stable_sort(sequences, less_than_bp);
28   for (auto *sequence : sequences) {
29     LineSequenceImpl *seq = reinterpret_cast<LineSequenceImpl *>(sequence);
30     m_entries.insert(m_entries.end(), seq->m_entries.begin(),
31       seq->m_entries.end());
32   }
33 }
34 
35 // Destructor
36 LineTable::~LineTable() {}
37 
38 void LineTable::InsertLineEntry(lldb::addr_t file_addr, uint32_t line,
39                                 uint16_t column, uint16_t file_idx,
40                                 bool is_start_of_statement,
41                                 bool is_start_of_basic_block,
42                                 bool is_prologue_end, bool is_epilogue_begin,
43                                 bool is_terminal_entry) {
44   Entry entry(file_addr, line, column, file_idx, is_start_of_statement,
45               is_start_of_basic_block, is_prologue_end, is_epilogue_begin,
46               is_terminal_entry);
47 
48   LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
49   entry_collection::iterator pos =
50       llvm::upper_bound(m_entries, entry, less_than_bp);
51 
52   //  Stream s(stdout);
53   //  s << "\n\nBefore:\n";
54   //  Dump (&s, Address::DumpStyleFileAddress);
55   m_entries.insert(pos, entry);
56   //  s << "After:\n";
57   //  Dump (&s, Address::DumpStyleFileAddress);
58 }
59 
60 LineSequence::LineSequence() {}
61 
62 void LineTable::LineSequenceImpl::Clear() { m_entries.clear(); }
63 
64 LineSequence *LineTable::CreateLineSequenceContainer() {
65   return new LineTable::LineSequenceImpl();
66 }
67 
68 void LineTable::AppendLineEntryToSequence(
69     LineSequence *sequence, lldb::addr_t file_addr, uint32_t line,
70     uint16_t column, uint16_t file_idx, bool is_start_of_statement,
71     bool is_start_of_basic_block, bool is_prologue_end, bool is_epilogue_begin,
72     bool is_terminal_entry) {
73   assert(sequence != nullptr);
74   LineSequenceImpl *seq = reinterpret_cast<LineSequenceImpl *>(sequence);
75   Entry entry(file_addr, line, column, file_idx, is_start_of_statement,
76               is_start_of_basic_block, is_prologue_end, is_epilogue_begin,
77               is_terminal_entry);
78   entry_collection &entries = seq->m_entries;
79   // Replace the last entry if the address is the same, otherwise append it. If
80   // we have multiple line entries at the same address, this indicates illegal
81   // DWARF so this "fixes" the line table to be correct. If not fixed this can
82   // cause a line entry's address that when resolved back to a symbol context,
83   // could resolve to a different line entry. We really want a
84   // 1 to 1 mapping
85   // here to avoid these kinds of inconsistencies. We will need tor revisit
86   // this if the DWARF line tables are updated to allow multiple entries at the
87   // same address legally.
88   if (!entries.empty() && entries.back().file_addr == file_addr) {
89     // GCC don't use the is_prologue_end flag to mark the first instruction
90     // after the prologue.
91     // Instead of it it is issuing a line table entry for the first instruction
92     // of the prologue and one for the first instruction after the prologue. If
93     // the size of the prologue is 0 instruction then the 2 line entry will
94     // have the same file address. Removing it will remove our ability to
95     // properly detect the location of the end of prologe so we set the
96     // prologue_end flag to preserve this information (setting the prologue_end
97     // flag for an entry what is after the prologue end don't have any effect)
98     entry.is_prologue_end = entry.file_idx == entries.back().file_idx;
99     entries.back() = entry;
100   } else
101     entries.push_back(entry);
102 }
103 
104 void LineTable::InsertSequence(LineSequence *sequence) {
105   assert(sequence != nullptr);
106   LineSequenceImpl *seq = reinterpret_cast<LineSequenceImpl *>(sequence);
107   if (seq->m_entries.empty())
108     return;
109   Entry &entry = seq->m_entries.front();
110 
111   // If the first entry address in this sequence is greater than or equal to
112   // the address of the last item in our entry collection, just append.
113   if (m_entries.empty() ||
114       !Entry::EntryAddressLessThan(entry, m_entries.back())) {
115     m_entries.insert(m_entries.end(), seq->m_entries.begin(),
116                      seq->m_entries.end());
117     return;
118   }
119 
120   // Otherwise, find where this belongs in the collection
121   entry_collection::iterator begin_pos = m_entries.begin();
122   entry_collection::iterator end_pos = m_entries.end();
123   LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
124   entry_collection::iterator pos =
125       upper_bound(begin_pos, end_pos, entry, less_than_bp);
126 
127   // We should never insert a sequence in the middle of another sequence
128   if (pos != begin_pos) {
129     while (pos < end_pos && !((pos - 1)->is_terminal_entry))
130       pos++;
131   }
132 
133 #ifndef NDEBUG
134   // If we aren't inserting at the beginning, the previous entry should
135   // terminate a sequence.
136   if (pos != begin_pos) {
137     entry_collection::iterator prev_pos = pos - 1;
138     assert(prev_pos->is_terminal_entry);
139   }
140 #endif
141   m_entries.insert(pos, seq->m_entries.begin(), seq->m_entries.end());
142 }
143 
144 LineTable::Entry::LessThanBinaryPredicate::LessThanBinaryPredicate(
145     LineTable *line_table)
146     : m_line_table(line_table) {}
147 
148 bool LineTable::Entry::LessThanBinaryPredicate::
149 operator()(const LineTable::Entry &a, const LineTable::Entry &b) const {
150 #define LT_COMPARE(a, b)                                                       \
151   if (a != b)                                                                  \
152   return a < b
153   LT_COMPARE(a.file_addr, b.file_addr);
154   // b and a reversed on purpose below.
155   LT_COMPARE(b.is_terminal_entry, a.is_terminal_entry);
156   LT_COMPARE(a.line, b.line);
157   LT_COMPARE(a.column, b.column);
158   LT_COMPARE(a.is_start_of_statement, b.is_start_of_statement);
159   LT_COMPARE(a.is_start_of_basic_block, b.is_start_of_basic_block);
160   // b and a reversed on purpose below.
161   LT_COMPARE(b.is_prologue_end, a.is_prologue_end);
162   LT_COMPARE(a.is_epilogue_begin, b.is_epilogue_begin);
163   LT_COMPARE(a.file_idx, b.file_idx);
164   return false;
165 #undef LT_COMPARE
166 }
167 
168 bool LineTable::Entry::LessThanBinaryPredicate::
169 operator()(const LineSequence *sequence_a, const LineSequence *sequence_b) const {
170   auto *seq_a = static_cast<const LineSequenceImpl *>(sequence_a);
171   auto *seq_b = static_cast<const LineSequenceImpl *>(sequence_b);
172   return (*this)(seq_a->m_entries.front(), seq_b->m_entries.front());
173 }
174 
175 uint32_t LineTable::GetSize() const { return m_entries.size(); }
176 
177 bool LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry &line_entry) {
178   if (idx < m_entries.size()) {
179     ConvertEntryAtIndexToLineEntry(idx, line_entry);
180     return true;
181   }
182   line_entry.Clear();
183   return false;
184 }
185 
186 bool LineTable::FindLineEntryByAddress(const Address &so_addr,
187                                        LineEntry &line_entry,
188                                        uint32_t *index_ptr) {
189   if (index_ptr != nullptr)
190     *index_ptr = UINT32_MAX;
191 
192   bool success = false;
193 
194   if (so_addr.GetModule().get() == m_comp_unit->GetModule().get()) {
195     Entry search_entry;
196     search_entry.file_addr = so_addr.GetFileAddress();
197     if (search_entry.file_addr != LLDB_INVALID_ADDRESS) {
198       entry_collection::const_iterator begin_pos = m_entries.begin();
199       entry_collection::const_iterator end_pos = m_entries.end();
200       entry_collection::const_iterator pos = lower_bound(
201           begin_pos, end_pos, search_entry, Entry::EntryAddressLessThan);
202       if (pos != end_pos) {
203         if (pos != begin_pos) {
204           if (pos->file_addr != search_entry.file_addr)
205             --pos;
206           else if (pos->file_addr == search_entry.file_addr) {
207             // If this is a termination entry, it shouldn't match since entries
208             // with the "is_terminal_entry" member set to true are termination
209             // entries that define the range for the previous entry.
210             if (pos->is_terminal_entry) {
211               // The matching entry is a terminal entry, so we skip ahead to
212               // the next entry to see if there is another entry following this
213               // one whose section/offset matches.
214               ++pos;
215               if (pos != end_pos) {
216                 if (pos->file_addr != search_entry.file_addr)
217                   pos = end_pos;
218               }
219             }
220 
221             if (pos != end_pos) {
222               // While in the same section/offset backup to find the first line
223               // entry that matches the address in case there are multiple
224               while (pos != begin_pos) {
225                 entry_collection::const_iterator prev_pos = pos - 1;
226                 if (prev_pos->file_addr == search_entry.file_addr &&
227                     prev_pos->is_terminal_entry == false)
228                   --pos;
229                 else
230                   break;
231               }
232             }
233           }
234         }
235         else
236         {
237           // There might be code in the containing objfile before the first
238           // line table entry.  Make sure that does not get considered part of
239           // the first line table entry.
240           if (pos->file_addr > so_addr.GetFileAddress())
241             return false;
242         }
243 
244         // Make sure we have a valid match and that the match isn't a
245         // terminating entry for a previous line...
246         if (pos != end_pos && pos->is_terminal_entry == false) {
247           uint32_t match_idx = std::distance(begin_pos, pos);
248           success = ConvertEntryAtIndexToLineEntry(match_idx, line_entry);
249           if (index_ptr != nullptr && success)
250             *index_ptr = match_idx;
251         }
252       }
253     }
254   }
255   return success;
256 }
257 
258 bool LineTable::ConvertEntryAtIndexToLineEntry(uint32_t idx,
259                                                LineEntry &line_entry) {
260   if (idx >= m_entries.size())
261     return false;
262 
263   const Entry &entry = m_entries[idx];
264   ModuleSP module_sp(m_comp_unit->GetModule());
265   if (!module_sp)
266     return false;
267 
268   addr_t file_addr = entry.file_addr;
269 
270   // A terminal entry can point outside of a module or a section. Decrement the
271   // address to ensure it resolves correctly.
272   if (entry.is_terminal_entry)
273     --file_addr;
274 
275   if (!module_sp->ResolveFileAddress(file_addr,
276                                      line_entry.range.GetBaseAddress()))
277     return false;
278 
279   // Now undo the decrement above.
280   if (entry.is_terminal_entry)
281     line_entry.range.GetBaseAddress().Slide(1);
282 
283   if (!entry.is_terminal_entry && idx + 1 < m_entries.size())
284     line_entry.range.SetByteSize(m_entries[idx + 1].file_addr -
285                                  entry.file_addr);
286   else
287     line_entry.range.SetByteSize(0);
288 
289   line_entry.file =
290       m_comp_unit->GetSupportFiles().GetFileSpecAtIndex(entry.file_idx);
291   line_entry.original_file =
292       m_comp_unit->GetSupportFiles().GetFileSpecAtIndex(entry.file_idx);
293   line_entry.line = entry.line;
294   line_entry.column = entry.column;
295   line_entry.is_start_of_statement = entry.is_start_of_statement;
296   line_entry.is_start_of_basic_block = entry.is_start_of_basic_block;
297   line_entry.is_prologue_end = entry.is_prologue_end;
298   line_entry.is_epilogue_begin = entry.is_epilogue_begin;
299   line_entry.is_terminal_entry = entry.is_terminal_entry;
300   return true;
301 }
302 
303 uint32_t LineTable::FindLineEntryIndexByFileIndex(
304     uint32_t start_idx, const std::vector<uint32_t> &file_indexes,
305     uint32_t line, bool exact, LineEntry *line_entry_ptr) {
306 
307   const size_t count = m_entries.size();
308   size_t best_match = UINT32_MAX;
309 
310   for (size_t idx = start_idx; idx < count; ++idx) {
311     // Skip line table rows that terminate the previous row (is_terminal_entry
312     // is non-zero)
313     if (m_entries[idx].is_terminal_entry)
314       continue;
315 
316     if (llvm::find(file_indexes, m_entries[idx].file_idx) == file_indexes.end())
317       continue;
318 
319     // Exact match always wins.  Otherwise try to find the closest line > the
320     // desired line.
321     // FIXME: Maybe want to find the line closest before and the line closest
322     // after and
323     // if they're not in the same function, don't return a match.
324 
325     if (m_entries[idx].line < line) {
326       continue;
327     } else if (m_entries[idx].line == line) {
328       if (line_entry_ptr)
329         ConvertEntryAtIndexToLineEntry(idx, *line_entry_ptr);
330       return idx;
331     } else if (!exact) {
332       if (best_match == UINT32_MAX)
333         best_match = idx;
334       else if (m_entries[idx].line < m_entries[best_match].line)
335         best_match = idx;
336     }
337   }
338 
339   if (best_match != UINT32_MAX) {
340     if (line_entry_ptr)
341       ConvertEntryAtIndexToLineEntry(best_match, *line_entry_ptr);
342     return best_match;
343   }
344   return UINT32_MAX;
345 }
346 
347 uint32_t LineTable::FindLineEntryIndexByFileIndex(uint32_t start_idx,
348                                                   uint32_t file_idx,
349                                                   uint32_t line, bool exact,
350                                                   LineEntry *line_entry_ptr) {
351   const size_t count = m_entries.size();
352   size_t best_match = UINT32_MAX;
353 
354   for (size_t idx = start_idx; idx < count; ++idx) {
355     // Skip line table rows that terminate the previous row (is_terminal_entry
356     // is non-zero)
357     if (m_entries[idx].is_terminal_entry)
358       continue;
359 
360     if (m_entries[idx].file_idx != file_idx)
361       continue;
362 
363     // Exact match always wins.  Otherwise try to find the closest line > the
364     // desired line.
365     // FIXME: Maybe want to find the line closest before and the line closest
366     // after and
367     // if they're not in the same function, don't return a match.
368 
369     if (m_entries[idx].line < line) {
370       continue;
371     } else if (m_entries[idx].line == line) {
372       if (line_entry_ptr)
373         ConvertEntryAtIndexToLineEntry(idx, *line_entry_ptr);
374       return idx;
375     } else if (!exact) {
376       if (best_match == UINT32_MAX)
377         best_match = idx;
378       else if (m_entries[idx].line < m_entries[best_match].line)
379         best_match = idx;
380     }
381   }
382 
383   if (best_match != UINT32_MAX) {
384     if (line_entry_ptr)
385       ConvertEntryAtIndexToLineEntry(best_match, *line_entry_ptr);
386     return best_match;
387   }
388   return UINT32_MAX;
389 }
390 
391 size_t LineTable::FineLineEntriesForFileIndex(uint32_t file_idx, bool append,
392                                               SymbolContextList &sc_list) {
393 
394   if (!append)
395     sc_list.Clear();
396 
397   size_t num_added = 0;
398   const size_t count = m_entries.size();
399   if (count > 0) {
400     SymbolContext sc(m_comp_unit);
401 
402     for (size_t idx = 0; idx < count; ++idx) {
403       // Skip line table rows that terminate the previous row
404       // (is_terminal_entry is non-zero)
405       if (m_entries[idx].is_terminal_entry)
406         continue;
407 
408       if (m_entries[idx].file_idx == file_idx) {
409         if (ConvertEntryAtIndexToLineEntry(idx, sc.line_entry)) {
410           ++num_added;
411           sc_list.Append(sc);
412         }
413       }
414     }
415   }
416   return num_added;
417 }
418 
419 void LineTable::Dump(Stream *s, Target *target, Address::DumpStyle style,
420                      Address::DumpStyle fallback_style, bool show_line_ranges) {
421   const size_t count = m_entries.size();
422   LineEntry line_entry;
423   FileSpec prev_file;
424   for (size_t idx = 0; idx < count; ++idx) {
425     ConvertEntryAtIndexToLineEntry(idx, line_entry);
426     line_entry.Dump(s, target, prev_file != line_entry.original_file, style,
427                     fallback_style, show_line_ranges);
428     s->EOL();
429     prev_file = line_entry.original_file;
430   }
431 }
432 
433 void LineTable::GetDescription(Stream *s, Target *target,
434                                DescriptionLevel level) {
435   const size_t count = m_entries.size();
436   LineEntry line_entry;
437   for (size_t idx = 0; idx < count; ++idx) {
438     ConvertEntryAtIndexToLineEntry(idx, line_entry);
439     line_entry.GetDescription(s, level, m_comp_unit, target, true);
440     s->EOL();
441   }
442 }
443 
444 size_t LineTable::GetContiguousFileAddressRanges(FileAddressRanges &file_ranges,
445                                                  bool append) {
446   if (!append)
447     file_ranges.Clear();
448   const size_t initial_count = file_ranges.GetSize();
449 
450   const size_t count = m_entries.size();
451   LineEntry line_entry;
452   FileAddressRanges::Entry range(LLDB_INVALID_ADDRESS, 0);
453   for (size_t idx = 0; idx < count; ++idx) {
454     const Entry &entry = m_entries[idx];
455 
456     if (entry.is_terminal_entry) {
457       if (range.GetRangeBase() != LLDB_INVALID_ADDRESS) {
458         range.SetRangeEnd(entry.file_addr);
459         file_ranges.Append(range);
460         range.Clear(LLDB_INVALID_ADDRESS);
461       }
462     } else if (range.GetRangeBase() == LLDB_INVALID_ADDRESS) {
463       range.SetRangeBase(entry.file_addr);
464     }
465   }
466   return file_ranges.GetSize() - initial_count;
467 }
468 
469 LineTable *LineTable::LinkLineTable(const FileRangeMap &file_range_map) {
470   std::unique_ptr<LineTable> line_table_up(new LineTable(m_comp_unit));
471   LineSequenceImpl sequence;
472   const size_t count = m_entries.size();
473   LineEntry line_entry;
474   const FileRangeMap::Entry *file_range_entry = nullptr;
475   const FileRangeMap::Entry *prev_file_range_entry = nullptr;
476   lldb::addr_t prev_file_addr = LLDB_INVALID_ADDRESS;
477   bool prev_entry_was_linked = false;
478   bool range_changed = false;
479   for (size_t idx = 0; idx < count; ++idx) {
480     const Entry &entry = m_entries[idx];
481 
482     const bool end_sequence = entry.is_terminal_entry;
483     const lldb::addr_t lookup_file_addr =
484         entry.file_addr - (end_sequence ? 1 : 0);
485     if (file_range_entry == nullptr ||
486         !file_range_entry->Contains(lookup_file_addr)) {
487       prev_file_range_entry = file_range_entry;
488       file_range_entry = file_range_map.FindEntryThatContains(lookup_file_addr);
489       range_changed = true;
490     }
491 
492     lldb::addr_t prev_end_entry_linked_file_addr = LLDB_INVALID_ADDRESS;
493     lldb::addr_t entry_linked_file_addr = LLDB_INVALID_ADDRESS;
494 
495     bool terminate_previous_entry = false;
496     if (file_range_entry) {
497       entry_linked_file_addr = entry.file_addr -
498                                file_range_entry->GetRangeBase() +
499                                file_range_entry->data;
500       // Determine if we need to terminate the previous entry when the previous
501       // entry was not contiguous with this one after being linked.
502       if (range_changed && prev_file_range_entry) {
503         prev_end_entry_linked_file_addr =
504             std::min<lldb::addr_t>(entry.file_addr,
505                                    prev_file_range_entry->GetRangeEnd()) -
506             prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
507         if (prev_end_entry_linked_file_addr != entry_linked_file_addr)
508           terminate_previous_entry = prev_entry_was_linked;
509       }
510     } else if (prev_entry_was_linked) {
511       // This entry doesn't have a remapping and it needs to be removed. Watch
512       // out in case we need to terminate a previous entry needs to be
513       // terminated now that one line entry in a sequence is not longer valid.
514       if (!sequence.m_entries.empty() &&
515           !sequence.m_entries.back().is_terminal_entry) {
516         terminate_previous_entry = true;
517       }
518     }
519 
520     if (terminate_previous_entry && !sequence.m_entries.empty()) {
521       assert(prev_file_addr != LLDB_INVALID_ADDRESS);
522       UNUSED_IF_ASSERT_DISABLED(prev_file_addr);
523       sequence.m_entries.push_back(sequence.m_entries.back());
524       if (prev_end_entry_linked_file_addr == LLDB_INVALID_ADDRESS)
525         prev_end_entry_linked_file_addr =
526             std::min<lldb::addr_t>(entry.file_addr,
527                                    prev_file_range_entry->GetRangeEnd()) -
528             prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
529       sequence.m_entries.back().file_addr = prev_end_entry_linked_file_addr;
530       sequence.m_entries.back().is_terminal_entry = true;
531 
532       // Append the sequence since we just terminated the previous one
533       line_table_up->InsertSequence(&sequence);
534       sequence.Clear();
535     }
536 
537     // Now link the current entry
538     if (file_range_entry) {
539       // This entry has an address remapping and it needs to have its address
540       // relinked
541       sequence.m_entries.push_back(entry);
542       sequence.m_entries.back().file_addr = entry_linked_file_addr;
543     }
544 
545     // If we have items in the sequence and the last entry is a terminal entry,
546     // insert this sequence into our new line table.
547     if (!sequence.m_entries.empty() &&
548         sequence.m_entries.back().is_terminal_entry) {
549       line_table_up->InsertSequence(&sequence);
550       sequence.Clear();
551       prev_entry_was_linked = false;
552     } else {
553       prev_entry_was_linked = file_range_entry != nullptr;
554     }
555     prev_file_addr = entry.file_addr;
556     range_changed = false;
557   }
558   if (line_table_up->m_entries.empty())
559     return nullptr;
560   return line_table_up.release();
561 }
562