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 
1030fdc8d8SChris Lattner #include "lldb/Core/SourceManager.h"
1130fdc8d8SChris Lattner 
1230fdc8d8SChris Lattner // C Includes
1330fdc8d8SChris Lattner // C++ Includes
1430fdc8d8SChris Lattner // Other libraries and framework includes
1530fdc8d8SChris Lattner // Project includes
1630fdc8d8SChris Lattner #include "lldb/Core/DataBuffer.h"
1730fdc8d8SChris Lattner #include "lldb/Core/Stream.h"
18176761e5SGreg Clayton #include "lldb/Symbol/SymbolContext.h"
197e14f91dSGreg Clayton #include "lldb/Target/Target.h"
2030fdc8d8SChris Lattner 
2130fdc8d8SChris Lattner using namespace lldb_private;
2230fdc8d8SChris Lattner 
2330fdc8d8SChris Lattner static inline bool is_newline_char(char ch)
2430fdc8d8SChris Lattner {
2530fdc8d8SChris Lattner     return ch == '\n' || ch == '\r';
2630fdc8d8SChris Lattner }
2730fdc8d8SChris Lattner 
2830fdc8d8SChris Lattner 
2930fdc8d8SChris Lattner //----------------------------------------------------------------------
3030fdc8d8SChris Lattner // SourceManager constructor
3130fdc8d8SChris Lattner //----------------------------------------------------------------------
32*b7f6b2faSJim Ingham SourceManager::SourceManager(Target *target) :
3330fdc8d8SChris Lattner     m_file_cache (),
3430fdc8d8SChris Lattner     m_last_file_sp (),
3530fdc8d8SChris Lattner     m_last_file_line (0),
3630fdc8d8SChris Lattner     m_last_file_context_before (0),
37*b7f6b2faSJim Ingham     m_last_file_context_after (10),
38*b7f6b2faSJim Ingham     m_target (target)
3930fdc8d8SChris Lattner {
4030fdc8d8SChris Lattner }
4130fdc8d8SChris Lattner 
4230fdc8d8SChris Lattner //----------------------------------------------------------------------
4330fdc8d8SChris Lattner // Destructor
4430fdc8d8SChris Lattner //----------------------------------------------------------------------
4530fdc8d8SChris Lattner SourceManager::~SourceManager()
4630fdc8d8SChris Lattner {
4730fdc8d8SChris Lattner }
4830fdc8d8SChris Lattner 
4930fdc8d8SChris Lattner size_t
5030fdc8d8SChris Lattner SourceManager::DisplaySourceLines
5130fdc8d8SChris Lattner (
5230fdc8d8SChris Lattner     const FileSpec &file_spec,
5330fdc8d8SChris Lattner     uint32_t line,
5430fdc8d8SChris Lattner     uint32_t context_before,
5530fdc8d8SChris Lattner     uint32_t context_after,
5630fdc8d8SChris Lattner     Stream *s
5730fdc8d8SChris Lattner )
5830fdc8d8SChris Lattner {
59*b7f6b2faSJim Ingham     m_last_file_sp = GetFile (file_spec);
6030fdc8d8SChris Lattner     m_last_file_line = line + context_after + 1;
6130fdc8d8SChris Lattner     m_last_file_context_before = context_before;
6230fdc8d8SChris Lattner     m_last_file_context_after = context_after;
6330fdc8d8SChris Lattner     if (m_last_file_sp.get())
6430fdc8d8SChris Lattner         return m_last_file_sp->DisplaySourceLines (line, context_before, context_after, s);
6530fdc8d8SChris Lattner 
6630fdc8d8SChris Lattner     return 0;
6730fdc8d8SChris Lattner }
6830fdc8d8SChris Lattner 
6930fdc8d8SChris Lattner SourceManager::FileSP
70*b7f6b2faSJim Ingham SourceManager::GetFile (const FileSpec &file_spec)
7130fdc8d8SChris Lattner {
7230fdc8d8SChris Lattner     FileSP file_sp;
7330fdc8d8SChris Lattner     FileCache::iterator pos = m_file_cache.find(file_spec);
7430fdc8d8SChris Lattner     if (pos != m_file_cache.end())
7530fdc8d8SChris Lattner         file_sp = pos->second;
7630fdc8d8SChris Lattner     else
7730fdc8d8SChris Lattner     {
78*b7f6b2faSJim Ingham         file_sp.reset (new File (file_spec, m_target));
7930fdc8d8SChris Lattner         m_file_cache[file_spec] = file_sp;
8030fdc8d8SChris Lattner     }
8130fdc8d8SChris Lattner     return file_sp;
8230fdc8d8SChris Lattner }
8330fdc8d8SChris Lattner 
8430fdc8d8SChris Lattner size_t
8530fdc8d8SChris Lattner SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile
8630fdc8d8SChris Lattner (
8730fdc8d8SChris Lattner     uint32_t line,
8830fdc8d8SChris Lattner     uint32_t context_before,
8930fdc8d8SChris Lattner     uint32_t context_after,
9030fdc8d8SChris Lattner     const char* current_line_cstr,
91176761e5SGreg Clayton     Stream *s,
92176761e5SGreg Clayton     const SymbolContextList *bp_locs
9330fdc8d8SChris Lattner )
9430fdc8d8SChris Lattner {
9530fdc8d8SChris Lattner     if (line == 0)
9630fdc8d8SChris Lattner     {
9730fdc8d8SChris Lattner         if (m_last_file_line != 0
9830fdc8d8SChris Lattner             && m_last_file_line != UINT32_MAX)
9930fdc8d8SChris Lattner             line = m_last_file_line + context_before;
10030fdc8d8SChris Lattner         else
10130fdc8d8SChris Lattner             line = 1;
10230fdc8d8SChris Lattner     }
10330fdc8d8SChris Lattner 
10430fdc8d8SChris Lattner     m_last_file_line = line + context_after + 1;
10530fdc8d8SChris Lattner     m_last_file_context_before = context_before;
10630fdc8d8SChris Lattner     m_last_file_context_after = context_after;
10730fdc8d8SChris Lattner 
10830fdc8d8SChris Lattner     if (context_before == UINT32_MAX)
10930fdc8d8SChris Lattner         context_before = 0;
11030fdc8d8SChris Lattner     if (context_after == UINT32_MAX)
11130fdc8d8SChris Lattner         context_after = 10;
11230fdc8d8SChris Lattner 
11330fdc8d8SChris Lattner     if (m_last_file_sp.get())
11430fdc8d8SChris Lattner     {
11530fdc8d8SChris Lattner         const uint32_t start_line = line <= context_before ? 1 : line - context_before;
11630fdc8d8SChris Lattner         const uint32_t end_line = line + context_after;
11730fdc8d8SChris Lattner         uint32_t curr_line;
11830fdc8d8SChris Lattner         for (curr_line = start_line; curr_line <= end_line; ++curr_line)
11930fdc8d8SChris Lattner         {
12030fdc8d8SChris Lattner             if (!m_last_file_sp->LineIsValid (curr_line))
12130fdc8d8SChris Lattner             {
12230fdc8d8SChris Lattner                 m_last_file_line = UINT32_MAX;
12330fdc8d8SChris Lattner                 break;
12430fdc8d8SChris Lattner             }
12530fdc8d8SChris Lattner 
126176761e5SGreg Clayton             char prefix[32] = "";
127176761e5SGreg Clayton             if (bp_locs)
128176761e5SGreg Clayton             {
129176761e5SGreg Clayton                 uint32_t bp_count = bp_locs->NumLineEntriesWithLine (curr_line);
130176761e5SGreg Clayton 
131176761e5SGreg Clayton                 if (bp_count > 0)
132176761e5SGreg Clayton                     ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count);
133176761e5SGreg Clayton                 else
134176761e5SGreg Clayton                     ::snprintf (prefix, sizeof (prefix), "    ");
135176761e5SGreg Clayton             }
136176761e5SGreg Clayton 
137176761e5SGreg Clayton             s->Printf("%s%2.2s %-4u\t",
138176761e5SGreg Clayton                       prefix,
139176761e5SGreg Clayton                       curr_line == line ? current_line_cstr : "",
140176761e5SGreg Clayton                       curr_line);
14130fdc8d8SChris Lattner             if (m_last_file_sp->DisplaySourceLines (curr_line, 0, 0, s) == 0)
14230fdc8d8SChris Lattner             {
14330fdc8d8SChris Lattner                 m_last_file_line = UINT32_MAX;
14430fdc8d8SChris Lattner                 break;
14530fdc8d8SChris Lattner             }
14630fdc8d8SChris Lattner         }
14730fdc8d8SChris Lattner     }
14830fdc8d8SChris Lattner     return 0;
14930fdc8d8SChris Lattner }
15030fdc8d8SChris Lattner 
15130fdc8d8SChris Lattner size_t
15230fdc8d8SChris Lattner SourceManager::DisplaySourceLinesWithLineNumbers
15330fdc8d8SChris Lattner (
15430fdc8d8SChris Lattner     const FileSpec &file_spec,
15530fdc8d8SChris Lattner     uint32_t line,
15630fdc8d8SChris Lattner     uint32_t context_before,
15730fdc8d8SChris Lattner     uint32_t context_after,
15830fdc8d8SChris Lattner     const char* current_line_cstr,
159176761e5SGreg Clayton     Stream *s,
160176761e5SGreg Clayton     const SymbolContextList *bp_locs
16130fdc8d8SChris Lattner )
16230fdc8d8SChris Lattner {
16330fdc8d8SChris Lattner     bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec);
16430fdc8d8SChris Lattner 
16530fdc8d8SChris Lattner     if (!same_as_previous)
166*b7f6b2faSJim Ingham         m_last_file_sp = GetFile (file_spec);
16730fdc8d8SChris Lattner 
16830fdc8d8SChris Lattner     if (line == 0)
16930fdc8d8SChris Lattner     {
17030fdc8d8SChris Lattner         if (!same_as_previous)
17130fdc8d8SChris Lattner             m_last_file_line = 0;
17230fdc8d8SChris Lattner     }
17330fdc8d8SChris Lattner 
174176761e5SGreg Clayton     return DisplaySourceLinesWithLineNumbersUsingLastFile (line, context_before, context_after, current_line_cstr, s, bp_locs);
17530fdc8d8SChris Lattner }
17630fdc8d8SChris Lattner 
17730fdc8d8SChris Lattner size_t
178176761e5SGreg Clayton SourceManager::DisplayMoreWithLineNumbers (Stream *s, const SymbolContextList *bp_locs)
17930fdc8d8SChris Lattner {
18030fdc8d8SChris Lattner     if (m_last_file_sp)
18130fdc8d8SChris Lattner     {
18230fdc8d8SChris Lattner         if (m_last_file_line == UINT32_MAX)
18330fdc8d8SChris Lattner             return 0;
184176761e5SGreg Clayton         DisplaySourceLinesWithLineNumbersUsingLastFile (0, m_last_file_context_before, m_last_file_context_after, "", s, bp_locs);
18530fdc8d8SChris Lattner     }
18630fdc8d8SChris Lattner     return 0;
18730fdc8d8SChris Lattner }
18830fdc8d8SChris Lattner 
189*b7f6b2faSJim Ingham bool
190*b7f6b2faSJim Ingham SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line)
191*b7f6b2faSJim Ingham {
192*b7f6b2faSJim Ingham     FileSP old_file_sp = m_last_file_sp;
193*b7f6b2faSJim Ingham     m_last_file_sp = GetFile (file_spec);
194*b7f6b2faSJim Ingham     if (m_last_file_sp)
195*b7f6b2faSJim Ingham     {
196*b7f6b2faSJim Ingham         m_last_file_line = line;
197*b7f6b2faSJim Ingham         return true;
198*b7f6b2faSJim Ingham     }
199*b7f6b2faSJim Ingham     else
200*b7f6b2faSJim Ingham     {
201*b7f6b2faSJim Ingham         m_last_file_sp = old_file_sp;
202*b7f6b2faSJim Ingham         return false;
203*b7f6b2faSJim Ingham     }
204*b7f6b2faSJim Ingham }
205*b7f6b2faSJim Ingham 
206*b7f6b2faSJim Ingham bool
207*b7f6b2faSJim Ingham SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line)
208*b7f6b2faSJim Ingham {
209*b7f6b2faSJim Ingham     if (m_last_file_sp)
210*b7f6b2faSJim Ingham     {
211*b7f6b2faSJim Ingham         file_spec = m_last_file_sp->GetFileSpec();
212*b7f6b2faSJim Ingham         line = m_last_file_line;
213*b7f6b2faSJim Ingham         return true;
214*b7f6b2faSJim Ingham     }
215*b7f6b2faSJim Ingham     else
216*b7f6b2faSJim Ingham         return false;
217*b7f6b2faSJim Ingham }
21830fdc8d8SChris Lattner 
21930fdc8d8SChris Lattner 
2207e14f91dSGreg Clayton SourceManager::File::File(const FileSpec &file_spec, Target *target) :
2217e14f91dSGreg Clayton     m_file_spec_orig (file_spec),
22230fdc8d8SChris Lattner     m_file_spec(file_spec),
2237e14f91dSGreg Clayton     m_mod_time (file_spec.GetModificationTime()),
2247e14f91dSGreg Clayton     m_data_sp(),
22530fdc8d8SChris Lattner     m_offsets()
22630fdc8d8SChris Lattner {
2277e14f91dSGreg Clayton     if (!m_mod_time.IsValid())
2287e14f91dSGreg Clayton     {
229*b7f6b2faSJim Ingham         if (target && target->GetSourcePathMap().RemapPath(file_spec.GetDirectory(), m_file_spec.GetDirectory()))
2307e14f91dSGreg Clayton             m_mod_time = file_spec.GetModificationTime();
2317e14f91dSGreg Clayton     }
2327e14f91dSGreg Clayton 
2337e14f91dSGreg Clayton     if (m_mod_time.IsValid())
2347e14f91dSGreg Clayton         m_data_sp = m_file_spec.ReadFileContents ();
23530fdc8d8SChris Lattner }
23630fdc8d8SChris Lattner 
23730fdc8d8SChris Lattner SourceManager::File::~File()
23830fdc8d8SChris Lattner {
23930fdc8d8SChris Lattner }
24030fdc8d8SChris Lattner 
24130fdc8d8SChris Lattner uint32_t
24230fdc8d8SChris Lattner SourceManager::File::GetLineOffset (uint32_t line)
24330fdc8d8SChris Lattner {
24430fdc8d8SChris Lattner     if (line == 0)
24530fdc8d8SChris Lattner         return UINT32_MAX;
24630fdc8d8SChris Lattner 
24730fdc8d8SChris Lattner     if (line == 1)
24830fdc8d8SChris Lattner         return 0;
24930fdc8d8SChris Lattner 
25030fdc8d8SChris Lattner     if (CalculateLineOffsets (line))
25130fdc8d8SChris Lattner     {
25230fdc8d8SChris Lattner         if (line < m_offsets.size())
25330fdc8d8SChris Lattner             return m_offsets[line - 1]; // yes we want "line - 1" in the index
25430fdc8d8SChris Lattner     }
25530fdc8d8SChris Lattner     return UINT32_MAX;
25630fdc8d8SChris Lattner }
25730fdc8d8SChris Lattner 
25830fdc8d8SChris Lattner bool
25930fdc8d8SChris Lattner SourceManager::File::LineIsValid (uint32_t line)
26030fdc8d8SChris Lattner {
26130fdc8d8SChris Lattner     if (line == 0)
26230fdc8d8SChris Lattner         return false;
26330fdc8d8SChris Lattner 
26430fdc8d8SChris Lattner     if (CalculateLineOffsets (line))
26530fdc8d8SChris Lattner         return line < m_offsets.size();
26630fdc8d8SChris Lattner     return false;
26730fdc8d8SChris Lattner }
26830fdc8d8SChris Lattner 
26930fdc8d8SChris Lattner size_t
27030fdc8d8SChris Lattner SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s)
27130fdc8d8SChris Lattner {
2729625d08cSGreg Clayton     // TODO: use host API to sign up for file modifications to anything in our
2739625d08cSGreg Clayton     // source cache and only update when we determine a file has been updated.
2749625d08cSGreg Clayton     // For now we check each time we want to display info for the file.
2759625d08cSGreg Clayton     TimeValue curr_mod_time (m_file_spec.GetModificationTime());
2769625d08cSGreg Clayton     if (m_mod_time != curr_mod_time)
2779625d08cSGreg Clayton     {
2789625d08cSGreg Clayton         m_mod_time = curr_mod_time;
2799625d08cSGreg Clayton         m_data_sp = m_file_spec.ReadFileContents ();
2809625d08cSGreg Clayton         m_offsets.clear();
2819625d08cSGreg Clayton     }
2829625d08cSGreg Clayton 
28330fdc8d8SChris Lattner     const uint32_t start_line = line <= context_before ? 1 : line - context_before;
28430fdc8d8SChris Lattner     const uint32_t start_line_offset = GetLineOffset (start_line);
28530fdc8d8SChris Lattner     if (start_line_offset != UINT32_MAX)
28630fdc8d8SChris Lattner     {
28730fdc8d8SChris Lattner         const uint32_t end_line = line + context_after;
28830fdc8d8SChris Lattner         uint32_t end_line_offset = GetLineOffset (end_line + 1);
28930fdc8d8SChris Lattner         if (end_line_offset == UINT32_MAX)
29030fdc8d8SChris Lattner             end_line_offset = m_data_sp->GetByteSize();
29130fdc8d8SChris Lattner 
29230fdc8d8SChris Lattner         assert (start_line_offset <= end_line_offset);
29330fdc8d8SChris Lattner         size_t bytes_written = 0;
29430fdc8d8SChris Lattner         if (start_line_offset < end_line_offset)
29530fdc8d8SChris Lattner         {
29630fdc8d8SChris Lattner             size_t count = end_line_offset - start_line_offset;
29730fdc8d8SChris Lattner             const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
29830fdc8d8SChris Lattner             bytes_written = s->Write(cstr, count);
29930fdc8d8SChris Lattner             if (!is_newline_char(cstr[count-1]))
30030fdc8d8SChris Lattner                 bytes_written += s->EOL();
30130fdc8d8SChris Lattner         }
30230fdc8d8SChris Lattner         return bytes_written;
30330fdc8d8SChris Lattner     }
30430fdc8d8SChris Lattner     return 0;
30530fdc8d8SChris Lattner }
30630fdc8d8SChris Lattner 
30730fdc8d8SChris Lattner bool
30830fdc8d8SChris Lattner SourceManager::File::FileSpecMatches (const FileSpec &file_spec)
30930fdc8d8SChris Lattner {
310644247c1SGreg Clayton     return FileSpec::Equal (m_file_spec, file_spec, false);
31130fdc8d8SChris Lattner }
31230fdc8d8SChris Lattner 
31330fdc8d8SChris Lattner 
31430fdc8d8SChris Lattner bool
31530fdc8d8SChris Lattner SourceManager::File::CalculateLineOffsets (uint32_t line)
31630fdc8d8SChris Lattner {
31730fdc8d8SChris Lattner     line = UINT32_MAX;  // TODO: take this line out when we support partial indexing
31830fdc8d8SChris Lattner     if (line == UINT32_MAX)
31930fdc8d8SChris Lattner     {
32030fdc8d8SChris Lattner         // Already done?
32130fdc8d8SChris Lattner         if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
32230fdc8d8SChris Lattner             return true;
32330fdc8d8SChris Lattner 
32430fdc8d8SChris Lattner         if (m_offsets.empty())
32530fdc8d8SChris Lattner         {
32630fdc8d8SChris Lattner             if (m_data_sp.get() == NULL)
32730fdc8d8SChris Lattner                 return false;
32830fdc8d8SChris Lattner 
32930fdc8d8SChris Lattner             const char *start = (char *)m_data_sp->GetBytes();
33030fdc8d8SChris Lattner             if (start)
33130fdc8d8SChris Lattner             {
33230fdc8d8SChris Lattner                 const char *end = start + m_data_sp->GetByteSize();
33330fdc8d8SChris Lattner 
33430fdc8d8SChris Lattner                 // Calculate all line offsets from scratch
33530fdc8d8SChris Lattner 
33630fdc8d8SChris Lattner                 // Push a 1 at index zero to indicate the file has been completely indexed.
33730fdc8d8SChris Lattner                 m_offsets.push_back(UINT32_MAX);
33830fdc8d8SChris Lattner                 register const char *s;
33930fdc8d8SChris Lattner                 for (s = start; s < end; ++s)
34030fdc8d8SChris Lattner                 {
34130fdc8d8SChris Lattner                     register char curr_ch = *s;
34230fdc8d8SChris Lattner                     if (is_newline_char (curr_ch))
34330fdc8d8SChris Lattner                     {
34430fdc8d8SChris Lattner                         register char next_ch = s[1];
34530fdc8d8SChris Lattner                         if (is_newline_char (next_ch))
34630fdc8d8SChris Lattner                         {
34730fdc8d8SChris Lattner                             if (curr_ch != next_ch)
34830fdc8d8SChris Lattner                                 ++s;
34930fdc8d8SChris Lattner                         }
35030fdc8d8SChris Lattner                         m_offsets.push_back(s + 1 - start);
35130fdc8d8SChris Lattner                     }
35230fdc8d8SChris Lattner                 }
35330fdc8d8SChris Lattner                 if (!m_offsets.empty())
35430fdc8d8SChris Lattner                 {
35530fdc8d8SChris Lattner                     if (m_offsets.back() < end - start)
35630fdc8d8SChris Lattner                         m_offsets.push_back(end - start);
35730fdc8d8SChris Lattner                 }
35830fdc8d8SChris Lattner                 return true;
35930fdc8d8SChris Lattner             }
36030fdc8d8SChris Lattner         }
36130fdc8d8SChris Lattner         else
36230fdc8d8SChris Lattner         {
36330fdc8d8SChris Lattner             // Some lines have been populated, start where we last left off
36430fdc8d8SChris Lattner             assert(!"Not implemented yet");
36530fdc8d8SChris Lattner         }
36630fdc8d8SChris Lattner 
36730fdc8d8SChris Lattner     }
36830fdc8d8SChris Lattner     else
36930fdc8d8SChris Lattner     {
37030fdc8d8SChris Lattner         // Calculate all line offsets up to "line"
37130fdc8d8SChris Lattner         assert(!"Not implemented yet");
37230fdc8d8SChris Lattner     }
37330fdc8d8SChris Lattner     return false;
37430fdc8d8SChris Lattner }
375