blob: 4d077b3bfe4bd7fae288cbea5395dcedc175a21d [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"
Sean Callananb6d70eb2011-10-12 02:08:07 +000019#include "lldb/Symbol/ClangNamespaceDecl.h"
Greg Clayton176761e2011-04-19 04:19:37 +000020#include "lldb/Symbol/SymbolContext.h"
Greg Clayton7e14f912011-04-23 02:04:55 +000021#include "lldb/Target/Target.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000022
23using namespace lldb_private;
24
25static inline bool is_newline_char(char ch)
26{
27 return ch == '\n' || ch == '\r';
28}
29
30
31//----------------------------------------------------------------------
32// SourceManager constructor
33//----------------------------------------------------------------------
Jim Inghame37d6052011-09-13 00:29:56 +000034SourceManager::SourceManager(Target &target) :
Chris Lattner30fdc8d2010-06-08 16:52:24 +000035 m_last_file_sp (),
36 m_last_file_line (0),
37 m_last_file_context_before (0),
Jim Inghamb7f6b2f2011-09-08 22:13:49 +000038 m_last_file_context_after (10),
Jim Inghamf3277752011-10-07 22:16:04 +000039 m_default_set(false),
Jim Inghame37d6052011-09-13 00:29:56 +000040 m_target (&target),
41 m_debugger(NULL)
42{
43 m_debugger = &(m_target->GetDebugger());
44}
45
46SourceManager::SourceManager(Debugger &debugger) :
47 m_last_file_sp (),
48 m_last_file_line (0),
49 m_last_file_context_before (0),
50 m_last_file_context_after (10),
Jim Inghamf3277752011-10-07 22:16:04 +000051 m_default_set(false),
Jim Inghame37d6052011-09-13 00:29:56 +000052 m_target (NULL),
53 m_debugger (&debugger)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000054{
55}
56
57//----------------------------------------------------------------------
58// Destructor
59//----------------------------------------------------------------------
60SourceManager::~SourceManager()
61{
62}
63
64size_t
65SourceManager::DisplaySourceLines
66(
67 const FileSpec &file_spec,
68 uint32_t line,
69 uint32_t context_before,
70 uint32_t context_after,
71 Stream *s
72)
73{
Jim Inghamb7f6b2f2011-09-08 22:13:49 +000074 m_last_file_sp = GetFile (file_spec);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000075 m_last_file_line = line + context_after + 1;
76 m_last_file_context_before = context_before;
77 m_last_file_context_after = context_after;
78 if (m_last_file_sp.get())
79 return m_last_file_sp->DisplaySourceLines (line, context_before, context_after, s);
80
81 return 0;
82}
83
84SourceManager::FileSP
Jim Inghamb7f6b2f2011-09-08 22:13:49 +000085SourceManager::GetFile (const FileSpec &file_spec)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000086{
87 FileSP file_sp;
Jim Inghame37d6052011-09-13 00:29:56 +000088 file_sp = m_debugger->GetSourceFileCache().FindSourceFile (file_spec);
Johnny Chen64bab482011-12-12 21:59:28 +000089 // If file_sp is no good or it points to a non-existent file, reset it.
90 if (!file_sp || !file_sp->GetFileSpec().Exists())
Chris Lattner30fdc8d2010-06-08 16:52:24 +000091 {
Jim Inghamb7f6b2f2011-09-08 22:13:49 +000092 file_sp.reset (new File (file_spec, m_target));
Jim Inghame37d6052011-09-13 00:29:56 +000093
94 m_debugger->GetSourceFileCache().AddSourceFile(file_sp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000095 }
96 return file_sp;
97}
98
99size_t
100SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile
101(
102 uint32_t line,
103 uint32_t context_before,
104 uint32_t context_after,
105 const char* current_line_cstr,
Greg Clayton176761e2011-04-19 04:19:37 +0000106 Stream *s,
107 const SymbolContextList *bp_locs
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000108)
109{
Jim Inghame37d6052011-09-13 00:29:56 +0000110 size_t return_value = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000111 if (line == 0)
112 {
113 if (m_last_file_line != 0
114 && m_last_file_line != UINT32_MAX)
115 line = m_last_file_line + context_before;
116 else
117 line = 1;
118 }
119
120 m_last_file_line = line + context_after + 1;
121 m_last_file_context_before = context_before;
122 m_last_file_context_after = context_after;
123
124 if (context_before == UINT32_MAX)
125 context_before = 0;
126 if (context_after == UINT32_MAX)
127 context_after = 10;
128
129 if (m_last_file_sp.get())
130 {
131 const uint32_t start_line = line <= context_before ? 1 : line - context_before;
132 const uint32_t end_line = line + context_after;
133 uint32_t curr_line;
134 for (curr_line = start_line; curr_line <= end_line; ++curr_line)
135 {
136 if (!m_last_file_sp->LineIsValid (curr_line))
137 {
138 m_last_file_line = UINT32_MAX;
139 break;
140 }
141
Greg Clayton176761e2011-04-19 04:19:37 +0000142 char prefix[32] = "";
143 if (bp_locs)
144 {
145 uint32_t bp_count = bp_locs->NumLineEntriesWithLine (curr_line);
146
147 if (bp_count > 0)
148 ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count);
149 else
150 ::snprintf (prefix, sizeof (prefix), " ");
151 }
152
Jim Inghame37d6052011-09-13 00:29:56 +0000153 return_value += s->Printf("%s%2.2s %-4u\t",
Greg Clayton176761e2011-04-19 04:19:37 +0000154 prefix,
155 curr_line == line ? current_line_cstr : "",
156 curr_line);
Jim Inghame37d6052011-09-13 00:29:56 +0000157 size_t this_line_size = m_last_file_sp->DisplaySourceLines (curr_line, 0, 0, s);
158 if (this_line_size == 0)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000159 {
160 m_last_file_line = UINT32_MAX;
161 break;
162 }
Jim Inghame37d6052011-09-13 00:29:56 +0000163 else
164 return_value += this_line_size;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000165 }
166 }
Jim Inghame37d6052011-09-13 00:29:56 +0000167 return return_value;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000168}
169
170size_t
171SourceManager::DisplaySourceLinesWithLineNumbers
172(
173 const FileSpec &file_spec,
174 uint32_t line,
175 uint32_t context_before,
176 uint32_t context_after,
177 const char* current_line_cstr,
Greg Clayton176761e2011-04-19 04:19:37 +0000178 Stream *s,
179 const SymbolContextList *bp_locs
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000180)
181{
182 bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec);
183
184 if (!same_as_previous)
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000185 m_last_file_sp = GetFile (file_spec);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000186
187 if (line == 0)
188 {
189 if (!same_as_previous)
190 m_last_file_line = 0;
191 }
192
Greg Clayton176761e2011-04-19 04:19:37 +0000193 return DisplaySourceLinesWithLineNumbersUsingLastFile (line, context_before, context_after, current_line_cstr, s, bp_locs);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000194}
195
196size_t
Greg Clayton176761e2011-04-19 04:19:37 +0000197SourceManager::DisplayMoreWithLineNumbers (Stream *s, const SymbolContextList *bp_locs)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000198{
199 if (m_last_file_sp)
200 {
201 if (m_last_file_line == UINT32_MAX)
202 return 0;
Jim Inghame37d6052011-09-13 00:29:56 +0000203 return DisplaySourceLinesWithLineNumbersUsingLastFile (0, m_last_file_context_before, m_last_file_context_after, "", s, bp_locs);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000204 }
205 return 0;
206}
207
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000208bool
209SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line)
210{
211 FileSP old_file_sp = m_last_file_sp;
212 m_last_file_sp = GetFile (file_spec);
Jim Inghamf3277752011-10-07 22:16:04 +0000213
214 m_default_set = true;
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000215 if (m_last_file_sp)
216 {
217 m_last_file_line = line;
218 return true;
219 }
220 else
221 {
222 m_last_file_sp = old_file_sp;
223 return false;
224 }
225}
226
227bool
228SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line)
229{
230 if (m_last_file_sp)
231 {
232 file_spec = m_last_file_sp->GetFileSpec();
233 line = m_last_file_line;
234 return true;
235 }
Jim Inghamf3277752011-10-07 22:16:04 +0000236 else if (!m_default_set)
237 {
238 // If nobody has set the default file and line then try here. If there's no executable, then we
239 // will try again later when there is one. Otherwise, if we can't find it we won't look again,
240 // somebody will have to set it (for instance when we stop somewhere...)
241 Module *executable_ptr = m_target->GetExecutableModulePointer();
242 if (executable_ptr)
243 {
244 SymbolContextList sc_list;
245 uint32_t num_matches;
246 ConstString main_name("main");
247 bool symbols_okay = false; // Force it to be a debug symbol.
Sean Callanan9df05fb2012-02-10 22:52:19 +0000248 bool inlines_okay = true;
Jim Inghamf3277752011-10-07 22:16:04 +0000249 bool append = false;
Sean Callanan9df05fb2012-02-10 22:52:19 +0000250 num_matches = executable_ptr->FindFunctions (main_name, NULL, lldb::eFunctionNameTypeBase, inlines_okay, symbols_okay, append, sc_list);
Jim Inghamf3277752011-10-07 22:16:04 +0000251 for (uint32_t idx = 0; idx < num_matches; idx++)
252 {
253 SymbolContext sc;
254 sc_list.GetContextAtIndex(idx, sc);
Greg Clayton6f6bf262011-12-10 21:05:26 +0000255 if (sc.function)
Jim Inghamf3277752011-10-07 22:16:04 +0000256 {
Greg Clayton6f6bf262011-12-10 21:05:26 +0000257 lldb_private::LineEntry line_entry;
258 if (sc.function->GetAddressRange().GetBaseAddress().CalculateSymbolContextLineEntry (line_entry))
259 {
260 SetDefaultFileAndLine (line_entry.file,
261 line_entry.line);
262 file_spec = m_last_file_sp->GetFileSpec();
263 line = m_last_file_line;
264 return true;
265 }
Jim Inghamf3277752011-10-07 22:16:04 +0000266 }
267 }
Jim Inghamf3277752011-10-07 22:16:04 +0000268 }
Jim Inghamf3277752011-10-07 22:16:04 +0000269 }
Greg Clayton6f6bf262011-12-10 21:05:26 +0000270 return false;
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000271}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000272
Jim Ingham969795f2011-09-21 01:17:13 +0000273void
274SourceManager::FindLinesMatchingRegex (FileSpec &file_spec,
275 RegularExpression& regex,
276 uint32_t start_line,
277 uint32_t end_line,
278 std::vector<uint32_t> &match_lines)
279{
280 match_lines.clear();
281 FileSP file_sp = GetFile (file_spec);
282 if (!file_sp)
283 return;
284 return file_sp->FindLinesMatchingRegex (regex, start_line, end_line, match_lines);
285}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000286
Greg Clayton7e14f912011-04-23 02:04:55 +0000287SourceManager::File::File(const FileSpec &file_spec, Target *target) :
288 m_file_spec_orig (file_spec),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000289 m_file_spec(file_spec),
Greg Clayton7e14f912011-04-23 02:04:55 +0000290 m_mod_time (file_spec.GetModificationTime()),
291 m_data_sp(),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000292 m_offsets()
293{
Greg Clayton7e14f912011-04-23 02:04:55 +0000294 if (!m_mod_time.IsValid())
295 {
Jim Inghame37d6052011-09-13 00:29:56 +0000296 if (target)
297 {
298 if (!file_spec.GetDirectory() && file_spec.GetFilename())
299 {
300 // If this is just a file name, lets see if we can find it in the target:
301 bool check_inlines = false;
302 SymbolContextList sc_list;
303 size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (file_spec.GetFilename().AsCString(),
304 0,
305 check_inlines,
306 lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit,
307 sc_list);
308 bool got_multiple = false;
309 if (num_matches != 0)
310 {
311 if (num_matches > 1)
312 {
313 SymbolContext sc;
314 FileSpec *test_cu_spec = NULL;
315
316 for (unsigned i = 0; i < num_matches; i++)
317 {
318 sc_list.GetContextAtIndex(i, sc);
319 if (sc.comp_unit)
320 {
321 if (test_cu_spec)
322 {
323 if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
324 got_multiple = true;
325 break;
326 }
327 else
328 test_cu_spec = sc.comp_unit;
329 }
330 }
331 }
332 if (!got_multiple)
333 {
334 SymbolContext sc;
335 sc_list.GetContextAtIndex (0, sc);
336 m_file_spec = static_cast<FileSpec *>(sc.comp_unit);
337 m_mod_time = m_file_spec.GetModificationTime();
338 }
339 }
340 }
Johnny Chen64bab482011-12-12 21:59:28 +0000341 // Try remapping if m_file_spec does not correspond to an existing file.
342 if (!m_file_spec.Exists())
Jim Inghame37d6052011-09-13 00:29:56 +0000343 {
Johnny Chen64bab482011-12-12 21:59:28 +0000344 ConstString new_path;
345 if (target->GetSourcePathMap().RemapPath(m_file_spec.GetDirectory(), new_path))
346 {
347 char resolved_path[PATH_MAX];
348 ::snprintf(resolved_path, PATH_MAX, "%s/%s", new_path.AsCString(), m_file_spec.GetFilename().AsCString());
349 m_file_spec = new FileSpec(resolved_path, true);
350 m_mod_time = m_file_spec.GetModificationTime();
351 }
Jim Inghame37d6052011-09-13 00:29:56 +0000352 }
353 }
Greg Clayton7e14f912011-04-23 02:04:55 +0000354 }
355
356 if (m_mod_time.IsValid())
357 m_data_sp = m_file_spec.ReadFileContents ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000358}
359
360SourceManager::File::~File()
361{
362}
363
364uint32_t
365SourceManager::File::GetLineOffset (uint32_t line)
366{
367 if (line == 0)
368 return UINT32_MAX;
369
370 if (line == 1)
371 return 0;
372
373 if (CalculateLineOffsets (line))
374 {
375 if (line < m_offsets.size())
376 return m_offsets[line - 1]; // yes we want "line - 1" in the index
377 }
378 return UINT32_MAX;
379}
380
381bool
382SourceManager::File::LineIsValid (uint32_t line)
383{
384 if (line == 0)
385 return false;
386
387 if (CalculateLineOffsets (line))
388 return line < m_offsets.size();
389 return false;
390}
391
392size_t
393SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s)
394{
Greg Clayton9625d082010-12-08 20:16:12 +0000395 // TODO: use host API to sign up for file modifications to anything in our
396 // source cache and only update when we determine a file has been updated.
397 // For now we check each time we want to display info for the file.
398 TimeValue curr_mod_time (m_file_spec.GetModificationTime());
Johnny Chen64bab482011-12-12 21:59:28 +0000399
400 if (curr_mod_time.IsValid() && m_mod_time != curr_mod_time)
Greg Clayton9625d082010-12-08 20:16:12 +0000401 {
402 m_mod_time = curr_mod_time;
403 m_data_sp = m_file_spec.ReadFileContents ();
404 m_offsets.clear();
405 }
406
Johnny Chen64bab482011-12-12 21:59:28 +0000407 // Sanity check m_data_sp before proceeding.
408 if (!m_data_sp)
409 return 0;
410
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000411 const uint32_t start_line = line <= context_before ? 1 : line - context_before;
412 const uint32_t start_line_offset = GetLineOffset (start_line);
413 if (start_line_offset != UINT32_MAX)
414 {
415 const uint32_t end_line = line + context_after;
416 uint32_t end_line_offset = GetLineOffset (end_line + 1);
417 if (end_line_offset == UINT32_MAX)
418 end_line_offset = m_data_sp->GetByteSize();
419
420 assert (start_line_offset <= end_line_offset);
421 size_t bytes_written = 0;
422 if (start_line_offset < end_line_offset)
423 {
424 size_t count = end_line_offset - start_line_offset;
425 const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
426 bytes_written = s->Write(cstr, count);
427 if (!is_newline_char(cstr[count-1]))
428 bytes_written += s->EOL();
429 }
430 return bytes_written;
431 }
432 return 0;
433}
434
Jim Ingham969795f2011-09-21 01:17:13 +0000435void
436SourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines)
437{
438 TimeValue curr_mod_time (m_file_spec.GetModificationTime());
439 if (m_mod_time != curr_mod_time)
440 {
441 m_mod_time = curr_mod_time;
442 m_data_sp = m_file_spec.ReadFileContents ();
443 m_offsets.clear();
444 }
445
446 match_lines.clear();
447
448 if (!LineIsValid(start_line) || (end_line != UINT32_MAX && !LineIsValid(end_line)))
449 return;
450 if (start_line > end_line)
451 return;
452
453 for (uint32_t line_no = start_line; line_no < end_line; line_no++)
454 {
455 std::string buffer;
456 if (!GetLine (line_no, buffer))
457 break;
458 if (regex.Execute(buffer.c_str()))
459 {
460 match_lines.push_back(line_no);
461 }
462 }
463}
464
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000465bool
466SourceManager::File::FileSpecMatches (const FileSpec &file_spec)
467{
Greg Clayton644247c2011-07-07 01:59:51 +0000468 return FileSpec::Equal (m_file_spec, file_spec, false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000469}
470
Jim Inghame37d6052011-09-13 00:29:56 +0000471bool
472lldb_private::operator== (const SourceManager::File &lhs, const SourceManager::File &rhs)
473{
474 if (lhs.m_file_spec == rhs.m_file_spec)
475 {
476 if (lhs.m_mod_time.IsValid())
477 {
478 if (rhs.m_mod_time.IsValid())
479 return lhs.m_mod_time == rhs.m_mod_time;
480 else
481 return false;
482 }
483 else if (rhs.m_mod_time.IsValid())
484 return false;
485 else
486 return true;
487 }
488 else
489 return false;
490}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000491
492bool
493SourceManager::File::CalculateLineOffsets (uint32_t line)
494{
495 line = UINT32_MAX; // TODO: take this line out when we support partial indexing
496 if (line == UINT32_MAX)
497 {
498 // Already done?
499 if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
500 return true;
501
502 if (m_offsets.empty())
503 {
504 if (m_data_sp.get() == NULL)
505 return false;
506
507 const char *start = (char *)m_data_sp->GetBytes();
508 if (start)
509 {
510 const char *end = start + m_data_sp->GetByteSize();
511
512 // Calculate all line offsets from scratch
513
514 // Push a 1 at index zero to indicate the file has been completely indexed.
515 m_offsets.push_back(UINT32_MAX);
516 register const char *s;
517 for (s = start; s < end; ++s)
518 {
519 register char curr_ch = *s;
520 if (is_newline_char (curr_ch))
521 {
522 register char next_ch = s[1];
523 if (is_newline_char (next_ch))
524 {
525 if (curr_ch != next_ch)
526 ++s;
527 }
528 m_offsets.push_back(s + 1 - start);
529 }
530 }
531 if (!m_offsets.empty())
532 {
533 if (m_offsets.back() < end - start)
534 m_offsets.push_back(end - start);
535 }
536 return true;
537 }
538 }
539 else
540 {
541 // Some lines have been populated, start where we last left off
542 assert(!"Not implemented yet");
543 }
544
545 }
546 else
547 {
548 // Calculate all line offsets up to "line"
549 assert(!"Not implemented yet");
550 }
551 return false;
552}
Jim Inghame37d6052011-09-13 00:29:56 +0000553
Jim Ingham969795f2011-09-21 01:17:13 +0000554bool
555SourceManager::File::GetLine (uint32_t line_no, std::string &buffer)
556{
557 if (!LineIsValid(line_no))
558 return false;
559
560 uint32_t start_offset = GetLineOffset (line_no);
561 uint32_t end_offset = GetLineOffset (line_no + 1);
562 if (end_offset == UINT32_MAX)
563 {
564 end_offset = m_data_sp->GetByteSize();
565 }
566 buffer.assign((char *) m_data_sp->GetBytes() + start_offset, end_offset - start_offset);
567
568 return true;
569}
570
Jim Inghame37d6052011-09-13 00:29:56 +0000571void
572SourceManager::SourceFileCache::AddSourceFile (const FileSP &file_sp)
573{
574 FileSpec file_spec;
575 FileCache::iterator pos = m_file_cache.find(file_spec);
576 if (pos == m_file_cache.end())
577 m_file_cache[file_spec] = file_sp;
578 else
579 {
580 if (file_sp != pos->second)
581 m_file_cache[file_spec] = file_sp;
582 }
583}
584
585SourceManager::FileSP
586SourceManager::SourceFileCache::FindSourceFile (const FileSpec &file_spec) const
587{
588 FileSP file_sp;
589 FileCache::const_iterator pos = m_file_cache.find(file_spec);
590 if (pos != m_file_cache.end())
591 file_sp = pos->second;
592 return file_sp;
593}
594