130fdc8d8SChris Lattner //===-- SourceManager.cpp ---------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1093a64300SDaniel Malea #include "lldb/lldb-python.h"
1193a64300SDaniel Malea 
1230fdc8d8SChris Lattner #include "lldb/Core/SourceManager.h"
1330fdc8d8SChris Lattner 
1430fdc8d8SChris Lattner // C Includes
1530fdc8d8SChris Lattner // C++ Includes
1630fdc8d8SChris Lattner // Other libraries and framework includes
1730fdc8d8SChris Lattner // Project includes
1830fdc8d8SChris Lattner #include "lldb/Core/DataBuffer.h"
19e37d605eSJim Ingham #include "lldb/Core/Debugger.h"
201f746071SGreg Clayton #include "lldb/Core/Module.h"
2130fdc8d8SChris Lattner #include "lldb/Core/Stream.h"
22b6d70ebcSSean Callanan #include "lldb/Symbol/ClangNamespaceDecl.h"
231f746071SGreg Clayton #include "lldb/Symbol/CompileUnit.h"
241f746071SGreg Clayton #include "lldb/Symbol/Function.h"
25176761e5SGreg Clayton #include "lldb/Symbol/SymbolContext.h"
267e14f91dSGreg Clayton #include "lldb/Target/Target.h"
2730fdc8d8SChris Lattner 
2830fdc8d8SChris Lattner using namespace lldb_private;
2930fdc8d8SChris Lattner 
3030fdc8d8SChris Lattner static inline bool is_newline_char(char ch)
3130fdc8d8SChris Lattner {
3230fdc8d8SChris Lattner     return ch == '\n' || ch == '\r';
3330fdc8d8SChris Lattner }
3430fdc8d8SChris Lattner 
3530fdc8d8SChris Lattner 
3630fdc8d8SChris Lattner //----------------------------------------------------------------------
3730fdc8d8SChris Lattner // SourceManager constructor
3830fdc8d8SChris Lattner //----------------------------------------------------------------------
39e37d605eSJim Ingham SourceManager::SourceManager(Target &target) :
4030fdc8d8SChris Lattner     m_last_file_sp (),
4130fdc8d8SChris Lattner     m_last_file_line (0),
4230fdc8d8SChris Lattner     m_last_file_context_before (0),
43b7f6b2faSJim Ingham     m_last_file_context_after (10),
44f3277750SJim Ingham     m_default_set(false),
45*196bbc25SJim Ingham     m_first_reverse(true),
46e37d605eSJim Ingham     m_target (&target),
47e37d605eSJim Ingham     m_debugger(NULL)
48e37d605eSJim Ingham {
49e37d605eSJim Ingham     m_debugger = &(m_target->GetDebugger());
50e37d605eSJim Ingham }
51e37d605eSJim Ingham 
52e37d605eSJim Ingham SourceManager::SourceManager(Debugger &debugger) :
53e37d605eSJim Ingham     m_last_file_sp (),
54e37d605eSJim Ingham     m_last_file_line (0),
55e37d605eSJim Ingham     m_last_file_context_before (0),
56e37d605eSJim Ingham     m_last_file_context_after (10),
57f3277750SJim Ingham     m_default_set(false),
58*196bbc25SJim Ingham     m_first_reverse (true),
59e37d605eSJim Ingham     m_target (NULL),
60e37d605eSJim Ingham     m_debugger (&debugger)
6130fdc8d8SChris Lattner {
6230fdc8d8SChris Lattner }
6330fdc8d8SChris Lattner 
6430fdc8d8SChris Lattner //----------------------------------------------------------------------
6530fdc8d8SChris Lattner // Destructor
6630fdc8d8SChris Lattner //----------------------------------------------------------------------
6730fdc8d8SChris Lattner SourceManager::~SourceManager()
6830fdc8d8SChris Lattner {
6930fdc8d8SChris Lattner }
7030fdc8d8SChris Lattner 
7130fdc8d8SChris Lattner SourceManager::FileSP
72b7f6b2faSJim Ingham SourceManager::GetFile (const FileSpec &file_spec)
7330fdc8d8SChris Lattner {
7430fdc8d8SChris Lattner     FileSP file_sp;
75e37d605eSJim Ingham     file_sp = m_debugger->GetSourceFileCache().FindSourceFile (file_spec);
7664bab489SJohnny Chen     // If file_sp is no good or it points to a non-existent file, reset it.
7764bab489SJohnny Chen     if (!file_sp || !file_sp->GetFileSpec().Exists())
7830fdc8d8SChris Lattner     {
79b7f6b2faSJim Ingham         file_sp.reset (new File (file_spec, m_target));
80e37d605eSJim Ingham 
81e37d605eSJim Ingham         m_debugger->GetSourceFileCache().AddSourceFile(file_sp);
8230fdc8d8SChris Lattner     }
8330fdc8d8SChris Lattner     return file_sp;
8430fdc8d8SChris Lattner }
8530fdc8d8SChris Lattner 
8630fdc8d8SChris Lattner size_t
8730fdc8d8SChris Lattner SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile
8830fdc8d8SChris Lattner (
8930fdc8d8SChris Lattner     uint32_t line,
9030fdc8d8SChris Lattner     uint32_t context_before,
9130fdc8d8SChris Lattner     uint32_t context_after,
9230fdc8d8SChris Lattner     const char* current_line_cstr,
93176761e5SGreg Clayton     Stream *s,
94176761e5SGreg Clayton     const SymbolContextList *bp_locs
9530fdc8d8SChris Lattner )
9630fdc8d8SChris Lattner {
97*196bbc25SJim Ingham     m_first_reverse = true;
98e37d605eSJim Ingham     size_t return_value = 0;
9930fdc8d8SChris Lattner     if (line == 0)
10030fdc8d8SChris Lattner     {
10130fdc8d8SChris Lattner         if (m_last_file_line != 0
10230fdc8d8SChris Lattner             && m_last_file_line != UINT32_MAX)
10330fdc8d8SChris Lattner             line = m_last_file_line + context_before;
10430fdc8d8SChris Lattner         else
10530fdc8d8SChris Lattner             line = 1;
10630fdc8d8SChris Lattner     }
10730fdc8d8SChris Lattner 
10830fdc8d8SChris Lattner     m_last_file_line = line + context_after + 1;
10930fdc8d8SChris Lattner     m_last_file_context_before = context_before;
11030fdc8d8SChris Lattner     m_last_file_context_after = context_after;
11130fdc8d8SChris Lattner 
11230fdc8d8SChris Lattner     if (context_before == UINT32_MAX)
11330fdc8d8SChris Lattner         context_before = 0;
11430fdc8d8SChris Lattner     if (context_after == UINT32_MAX)
11530fdc8d8SChris Lattner         context_after = 10;
11630fdc8d8SChris Lattner 
11730fdc8d8SChris Lattner     if (m_last_file_sp.get())
11830fdc8d8SChris Lattner     {
11930fdc8d8SChris Lattner         const uint32_t start_line = line <= context_before ? 1 : line - context_before;
12030fdc8d8SChris Lattner         const uint32_t end_line = line + context_after;
12130fdc8d8SChris Lattner         uint32_t curr_line;
12230fdc8d8SChris Lattner         for (curr_line = start_line; curr_line <= end_line; ++curr_line)
12330fdc8d8SChris Lattner         {
12430fdc8d8SChris Lattner             if (!m_last_file_sp->LineIsValid (curr_line))
12530fdc8d8SChris Lattner             {
12630fdc8d8SChris Lattner                 m_last_file_line = UINT32_MAX;
12730fdc8d8SChris Lattner                 break;
12830fdc8d8SChris Lattner             }
12930fdc8d8SChris Lattner 
130176761e5SGreg Clayton             char prefix[32] = "";
131176761e5SGreg Clayton             if (bp_locs)
132176761e5SGreg Clayton             {
133176761e5SGreg Clayton                 uint32_t bp_count = bp_locs->NumLineEntriesWithLine (curr_line);
134176761e5SGreg Clayton 
135176761e5SGreg Clayton                 if (bp_count > 0)
136176761e5SGreg Clayton                     ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count);
137176761e5SGreg Clayton                 else
138176761e5SGreg Clayton                     ::snprintf (prefix, sizeof (prefix), "    ");
139176761e5SGreg Clayton             }
140176761e5SGreg Clayton 
141e37d605eSJim Ingham             return_value += s->Printf("%s%2.2s %-4u\t",
142176761e5SGreg Clayton                       prefix,
143176761e5SGreg Clayton                       curr_line == line ? current_line_cstr : "",
144176761e5SGreg Clayton                       curr_line);
145e37d605eSJim Ingham             size_t this_line_size = m_last_file_sp->DisplaySourceLines (curr_line, 0, 0, s);
146e37d605eSJim Ingham             if (this_line_size == 0)
14730fdc8d8SChris Lattner             {
14830fdc8d8SChris Lattner                 m_last_file_line = UINT32_MAX;
14930fdc8d8SChris Lattner                 break;
15030fdc8d8SChris Lattner             }
151e37d605eSJim Ingham             else
152e37d605eSJim Ingham                 return_value += this_line_size;
15330fdc8d8SChris Lattner         }
15430fdc8d8SChris Lattner     }
155e37d605eSJim Ingham     return return_value;
15630fdc8d8SChris Lattner }
15730fdc8d8SChris Lattner 
15830fdc8d8SChris Lattner size_t
15930fdc8d8SChris Lattner SourceManager::DisplaySourceLinesWithLineNumbers
16030fdc8d8SChris Lattner (
16130fdc8d8SChris Lattner     const FileSpec &file_spec,
16230fdc8d8SChris Lattner     uint32_t line,
16330fdc8d8SChris Lattner     uint32_t context_before,
16430fdc8d8SChris Lattner     uint32_t context_after,
16530fdc8d8SChris Lattner     const char* current_line_cstr,
166176761e5SGreg Clayton     Stream *s,
167176761e5SGreg Clayton     const SymbolContextList *bp_locs
16830fdc8d8SChris Lattner )
16930fdc8d8SChris Lattner {
17030fdc8d8SChris Lattner     bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec);
17130fdc8d8SChris Lattner 
17230fdc8d8SChris Lattner     if (!same_as_previous)
173b7f6b2faSJim Ingham         m_last_file_sp = GetFile (file_spec);
17430fdc8d8SChris Lattner 
17530fdc8d8SChris Lattner     if (line == 0)
17630fdc8d8SChris Lattner     {
17730fdc8d8SChris Lattner         if (!same_as_previous)
17830fdc8d8SChris Lattner             m_last_file_line = 0;
17930fdc8d8SChris Lattner     }
18030fdc8d8SChris Lattner 
181176761e5SGreg Clayton     return DisplaySourceLinesWithLineNumbersUsingLastFile (line, context_before, context_after, current_line_cstr, s, bp_locs);
18230fdc8d8SChris Lattner }
18330fdc8d8SChris Lattner 
18430fdc8d8SChris Lattner size_t
185*196bbc25SJim Ingham SourceManager::DisplayMoreWithLineNumbers (Stream *s, const SymbolContextList *bp_locs, bool reverse)
18630fdc8d8SChris Lattner {
187*196bbc25SJim Ingham     // If we get called before anybody has set a default file and line, then try to figure it out here.
188*196bbc25SJim Ingham     if (!m_default_set)
189*196bbc25SJim Ingham     {
190*196bbc25SJim Ingham         FileSpec tmp_spec;
191*196bbc25SJim Ingham         uint32_t tmp_line;
192*196bbc25SJim Ingham         GetDefaultFileAndLine(tmp_spec, tmp_line);
193*196bbc25SJim Ingham     }
194*196bbc25SJim Ingham 
19530fdc8d8SChris Lattner     if (m_last_file_sp)
19630fdc8d8SChris Lattner     {
19730fdc8d8SChris Lattner         if (m_last_file_line == UINT32_MAX)
19830fdc8d8SChris Lattner             return 0;
199*196bbc25SJim Ingham 
200*196bbc25SJim Ingham         if (reverse && m_last_file_line == 1)
201*196bbc25SJim Ingham             return 0;
202*196bbc25SJim Ingham 
203*196bbc25SJim Ingham         uint32_t line;
204*196bbc25SJim Ingham         uint32_t new_last_file_line = 0;
205*196bbc25SJim Ingham 
206*196bbc25SJim Ingham         if (m_last_file_line != 0
207*196bbc25SJim Ingham             && m_last_file_line != UINT32_MAX)
208*196bbc25SJim Ingham         {
209*196bbc25SJim Ingham             if (reverse)
210*196bbc25SJim Ingham             {
211*196bbc25SJim Ingham                 // If this is the first time we've done a reverse, then back up one more time so we end
212*196bbc25SJim Ingham                 // up showing the chunk before the last one we've shown:
213*196bbc25SJim Ingham                 if (m_first_reverse)
214*196bbc25SJim Ingham                 {
215*196bbc25SJim Ingham                     if (m_last_file_line > m_last_file_context_after)
216*196bbc25SJim Ingham                         m_last_file_line -= m_last_file_context_after + 1;
217*196bbc25SJim Ingham                 }
218*196bbc25SJim Ingham 
219*196bbc25SJim Ingham                 if (m_last_file_line > m_last_file_context_after)
220*196bbc25SJim Ingham                 {
221*196bbc25SJim Ingham                     line = m_last_file_line - m_last_file_context_after;
222*196bbc25SJim Ingham                     if (line > m_last_file_context_before)
223*196bbc25SJim Ingham                         new_last_file_line = line - m_last_file_context_before - 1;
224*196bbc25SJim Ingham                     else
225*196bbc25SJim Ingham                         new_last_file_line = 1;
226*196bbc25SJim Ingham                 }
227*196bbc25SJim Ingham                 else
228*196bbc25SJim Ingham                 {
229*196bbc25SJim Ingham                     line = 1;
230*196bbc25SJim Ingham                     new_last_file_line = 1;
231*196bbc25SJim Ingham                 }
232*196bbc25SJim Ingham             }
233*196bbc25SJim Ingham             else
234*196bbc25SJim Ingham                 line = m_last_file_line + m_last_file_context_before;
235*196bbc25SJim Ingham         }
236*196bbc25SJim Ingham         else
237*196bbc25SJim Ingham             line = 1;
238*196bbc25SJim Ingham 
239*196bbc25SJim Ingham         size_t num_chars_shown = DisplaySourceLinesWithLineNumbersUsingLastFile (line, m_last_file_context_before, m_last_file_context_after, "", s, bp_locs);
240*196bbc25SJim Ingham         if (new_last_file_line != 0)
241*196bbc25SJim Ingham             m_last_file_line = new_last_file_line;
242*196bbc25SJim Ingham         if (reverse)
243*196bbc25SJim Ingham             m_first_reverse = false;
244*196bbc25SJim Ingham 
245*196bbc25SJim Ingham         return num_chars_shown;
24630fdc8d8SChris Lattner     }
24730fdc8d8SChris Lattner     return 0;
24830fdc8d8SChris Lattner }
24930fdc8d8SChris Lattner 
250b7f6b2faSJim Ingham bool
251b7f6b2faSJim Ingham SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line)
252b7f6b2faSJim Ingham {
253b7f6b2faSJim Ingham     FileSP old_file_sp = m_last_file_sp;
254b7f6b2faSJim Ingham     m_last_file_sp = GetFile (file_spec);
255f3277750SJim Ingham 
256f3277750SJim Ingham     m_default_set = true;
257b7f6b2faSJim Ingham     if (m_last_file_sp)
258b7f6b2faSJim Ingham     {
259b7f6b2faSJim Ingham         m_last_file_line = line;
260b7f6b2faSJim Ingham         return true;
261b7f6b2faSJim Ingham     }
262b7f6b2faSJim Ingham     else
263b7f6b2faSJim Ingham     {
264b7f6b2faSJim Ingham         m_last_file_sp = old_file_sp;
265b7f6b2faSJim Ingham         return false;
266b7f6b2faSJim Ingham     }
267b7f6b2faSJim Ingham }
268b7f6b2faSJim Ingham 
269b7f6b2faSJim Ingham bool
270b7f6b2faSJim Ingham SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line)
271b7f6b2faSJim Ingham {
272b7f6b2faSJim Ingham     if (m_last_file_sp)
273b7f6b2faSJim Ingham     {
274b7f6b2faSJim Ingham         file_spec = m_last_file_sp->GetFileSpec();
275b7f6b2faSJim Ingham         line = m_last_file_line;
276b7f6b2faSJim Ingham         return true;
277b7f6b2faSJim Ingham     }
278f3277750SJim Ingham     else if (!m_default_set)
279f3277750SJim Ingham     {
280f3277750SJim Ingham         // If nobody has set the default file and line then try here.  If there's no executable, then we
281f3277750SJim Ingham         // will try again later when there is one.  Otherwise, if we can't find it we won't look again,
282f3277750SJim Ingham         // somebody will have to set it (for instance when we stop somewhere...)
283f3277750SJim Ingham         Module *executable_ptr = m_target->GetExecutableModulePointer();
284f3277750SJim Ingham         if (executable_ptr)
285f3277750SJim Ingham         {
286f3277750SJim Ingham             SymbolContextList sc_list;
287f3277750SJim Ingham             uint32_t num_matches;
288f3277750SJim Ingham             ConstString main_name("main");
289f3277750SJim Ingham             bool symbols_okay = false;  // Force it to be a debug symbol.
2909df05fbbSSean Callanan             bool inlines_okay = true;
291f3277750SJim Ingham             bool append = false;
2929df05fbbSSean Callanan             num_matches = executable_ptr->FindFunctions (main_name, NULL, lldb::eFunctionNameTypeBase, inlines_okay, symbols_okay, append, sc_list);
293f3277750SJim Ingham             for (uint32_t idx = 0; idx < num_matches; idx++)
294f3277750SJim Ingham             {
295f3277750SJim Ingham                 SymbolContext sc;
296f3277750SJim Ingham                 sc_list.GetContextAtIndex(idx, sc);
2976f6bf26aSGreg Clayton                 if (sc.function)
298f3277750SJim Ingham                 {
2996f6bf26aSGreg Clayton                     lldb_private::LineEntry line_entry;
3006f6bf26aSGreg Clayton                     if (sc.function->GetAddressRange().GetBaseAddress().CalculateSymbolContextLineEntry (line_entry))
3016f6bf26aSGreg Clayton                     {
3026f6bf26aSGreg Clayton                         SetDefaultFileAndLine (line_entry.file,
3036f6bf26aSGreg Clayton                                                line_entry.line);
3046f6bf26aSGreg Clayton                         file_spec = m_last_file_sp->GetFileSpec();
3056f6bf26aSGreg Clayton                         line = m_last_file_line;
3066f6bf26aSGreg Clayton                         return true;
307f3277750SJim Ingham                     }
308f3277750SJim Ingham                 }
309f3277750SJim Ingham             }
310f3277750SJim Ingham         }
3116f6bf26aSGreg Clayton     }
312b7f6b2faSJim Ingham     return false;
313b7f6b2faSJim Ingham }
31430fdc8d8SChris Lattner 
315969795f1SJim Ingham void
316969795f1SJim Ingham SourceManager::FindLinesMatchingRegex (FileSpec &file_spec,
317969795f1SJim Ingham                                        RegularExpression& regex,
318969795f1SJim Ingham                                        uint32_t start_line,
319969795f1SJim Ingham                                        uint32_t end_line,
320969795f1SJim Ingham                                        std::vector<uint32_t> &match_lines)
321969795f1SJim Ingham {
322969795f1SJim Ingham     match_lines.clear();
323969795f1SJim Ingham     FileSP file_sp = GetFile (file_spec);
324969795f1SJim Ingham     if (!file_sp)
325969795f1SJim Ingham         return;
326969795f1SJim Ingham     return file_sp->FindLinesMatchingRegex (regex, start_line, end_line, match_lines);
327969795f1SJim Ingham }
32830fdc8d8SChris Lattner 
3297e14f91dSGreg Clayton SourceManager::File::File(const FileSpec &file_spec, Target *target) :
3307e14f91dSGreg Clayton     m_file_spec_orig (file_spec),
33130fdc8d8SChris Lattner     m_file_spec(file_spec),
3327e14f91dSGreg Clayton     m_mod_time (file_spec.GetModificationTime()),
3337e14f91dSGreg Clayton     m_data_sp(),
33430fdc8d8SChris Lattner     m_offsets()
33530fdc8d8SChris Lattner {
3367e14f91dSGreg Clayton     if (!m_mod_time.IsValid())
3377e14f91dSGreg Clayton     {
338e37d605eSJim Ingham         if (target)
339e37d605eSJim Ingham         {
340e37d605eSJim Ingham             if (!file_spec.GetDirectory() && file_spec.GetFilename())
341e37d605eSJim Ingham             {
342e37d605eSJim Ingham                 // If this is just a file name, lets see if we can find it in the target:
343e37d605eSJim Ingham                 bool check_inlines = false;
344e37d605eSJim Ingham                 SymbolContextList sc_list;
345e37d605eSJim Ingham                 size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (file_spec.GetFilename().AsCString(),
346e37d605eSJim Ingham                                                                                           0,
347e37d605eSJim Ingham                                                                                           check_inlines,
348e37d605eSJim Ingham                                                                                           lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit,
349e37d605eSJim Ingham                                                                                           sc_list);
350e37d605eSJim Ingham                 bool got_multiple = false;
351e37d605eSJim Ingham                 if (num_matches != 0)
352e37d605eSJim Ingham                 {
353e37d605eSJim Ingham                     if (num_matches > 1)
354e37d605eSJim Ingham                     {
355e37d605eSJim Ingham                         SymbolContext sc;
356e37d605eSJim Ingham                         FileSpec *test_cu_spec = NULL;
357e37d605eSJim Ingham 
358e37d605eSJim Ingham                         for (unsigned i = 0; i < num_matches; i++)
359e37d605eSJim Ingham                         {
360e37d605eSJim Ingham                             sc_list.GetContextAtIndex(i, sc);
361e37d605eSJim Ingham                             if (sc.comp_unit)
362e37d605eSJim Ingham                             {
363e37d605eSJim Ingham                                 if (test_cu_spec)
364e37d605eSJim Ingham                                 {
365e37d605eSJim Ingham                                     if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
366e37d605eSJim Ingham                                         got_multiple = true;
367e37d605eSJim Ingham                                         break;
368e37d605eSJim Ingham                                 }
369e37d605eSJim Ingham                                 else
370e37d605eSJim Ingham                                     test_cu_spec = sc.comp_unit;
371e37d605eSJim Ingham                             }
372e37d605eSJim Ingham                         }
373e37d605eSJim Ingham                     }
374e37d605eSJim Ingham                     if (!got_multiple)
375e37d605eSJim Ingham                     {
376e37d605eSJim Ingham                         SymbolContext sc;
377e37d605eSJim Ingham                         sc_list.GetContextAtIndex (0, sc);
378d804d285SGreg Clayton                         m_file_spec = sc.comp_unit;
379e37d605eSJim Ingham                         m_mod_time = m_file_spec.GetModificationTime();
380e37d605eSJim Ingham                     }
381e37d605eSJim Ingham                 }
382e37d605eSJim Ingham             }
38364bab489SJohnny Chen             // Try remapping if m_file_spec does not correspond to an existing file.
38464bab489SJohnny Chen             if (!m_file_spec.Exists())
385e37d605eSJim Ingham             {
386d804d285SGreg Clayton                 FileSpec new_file_spec;
387d804d285SGreg Clayton                 // Check target specific source remappings first, then fall back to
388d804d285SGreg Clayton                 // modules objects can have individual path remappings that were detected
389d804d285SGreg Clayton                 // when the debug info for a module was found.
390d804d285SGreg Clayton                 // then
391d804d285SGreg Clayton                 if (target->GetSourcePathMap().FindFile (m_file_spec, new_file_spec) ||
392d804d285SGreg Clayton                     target->GetImages().FindSourceFile (m_file_spec, new_file_spec))
39364bab489SJohnny Chen                 {
394d804d285SGreg Clayton                     m_file_spec = new_file_spec;
39564bab489SJohnny Chen                     m_mod_time = m_file_spec.GetModificationTime();
39664bab489SJohnny Chen                 }
3977e14f91dSGreg Clayton             }
398e37d605eSJim Ingham         }
399e37d605eSJim Ingham     }
4007e14f91dSGreg Clayton 
4017e14f91dSGreg Clayton     if (m_mod_time.IsValid())
4027e14f91dSGreg Clayton         m_data_sp = m_file_spec.ReadFileContents ();
40330fdc8d8SChris Lattner }
40430fdc8d8SChris Lattner 
40530fdc8d8SChris Lattner SourceManager::File::~File()
40630fdc8d8SChris Lattner {
40730fdc8d8SChris Lattner }
40830fdc8d8SChris Lattner 
40930fdc8d8SChris Lattner uint32_t
41030fdc8d8SChris Lattner SourceManager::File::GetLineOffset (uint32_t line)
41130fdc8d8SChris Lattner {
41230fdc8d8SChris Lattner     if (line == 0)
41330fdc8d8SChris Lattner         return UINT32_MAX;
41430fdc8d8SChris Lattner 
41530fdc8d8SChris Lattner     if (line == 1)
41630fdc8d8SChris Lattner         return 0;
41730fdc8d8SChris Lattner 
41830fdc8d8SChris Lattner     if (CalculateLineOffsets (line))
41930fdc8d8SChris Lattner     {
42030fdc8d8SChris Lattner         if (line < m_offsets.size())
42130fdc8d8SChris Lattner             return m_offsets[line - 1]; // yes we want "line - 1" in the index
42230fdc8d8SChris Lattner     }
42330fdc8d8SChris Lattner     return UINT32_MAX;
42430fdc8d8SChris Lattner }
42530fdc8d8SChris Lattner 
42630fdc8d8SChris Lattner bool
42730fdc8d8SChris Lattner SourceManager::File::LineIsValid (uint32_t line)
42830fdc8d8SChris Lattner {
42930fdc8d8SChris Lattner     if (line == 0)
43030fdc8d8SChris Lattner         return false;
43130fdc8d8SChris Lattner 
43230fdc8d8SChris Lattner     if (CalculateLineOffsets (line))
43330fdc8d8SChris Lattner         return line < m_offsets.size();
43430fdc8d8SChris Lattner     return false;
43530fdc8d8SChris Lattner }
43630fdc8d8SChris Lattner 
43730fdc8d8SChris Lattner size_t
43830fdc8d8SChris Lattner SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s)
43930fdc8d8SChris Lattner {
4409625d08cSGreg Clayton     // TODO: use host API to sign up for file modifications to anything in our
4419625d08cSGreg Clayton     // source cache and only update when we determine a file has been updated.
4429625d08cSGreg Clayton     // For now we check each time we want to display info for the file.
4439625d08cSGreg Clayton     TimeValue curr_mod_time (m_file_spec.GetModificationTime());
44464bab489SJohnny Chen 
44564bab489SJohnny Chen     if (curr_mod_time.IsValid() && m_mod_time != curr_mod_time)
4469625d08cSGreg Clayton     {
4479625d08cSGreg Clayton         m_mod_time = curr_mod_time;
4489625d08cSGreg Clayton         m_data_sp = m_file_spec.ReadFileContents ();
4499625d08cSGreg Clayton         m_offsets.clear();
4509625d08cSGreg Clayton     }
4519625d08cSGreg Clayton 
45264bab489SJohnny Chen     // Sanity check m_data_sp before proceeding.
45364bab489SJohnny Chen     if (!m_data_sp)
45464bab489SJohnny Chen         return 0;
45564bab489SJohnny Chen 
45630fdc8d8SChris Lattner     const uint32_t start_line = line <= context_before ? 1 : line - context_before;
45730fdc8d8SChris Lattner     const uint32_t start_line_offset = GetLineOffset (start_line);
45830fdc8d8SChris Lattner     if (start_line_offset != UINT32_MAX)
45930fdc8d8SChris Lattner     {
46030fdc8d8SChris Lattner         const uint32_t end_line = line + context_after;
46130fdc8d8SChris Lattner         uint32_t end_line_offset = GetLineOffset (end_line + 1);
46230fdc8d8SChris Lattner         if (end_line_offset == UINT32_MAX)
46330fdc8d8SChris Lattner             end_line_offset = m_data_sp->GetByteSize();
46430fdc8d8SChris Lattner 
46530fdc8d8SChris Lattner         assert (start_line_offset <= end_line_offset);
46630fdc8d8SChris Lattner         size_t bytes_written = 0;
46730fdc8d8SChris Lattner         if (start_line_offset < end_line_offset)
46830fdc8d8SChris Lattner         {
46930fdc8d8SChris Lattner             size_t count = end_line_offset - start_line_offset;
47030fdc8d8SChris Lattner             const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
47130fdc8d8SChris Lattner             bytes_written = s->Write(cstr, count);
47230fdc8d8SChris Lattner             if (!is_newline_char(cstr[count-1]))
47330fdc8d8SChris Lattner                 bytes_written += s->EOL();
47430fdc8d8SChris Lattner         }
47530fdc8d8SChris Lattner         return bytes_written;
47630fdc8d8SChris Lattner     }
47730fdc8d8SChris Lattner     return 0;
47830fdc8d8SChris Lattner }
47930fdc8d8SChris Lattner 
480969795f1SJim Ingham void
481969795f1SJim Ingham SourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines)
482969795f1SJim Ingham {
483969795f1SJim Ingham     TimeValue curr_mod_time (m_file_spec.GetModificationTime());
484969795f1SJim Ingham     if (m_mod_time != curr_mod_time)
485969795f1SJim Ingham     {
486969795f1SJim Ingham         m_mod_time = curr_mod_time;
487969795f1SJim Ingham         m_data_sp = m_file_spec.ReadFileContents ();
488969795f1SJim Ingham         m_offsets.clear();
489969795f1SJim Ingham     }
490969795f1SJim Ingham 
491969795f1SJim Ingham     match_lines.clear();
492969795f1SJim Ingham 
493969795f1SJim Ingham     if (!LineIsValid(start_line) || (end_line != UINT32_MAX && !LineIsValid(end_line)))
494969795f1SJim Ingham         return;
495969795f1SJim Ingham     if (start_line > end_line)
496969795f1SJim Ingham         return;
497969795f1SJim Ingham 
498969795f1SJim Ingham     for (uint32_t line_no = start_line; line_no < end_line; line_no++)
499969795f1SJim Ingham     {
500969795f1SJim Ingham         std::string buffer;
501969795f1SJim Ingham         if (!GetLine (line_no, buffer))
502969795f1SJim Ingham             break;
503969795f1SJim Ingham         if (regex.Execute(buffer.c_str()))
504969795f1SJim Ingham         {
505969795f1SJim Ingham             match_lines.push_back(line_no);
506969795f1SJim Ingham         }
507969795f1SJim Ingham     }
508969795f1SJim Ingham }
509969795f1SJim Ingham 
51030fdc8d8SChris Lattner bool
51130fdc8d8SChris Lattner SourceManager::File::FileSpecMatches (const FileSpec &file_spec)
51230fdc8d8SChris Lattner {
513644247c1SGreg Clayton     return FileSpec::Equal (m_file_spec, file_spec, false);
51430fdc8d8SChris Lattner }
51530fdc8d8SChris Lattner 
516e37d605eSJim Ingham bool
517e37d605eSJim Ingham lldb_private::operator== (const SourceManager::File &lhs, const SourceManager::File &rhs)
518e37d605eSJim Ingham {
519e37d605eSJim Ingham     if (lhs.m_file_spec == rhs.m_file_spec)
520e37d605eSJim Ingham     {
521e37d605eSJim Ingham         if (lhs.m_mod_time.IsValid())
522e37d605eSJim Ingham         {
523e37d605eSJim Ingham             if (rhs.m_mod_time.IsValid())
524e37d605eSJim Ingham                 return lhs.m_mod_time == rhs.m_mod_time;
525e37d605eSJim Ingham             else
526e37d605eSJim Ingham                 return false;
527e37d605eSJim Ingham         }
528e37d605eSJim Ingham         else if (rhs.m_mod_time.IsValid())
529e37d605eSJim Ingham             return false;
530e37d605eSJim Ingham         else
531e37d605eSJim Ingham             return true;
532e37d605eSJim Ingham     }
533e37d605eSJim Ingham     else
534e37d605eSJim Ingham         return false;
535e37d605eSJim Ingham }
53630fdc8d8SChris Lattner 
53730fdc8d8SChris Lattner bool
53830fdc8d8SChris Lattner SourceManager::File::CalculateLineOffsets (uint32_t line)
53930fdc8d8SChris Lattner {
54030fdc8d8SChris Lattner     line = UINT32_MAX;  // TODO: take this line out when we support partial indexing
54130fdc8d8SChris Lattner     if (line == UINT32_MAX)
54230fdc8d8SChris Lattner     {
54330fdc8d8SChris Lattner         // Already done?
54430fdc8d8SChris Lattner         if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
54530fdc8d8SChris Lattner             return true;
54630fdc8d8SChris Lattner 
54730fdc8d8SChris Lattner         if (m_offsets.empty())
54830fdc8d8SChris Lattner         {
54930fdc8d8SChris Lattner             if (m_data_sp.get() == NULL)
55030fdc8d8SChris Lattner                 return false;
55130fdc8d8SChris Lattner 
55230fdc8d8SChris Lattner             const char *start = (char *)m_data_sp->GetBytes();
55330fdc8d8SChris Lattner             if (start)
55430fdc8d8SChris Lattner             {
55530fdc8d8SChris Lattner                 const char *end = start + m_data_sp->GetByteSize();
55630fdc8d8SChris Lattner 
55730fdc8d8SChris Lattner                 // Calculate all line offsets from scratch
55830fdc8d8SChris Lattner 
55930fdc8d8SChris Lattner                 // Push a 1 at index zero to indicate the file has been completely indexed.
56030fdc8d8SChris Lattner                 m_offsets.push_back(UINT32_MAX);
56130fdc8d8SChris Lattner                 register const char *s;
56230fdc8d8SChris Lattner                 for (s = start; s < end; ++s)
56330fdc8d8SChris Lattner                 {
56430fdc8d8SChris Lattner                     register char curr_ch = *s;
56530fdc8d8SChris Lattner                     if (is_newline_char (curr_ch))
56630fdc8d8SChris Lattner                     {
56730fdc8d8SChris Lattner                         register char next_ch = s[1];
56830fdc8d8SChris Lattner                         if (is_newline_char (next_ch))
56930fdc8d8SChris Lattner                         {
57030fdc8d8SChris Lattner                             if (curr_ch != next_ch)
57130fdc8d8SChris Lattner                                 ++s;
57230fdc8d8SChris Lattner                         }
57330fdc8d8SChris Lattner                         m_offsets.push_back(s + 1 - start);
57430fdc8d8SChris Lattner                     }
57530fdc8d8SChris Lattner                 }
57630fdc8d8SChris Lattner                 if (!m_offsets.empty())
57730fdc8d8SChris Lattner                 {
57830fdc8d8SChris Lattner                     if (m_offsets.back() < end - start)
57930fdc8d8SChris Lattner                         m_offsets.push_back(end - start);
58030fdc8d8SChris Lattner                 }
58130fdc8d8SChris Lattner                 return true;
58230fdc8d8SChris Lattner             }
58330fdc8d8SChris Lattner         }
58430fdc8d8SChris Lattner         else
58530fdc8d8SChris Lattner         {
58630fdc8d8SChris Lattner             // Some lines have been populated, start where we last left off
58730fdc8d8SChris Lattner             assert(!"Not implemented yet");
58830fdc8d8SChris Lattner         }
58930fdc8d8SChris Lattner 
59030fdc8d8SChris Lattner     }
59130fdc8d8SChris Lattner     else
59230fdc8d8SChris Lattner     {
59330fdc8d8SChris Lattner         // Calculate all line offsets up to "line"
59430fdc8d8SChris Lattner         assert(!"Not implemented yet");
59530fdc8d8SChris Lattner     }
59630fdc8d8SChris Lattner     return false;
59730fdc8d8SChris Lattner }
598e37d605eSJim Ingham 
599969795f1SJim Ingham bool
600969795f1SJim Ingham SourceManager::File::GetLine (uint32_t line_no, std::string &buffer)
601969795f1SJim Ingham {
602969795f1SJim Ingham     if (!LineIsValid(line_no))
603969795f1SJim Ingham         return false;
604969795f1SJim Ingham 
605969795f1SJim Ingham     uint32_t start_offset = GetLineOffset (line_no);
606969795f1SJim Ingham     uint32_t end_offset = GetLineOffset (line_no + 1);
607969795f1SJim Ingham     if (end_offset == UINT32_MAX)
608969795f1SJim Ingham     {
609969795f1SJim Ingham         end_offset = m_data_sp->GetByteSize();
610969795f1SJim Ingham     }
611969795f1SJim Ingham     buffer.assign((char *) m_data_sp->GetBytes() + start_offset, end_offset - start_offset);
612969795f1SJim Ingham 
613969795f1SJim Ingham     return true;
614969795f1SJim Ingham }
615969795f1SJim Ingham 
616e37d605eSJim Ingham void
617e37d605eSJim Ingham SourceManager::SourceFileCache::AddSourceFile (const FileSP &file_sp)
618e37d605eSJim Ingham {
619e37d605eSJim Ingham     FileSpec file_spec;
620e37d605eSJim Ingham     FileCache::iterator pos = m_file_cache.find(file_spec);
621e37d605eSJim Ingham     if (pos == m_file_cache.end())
622e37d605eSJim Ingham         m_file_cache[file_spec] = file_sp;
623e37d605eSJim Ingham     else
624e37d605eSJim Ingham     {
625e37d605eSJim Ingham         if (file_sp != pos->second)
626e37d605eSJim Ingham             m_file_cache[file_spec] = file_sp;
627e37d605eSJim Ingham     }
628e37d605eSJim Ingham }
629e37d605eSJim Ingham 
630e37d605eSJim Ingham SourceManager::FileSP
631e37d605eSJim Ingham SourceManager::SourceFileCache::FindSourceFile (const FileSpec &file_spec) const
632e37d605eSJim Ingham {
633e37d605eSJim Ingham     FileSP file_sp;
634e37d605eSJim Ingham     FileCache::const_iterator pos = m_file_cache.find(file_spec);
635e37d605eSJim Ingham     if (pos != m_file_cache.end())
636e37d605eSJim Ingham         file_sp = pos->second;
637e37d605eSJim Ingham     return file_sp;
638e37d605eSJim Ingham }
639e37d605eSJim Ingham 
640