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