blob: 743f2d1163cafa8ecd6e7d42120a281e51e8a757 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- SourceManager.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/SourceManager.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Core/DataBuffer.h"
Jim Inghame37d6052011-09-13 00:29:56 +000017#include "lldb/Core/Debugger.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000018#include "lldb/Core/Stream.h"
Greg Clayton176761e2011-04-19 04:19:37 +000019#include "lldb/Symbol/SymbolContext.h"
Greg Clayton7e14f912011-04-23 02:04:55 +000020#include "lldb/Target/Target.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000021
22using namespace lldb_private;
23
24static inline bool is_newline_char(char ch)
25{
26 return ch == '\n' || ch == '\r';
27}
28
29
30//----------------------------------------------------------------------
31// SourceManager constructor
32//----------------------------------------------------------------------
Jim Inghame37d6052011-09-13 00:29:56 +000033SourceManager::SourceManager(Target &target) :
Chris Lattner30fdc8d2010-06-08 16:52:24 +000034 m_last_file_sp (),
35 m_last_file_line (0),
36 m_last_file_context_before (0),
Jim Inghamb7f6b2f2011-09-08 22:13:49 +000037 m_last_file_context_after (10),
Jim Inghamf3277752011-10-07 22:16:04 +000038 m_default_set(false),
Jim Inghame37d6052011-09-13 00:29:56 +000039 m_target (&target),
40 m_debugger(NULL)
41{
42 m_debugger = &(m_target->GetDebugger());
43}
44
45SourceManager::SourceManager(Debugger &debugger) :
46 m_last_file_sp (),
47 m_last_file_line (0),
48 m_last_file_context_before (0),
49 m_last_file_context_after (10),
Jim Inghamf3277752011-10-07 22:16:04 +000050 m_default_set(false),
Jim Inghame37d6052011-09-13 00:29:56 +000051 m_target (NULL),
52 m_debugger (&debugger)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000053{
54}
55
56//----------------------------------------------------------------------
57// Destructor
58//----------------------------------------------------------------------
59SourceManager::~SourceManager()
60{
61}
62
63size_t
64SourceManager::DisplaySourceLines
65(
66 const FileSpec &file_spec,
67 uint32_t line,
68 uint32_t context_before,
69 uint32_t context_after,
70 Stream *s
71)
72{
Jim Inghamb7f6b2f2011-09-08 22:13:49 +000073 m_last_file_sp = GetFile (file_spec);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000074 m_last_file_line = line + context_after + 1;
75 m_last_file_context_before = context_before;
76 m_last_file_context_after = context_after;
77 if (m_last_file_sp.get())
78 return m_last_file_sp->DisplaySourceLines (line, context_before, context_after, s);
79
80 return 0;
81}
82
83SourceManager::FileSP
Jim Inghamb7f6b2f2011-09-08 22:13:49 +000084SourceManager::GetFile (const FileSpec &file_spec)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000085{
86 FileSP file_sp;
Jim Inghame37d6052011-09-13 00:29:56 +000087 file_sp = m_debugger->GetSourceFileCache().FindSourceFile (file_spec);
88 if (!file_sp)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000089 {
Jim Inghamb7f6b2f2011-09-08 22:13:49 +000090 file_sp.reset (new File (file_spec, m_target));
Jim Inghame37d6052011-09-13 00:29:56 +000091
92 m_debugger->GetSourceFileCache().AddSourceFile(file_sp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000093 }
94 return file_sp;
95}
96
97size_t
98SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile
99(
100 uint32_t line,
101 uint32_t context_before,
102 uint32_t context_after,
103 const char* current_line_cstr,
Greg Clayton176761e2011-04-19 04:19:37 +0000104 Stream *s,
105 const SymbolContextList *bp_locs
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000106)
107{
Jim Inghame37d6052011-09-13 00:29:56 +0000108 size_t return_value = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000109 if (line == 0)
110 {
111 if (m_last_file_line != 0
112 && m_last_file_line != UINT32_MAX)
113 line = m_last_file_line + context_before;
114 else
115 line = 1;
116 }
117
118 m_last_file_line = line + context_after + 1;
119 m_last_file_context_before = context_before;
120 m_last_file_context_after = context_after;
121
122 if (context_before == UINT32_MAX)
123 context_before = 0;
124 if (context_after == UINT32_MAX)
125 context_after = 10;
126
127 if (m_last_file_sp.get())
128 {
129 const uint32_t start_line = line <= context_before ? 1 : line - context_before;
130 const uint32_t end_line = line + context_after;
131 uint32_t curr_line;
132 for (curr_line = start_line; curr_line <= end_line; ++curr_line)
133 {
134 if (!m_last_file_sp->LineIsValid (curr_line))
135 {
136 m_last_file_line = UINT32_MAX;
137 break;
138 }
139
Greg Clayton176761e2011-04-19 04:19:37 +0000140 char prefix[32] = "";
141 if (bp_locs)
142 {
143 uint32_t bp_count = bp_locs->NumLineEntriesWithLine (curr_line);
144
145 if (bp_count > 0)
146 ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count);
147 else
148 ::snprintf (prefix, sizeof (prefix), " ");
149 }
150
Jim Inghame37d6052011-09-13 00:29:56 +0000151 return_value += s->Printf("%s%2.2s %-4u\t",
Greg Clayton176761e2011-04-19 04:19:37 +0000152 prefix,
153 curr_line == line ? current_line_cstr : "",
154 curr_line);
Jim Inghame37d6052011-09-13 00:29:56 +0000155 size_t this_line_size = m_last_file_sp->DisplaySourceLines (curr_line, 0, 0, s);
156 if (this_line_size == 0)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000157 {
158 m_last_file_line = UINT32_MAX;
159 break;
160 }
Jim Inghame37d6052011-09-13 00:29:56 +0000161 else
162 return_value += this_line_size;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000163 }
164 }
Jim Inghame37d6052011-09-13 00:29:56 +0000165 return return_value;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000166}
167
168size_t
169SourceManager::DisplaySourceLinesWithLineNumbers
170(
171 const FileSpec &file_spec,
172 uint32_t line,
173 uint32_t context_before,
174 uint32_t context_after,
175 const char* current_line_cstr,
Greg Clayton176761e2011-04-19 04:19:37 +0000176 Stream *s,
177 const SymbolContextList *bp_locs
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000178)
179{
180 bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec);
181
182 if (!same_as_previous)
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000183 m_last_file_sp = GetFile (file_spec);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000184
185 if (line == 0)
186 {
187 if (!same_as_previous)
188 m_last_file_line = 0;
189 }
190
Greg Clayton176761e2011-04-19 04:19:37 +0000191 return DisplaySourceLinesWithLineNumbersUsingLastFile (line, context_before, context_after, current_line_cstr, s, bp_locs);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000192}
193
194size_t
Greg Clayton176761e2011-04-19 04:19:37 +0000195SourceManager::DisplayMoreWithLineNumbers (Stream *s, const SymbolContextList *bp_locs)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000196{
197 if (m_last_file_sp)
198 {
199 if (m_last_file_line == UINT32_MAX)
200 return 0;
Jim Inghame37d6052011-09-13 00:29:56 +0000201 return DisplaySourceLinesWithLineNumbersUsingLastFile (0, m_last_file_context_before, m_last_file_context_after, "", s, bp_locs);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000202 }
203 return 0;
204}
205
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000206bool
207SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line)
208{
209 FileSP old_file_sp = m_last_file_sp;
210 m_last_file_sp = GetFile (file_spec);
Jim Inghamf3277752011-10-07 22:16:04 +0000211
212 m_default_set = true;
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000213 if (m_last_file_sp)
214 {
215 m_last_file_line = line;
216 return true;
217 }
218 else
219 {
220 m_last_file_sp = old_file_sp;
221 return false;
222 }
223}
224
225bool
226SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line)
227{
228 if (m_last_file_sp)
229 {
230 file_spec = m_last_file_sp->GetFileSpec();
231 line = m_last_file_line;
232 return true;
233 }
Jim Inghamf3277752011-10-07 22:16:04 +0000234 else if (!m_default_set)
235 {
236 // If nobody has set the default file and line then try here. If there's no executable, then we
237 // will try again later when there is one. Otherwise, if we can't find it we won't look again,
238 // somebody will have to set it (for instance when we stop somewhere...)
239 Module *executable_ptr = m_target->GetExecutableModulePointer();
240 if (executable_ptr)
241 {
242 SymbolContextList sc_list;
243 uint32_t num_matches;
244 ConstString main_name("main");
245 bool symbols_okay = false; // Force it to be a debug symbol.
246 bool append = false;
247 num_matches = executable_ptr->FindFunctions (main_name, lldb::eFunctionNameTypeBase, symbols_okay, append, sc_list);
248 for (uint32_t idx = 0; idx < num_matches; idx++)
249 {
250 SymbolContext sc;
251 sc_list.GetContextAtIndex(idx, sc);
252 if (sc.line_entry.file)
253 {
254 SetDefaultFileAndLine(sc.line_entry.file, sc.line_entry.line);
255 break;
256 }
257 }
258 return GetDefaultFileAndLine (file_spec, line);
259 }
260 else
261 return false;
262 }
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000263 else
264 return false;
265}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000266
Jim Ingham969795f2011-09-21 01:17:13 +0000267void
268SourceManager::FindLinesMatchingRegex (FileSpec &file_spec,
269 RegularExpression& regex,
270 uint32_t start_line,
271 uint32_t end_line,
272 std::vector<uint32_t> &match_lines)
273{
274 match_lines.clear();
275 FileSP file_sp = GetFile (file_spec);
276 if (!file_sp)
277 return;
278 return file_sp->FindLinesMatchingRegex (regex, start_line, end_line, match_lines);
279}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000280
Greg Clayton7e14f912011-04-23 02:04:55 +0000281SourceManager::File::File(const FileSpec &file_spec, Target *target) :
282 m_file_spec_orig (file_spec),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000283 m_file_spec(file_spec),
Greg Clayton7e14f912011-04-23 02:04:55 +0000284 m_mod_time (file_spec.GetModificationTime()),
285 m_data_sp(),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000286 m_offsets()
287{
Greg Clayton7e14f912011-04-23 02:04:55 +0000288 if (!m_mod_time.IsValid())
289 {
Jim Inghame37d6052011-09-13 00:29:56 +0000290 if (target)
291 {
292 if (!file_spec.GetDirectory() && file_spec.GetFilename())
293 {
294 // If this is just a file name, lets see if we can find it in the target:
295 bool check_inlines = false;
296 SymbolContextList sc_list;
297 size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (file_spec.GetFilename().AsCString(),
298 0,
299 check_inlines,
300 lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit,
301 sc_list);
302 bool got_multiple = false;
303 if (num_matches != 0)
304 {
305 if (num_matches > 1)
306 {
307 SymbolContext sc;
308 FileSpec *test_cu_spec = NULL;
309
310 for (unsigned i = 0; i < num_matches; i++)
311 {
312 sc_list.GetContextAtIndex(i, sc);
313 if (sc.comp_unit)
314 {
315 if (test_cu_spec)
316 {
317 if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
318 got_multiple = true;
319 break;
320 }
321 else
322 test_cu_spec = sc.comp_unit;
323 }
324 }
325 }
326 if (!got_multiple)
327 {
328 SymbolContext sc;
329 sc_list.GetContextAtIndex (0, sc);
330 m_file_spec = static_cast<FileSpec *>(sc.comp_unit);
331 m_mod_time = m_file_spec.GetModificationTime();
332 }
333 }
334 }
335 else
336 {
337 if (target->GetSourcePathMap().RemapPath(file_spec.GetDirectory(), m_file_spec.GetDirectory()))
338 m_mod_time = file_spec.GetModificationTime();
339 }
340 }
Greg Clayton7e14f912011-04-23 02:04:55 +0000341 }
342
343 if (m_mod_time.IsValid())
344 m_data_sp = m_file_spec.ReadFileContents ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000345}
346
347SourceManager::File::~File()
348{
349}
350
351uint32_t
352SourceManager::File::GetLineOffset (uint32_t line)
353{
354 if (line == 0)
355 return UINT32_MAX;
356
357 if (line == 1)
358 return 0;
359
360 if (CalculateLineOffsets (line))
361 {
362 if (line < m_offsets.size())
363 return m_offsets[line - 1]; // yes we want "line - 1" in the index
364 }
365 return UINT32_MAX;
366}
367
368bool
369SourceManager::File::LineIsValid (uint32_t line)
370{
371 if (line == 0)
372 return false;
373
374 if (CalculateLineOffsets (line))
375 return line < m_offsets.size();
376 return false;
377}
378
379size_t
380SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s)
381{
Greg Clayton9625d082010-12-08 20:16:12 +0000382 // TODO: use host API to sign up for file modifications to anything in our
383 // source cache and only update when we determine a file has been updated.
384 // For now we check each time we want to display info for the file.
385 TimeValue curr_mod_time (m_file_spec.GetModificationTime());
386 if (m_mod_time != curr_mod_time)
387 {
388 m_mod_time = curr_mod_time;
389 m_data_sp = m_file_spec.ReadFileContents ();
390 m_offsets.clear();
391 }
392
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000393 const uint32_t start_line = line <= context_before ? 1 : line - context_before;
394 const uint32_t start_line_offset = GetLineOffset (start_line);
395 if (start_line_offset != UINT32_MAX)
396 {
397 const uint32_t end_line = line + context_after;
398 uint32_t end_line_offset = GetLineOffset (end_line + 1);
399 if (end_line_offset == UINT32_MAX)
400 end_line_offset = m_data_sp->GetByteSize();
401
402 assert (start_line_offset <= end_line_offset);
403 size_t bytes_written = 0;
404 if (start_line_offset < end_line_offset)
405 {
406 size_t count = end_line_offset - start_line_offset;
407 const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
408 bytes_written = s->Write(cstr, count);
409 if (!is_newline_char(cstr[count-1]))
410 bytes_written += s->EOL();
411 }
412 return bytes_written;
413 }
414 return 0;
415}
416
Jim Ingham969795f2011-09-21 01:17:13 +0000417void
418SourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines)
419{
420 TimeValue curr_mod_time (m_file_spec.GetModificationTime());
421 if (m_mod_time != curr_mod_time)
422 {
423 m_mod_time = curr_mod_time;
424 m_data_sp = m_file_spec.ReadFileContents ();
425 m_offsets.clear();
426 }
427
428 match_lines.clear();
429
430 if (!LineIsValid(start_line) || (end_line != UINT32_MAX && !LineIsValid(end_line)))
431 return;
432 if (start_line > end_line)
433 return;
434
435 for (uint32_t line_no = start_line; line_no < end_line; line_no++)
436 {
437 std::string buffer;
438 if (!GetLine (line_no, buffer))
439 break;
440 if (regex.Execute(buffer.c_str()))
441 {
442 match_lines.push_back(line_no);
443 }
444 }
445}
446
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000447bool
448SourceManager::File::FileSpecMatches (const FileSpec &file_spec)
449{
Greg Clayton644247c2011-07-07 01:59:51 +0000450 return FileSpec::Equal (m_file_spec, file_spec, false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000451}
452
Jim Inghame37d6052011-09-13 00:29:56 +0000453bool
454lldb_private::operator== (const SourceManager::File &lhs, const SourceManager::File &rhs)
455{
456 if (lhs.m_file_spec == rhs.m_file_spec)
457 {
458 if (lhs.m_mod_time.IsValid())
459 {
460 if (rhs.m_mod_time.IsValid())
461 return lhs.m_mod_time == rhs.m_mod_time;
462 else
463 return false;
464 }
465 else if (rhs.m_mod_time.IsValid())
466 return false;
467 else
468 return true;
469 }
470 else
471 return false;
472}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000473
474bool
475SourceManager::File::CalculateLineOffsets (uint32_t line)
476{
477 line = UINT32_MAX; // TODO: take this line out when we support partial indexing
478 if (line == UINT32_MAX)
479 {
480 // Already done?
481 if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
482 return true;
483
484 if (m_offsets.empty())
485 {
486 if (m_data_sp.get() == NULL)
487 return false;
488
489 const char *start = (char *)m_data_sp->GetBytes();
490 if (start)
491 {
492 const char *end = start + m_data_sp->GetByteSize();
493
494 // Calculate all line offsets from scratch
495
496 // Push a 1 at index zero to indicate the file has been completely indexed.
497 m_offsets.push_back(UINT32_MAX);
498 register const char *s;
499 for (s = start; s < end; ++s)
500 {
501 register char curr_ch = *s;
502 if (is_newline_char (curr_ch))
503 {
504 register char next_ch = s[1];
505 if (is_newline_char (next_ch))
506 {
507 if (curr_ch != next_ch)
508 ++s;
509 }
510 m_offsets.push_back(s + 1 - start);
511 }
512 }
513 if (!m_offsets.empty())
514 {
515 if (m_offsets.back() < end - start)
516 m_offsets.push_back(end - start);
517 }
518 return true;
519 }
520 }
521 else
522 {
523 // Some lines have been populated, start where we last left off
524 assert(!"Not implemented yet");
525 }
526
527 }
528 else
529 {
530 // Calculate all line offsets up to "line"
531 assert(!"Not implemented yet");
532 }
533 return false;
534}
Jim Inghame37d6052011-09-13 00:29:56 +0000535
Jim Ingham969795f2011-09-21 01:17:13 +0000536bool
537SourceManager::File::GetLine (uint32_t line_no, std::string &buffer)
538{
539 if (!LineIsValid(line_no))
540 return false;
541
542 uint32_t start_offset = GetLineOffset (line_no);
543 uint32_t end_offset = GetLineOffset (line_no + 1);
544 if (end_offset == UINT32_MAX)
545 {
546 end_offset = m_data_sp->GetByteSize();
547 }
548 buffer.assign((char *) m_data_sp->GetBytes() + start_offset, end_offset - start_offset);
549
550 return true;
551}
552
Jim Inghame37d6052011-09-13 00:29:56 +0000553void
554SourceManager::SourceFileCache::AddSourceFile (const FileSP &file_sp)
555{
556 FileSpec file_spec;
557 FileCache::iterator pos = m_file_cache.find(file_spec);
558 if (pos == m_file_cache.end())
559 m_file_cache[file_spec] = file_sp;
560 else
561 {
562 if (file_sp != pos->second)
563 m_file_cache[file_spec] = file_sp;
564 }
565}
566
567SourceManager::FileSP
568SourceManager::SourceFileCache::FindSourceFile (const FileSpec &file_spec) const
569{
570 FileSP file_sp;
571 FileCache::const_iterator pos = m_file_cache.find(file_spec);
572 if (pos != m_file_cache.end())
573 file_sp = pos->second;
574 return file_sp;
575}
576