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     {
108         // GCC don't use the is_prologue_end flag to mark the first instruction after the prologue.
109         // Instead of it it is issueing a line table entry for the first instruction of the prologue
110         // and one for the first instruction after the prologue. If the size of the prologue is 0
111         // instruction then the 2 line entry will have the same file address. Removing it will remove
112         // our ability to properly detect the location of the end of prologe so we set the prologue_end
113         // flag to preserve this information (setting the prologue_end flag for an entry what is after
114         // the prologue end don't have any effect)
115         entry.is_prologue_end = entry.file_idx == entries.back().file_idx;
116         entries.back() = entry;
117     }
118     else
119         entries.push_back (entry);
120 }
121 
122 void
123 LineTable::InsertSequence (LineSequence* sequence)
124 {
125     assert(sequence != nullptr);
126     LineSequenceImpl* seq = reinterpret_cast<LineSequenceImpl*>(sequence);
127     if (seq->m_entries.empty())
128         return;
129     Entry& entry = seq->m_entries.front();
130 
131     // If the first entry address in this sequence is greater than or equal to
132     // the address of the last item in our entry collection, just append.
133     if (m_entries.empty() || !Entry::EntryAddressLessThan(entry, m_entries.back()))
134     {
135         m_entries.insert(m_entries.end(),
136                          seq->m_entries.begin(),
137                          seq->m_entries.end());
138         return;
139     }
140 
141     // Otherwise, find where this belongs in the collection
142     entry_collection::iterator begin_pos = m_entries.begin();
143     entry_collection::iterator end_pos = m_entries.end();
144     LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
145     entry_collection::iterator pos = upper_bound(begin_pos, end_pos, entry, less_than_bp);
146 #ifdef LLDB_CONFIGURATION_DEBUG
147     // If we aren't inserting at the beginning, the previous entry should
148     // terminate a sequence.
149     if (pos != begin_pos)
150     {
151         entry_collection::iterator prev_pos = pos - 1;
152         assert(prev_pos->is_terminal_entry);
153     }
154 #endif
155     m_entries.insert(pos, seq->m_entries.begin(), seq->m_entries.end());
156 }
157 
158 //----------------------------------------------------------------------
159 LineTable::Entry::LessThanBinaryPredicate::LessThanBinaryPredicate(LineTable *line_table) :
160     m_line_table (line_table)
161 {
162 }
163 
164 bool
165 LineTable::Entry::LessThanBinaryPredicate::operator() (const LineTable::Entry& a, const LineTable::Entry& b) const
166 {
167     #define LT_COMPARE(a,b) if (a != b) return a < b
168     LT_COMPARE (a.file_addr, b.file_addr);
169     // b and a reversed on purpose below.
170     LT_COMPARE (b.is_terminal_entry, a.is_terminal_entry);
171     LT_COMPARE (a.line, b.line);
172     LT_COMPARE (a.column, b.column);
173     LT_COMPARE (a.is_start_of_statement, b.is_start_of_statement);
174     LT_COMPARE (a.is_start_of_basic_block, b.is_start_of_basic_block);
175     // b and a reversed on purpose below.
176     LT_COMPARE (b.is_prologue_end, a.is_prologue_end);
177     LT_COMPARE (a.is_epilogue_begin, b.is_epilogue_begin);
178     LT_COMPARE (a.file_idx, b.file_idx);
179     return false;
180     #undef LT_COMPARE
181 }
182 
183 
184 
185 uint32_t
186 LineTable::GetSize() const
187 {
188     return m_entries.size();
189 }
190 
191 bool
192 LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry& line_entry)
193 {
194     if (idx < m_entries.size())
195     {
196         ConvertEntryAtIndexToLineEntry (idx, line_entry);
197         return true;
198     }
199     line_entry.Clear();
200     return false;
201 }
202 
203 bool
204 LineTable::FindLineEntryByAddress (const Address &so_addr, LineEntry& line_entry, uint32_t *index_ptr)
205 {
206     if (index_ptr != nullptr )
207         *index_ptr = UINT32_MAX;
208 
209     bool success = false;
210 
211     if (so_addr.GetModule().get() == m_comp_unit->GetModule().get())
212     {
213         Entry search_entry;
214         search_entry.file_addr = so_addr.GetFileAddress();
215         if (search_entry.file_addr != LLDB_INVALID_ADDRESS)
216         {
217             entry_collection::const_iterator begin_pos = m_entries.begin();
218             entry_collection::const_iterator end_pos = m_entries.end();
219             entry_collection::const_iterator pos = lower_bound(begin_pos, end_pos, search_entry, Entry::EntryAddressLessThan);
220             if (pos != end_pos)
221             {
222                 if (pos != begin_pos)
223                 {
224                     if (pos->file_addr != search_entry.file_addr)
225                         --pos;
226                     else if (pos->file_addr == search_entry.file_addr)
227                     {
228                         // If this is a termination entry, it shouldn't match since
229                         // entries with the "is_terminal_entry" member set to true
230                         // are termination entries that define the range for the
231                         // previous entry.
232                         if (pos->is_terminal_entry)
233                         {
234                             // The matching entry is a terminal entry, so we skip
235                             // ahead to the next entry to see if there is another
236                             // entry following this one whose section/offset matches.
237                             ++pos;
238                             if (pos != end_pos)
239                             {
240                                 if (pos->file_addr != search_entry.file_addr)
241                                     pos = end_pos;
242                             }
243                         }
244 
245                         if (pos != end_pos)
246                         {
247                             // While in the same section/offset backup to find the first
248                             // line entry that matches the address in case there are
249                             // multiple
250                             while (pos != begin_pos)
251                             {
252                                 entry_collection::const_iterator prev_pos = pos - 1;
253                                 if (prev_pos->file_addr == search_entry.file_addr &&
254                                     prev_pos->is_terminal_entry == false)
255                                     --pos;
256                                 else
257                                     break;
258                             }
259                         }
260                     }
261 
262                 }
263 
264                 // Make sure we have a valid match and that the match isn't a terminating
265                 // entry for a previous line...
266                 if (pos != end_pos && pos->is_terminal_entry == false)
267                 {
268                     uint32_t match_idx = std::distance (begin_pos, pos);
269                     success = ConvertEntryAtIndexToLineEntry(match_idx, line_entry);
270                     if (index_ptr != nullptr && success)
271                         *index_ptr = match_idx;
272                 }
273             }
274         }
275     }
276     return success;
277 }
278 
279 
280 bool
281 LineTable::ConvertEntryAtIndexToLineEntry (uint32_t idx, LineEntry &line_entry)
282 {
283     if (idx < m_entries.size())
284     {
285         const Entry& entry = m_entries[idx];
286         ModuleSP module_sp (m_comp_unit->GetModule());
287         if (module_sp && module_sp->ResolveFileAddress(entry.file_addr, line_entry.range.GetBaseAddress()))
288         {
289             if (!entry.is_terminal_entry && idx + 1 < m_entries.size())
290                 line_entry.range.SetByteSize(m_entries[idx+1].file_addr - entry.file_addr);
291             else
292                 line_entry.range.SetByteSize(0);
293 
294             line_entry.file = m_comp_unit->GetSupportFiles().GetFileSpecAtIndex (entry.file_idx);
295             line_entry.line = entry.line;
296             line_entry.column = entry.column;
297             line_entry.is_start_of_statement = entry.is_start_of_statement;
298             line_entry.is_start_of_basic_block = entry.is_start_of_basic_block;
299             line_entry.is_prologue_end = entry.is_prologue_end;
300             line_entry.is_epilogue_begin = entry.is_epilogue_begin;
301             line_entry.is_terminal_entry = entry.is_terminal_entry;
302             return true;
303         }
304     }
305     return false;
306 }
307 
308 uint32_t
309 LineTable::FindLineEntryIndexByFileIndex
310 (
311     uint32_t start_idx,
312     const std::vector<uint32_t> &file_indexes,
313     uint32_t line,
314     bool exact,
315     LineEntry* line_entry_ptr
316 )
317 {
318 
319     const size_t count = m_entries.size();
320     std::vector<uint32_t>::const_iterator begin_pos = file_indexes.begin();
321     std::vector<uint32_t>::const_iterator end_pos = file_indexes.end();
322     size_t best_match = UINT32_MAX;
323 
324     for (size_t idx = start_idx; idx < count; ++idx)
325     {
326         // Skip line table rows that terminate the previous row (is_terminal_entry is non-zero)
327         if (m_entries[idx].is_terminal_entry)
328             continue;
329 
330         if (find (begin_pos, end_pos, m_entries[idx].file_idx) == end_pos)
331             continue;
332 
333         // Exact match always wins.  Otherwise try to find the closest line > the desired
334         // line.
335         // FIXME: Maybe want to find the line closest before and the line closest after and
336         // if they're not in the same function, don't return a match.
337 
338         if (m_entries[idx].line < line)
339         {
340             continue;
341         }
342         else if (m_entries[idx].line == line)
343         {
344             if (line_entry_ptr)
345                 ConvertEntryAtIndexToLineEntry (idx, *line_entry_ptr);
346             return idx;
347         }
348         else if (!exact)
349         {
350             if (best_match == UINT32_MAX)
351                 best_match = idx;
352             else if (m_entries[idx].line < m_entries[best_match].line)
353                 best_match = idx;
354         }
355     }
356 
357     if (best_match != UINT32_MAX)
358     {
359         if (line_entry_ptr)
360             ConvertEntryAtIndexToLineEntry (best_match, *line_entry_ptr);
361         return best_match;
362     }
363     return UINT32_MAX;
364 }
365 
366 uint32_t
367 LineTable::FindLineEntryIndexByFileIndex (uint32_t start_idx, uint32_t file_idx, uint32_t line, bool exact, LineEntry* line_entry_ptr)
368 {
369     const size_t count = m_entries.size();
370     size_t best_match = UINT32_MAX;
371 
372     for (size_t idx = start_idx; idx < count; ++idx)
373     {
374         // Skip line table rows that terminate the previous row (is_terminal_entry is non-zero)
375         if (m_entries[idx].is_terminal_entry)
376             continue;
377 
378         if (m_entries[idx].file_idx != file_idx)
379             continue;
380 
381         // Exact match always wins.  Otherwise try to find the closest line > the desired
382         // line.
383         // FIXME: Maybe want to find the line closest before and the line closest after and
384         // if they're not in the same function, don't return a match.
385 
386         if (m_entries[idx].line < line)
387         {
388             continue;
389         }
390         else if (m_entries[idx].line == line)
391         {
392             if (line_entry_ptr)
393                 ConvertEntryAtIndexToLineEntry (idx, *line_entry_ptr);
394             return idx;
395         }
396         else if (!exact)
397         {
398             if (best_match == UINT32_MAX)
399                 best_match = idx;
400             else if (m_entries[idx].line < m_entries[best_match].line)
401                 best_match = idx;
402         }
403     }
404 
405     if (best_match != UINT32_MAX)
406     {
407         if (line_entry_ptr)
408             ConvertEntryAtIndexToLineEntry (best_match, *line_entry_ptr);
409         return best_match;
410     }
411     return UINT32_MAX;
412 }
413 
414 size_t
415 LineTable::FineLineEntriesForFileIndex (uint32_t file_idx,
416                                         bool append,
417                                         SymbolContextList &sc_list)
418 {
419 
420     if (!append)
421         sc_list.Clear();
422 
423     size_t num_added = 0;
424     const size_t count = m_entries.size();
425     if (count > 0)
426     {
427         SymbolContext sc (m_comp_unit);
428 
429         for (size_t idx = 0; idx < count; ++idx)
430         {
431             // Skip line table rows that terminate the previous row (is_terminal_entry is non-zero)
432             if (m_entries[idx].is_terminal_entry)
433                 continue;
434 
435             if (m_entries[idx].file_idx == file_idx)
436             {
437                 if (ConvertEntryAtIndexToLineEntry (idx, sc.line_entry))
438                 {
439                     ++num_added;
440                     sc_list.Append(sc);
441                 }
442             }
443         }
444     }
445     return num_added;
446 }
447 
448 
449 void
450 LineTable::Dump (Stream *s, Target *target, Address::DumpStyle style, Address::DumpStyle fallback_style, bool show_line_ranges)
451 {
452     const size_t count = m_entries.size();
453     LineEntry line_entry;
454     FileSpec prev_file;
455     for (size_t idx = 0; idx < count; ++idx)
456     {
457         ConvertEntryAtIndexToLineEntry (idx, line_entry);
458         line_entry.Dump (s, target, prev_file != line_entry.file, style, fallback_style, show_line_ranges);
459         s->EOL();
460         prev_file = line_entry.file;
461     }
462 }
463 
464 
465 void
466 LineTable::GetDescription (Stream *s, Target *target, DescriptionLevel level)
467 {
468     const size_t count = m_entries.size();
469     LineEntry line_entry;
470     for (size_t idx = 0; idx < count; ++idx)
471     {
472         ConvertEntryAtIndexToLineEntry (idx, line_entry);
473         line_entry.GetDescription (s, level, m_comp_unit, target, true);
474         s->EOL();
475     }
476 }
477 
478 size_t
479 LineTable::GetContiguousFileAddressRanges (FileAddressRanges &file_ranges, bool append)
480 {
481     if (!append)
482         file_ranges.Clear();
483     const size_t initial_count = file_ranges.GetSize();
484 
485     const size_t count = m_entries.size();
486     LineEntry line_entry;
487     FileAddressRanges::Entry range (LLDB_INVALID_ADDRESS, 0);
488     for (size_t idx = 0; idx < count; ++idx)
489     {
490         const Entry& entry = m_entries[idx];
491 
492         if (entry.is_terminal_entry)
493         {
494             if (range.GetRangeBase() != LLDB_INVALID_ADDRESS)
495             {
496                 range.SetRangeEnd(entry.file_addr);
497                 file_ranges.Append(range);
498                 range.Clear(LLDB_INVALID_ADDRESS);
499             }
500         }
501         else if (range.GetRangeBase() == LLDB_INVALID_ADDRESS)
502         {
503             range.SetRangeBase(entry.file_addr);
504         }
505     }
506     return file_ranges.GetSize() - initial_count;
507 }
508 
509 LineTable *
510 LineTable::LinkLineTable (const FileRangeMap &file_range_map)
511 {
512     std::unique_ptr<LineTable> line_table_ap (new LineTable (m_comp_unit));
513     LineSequenceImpl sequence;
514     const size_t count = m_entries.size();
515     LineEntry line_entry;
516     const FileRangeMap::Entry *file_range_entry = nullptr;
517     const FileRangeMap::Entry *prev_file_range_entry = nullptr;
518     lldb::addr_t prev_file_addr = LLDB_INVALID_ADDRESS;
519     bool prev_entry_was_linked = false;
520     bool range_changed = false;
521     for (size_t idx = 0; idx < count; ++idx)
522     {
523         const Entry& entry = m_entries[idx];
524 
525         const bool end_sequence = entry.is_terminal_entry;
526         const lldb::addr_t lookup_file_addr = entry.file_addr - (end_sequence ? 1 : 0);
527         if (file_range_entry == nullptr || !file_range_entry->Contains(lookup_file_addr))
528         {
529             prev_file_range_entry = file_range_entry;
530             file_range_entry = file_range_map.FindEntryThatContains(lookup_file_addr);
531             range_changed = true;
532         }
533 
534         lldb::addr_t prev_end_entry_linked_file_addr = LLDB_INVALID_ADDRESS;
535         lldb::addr_t entry_linked_file_addr = LLDB_INVALID_ADDRESS;
536 
537         bool terminate_previous_entry = false;
538         if (file_range_entry)
539         {
540             entry_linked_file_addr = entry.file_addr - file_range_entry->GetRangeBase() + file_range_entry->data;
541             // Determine if we need to terminate the previous entry when the previous
542             // entry was not contiguous with this one after being linked.
543             if (range_changed && prev_file_range_entry)
544             {
545                 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;
546                 if (prev_end_entry_linked_file_addr != entry_linked_file_addr)
547                     terminate_previous_entry = prev_entry_was_linked;
548             }
549         }
550         else if (prev_entry_was_linked)
551         {
552             // This entry doesn't have a remapping and it needs to be removed.
553             // Watch out in case we need to terminate a previous entry needs to
554             // be terminated now that one line entry in a sequence is not longer valid.
555             if (!sequence.m_entries.empty() &&
556                 !sequence.m_entries.back().is_terminal_entry)
557             {
558                 terminate_previous_entry = true;
559             }
560         }
561 
562         if (terminate_previous_entry && !sequence.m_entries.empty())
563         {
564             assert (prev_file_addr != LLDB_INVALID_ADDRESS);
565             sequence.m_entries.push_back(sequence.m_entries.back());
566             if (prev_end_entry_linked_file_addr == LLDB_INVALID_ADDRESS)
567                 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;
568             sequence.m_entries.back().file_addr = prev_end_entry_linked_file_addr;
569             sequence.m_entries.back().is_terminal_entry = true;
570 
571             // Append the sequence since we just terminated the previous one
572             line_table_ap->InsertSequence (&sequence);
573             sequence.Clear();
574         }
575 
576         // Now link the current entry
577         if (file_range_entry)
578         {
579             // This entry has an address remapping and it needs to have its address relinked
580             sequence.m_entries.push_back(entry);
581             sequence.m_entries.back().file_addr = entry_linked_file_addr;
582         }
583 
584         // If we have items in the sequence and the last entry is a terminal entry,
585         // insert this sequence into our new line table.
586         if (!sequence.m_entries.empty() && sequence.m_entries.back().is_terminal_entry)
587         {
588             line_table_ap->InsertSequence (&sequence);
589             sequence.Clear();
590             prev_entry_was_linked = false;
591         }
592         else
593         {
594             prev_entry_was_linked = file_range_entry != nullptr;
595         }
596         prev_file_addr = entry.file_addr;
597         range_changed = false;
598     }
599     if (line_table_ap->m_entries.empty())
600         return nullptr;
601     return line_table_ap.release();
602 }
603 
604 
605 
606 
607