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