blob: 69deba4ba34db27cdcdd5790ef893b508b915391 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- 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/Section.h"
12#include "lldb/Core/Stream.h"
13#include "lldb/Symbol/CompileUnit.h"
14#include "lldb/Symbol/LineTable.h"
Eli Friedmanb1ed5162010-06-09 09:32:42 +000015#include <algorithm>
Chris Lattner24943d22010-06-08 16:52:24 +000016
17using namespace lldb;
18using namespace lldb_private;
19
20//----------------------------------------------------------------------
21// LineTable constructor
22//----------------------------------------------------------------------
23LineTable::LineTable(CompileUnit* comp_unit) :
24 m_comp_unit(comp_unit),
25 m_section_list(),
26 m_entries()
27{
28}
29
30//----------------------------------------------------------------------
31// Destructor
32//----------------------------------------------------------------------
33LineTable::~LineTable()
34{
35}
36
37//void
38//LineTable::AddLineEntry(const LineEntry& entry)
39//{
40// // Do a binary search for the correct entry and insert it
41// m_line_entries.insert(std::upper_bound(m_line_entries.begin(), m_line_entries.end(), entry), entry);
42//}
43
44void
45LineTable::AppendLineEntry
46(
47 SectionSP& section_sp,
48 lldb::addr_t section_offset,
49 uint32_t line,
50 uint16_t column,
51 uint16_t file_idx,
52 bool is_start_of_statement,
53 bool is_start_of_basic_block,
54 bool is_prologue_end,
55 bool is_epilogue_begin,
56 bool is_terminal_entry
57)
58{
59 uint32_t sect_idx = m_section_list.AddUniqueSection (section_sp);
Chris Lattner24943d22010-06-08 16:52:24 +000060 Entry entry(sect_idx, section_offset, line, column, file_idx, is_start_of_statement, is_start_of_basic_block, is_prologue_end, is_epilogue_begin, is_terminal_entry);
61 m_entries.push_back (entry);
62}
63
64
65void
66LineTable::InsertLineEntry
67(
68 SectionSP& section_sp,
69 lldb::addr_t section_offset,
70 uint32_t line,
71 uint16_t column,
72 uint16_t file_idx,
73 bool is_start_of_statement,
74 bool is_start_of_basic_block,
75 bool is_prologue_end,
76 bool is_epilogue_begin,
77 bool is_terminal_entry
78)
79{
80 SectionSP line_section_sp(section_sp);
81 const Section *linked_section = line_section_sp->GetLinkedSection();
82 if (linked_section)
83 {
84 section_offset += line_section_sp->GetLinkedOffset();
85 line_section_sp = linked_section->GetSharedPointer();
86 assert(line_section_sp.get());
87 }
88
89 uint32_t sect_idx = m_section_list.AddUniqueSection (line_section_sp);
Chris Lattner24943d22010-06-08 16:52:24 +000090 Entry entry(sect_idx, section_offset, line, column, file_idx, is_start_of_statement, is_start_of_basic_block, is_prologue_end, is_epilogue_begin, is_terminal_entry);
91
92 entry_collection::iterator begin_pos = m_entries.begin();
93 entry_collection::iterator end_pos = m_entries.end();
94 LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
95 entry_collection::iterator pos = upper_bound(begin_pos, end_pos, entry, less_than_bp);
96
97// Stream s(stdout);
98// s << "\n\nBefore:\n";
99// Dump (&s, Address::DumpStyleFileAddress);
100 m_entries.insert(pos, entry);
101// s << "After:\n";
102// Dump (&s, Address::DumpStyleFileAddress);
103}
104
105//----------------------------------------------------------------------
106LineTable::Entry::LessThanBinaryPredicate::LessThanBinaryPredicate(LineTable *line_table) :
107 m_line_table (line_table)
108{
109}
110
111bool
112LineTable::Entry::LessThanBinaryPredicate::operator() (const LineTable::Entry& a, const LineTable::Entry& b) const
113{
114 if (a.sect_idx == b.sect_idx)
115 {
116 #define LT_COMPARE(a,b) if (a != b) return a < b
117 LT_COMPARE (a.sect_offset, b.sect_offset);
118 LT_COMPARE (a.line, b.line);
119 LT_COMPARE (a.column, b.column);
120 LT_COMPARE (a.is_start_of_statement, b.is_start_of_statement);
121 LT_COMPARE (a.is_start_of_basic_block, b.is_start_of_basic_block);
122 // b and a reversed on purpose below.
123 LT_COMPARE (b.is_prologue_end, a.is_prologue_end);
124 LT_COMPARE (a.is_epilogue_begin, b.is_epilogue_begin);
125 // b and a reversed on purpose below.
126 LT_COMPARE (b.is_terminal_entry, a.is_terminal_entry);
127 LT_COMPARE (a.file_idx, b.file_idx);
128 return false;
Eli Friedmanb1ed5162010-06-09 09:32:42 +0000129 #undef LT_COMPARE
Chris Lattner24943d22010-06-08 16:52:24 +0000130 }
131
132 const Section *a_section = m_line_table->GetSectionForEntryIndex (a.sect_idx);
133 const Section *b_section = m_line_table->GetSectionForEntryIndex (b.sect_idx);
134 return Section::Compare(*a_section, *b_section) < 0;
Eli Friedmanb1ed5162010-06-09 09:32:42 +0000135}
Chris Lattner24943d22010-06-08 16:52:24 +0000136
137
138Section *
139LineTable::GetSectionForEntryIndex (uint32_t idx)
140{
141 if (idx < m_section_list.GetSize())
142 return m_section_list.GetSectionAtIndex(idx).get();
143 return NULL;
144}
145
146uint32_t
147LineTable::GetSize() const
148{
149 return m_entries.size();
150}
151
152bool
153LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry& line_entry)
154{
155 if (idx < m_entries.size())
156 {
157 ConvertEntryAtIndexToLineEntry (idx, line_entry);
158 return true;
159 }
160 line_entry.Clear();
161 return false;
162}
163
164bool
165LineTable::FindLineEntryByAddress (const Address &so_addr, LineEntry& line_entry, uint32_t *index_ptr)
166{
167 if (index_ptr != NULL )
168 *index_ptr = UINT32_MAX;
169
170 bool success = false;
171 uint32_t sect_idx = m_section_list.FindSectionIndex (so_addr.GetSection());
172 if (sect_idx != UINT32_MAX)
173 {
174 Entry search_entry;
175 search_entry.sect_idx = sect_idx;
176 search_entry.sect_offset = so_addr.GetOffset();
177
178 entry_collection::const_iterator begin_pos = m_entries.begin();
179 entry_collection::const_iterator end_pos = m_entries.end();
180 entry_collection::const_iterator pos = lower_bound(begin_pos, end_pos, search_entry, Entry::EntryAddressLessThan);
181 if (pos != end_pos)
182 {
183 if (pos != begin_pos)
184 {
185 if (pos->sect_offset != search_entry.sect_offset)
186 --pos;
187 else if (pos->sect_offset == search_entry.sect_offset)
188 {
Greg Clayton748b72f2010-07-06 23:34:08 +0000189 // If this is a termination entry, it should't match since
190 // entries with the "is_terminal_entry" member set to true
191 // are termination entries that define the range for the
192 // previous entry.
193 if (pos->is_terminal_entry)
Chris Lattner24943d22010-06-08 16:52:24 +0000194 {
Greg Clayton748b72f2010-07-06 23:34:08 +0000195 // The matching entry is a terminal entry, so we skip
196 // ahead to the next entry to see if there is another
197 // entry following this one whose section/offset matches.
198 ++pos;
199 if (pos != end_pos)
200 {
201 if (pos->sect_offset != search_entry.sect_offset)
202 pos = end_pos;
203 }
204 }
205
206 if (pos != end_pos)
207 {
208 // While in the same section/offset backup to find the first
209 // line entry that matches the address in case there are
210 // multiple
211 while (pos != begin_pos)
212 {
213 entry_collection::const_iterator prev_pos = pos - 1;
214 if (prev_pos->sect_idx == search_entry.sect_idx &&
215 prev_pos->sect_offset == search_entry.sect_offset &&
216 prev_pos->is_terminal_entry == false)
217 --pos;
218 else
219 break;
220 }
Chris Lattner24943d22010-06-08 16:52:24 +0000221 }
222 }
223
224 }
Greg Clayton748b72f2010-07-06 23:34:08 +0000225
226 if (pos != end_pos)
227 {
228 uint32_t match_idx = std::distance (begin_pos, pos);
229 success = ConvertEntryAtIndexToLineEntry(match_idx, line_entry);
230 if (index_ptr != NULL && success)
231 *index_ptr = match_idx;
232 }
Chris Lattner24943d22010-06-08 16:52:24 +0000233 }
234 }
235 return success;
236}
237
238
239bool
240LineTable::ConvertEntryAtIndexToLineEntry (uint32_t idx, LineEntry &line_entry)
241{
242 if (idx < m_entries.size())
243 {
244 const Entry& entry = m_entries[idx];
245 line_entry.range.GetBaseAddress().SetSection(m_section_list.GetSectionAtIndex (entry.sect_idx).get());
246 line_entry.range.GetBaseAddress().SetOffset(entry.sect_offset);
247 if (!entry.is_terminal_entry && idx + 1 < m_entries.size())
248 {
249 const Entry& next_entry = m_entries[idx+1];
250 if (next_entry.sect_idx == entry.sect_idx)
251 {
252 line_entry.range.SetByteSize(next_entry.sect_offset - entry.sect_offset);
253 }
254 else
255 {
256 Address next_line_addr(m_section_list.GetSectionAtIndex (next_entry.sect_idx).get(), next_entry.sect_offset);
257 line_entry.range.SetByteSize(next_line_addr.GetFileAddress() - line_entry.range.GetBaseAddress().GetFileAddress());
258 }
259 }
260 else
261 line_entry.range.SetByteSize(0);
262 line_entry.file = m_comp_unit->GetSupportFiles().GetFileSpecAtIndex (entry.file_idx);
263 line_entry.line = entry.line;
264 line_entry.column = entry.column;
265 line_entry.is_start_of_statement = entry.is_start_of_statement;
266 line_entry.is_start_of_basic_block = entry.is_start_of_basic_block;
267 line_entry.is_prologue_end = entry.is_prologue_end;
268 line_entry.is_epilogue_begin = entry.is_epilogue_begin;
269 line_entry.is_terminal_entry = entry.is_terminal_entry;
270 return true;
271 }
272 return false;
273}
274
275uint32_t
Greg Clayton8019d7f2010-09-12 06:24:05 +0000276LineTable::FindLineEntryIndexByFileIndex
277(
278 uint32_t start_idx,
279 const std::vector<uint32_t> &file_indexes,
280 uint32_t line,
281 bool exact,
282 LineEntry* line_entry_ptr
283)
284{
285
286 const size_t count = m_entries.size();
287 std::vector<uint32_t>::const_iterator begin_pos = file_indexes.begin();
288 std::vector<uint32_t>::const_iterator end_pos = file_indexes.end();
Greg Clayton178710c2010-09-14 02:20:48 +0000289 size_t best_match = UINT32_MAX;
Greg Clayton8019d7f2010-09-12 06:24:05 +0000290
291 for (size_t idx = start_idx; idx < count; ++idx)
292 {
293 // Skip line table rows that terminate the previous row (is_terminal_entry is non-zero)
294 if (m_entries[idx].is_terminal_entry)
295 continue;
296
297 if (find (begin_pos, end_pos, m_entries[idx].file_idx) == end_pos)
298 continue;
299
300 // Exact match always wins. Otherwise try to find the closest line > the desired
301 // line.
302 // FIXME: Maybe want to find the line closest before and the line closest after and
303 // if they're not in the same function, don't return a match.
304
305 if (m_entries[idx].line < line)
306 {
307 continue;
308 }
309 else if (m_entries[idx].line == line)
310 {
311 if (line_entry_ptr)
312 ConvertEntryAtIndexToLineEntry (idx, *line_entry_ptr);
313 return idx;
314 }
315 else if (!exact)
316 {
317 if (best_match == UINT32_MAX)
318 best_match = idx;
319 else if (m_entries[idx].line < m_entries[best_match].line)
320 best_match = idx;
321 }
322 }
323
Greg Clayton178710c2010-09-14 02:20:48 +0000324 if (best_match != UINT32_MAX)
Greg Clayton8019d7f2010-09-12 06:24:05 +0000325 {
326 if (line_entry_ptr)
327 ConvertEntryAtIndexToLineEntry (best_match, *line_entry_ptr);
328 return best_match;
329 }
Greg Clayton178710c2010-09-14 02:20:48 +0000330 return UINT32_MAX;
Greg Clayton8019d7f2010-09-12 06:24:05 +0000331}
332
333uint32_t
Chris Lattner24943d22010-06-08 16:52:24 +0000334LineTable::FindLineEntryIndexByFileIndex (uint32_t start_idx, uint32_t file_idx, uint32_t line, bool exact, LineEntry* line_entry_ptr)
335{
336 const size_t count = m_entries.size();
Greg Clayton178710c2010-09-14 02:20:48 +0000337 size_t best_match = UINT32_MAX;
Chris Lattner24943d22010-06-08 16:52:24 +0000338
339 for (size_t idx = start_idx; idx < count; ++idx)
340 {
341 // Skip line table rows that terminate the previous row (is_terminal_entry is non-zero)
342 if (m_entries[idx].is_terminal_entry)
343 continue;
344
345 if (m_entries[idx].file_idx != file_idx)
346 continue;
347
348 // Exact match always wins. Otherwise try to find the closest line > the desired
349 // line.
350 // FIXME: Maybe want to find the line closest before and the line closest after and
351 // if they're not in the same function, don't return a match.
352
353 if (m_entries[idx].line < line)
354 {
355 continue;
356 }
357 else if (m_entries[idx].line == line)
358 {
359 if (line_entry_ptr)
360 ConvertEntryAtIndexToLineEntry (idx, *line_entry_ptr);
361 return idx;
362 }
363 else if (!exact)
364 {
365 if (best_match == UINT32_MAX)
366 best_match = idx;
367 else if (m_entries[idx].line < m_entries[best_match].line)
368 best_match = idx;
369 }
370 }
371
Greg Clayton178710c2010-09-14 02:20:48 +0000372 if (best_match != UINT32_MAX)
Chris Lattner24943d22010-06-08 16:52:24 +0000373 {
374 if (line_entry_ptr)
375 ConvertEntryAtIndexToLineEntry (best_match, *line_entry_ptr);
376 return best_match;
377 }
Greg Clayton178710c2010-09-14 02:20:48 +0000378 return UINT32_MAX;
Chris Lattner24943d22010-06-08 16:52:24 +0000379}
380
Greg Clayton52c8b6e2011-04-19 04:19:37 +0000381size_t
382LineTable::FineLineEntriesForFileIndex (uint32_t file_idx,
383 bool append,
384 SymbolContextList &sc_list)
385{
386
387 if (!append)
388 sc_list.Clear();
389
390 size_t num_added = 0;
391 const size_t count = m_entries.size();
392 if (count > 0)
393 {
394 SymbolContext sc (m_comp_unit);
395
396 for (size_t idx = 0; idx < count; ++idx)
397 {
398 // Skip line table rows that terminate the previous row (is_terminal_entry is non-zero)
399 if (m_entries[idx].is_terminal_entry)
400 continue;
401
402 if (m_entries[idx].file_idx == file_idx)
403 {
404 if (ConvertEntryAtIndexToLineEntry (idx, sc.line_entry))
405 {
406 ++num_added;
407 sc_list.Append(sc);
408 }
409 }
410 }
411 }
412 return num_added;
413}
414
415
Chris Lattner24943d22010-06-08 16:52:24 +0000416void
Greg Claytoneea26402010-09-14 23:36:40 +0000417LineTable::Dump (Stream *s, Target *target, Address::DumpStyle style, Address::DumpStyle fallback_style, bool show_line_ranges)
Chris Lattner24943d22010-06-08 16:52:24 +0000418{
419 const size_t count = m_entries.size();
420 LineEntry line_entry;
421 FileSpec prev_file;
422 for (size_t idx = 0; idx < count; ++idx)
423 {
424 ConvertEntryAtIndexToLineEntry (idx, line_entry);
Greg Claytoneea26402010-09-14 23:36:40 +0000425 line_entry.Dump (s, target, prev_file != line_entry.file, style, fallback_style, show_line_ranges);
Chris Lattner24943d22010-06-08 16:52:24 +0000426 s->EOL();
427 prev_file = line_entry.file;
428 }
429}
430
431
432void
Greg Claytoneea26402010-09-14 23:36:40 +0000433LineTable::GetDescription (Stream *s, Target *target, DescriptionLevel level)
Chris Lattner24943d22010-06-08 16:52:24 +0000434{
435 const size_t count = m_entries.size();
436 LineEntry line_entry;
437 for (size_t idx = 0; idx < count; ++idx)
438 {
439 ConvertEntryAtIndexToLineEntry (idx, line_entry);
Greg Claytoneea26402010-09-14 23:36:40 +0000440 line_entry.GetDescription (s, level, m_comp_unit, target, true);
Chris Lattner24943d22010-06-08 16:52:24 +0000441 s->EOL();
442 }
443}
444
445
446