blob: 482ccbbcdb0816a6371098ab6d50b203a15189bb [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);
89 if (!file_sp)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000090 {
Jim Inghamb7f6b2f2011-09-08 22:13:49 +000091 file_sp.reset (new File (file_spec, m_target));
Jim Inghame37d6052011-09-13 00:29:56 +000092
93 m_debugger->GetSourceFileCache().AddSourceFile(file_sp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000094 }
95 return file_sp;
96}
97
98size_t
99SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile
100(
101 uint32_t line,
102 uint32_t context_before,
103 uint32_t context_after,
104 const char* current_line_cstr,
Greg Clayton176761e2011-04-19 04:19:37 +0000105 Stream *s,
106 const SymbolContextList *bp_locs
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000107)
108{
Jim Inghame37d6052011-09-13 00:29:56 +0000109 size_t return_value = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000110 if (line == 0)
111 {
112 if (m_last_file_line != 0
113 && m_last_file_line != UINT32_MAX)
114 line = m_last_file_line + context_before;
115 else
116 line = 1;
117 }
118
119 m_last_file_line = line + context_after + 1;
120 m_last_file_context_before = context_before;
121 m_last_file_context_after = context_after;
122
123 if (context_before == UINT32_MAX)
124 context_before = 0;
125 if (context_after == UINT32_MAX)
126 context_after = 10;
127
128 if (m_last_file_sp.get())
129 {
130 const uint32_t start_line = line <= context_before ? 1 : line - context_before;
131 const uint32_t end_line = line + context_after;
132 uint32_t curr_line;
133 for (curr_line = start_line; curr_line <= end_line; ++curr_line)
134 {
135 if (!m_last_file_sp->LineIsValid (curr_line))
136 {
137 m_last_file_line = UINT32_MAX;
138 break;
139 }
140
Greg Clayton176761e2011-04-19 04:19:37 +0000141 char prefix[32] = "";
142 if (bp_locs)
143 {
144 uint32_t bp_count = bp_locs->NumLineEntriesWithLine (curr_line);
145
146 if (bp_count > 0)
147 ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count);
148 else
149 ::snprintf (prefix, sizeof (prefix), " ");
150 }
151
Jim Inghame37d6052011-09-13 00:29:56 +0000152 return_value += s->Printf("%s%2.2s %-4u\t",
Greg Clayton176761e2011-04-19 04:19:37 +0000153 prefix,
154 curr_line == line ? current_line_cstr : "",
155 curr_line);
Jim Inghame37d6052011-09-13 00:29:56 +0000156 size_t this_line_size = m_last_file_sp->DisplaySourceLines (curr_line, 0, 0, s);
157 if (this_line_size == 0)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000158 {
159 m_last_file_line = UINT32_MAX;
160 break;
161 }
Jim Inghame37d6052011-09-13 00:29:56 +0000162 else
163 return_value += this_line_size;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000164 }
165 }
Jim Inghame37d6052011-09-13 00:29:56 +0000166 return return_value;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000167}
168
169size_t
170SourceManager::DisplaySourceLinesWithLineNumbers
171(
172 const FileSpec &file_spec,
173 uint32_t line,
174 uint32_t context_before,
175 uint32_t context_after,
176 const char* current_line_cstr,
Greg Clayton176761e2011-04-19 04:19:37 +0000177 Stream *s,
178 const SymbolContextList *bp_locs
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000179)
180{
181 bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec);
182
183 if (!same_as_previous)
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000184 m_last_file_sp = GetFile (file_spec);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000185
186 if (line == 0)
187 {
188 if (!same_as_previous)
189 m_last_file_line = 0;
190 }
191
Greg Clayton176761e2011-04-19 04:19:37 +0000192 return DisplaySourceLinesWithLineNumbersUsingLastFile (line, context_before, context_after, current_line_cstr, s, bp_locs);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000193}
194
195size_t
Greg Clayton176761e2011-04-19 04:19:37 +0000196SourceManager::DisplayMoreWithLineNumbers (Stream *s, const SymbolContextList *bp_locs)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000197{
198 if (m_last_file_sp)
199 {
200 if (m_last_file_line == UINT32_MAX)
201 return 0;
Jim Inghame37d6052011-09-13 00:29:56 +0000202 return DisplaySourceLinesWithLineNumbersUsingLastFile (0, m_last_file_context_before, m_last_file_context_after, "", s, bp_locs);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000203 }
204 return 0;
205}
206
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000207bool
208SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line)
209{
210 FileSP old_file_sp = m_last_file_sp;
211 m_last_file_sp = GetFile (file_spec);
Jim Inghamf3277752011-10-07 22:16:04 +0000212
213 m_default_set = true;
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000214 if (m_last_file_sp)
215 {
216 m_last_file_line = line;
217 return true;
218 }
219 else
220 {
221 m_last_file_sp = old_file_sp;
222 return false;
223 }
224}
225
226bool
227SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line)
228{
229 if (m_last_file_sp)
230 {
231 file_spec = m_last_file_sp->GetFileSpec();
232 line = m_last_file_line;
233 return true;
234 }
Jim Inghamf3277752011-10-07 22:16:04 +0000235 else if (!m_default_set)
236 {
237 // If nobody has set the default file and line then try here. If there's no executable, then we
238 // will try again later when there is one. Otherwise, if we can't find it we won't look again,
239 // somebody will have to set it (for instance when we stop somewhere...)
240 Module *executable_ptr = m_target->GetExecutableModulePointer();
241 if (executable_ptr)
242 {
243 SymbolContextList sc_list;
244 uint32_t num_matches;
245 ConstString main_name("main");
246 bool symbols_okay = false; // Force it to be a debug symbol.
247 bool append = false;
Sean Callananb6d70eb2011-10-12 02:08:07 +0000248 num_matches = executable_ptr->FindFunctions (main_name, NULL, lldb::eFunctionNameTypeBase, symbols_okay, append, sc_list);
Jim Inghamf3277752011-10-07 22:16:04 +0000249 for (uint32_t idx = 0; idx < num_matches; idx++)
250 {
251 SymbolContext sc;
252 sc_list.GetContextAtIndex(idx, sc);
253 if (sc.line_entry.file)
254 {
255 SetDefaultFileAndLine(sc.line_entry.file, sc.line_entry.line);
256 break;
257 }
258 }
259 return GetDefaultFileAndLine (file_spec, line);
260 }
261 else
262 return false;
263 }
Jim Inghamb7f6b2f2011-09-08 22:13:49 +0000264 else
265 return false;
266}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000267
Jim Ingham969795f2011-09-21 01:17:13 +0000268void
269SourceManager::FindLinesMatchingRegex (FileSpec &file_spec,
270 RegularExpression& regex,
271 uint32_t start_line,
272 uint32_t end_line,
273 std::vector<uint32_t> &match_lines)
274{
275 match_lines.clear();
276 FileSP file_sp = GetFile (file_spec);
277 if (!file_sp)
278 return;
279 return file_sp->FindLinesMatchingRegex (regex, start_line, end_line, match_lines);
280}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000281
Greg Clayton7e14f912011-04-23 02:04:55 +0000282SourceManager::File::File(const FileSpec &file_spec, Target *target) :
283 m_file_spec_orig (file_spec),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000284 m_file_spec(file_spec),
Greg Clayton7e14f912011-04-23 02:04:55 +0000285 m_mod_time (file_spec.GetModificationTime()),
286 m_data_sp(),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000287 m_offsets()
288{
Greg Clayton7e14f912011-04-23 02:04:55 +0000289 if (!m_mod_time.IsValid())
290 {
Jim Inghame37d6052011-09-13 00:29:56 +0000291 if (target)
292 {
293 if (!file_spec.GetDirectory() && file_spec.GetFilename())
294 {
295 // If this is just a file name, lets see if we can find it in the target:
296 bool check_inlines = false;
297 SymbolContextList sc_list;
298 size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (file_spec.GetFilename().AsCString(),
299 0,
300 check_inlines,
301 lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit,
302 sc_list);
303 bool got_multiple = false;
304 if (num_matches != 0)
305 {
306 if (num_matches > 1)
307 {
308 SymbolContext sc;
309 FileSpec *test_cu_spec = NULL;
310
311 for (unsigned i = 0; i < num_matches; i++)
312 {
313 sc_list.GetContextAtIndex(i, sc);
314 if (sc.comp_unit)
315 {
316 if (test_cu_spec)
317 {
318 if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
319 got_multiple = true;
320 break;
321 }
322 else
323 test_cu_spec = sc.comp_unit;
324 }
325 }
326 }
327 if (!got_multiple)
328 {
329 SymbolContext sc;
330 sc_list.GetContextAtIndex (0, sc);
331 m_file_spec = static_cast<FileSpec *>(sc.comp_unit);
332 m_mod_time = m_file_spec.GetModificationTime();
333 }
334 }
335 }
336 else
337 {
338 if (target->GetSourcePathMap().RemapPath(file_spec.GetDirectory(), m_file_spec.GetDirectory()))
339 m_mod_time = file_spec.GetModificationTime();
340 }
341 }
Greg Clayton7e14f912011-04-23 02:04:55 +0000342 }
343
344 if (m_mod_time.IsValid())
345 m_data_sp = m_file_spec.ReadFileContents ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000346}
347
348SourceManager::File::~File()
349{
350}
351
352uint32_t
353SourceManager::File::GetLineOffset (uint32_t line)
354{
355 if (line == 0)
356 return UINT32_MAX;
357
358 if (line == 1)
359 return 0;
360
361 if (CalculateLineOffsets (line))
362 {
363 if (line < m_offsets.size())
364 return m_offsets[line - 1]; // yes we want "line - 1" in the index
365 }
366 return UINT32_MAX;
367}
368
369bool
370SourceManager::File::LineIsValid (uint32_t line)
371{
372 if (line == 0)
373 return false;
374
375 if (CalculateLineOffsets (line))
376 return line < m_offsets.size();
377 return false;
378}
379
380size_t
381SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s)
382{
Greg Clayton9625d082010-12-08 20:16:12 +0000383 // TODO: use host API to sign up for file modifications to anything in our
384 // source cache and only update when we determine a file has been updated.
385 // For now we check each time we want to display info for the file.
386 TimeValue curr_mod_time (m_file_spec.GetModificationTime());
387 if (m_mod_time != curr_mod_time)
388 {
389 m_mod_time = curr_mod_time;
390 m_data_sp = m_file_spec.ReadFileContents ();
391 m_offsets.clear();
392 }
393
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000394 const uint32_t start_line = line <= context_before ? 1 : line - context_before;
395 const uint32_t start_line_offset = GetLineOffset (start_line);
396 if (start_line_offset != UINT32_MAX)
397 {
398 const uint32_t end_line = line + context_after;
399 uint32_t end_line_offset = GetLineOffset (end_line + 1);
400 if (end_line_offset == UINT32_MAX)
401 end_line_offset = m_data_sp->GetByteSize();
402
403 assert (start_line_offset <= end_line_offset);
404 size_t bytes_written = 0;
405 if (start_line_offset < end_line_offset)
406 {
407 size_t count = end_line_offset - start_line_offset;
408 const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
409 bytes_written = s->Write(cstr, count);
410 if (!is_newline_char(cstr[count-1]))
411 bytes_written += s->EOL();
412 }
413 return bytes_written;
414 }
415 return 0;
416}
417
Jim Ingham969795f2011-09-21 01:17:13 +0000418void
419SourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines)
420{
421 TimeValue curr_mod_time (m_file_spec.GetModificationTime());
422 if (m_mod_time != curr_mod_time)
423 {
424 m_mod_time = curr_mod_time;
425 m_data_sp = m_file_spec.ReadFileContents ();
426 m_offsets.clear();
427 }
428
429 match_lines.clear();
430
431 if (!LineIsValid(start_line) || (end_line != UINT32_MAX && !LineIsValid(end_line)))
432 return;
433 if (start_line > end_line)
434 return;
435
436 for (uint32_t line_no = start_line; line_no < end_line; line_no++)
437 {
438 std::string buffer;
439 if (!GetLine (line_no, buffer))
440 break;
441 if (regex.Execute(buffer.c_str()))
442 {
443 match_lines.push_back(line_no);
444 }
445 }
446}
447
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000448bool
449SourceManager::File::FileSpecMatches (const FileSpec &file_spec)
450{
Greg Clayton644247c2011-07-07 01:59:51 +0000451 return FileSpec::Equal (m_file_spec, file_spec, false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000452}
453
Jim Inghame37d6052011-09-13 00:29:56 +0000454bool
455lldb_private::operator== (const SourceManager::File &lhs, const SourceManager::File &rhs)
456{
457 if (lhs.m_file_spec == rhs.m_file_spec)
458 {
459 if (lhs.m_mod_time.IsValid())
460 {
461 if (rhs.m_mod_time.IsValid())
462 return lhs.m_mod_time == rhs.m_mod_time;
463 else
464 return false;
465 }
466 else if (rhs.m_mod_time.IsValid())
467 return false;
468 else
469 return true;
470 }
471 else
472 return false;
473}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000474
475bool
476SourceManager::File::CalculateLineOffsets (uint32_t line)
477{
478 line = UINT32_MAX; // TODO: take this line out when we support partial indexing
479 if (line == UINT32_MAX)
480 {
481 // Already done?
482 if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
483 return true;
484
485 if (m_offsets.empty())
486 {
487 if (m_data_sp.get() == NULL)
488 return false;
489
490 const char *start = (char *)m_data_sp->GetBytes();
491 if (start)
492 {
493 const char *end = start + m_data_sp->GetByteSize();
494
495 // Calculate all line offsets from scratch
496
497 // Push a 1 at index zero to indicate the file has been completely indexed.
498 m_offsets.push_back(UINT32_MAX);
499 register const char *s;
500 for (s = start; s < end; ++s)
501 {
502 register char curr_ch = *s;
503 if (is_newline_char (curr_ch))
504 {
505 register char next_ch = s[1];
506 if (is_newline_char (next_ch))
507 {
508 if (curr_ch != next_ch)
509 ++s;
510 }
511 m_offsets.push_back(s + 1 - start);
512 }
513 }
514 if (!m_offsets.empty())
515 {
516 if (m_offsets.back() < end - start)
517 m_offsets.push_back(end - start);
518 }
519 return true;
520 }
521 }
522 else
523 {
524 // Some lines have been populated, start where we last left off
525 assert(!"Not implemented yet");
526 }
527
528 }
529 else
530 {
531 // Calculate all line offsets up to "line"
532 assert(!"Not implemented yet");
533 }
534 return false;
535}
Jim Inghame37d6052011-09-13 00:29:56 +0000536
Jim Ingham969795f2011-09-21 01:17:13 +0000537bool
538SourceManager::File::GetLine (uint32_t line_no, std::string &buffer)
539{
540 if (!LineIsValid(line_no))
541 return false;
542
543 uint32_t start_offset = GetLineOffset (line_no);
544 uint32_t end_offset = GetLineOffset (line_no + 1);
545 if (end_offset == UINT32_MAX)
546 {
547 end_offset = m_data_sp->GetByteSize();
548 }
549 buffer.assign((char *) m_data_sp->GetBytes() + start_offset, end_offset - start_offset);
550
551 return true;
552}
553
Jim Inghame37d6052011-09-13 00:29:56 +0000554void
555SourceManager::SourceFileCache::AddSourceFile (const FileSP &file_sp)
556{
557 FileSpec file_spec;
558 FileCache::iterator pos = m_file_cache.find(file_spec);
559 if (pos == m_file_cache.end())
560 m_file_cache[file_spec] = file_sp;
561 else
562 {
563 if (file_sp != pos->second)
564 m_file_cache[file_spec] = file_sp;
565 }
566}
567
568SourceManager::FileSP
569SourceManager::SourceFileCache::FindSourceFile (const FileSpec &file_spec) const
570{
571 FileSP file_sp;
572 FileCache::const_iterator pos = m_file_cache.find(file_spec);
573 if (pos != m_file_cache.end())
574 file_sp = pos->second;
575 return file_sp;
576}
577