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 
12*2f3df613SZachary Turner #include "lldb/Core/Address.h"      // for Address
13*2f3df613SZachary Turner #include "lldb/Core/AddressRange.h" // for AddressRange
14e37d605eSJim Ingham #include "lldb/Core/Debugger.h"
15*2f3df613SZachary Turner #include "lldb/Core/FormatEntity.h" // for FormatEntity
161f746071SGreg Clayton #include "lldb/Core/Module.h"
17*2f3df613SZachary Turner #include "lldb/Core/ModuleList.h" // for ModuleList
181408bf72SPavel Labath #include "lldb/Host/FileSystem.h"
191f746071SGreg Clayton #include "lldb/Symbol/CompileUnit.h"
201f746071SGreg Clayton #include "lldb/Symbol/Function.h"
21*2f3df613SZachary Turner #include "lldb/Symbol/LineEntry.h" // for LineEntry
22176761e5SGreg Clayton #include "lldb/Symbol/SymbolContext.h"
23*2f3df613SZachary Turner #include "lldb/Target/PathMappingList.h" // for PathMappingList
247e14f91dSGreg Clayton #include "lldb/Target/Target.h"
25*2f3df613SZachary Turner #include "lldb/Utility/ConstString.h" // for ConstString
26666cc0b2SZachary Turner #include "lldb/Utility/DataBuffer.h"
277f6a7a37SZachary Turner #include "lldb/Utility/DataBufferLLVM.h"
28bf9a7730SZachary Turner #include "lldb/Utility/RegularExpression.h"
29bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
30*2f3df613SZachary Turner #include "lldb/lldb-enumerations.h" // for StopShowColumn::eStopSho...
31*2f3df613SZachary Turner 
32*2f3df613SZachary Turner #include "llvm/ADT/Twine.h" // for Twine
33*2f3df613SZachary Turner 
34*2f3df613SZachary Turner #include <memory>
35*2f3df613SZachary Turner #include <utility> // for pair
36*2f3df613SZachary Turner 
37*2f3df613SZachary Turner #include <assert.h> // for assert
38*2f3df613SZachary Turner #include <stdio.h>  // for size_t, NULL, snprintf
39*2f3df613SZachary Turner 
40*2f3df613SZachary Turner namespace lldb_private {
41*2f3df613SZachary Turner class ExecutionContext;
42*2f3df613SZachary Turner }
43*2f3df613SZachary Turner namespace lldb_private {
44*2f3df613SZachary Turner class ValueObject;
45*2f3df613SZachary Turner }
4630fdc8d8SChris Lattner 
479585fbfcSGreg Clayton using namespace lldb;
4830fdc8d8SChris Lattner using namespace lldb_private;
4930fdc8d8SChris Lattner 
50b9c1b51eSKate Stone static inline bool is_newline_char(char ch) { return ch == '\n' || ch == '\r'; }
5130fdc8d8SChris Lattner 
5230fdc8d8SChris Lattner //----------------------------------------------------------------------
5330fdc8d8SChris Lattner // SourceManager constructor
5430fdc8d8SChris Lattner //----------------------------------------------------------------------
55b9c1b51eSKate Stone SourceManager::SourceManager(const TargetSP &target_sp)
56b9c1b51eSKate Stone     : m_last_file_sp(), m_last_line(0), m_last_count(0), m_default_set(false),
579585fbfcSGreg Clayton       m_target_wp(target_sp),
58b9c1b51eSKate Stone       m_debugger_wp(target_sp->GetDebugger().shared_from_this()) {}
59e37d605eSJim Ingham 
60b9c1b51eSKate Stone SourceManager::SourceManager(const DebuggerSP &debugger_sp)
61b9c1b51eSKate Stone     : m_last_file_sp(), m_last_line(0), m_last_count(0), m_default_set(false),
62b9c1b51eSKate Stone       m_target_wp(), m_debugger_wp(debugger_sp) {}
6330fdc8d8SChris Lattner 
6430fdc8d8SChris Lattner //----------------------------------------------------------------------
6530fdc8d8SChris Lattner // Destructor
6630fdc8d8SChris Lattner //----------------------------------------------------------------------
67b9c1b51eSKate Stone SourceManager::~SourceManager() {}
6830fdc8d8SChris Lattner 
69b9c1b51eSKate Stone SourceManager::FileSP SourceManager::GetFile(const FileSpec &file_spec) {
70b9c1b51eSKate Stone   bool same_as_previous =
71b9c1b51eSKate Stone       m_last_file_sp && m_last_file_sp->FileSpecMatches(file_spec);
724a89501fSGreg Clayton 
739585fbfcSGreg Clayton   DebuggerSP debugger_sp(m_debugger_wp.lock());
7430fdc8d8SChris Lattner   FileSP file_sp;
754a89501fSGreg Clayton   if (same_as_previous)
764a89501fSGreg Clayton     file_sp = m_last_file_sp;
779585fbfcSGreg Clayton   else if (debugger_sp)
789585fbfcSGreg Clayton     file_sp = debugger_sp->GetSourceFileCache().FindSourceFile(file_spec);
799585fbfcSGreg Clayton 
809585fbfcSGreg Clayton   TargetSP target_sp(m_target_wp.lock());
814a89501fSGreg Clayton 
824a89501fSGreg Clayton   // It the target source path map has been updated, get this file again so we
834a89501fSGreg Clayton   // can successfully remap the source file
84b9c1b51eSKate Stone   if (target_sp && file_sp &&
85b9c1b51eSKate Stone       file_sp->GetSourceMapModificationID() !=
86b9c1b51eSKate Stone           target_sp->GetSourcePathMap().GetModificationID())
874a89501fSGreg Clayton     file_sp.reset();
884a89501fSGreg Clayton 
890d5b0a8aSGreg Clayton   // Update the file contents if needed if we found a file
900d5b0a8aSGreg Clayton   if (file_sp)
910d5b0a8aSGreg Clayton     file_sp->UpdateIfNeeded();
920d5b0a8aSGreg Clayton 
9364bab489SJohnny Chen   // If file_sp is no good or it points to a non-existent file, reset it.
94b9c1b51eSKate Stone   if (!file_sp || !file_sp->GetFileSpec().Exists()) {
959666ba75STodd Fiala     if (target_sp)
96*2f3df613SZachary Turner       file_sp = std::make_shared<File>(file_spec, target_sp.get());
979666ba75STodd Fiala     else
98*2f3df613SZachary Turner       file_sp = std::make_shared<File>(file_spec, debugger_sp);
99e37d605eSJim Ingham 
1009585fbfcSGreg Clayton     if (debugger_sp)
1019585fbfcSGreg Clayton       debugger_sp->GetSourceFileCache().AddSourceFile(file_sp);
10230fdc8d8SChris Lattner   }
10330fdc8d8SChris Lattner   return file_sp;
10430fdc8d8SChris Lattner }
10530fdc8d8SChris Lattner 
1069666ba75STodd Fiala static bool should_show_stop_column_with_ansi(DebuggerSP debugger_sp) {
1079666ba75STodd Fiala   // We don't use ANSI stop column formatting if we can't lookup values from
1089666ba75STodd Fiala   // the debugger.
1099666ba75STodd Fiala   if (!debugger_sp)
1109666ba75STodd Fiala     return false;
1119666ba75STodd Fiala 
1129666ba75STodd Fiala   // We don't use ANSI stop column formatting if the debugger doesn't think
1139666ba75STodd Fiala   // it should be using color.
1149666ba75STodd Fiala   if (!debugger_sp->GetUseColor())
1159666ba75STodd Fiala     return false;
1169666ba75STodd Fiala 
1179666ba75STodd Fiala   // We only use ANSI stop column formatting if we're either supposed to show
1189666ba75STodd Fiala   // ANSI where available (which we know we have when we get to this point), or
1199666ba75STodd Fiala   // if we're only supposed to use ANSI.
1209666ba75STodd Fiala   const auto value = debugger_sp->GetStopShowColumn();
1219666ba75STodd Fiala   return ((value == eStopShowColumnAnsiOrCaret) ||
1229666ba75STodd Fiala           (value == eStopShowColumnAnsi));
1239666ba75STodd Fiala }
1249666ba75STodd Fiala 
1259666ba75STodd Fiala static bool should_show_stop_column_with_caret(DebuggerSP debugger_sp) {
1269666ba75STodd Fiala   // We don't use text-based stop column formatting if we can't lookup values
1279666ba75STodd Fiala   // from the debugger.
1289666ba75STodd Fiala   if (!debugger_sp)
1299666ba75STodd Fiala     return false;
1309666ba75STodd Fiala 
1319666ba75STodd Fiala   // If we're asked to show the first available of ANSI or caret, then
1329666ba75STodd Fiala   // we do show the caret when ANSI is not available.
1339666ba75STodd Fiala   const auto value = debugger_sp->GetStopShowColumn();
1349666ba75STodd Fiala   if ((value == eStopShowColumnAnsiOrCaret) && !debugger_sp->GetUseColor())
1359666ba75STodd Fiala     return true;
1369666ba75STodd Fiala 
1379666ba75STodd Fiala   // The only other time we use caret is if we're explicitly asked to show
1389666ba75STodd Fiala   // caret.
1399666ba75STodd Fiala   return value == eStopShowColumnCaret;
1409666ba75STodd Fiala }
1419666ba75STodd Fiala 
142b9c1b51eSKate Stone size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile(
1439666ba75STodd Fiala     uint32_t start_line, uint32_t count, uint32_t curr_line, uint32_t column,
144b9c1b51eSKate Stone     const char *current_line_cstr, Stream *s,
145b9c1b51eSKate Stone     const SymbolContextList *bp_locs) {
146e4ca515aSGreg Clayton   if (count == 0)
147e4ca515aSGreg Clayton     return 0;
148e37d605eSJim Ingham   size_t return_value = 0;
149b9c1b51eSKate Stone   if (start_line == 0) {
150e4ca515aSGreg Clayton     if (m_last_line != 0 && m_last_line != UINT32_MAX)
151e4ca515aSGreg Clayton       start_line = m_last_line + m_last_count;
15230fdc8d8SChris Lattner     else
153e4ca515aSGreg Clayton       start_line = 1;
15430fdc8d8SChris Lattner   }
15530fdc8d8SChris Lattner 
156b9c1b51eSKate Stone   if (!m_default_set) {
157e4ca515aSGreg Clayton     FileSpec tmp_spec;
158e4ca515aSGreg Clayton     uint32_t tmp_line;
159e4ca515aSGreg Clayton     GetDefaultFileAndLine(tmp_spec, tmp_line);
160e4ca515aSGreg Clayton   }
16130fdc8d8SChris Lattner 
162e4ca515aSGreg Clayton   m_last_line = start_line;
163e4ca515aSGreg Clayton   m_last_count = count;
16430fdc8d8SChris Lattner 
165b9c1b51eSKate Stone   if (m_last_file_sp.get()) {
166e4ca515aSGreg Clayton     const uint32_t end_line = start_line + count - 1;
167b9c1b51eSKate Stone     for (uint32_t line = start_line; line <= end_line; ++line) {
168b9c1b51eSKate Stone       if (!m_last_file_sp->LineIsValid(line)) {
169e4ca515aSGreg Clayton         m_last_line = UINT32_MAX;
17030fdc8d8SChris Lattner         break;
17130fdc8d8SChris Lattner       }
17230fdc8d8SChris Lattner 
173176761e5SGreg Clayton       char prefix[32] = "";
174b9c1b51eSKate Stone       if (bp_locs) {
175e4ca515aSGreg Clayton         uint32_t bp_count = bp_locs->NumLineEntriesWithLine(line);
176176761e5SGreg Clayton 
177176761e5SGreg Clayton         if (bp_count > 0)
178176761e5SGreg Clayton           ::snprintf(prefix, sizeof(prefix), "[%u] ", bp_count);
179176761e5SGreg Clayton         else
180176761e5SGreg Clayton           ::snprintf(prefix, sizeof(prefix), "    ");
181176761e5SGreg Clayton       }
182176761e5SGreg Clayton 
183b9c1b51eSKate Stone       return_value +=
184b9c1b51eSKate Stone           s->Printf("%s%2.2s %-4u\t", prefix,
185b9c1b51eSKate Stone                     line == curr_line ? current_line_cstr : "", line);
1869666ba75STodd Fiala       size_t this_line_size = m_last_file_sp->DisplaySourceLines(
1879666ba75STodd Fiala           line, line == curr_line ? column : 0, 0, 0, s);
1889666ba75STodd Fiala       if (column != 0 && line == curr_line &&
1899666ba75STodd Fiala           should_show_stop_column_with_caret(m_debugger_wp.lock())) {
1909666ba75STodd Fiala         // Display caret cursor.
1919666ba75STodd Fiala         std::string src_line;
1929666ba75STodd Fiala         m_last_file_sp->GetLine(line, src_line);
1939666ba75STodd Fiala         return_value += s->Printf("    \t");
1949666ba75STodd Fiala         // Insert a space for every non-tab character in the source line.
19505092039SEd Maste         for (size_t i = 0; i + 1 < column && i < src_line.length(); ++i)
1969666ba75STodd Fiala           return_value += s->PutChar(src_line[i] == '\t' ? '\t' : ' ');
1979666ba75STodd Fiala         // Now add the caret.
1989666ba75STodd Fiala         return_value += s->Printf("^\n");
1999666ba75STodd Fiala       }
200b9c1b51eSKate Stone       if (this_line_size == 0) {
201e4ca515aSGreg Clayton         m_last_line = UINT32_MAX;
20230fdc8d8SChris Lattner         break;
203b9c1b51eSKate Stone       } else
204e37d605eSJim Ingham         return_value += this_line_size;
20530fdc8d8SChris Lattner     }
20630fdc8d8SChris Lattner   }
207e37d605eSJim Ingham   return return_value;
20830fdc8d8SChris Lattner }
20930fdc8d8SChris Lattner 
210b9c1b51eSKate Stone size_t SourceManager::DisplaySourceLinesWithLineNumbers(
2119666ba75STodd Fiala     const FileSpec &file_spec, uint32_t line, uint32_t column,
2129666ba75STodd Fiala     uint32_t context_before, uint32_t context_after,
2139666ba75STodd Fiala     const char *current_line_cstr, Stream *s,
214b9c1b51eSKate Stone     const SymbolContextList *bp_locs) {
2154a89501fSGreg Clayton   FileSP file_sp(GetFile(file_spec));
21630fdc8d8SChris Lattner 
217e4ca515aSGreg Clayton   uint32_t start_line;
218e4ca515aSGreg Clayton   uint32_t count = context_before + context_after + 1;
219e4ca515aSGreg Clayton   if (line > context_before)
220e4ca515aSGreg Clayton     start_line = line - context_before;
221e4ca515aSGreg Clayton   else
222e4ca515aSGreg Clayton     start_line = 1;
223e4ca515aSGreg Clayton 
224b9c1b51eSKate Stone   if (m_last_file_sp.get() != file_sp.get()) {
2254a89501fSGreg Clayton     if (line == 0)
226e4ca515aSGreg Clayton       m_last_line = 0;
2274a89501fSGreg Clayton     m_last_file_sp = file_sp;
22830fdc8d8SChris Lattner   }
229b9c1b51eSKate Stone   return DisplaySourceLinesWithLineNumbersUsingLastFile(
2309666ba75STodd Fiala       start_line, count, line, column, current_line_cstr, s, bp_locs);
23130fdc8d8SChris Lattner }
23230fdc8d8SChris Lattner 
233b9c1b51eSKate Stone size_t SourceManager::DisplayMoreWithLineNumbers(
234b9c1b51eSKate Stone     Stream *s, uint32_t count, bool reverse, const SymbolContextList *bp_locs) {
235b9c1b51eSKate Stone   // If we get called before anybody has set a default file and line, then try
236b9c1b51eSKate Stone   // to figure it out here.
2379585fbfcSGreg Clayton   const bool have_default_file_line = m_last_file_sp && m_last_line > 0;
238b9c1b51eSKate Stone   if (!m_default_set) {
239196bbc25SJim Ingham     FileSpec tmp_spec;
240196bbc25SJim Ingham     uint32_t tmp_line;
241196bbc25SJim Ingham     GetDefaultFileAndLine(tmp_spec, tmp_line);
242196bbc25SJim Ingham   }
243196bbc25SJim Ingham 
244b9c1b51eSKate Stone   if (m_last_file_sp) {
245e4ca515aSGreg Clayton     if (m_last_line == UINT32_MAX)
24630fdc8d8SChris Lattner       return 0;
247196bbc25SJim Ingham 
248e4ca515aSGreg Clayton     if (reverse && m_last_line == 1)
249196bbc25SJim Ingham       return 0;
250196bbc25SJim Ingham 
251e4ca515aSGreg Clayton     if (count > 0)
252e4ca515aSGreg Clayton       m_last_count = count;
253e4ca515aSGreg Clayton     else if (m_last_count == 0)
254e4ca515aSGreg Clayton       m_last_count = 10;
255196bbc25SJim Ingham 
256b9c1b51eSKate Stone     if (m_last_line > 0) {
257b9c1b51eSKate Stone       if (reverse) {
258b9c1b51eSKate Stone         // If this is the first time we've done a reverse, then back up one more
259b9c1b51eSKate Stone         // time so we end
260196bbc25SJim Ingham         // up showing the chunk before the last one we've shown:
261e4ca515aSGreg Clayton         if (m_last_line > m_last_count)
262e4ca515aSGreg Clayton           m_last_line -= m_last_count;
263e4ca515aSGreg Clayton         else
264e4ca515aSGreg Clayton           m_last_line = 1;
265b9c1b51eSKate Stone       } else if (have_default_file_line)
266e4ca515aSGreg Clayton         m_last_line += m_last_count;
267b9c1b51eSKate Stone     } else
268e4ca515aSGreg Clayton       m_last_line = 1;
269196bbc25SJim Ingham 
2709666ba75STodd Fiala     const uint32_t column = 0;
271b9c1b51eSKate Stone     return DisplaySourceLinesWithLineNumbersUsingLastFile(
2729666ba75STodd Fiala         m_last_line, m_last_count, UINT32_MAX, column, "", s, bp_locs);
27330fdc8d8SChris Lattner   }
27430fdc8d8SChris Lattner   return 0;
27530fdc8d8SChris Lattner }
27630fdc8d8SChris Lattner 
277b9c1b51eSKate Stone bool SourceManager::SetDefaultFileAndLine(const FileSpec &file_spec,
278b9c1b51eSKate Stone                                           uint32_t line) {
279b7f6b2faSJim Ingham   FileSP old_file_sp = m_last_file_sp;
280b7f6b2faSJim Ingham   m_last_file_sp = GetFile(file_spec);
281f3277750SJim Ingham 
282f3277750SJim Ingham   m_default_set = true;
283b9c1b51eSKate Stone   if (m_last_file_sp) {
284e4ca515aSGreg Clayton     m_last_line = line;
285b7f6b2faSJim Ingham     return true;
286b9c1b51eSKate Stone   } else {
287b7f6b2faSJim Ingham     m_last_file_sp = old_file_sp;
288b7f6b2faSJim Ingham     return false;
289b7f6b2faSJim Ingham   }
290b7f6b2faSJim Ingham }
291b7f6b2faSJim Ingham 
292b9c1b51eSKate Stone bool SourceManager::GetDefaultFileAndLine(FileSpec &file_spec, uint32_t &line) {
293b9c1b51eSKate Stone   if (m_last_file_sp) {
294b7f6b2faSJim Ingham     file_spec = m_last_file_sp->GetFileSpec();
295e4ca515aSGreg Clayton     line = m_last_line;
296b7f6b2faSJim Ingham     return true;
297b9c1b51eSKate Stone   } else if (!m_default_set) {
2989585fbfcSGreg Clayton     TargetSP target_sp(m_target_wp.lock());
2999585fbfcSGreg Clayton 
300b9c1b51eSKate Stone     if (target_sp) {
301b9c1b51eSKate Stone       // If nobody has set the default file and line then try here.  If there's
302b9c1b51eSKate Stone       // no executable, then we
303b9c1b51eSKate Stone       // will try again later when there is one.  Otherwise, if we can't find it
304b9c1b51eSKate Stone       // we won't look again,
305f3277750SJim Ingham       // somebody will have to set it (for instance when we stop somewhere...)
3069585fbfcSGreg Clayton       Module *executable_ptr = target_sp->GetExecutableModulePointer();
307b9c1b51eSKate Stone       if (executable_ptr) {
308f3277750SJim Ingham         SymbolContextList sc_list;
309f3277750SJim Ingham         ConstString main_name("main");
310f3277750SJim Ingham         bool symbols_okay = false; // Force it to be a debug symbol.
3119df05fbbSSean Callanan         bool inlines_okay = true;
312f3277750SJim Ingham         bool append = false;
313b9c1b51eSKate Stone         size_t num_matches = executable_ptr->FindFunctions(
314b9c1b51eSKate Stone             main_name, NULL, lldb::eFunctionNameTypeBase, inlines_okay,
315b9c1b51eSKate Stone             symbols_okay, append, sc_list);
316b9c1b51eSKate Stone         for (size_t idx = 0; idx < num_matches; idx++) {
317f3277750SJim Ingham           SymbolContext sc;
318f3277750SJim Ingham           sc_list.GetContextAtIndex(idx, sc);
319b9c1b51eSKate Stone           if (sc.function) {
3206f6bf26aSGreg Clayton             lldb_private::LineEntry line_entry;
321b9c1b51eSKate Stone             if (sc.function->GetAddressRange()
322b9c1b51eSKate Stone                     .GetBaseAddress()
323b9c1b51eSKate Stone                     .CalculateSymbolContextLineEntry(line_entry)) {
324b9c1b51eSKate Stone               SetDefaultFileAndLine(line_entry.file, line_entry.line);
3256f6bf26aSGreg Clayton               file_spec = m_last_file_sp->GetFileSpec();
326e4ca515aSGreg Clayton               line = m_last_line;
3276f6bf26aSGreg Clayton               return true;
328f3277750SJim Ingham             }
329f3277750SJim Ingham           }
330f3277750SJim Ingham         }
331f3277750SJim Ingham       }
3326f6bf26aSGreg Clayton     }
3339585fbfcSGreg Clayton   }
334b7f6b2faSJim Ingham   return false;
335b7f6b2faSJim Ingham }
33630fdc8d8SChris Lattner 
337b9c1b51eSKate Stone void SourceManager::FindLinesMatchingRegex(FileSpec &file_spec,
338969795f1SJim Ingham                                            RegularExpression &regex,
339969795f1SJim Ingham                                            uint32_t start_line,
340969795f1SJim Ingham                                            uint32_t end_line,
341b9c1b51eSKate Stone                                            std::vector<uint32_t> &match_lines) {
342969795f1SJim Ingham   match_lines.clear();
343969795f1SJim Ingham   FileSP file_sp = GetFile(file_spec);
344969795f1SJim Ingham   if (!file_sp)
345969795f1SJim Ingham     return;
346b9c1b51eSKate Stone   return file_sp->FindLinesMatchingRegex(regex, start_line, end_line,
347b9c1b51eSKate Stone                                          match_lines);
348969795f1SJim Ingham }
34930fdc8d8SChris Lattner 
3509666ba75STodd Fiala SourceManager::File::File(const FileSpec &file_spec,
3519666ba75STodd Fiala                           lldb::DebuggerSP debugger_sp)
3529666ba75STodd Fiala     : m_file_spec_orig(file_spec), m_file_spec(file_spec),
3531408bf72SPavel Labath       m_mod_time(FileSystem::GetModificationTime(file_spec)),
3541408bf72SPavel Labath       m_debugger_wp(debugger_sp) {
3559666ba75STodd Fiala   CommonInitializer(file_spec, nullptr);
3569666ba75STodd Fiala }
3579666ba75STodd Fiala 
358b9c1b51eSKate Stone SourceManager::File::File(const FileSpec &file_spec, Target *target)
359b9c1b51eSKate Stone     : m_file_spec_orig(file_spec), m_file_spec(file_spec),
3601408bf72SPavel Labath       m_mod_time(FileSystem::GetModificationTime(file_spec)),
3619666ba75STodd Fiala       m_debugger_wp(target ? target->GetDebugger().shared_from_this()
3629666ba75STodd Fiala                            : DebuggerSP()) {
3639666ba75STodd Fiala   CommonInitializer(file_spec, target);
3649666ba75STodd Fiala }
3659666ba75STodd Fiala 
3669666ba75STodd Fiala void SourceManager::File::CommonInitializer(const FileSpec &file_spec,
3679666ba75STodd Fiala                                             Target *target) {
3683dc342ebSPavel Labath   if (m_mod_time == llvm::sys::TimePoint<>()) {
369b9c1b51eSKate Stone     if (target) {
3704a89501fSGreg Clayton       m_source_map_mod_id = target->GetSourcePathMap().GetModificationID();
3714a89501fSGreg Clayton 
372b9c1b51eSKate Stone       if (!file_spec.GetDirectory() && file_spec.GetFilename()) {
373b9c1b51eSKate Stone         // If this is just a file name, lets see if we can find it in the
374b9c1b51eSKate Stone         // target:
375e37d605eSJim Ingham         bool check_inlines = false;
376e37d605eSJim Ingham         SymbolContextList sc_list;
377b9c1b51eSKate Stone         size_t num_matches =
378b9c1b51eSKate Stone             target->GetImages().ResolveSymbolContextForFilePath(
379b9c1b51eSKate Stone                 file_spec.GetFilename().AsCString(), 0, check_inlines,
380e37d605eSJim Ingham                 lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit,
381e37d605eSJim Ingham                 sc_list);
382e37d605eSJim Ingham         bool got_multiple = false;
383b9c1b51eSKate Stone         if (num_matches != 0) {
384b9c1b51eSKate Stone           if (num_matches > 1) {
385e37d605eSJim Ingham             SymbolContext sc;
386e37d605eSJim Ingham             FileSpec *test_cu_spec = NULL;
387e37d605eSJim Ingham 
388b9c1b51eSKate Stone             for (unsigned i = 0; i < num_matches; i++) {
389e37d605eSJim Ingham               sc_list.GetContextAtIndex(i, sc);
390b9c1b51eSKate Stone               if (sc.comp_unit) {
391b9c1b51eSKate Stone                 if (test_cu_spec) {
392e37d605eSJim Ingham                   if (test_cu_spec != static_cast<FileSpec *>(sc.comp_unit))
393e37d605eSJim Ingham                     got_multiple = true;
394e37d605eSJim Ingham                   break;
395b9c1b51eSKate Stone                 } else
396e37d605eSJim Ingham                   test_cu_spec = sc.comp_unit;
397e37d605eSJim Ingham               }
398e37d605eSJim Ingham             }
399e37d605eSJim Ingham           }
400b9c1b51eSKate Stone           if (!got_multiple) {
401e37d605eSJim Ingham             SymbolContext sc;
402e37d605eSJim Ingham             sc_list.GetContextAtIndex(0, sc);
403d804d285SGreg Clayton             m_file_spec = sc.comp_unit;
4041408bf72SPavel Labath             m_mod_time = FileSystem::GetModificationTime(m_file_spec);
405e37d605eSJim Ingham           }
406e37d605eSJim Ingham         }
407e37d605eSJim Ingham       }
40864bab489SJohnny Chen       // Try remapping if m_file_spec does not correspond to an existing file.
409b9c1b51eSKate Stone       if (!m_file_spec.Exists()) {
410d804d285SGreg Clayton         FileSpec new_file_spec;
411d804d285SGreg Clayton         // Check target specific source remappings first, then fall back to
412b9c1b51eSKate Stone         // modules objects can have individual path remappings that were
413b9c1b51eSKate Stone         // detected
414d804d285SGreg Clayton         // when the debug info for a module was found.
415d804d285SGreg Clayton         // then
416d804d285SGreg Clayton         if (target->GetSourcePathMap().FindFile(m_file_spec, new_file_spec) ||
417b9c1b51eSKate Stone             target->GetImages().FindSourceFile(m_file_spec, new_file_spec)) {
418d804d285SGreg Clayton           m_file_spec = new_file_spec;
4191408bf72SPavel Labath           m_mod_time = FileSystem::GetModificationTime(m_file_spec);
42064bab489SJohnny Chen         }
4217e14f91dSGreg Clayton       }
422e37d605eSJim Ingham     }
423e37d605eSJim Ingham   }
4247e14f91dSGreg Clayton 
4253dc342ebSPavel Labath   if (m_mod_time != llvm::sys::TimePoint<>())
4267f6a7a37SZachary Turner     m_data_sp = DataBufferLLVM::CreateFromPath(m_file_spec.GetPath());
42730fdc8d8SChris Lattner }
42830fdc8d8SChris Lattner 
429b9c1b51eSKate Stone uint32_t SourceManager::File::GetLineOffset(uint32_t line) {
43030fdc8d8SChris Lattner   if (line == 0)
43130fdc8d8SChris Lattner     return UINT32_MAX;
43230fdc8d8SChris Lattner 
43330fdc8d8SChris Lattner   if (line == 1)
43430fdc8d8SChris Lattner     return 0;
43530fdc8d8SChris Lattner 
436b9c1b51eSKate Stone   if (CalculateLineOffsets(line)) {
43730fdc8d8SChris Lattner     if (line < m_offsets.size())
43830fdc8d8SChris Lattner       return m_offsets[line - 1]; // yes we want "line - 1" in the index
43930fdc8d8SChris Lattner   }
44030fdc8d8SChris Lattner   return UINT32_MAX;
44130fdc8d8SChris Lattner }
44230fdc8d8SChris Lattner 
443b9c1b51eSKate Stone uint32_t SourceManager::File::GetNumLines() {
44444d93782SGreg Clayton   CalculateLineOffsets();
44544d93782SGreg Clayton   return m_offsets.size();
44644d93782SGreg Clayton }
44744d93782SGreg Clayton 
448b9c1b51eSKate Stone const char *SourceManager::File::PeekLineData(uint32_t line) {
44944d93782SGreg Clayton   if (!LineIsValid(line))
45044d93782SGreg Clayton     return NULL;
45144d93782SGreg Clayton 
45244d93782SGreg Clayton   size_t line_offset = GetLineOffset(line);
45344d93782SGreg Clayton   if (line_offset < m_data_sp->GetByteSize())
45444d93782SGreg Clayton     return (const char *)m_data_sp->GetBytes() + line_offset;
45544d93782SGreg Clayton   return NULL;
45644d93782SGreg Clayton }
45744d93782SGreg Clayton 
458b9c1b51eSKate Stone uint32_t SourceManager::File::GetLineLength(uint32_t line,
459b9c1b51eSKate Stone                                             bool include_newline_chars) {
46044d93782SGreg Clayton   if (!LineIsValid(line))
46144d93782SGreg Clayton     return false;
46244d93782SGreg Clayton 
46344d93782SGreg Clayton   size_t start_offset = GetLineOffset(line);
46444d93782SGreg Clayton   size_t end_offset = GetLineOffset(line + 1);
46544d93782SGreg Clayton   if (end_offset == UINT32_MAX)
46644d93782SGreg Clayton     end_offset = m_data_sp->GetByteSize();
46744d93782SGreg Clayton 
468b9c1b51eSKate Stone   if (end_offset > start_offset) {
46944d93782SGreg Clayton     uint32_t length = end_offset - start_offset;
470b9c1b51eSKate Stone     if (include_newline_chars == false) {
471b9c1b51eSKate Stone       const char *line_start =
472b9c1b51eSKate Stone           (const char *)m_data_sp->GetBytes() + start_offset;
473b9c1b51eSKate Stone       while (length > 0) {
47444d93782SGreg Clayton         const char last_char = line_start[length - 1];
47544d93782SGreg Clayton         if ((last_char == '\r') || (last_char == '\n'))
47644d93782SGreg Clayton           --length;
47744d93782SGreg Clayton         else
47844d93782SGreg Clayton           break;
47944d93782SGreg Clayton       }
48044d93782SGreg Clayton     }
48144d93782SGreg Clayton     return length;
48244d93782SGreg Clayton   }
48344d93782SGreg Clayton   return 0;
48444d93782SGreg Clayton }
48544d93782SGreg Clayton 
486b9c1b51eSKate Stone bool SourceManager::File::LineIsValid(uint32_t line) {
48730fdc8d8SChris Lattner   if (line == 0)
48830fdc8d8SChris Lattner     return false;
48930fdc8d8SChris Lattner 
49030fdc8d8SChris Lattner   if (CalculateLineOffsets(line))
49130fdc8d8SChris Lattner     return line < m_offsets.size();
49230fdc8d8SChris Lattner   return false;
49330fdc8d8SChris Lattner }
49430fdc8d8SChris Lattner 
495b9c1b51eSKate Stone void SourceManager::File::UpdateIfNeeded() {
4969625d08cSGreg Clayton   // TODO: use host API to sign up for file modifications to anything in our
4979625d08cSGreg Clayton   // source cache and only update when we determine a file has been updated.
4989625d08cSGreg Clayton   // For now we check each time we want to display info for the file.
4993dc342ebSPavel Labath   auto curr_mod_time = FileSystem::GetModificationTime(m_file_spec);
50064bab489SJohnny Chen 
5013dc342ebSPavel Labath   if (curr_mod_time != llvm::sys::TimePoint<>() &&
5023dc342ebSPavel Labath       m_mod_time != curr_mod_time) {
5039625d08cSGreg Clayton     m_mod_time = curr_mod_time;
5047f6a7a37SZachary Turner     m_data_sp = DataBufferLLVM::CreateFromPath(m_file_spec.GetPath());
5059625d08cSGreg Clayton     m_offsets.clear();
5069625d08cSGreg Clayton   }
5070d5b0a8aSGreg Clayton }
5089625d08cSGreg Clayton 
5099666ba75STodd Fiala size_t SourceManager::File::DisplaySourceLines(uint32_t line, uint32_t column,
510b9c1b51eSKate Stone                                                uint32_t context_before,
511b9c1b51eSKate Stone                                                uint32_t context_after,
512b9c1b51eSKate Stone                                                Stream *s) {
5139666ba75STodd Fiala   // Nothing to write if there's no stream.
5149666ba75STodd Fiala   if (!s)
5159666ba75STodd Fiala     return 0;
5169666ba75STodd Fiala 
51764bab489SJohnny Chen   // Sanity check m_data_sp before proceeding.
51864bab489SJohnny Chen   if (!m_data_sp)
51964bab489SJohnny Chen     return 0;
52064bab489SJohnny Chen 
521b9c1b51eSKate Stone   const uint32_t start_line =
522b9c1b51eSKate Stone       line <= context_before ? 1 : line - context_before;
52330fdc8d8SChris Lattner   const uint32_t start_line_offset = GetLineOffset(start_line);
524b9c1b51eSKate Stone   if (start_line_offset != UINT32_MAX) {
52530fdc8d8SChris Lattner     const uint32_t end_line = line + context_after;
52630fdc8d8SChris Lattner     uint32_t end_line_offset = GetLineOffset(end_line + 1);
52730fdc8d8SChris Lattner     if (end_line_offset == UINT32_MAX)
52830fdc8d8SChris Lattner       end_line_offset = m_data_sp->GetByteSize();
52930fdc8d8SChris Lattner 
53030fdc8d8SChris Lattner     assert(start_line_offset <= end_line_offset);
53130fdc8d8SChris Lattner     size_t bytes_written = 0;
532b9c1b51eSKate Stone     if (start_line_offset < end_line_offset) {
53330fdc8d8SChris Lattner       size_t count = end_line_offset - start_line_offset;
53430fdc8d8SChris Lattner       const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
5359666ba75STodd Fiala 
5369666ba75STodd Fiala       bool displayed_line = false;
5379666ba75STodd Fiala 
5389666ba75STodd Fiala       if (column && (column < count)) {
5399666ba75STodd Fiala         auto debugger_sp = m_debugger_wp.lock();
5409666ba75STodd Fiala         if (should_show_stop_column_with_ansi(debugger_sp) && debugger_sp) {
5419666ba75STodd Fiala           // Check if we have any ANSI codes with which to mark this column.
5429666ba75STodd Fiala           // If not, no need to do this work.
5439666ba75STodd Fiala           auto ansi_prefix_entry = debugger_sp->GetStopShowColumnAnsiPrefix();
5449666ba75STodd Fiala           auto ansi_suffix_entry = debugger_sp->GetStopShowColumnAnsiSuffix();
5459666ba75STodd Fiala 
5469666ba75STodd Fiala           // We only bother breaking up the line to format the marked column if
5479666ba75STodd Fiala           // there is any marking specified on both sides of the marked column.
5489666ba75STodd Fiala           // In ANSI-terminal-sequence land, there must be a post if there is a
5499666ba75STodd Fiala           // pre format, and vice versa.
5509666ba75STodd Fiala           if (ansi_prefix_entry && ansi_suffix_entry) {
5519666ba75STodd Fiala             // Mark the current column with the desired escape sequence for
5529666ba75STodd Fiala             // formatting the column (e.g. underline, inverse, etc.)
5539666ba75STodd Fiala 
5549666ba75STodd Fiala             // First print the part before the column to mark.
5559666ba75STodd Fiala             bytes_written = s->Write(cstr, column - 1);
5569666ba75STodd Fiala 
5579666ba75STodd Fiala             // Write the pre escape sequence.
5589666ba75STodd Fiala             const SymbolContext *sc = nullptr;
5599666ba75STodd Fiala             const ExecutionContext *exe_ctx = nullptr;
5609666ba75STodd Fiala             const Address addr = LLDB_INVALID_ADDRESS;
5619666ba75STodd Fiala             ValueObject *valobj = nullptr;
5629666ba75STodd Fiala             const bool function_changed = false;
5639666ba75STodd Fiala             const bool initial_function = false;
5649666ba75STodd Fiala 
5659666ba75STodd Fiala             FormatEntity::Format(*ansi_prefix_entry, *s, sc, exe_ctx, &addr,
5669666ba75STodd Fiala                                  valobj, function_changed, initial_function);
5679666ba75STodd Fiala 
5689666ba75STodd Fiala             // Write the marked column.
5699666ba75STodd Fiala             bytes_written += s->Write(cstr + column - 1, 1);
5709666ba75STodd Fiala 
5719666ba75STodd Fiala             // Write the post escape sequence.
5729666ba75STodd Fiala             FormatEntity::Format(*ansi_suffix_entry, *s, sc, exe_ctx, &addr,
5739666ba75STodd Fiala                                  valobj, function_changed, initial_function);
5749666ba75STodd Fiala 
5759666ba75STodd Fiala             // And finish up with the rest of the line.
5769666ba75STodd Fiala             bytes_written += s->Write(cstr + column, count - column);
5779666ba75STodd Fiala 
5789666ba75STodd Fiala             // Keep track of the fact that we just wrote the line.
5799666ba75STodd Fiala             displayed_line = true;
5809666ba75STodd Fiala           }
5819666ba75STodd Fiala         }
5829666ba75STodd Fiala       }
5839666ba75STodd Fiala 
5849666ba75STodd Fiala       // If we didn't end up displaying the line with ANSI codes for whatever
5859666ba75STodd Fiala       // reason, display it now sans codes.
5869666ba75STodd Fiala       if (!displayed_line)
58730fdc8d8SChris Lattner         bytes_written = s->Write(cstr, count);
5889666ba75STodd Fiala 
5899666ba75STodd Fiala       // Ensure we get an end of line character one way or another.
59030fdc8d8SChris Lattner       if (!is_newline_char(cstr[count - 1]))
59130fdc8d8SChris Lattner         bytes_written += s->EOL();
59230fdc8d8SChris Lattner     }
59330fdc8d8SChris Lattner     return bytes_written;
59430fdc8d8SChris Lattner   }
59530fdc8d8SChris Lattner   return 0;
59630fdc8d8SChris Lattner }
59730fdc8d8SChris Lattner 
598b9c1b51eSKate Stone void SourceManager::File::FindLinesMatchingRegex(
599b9c1b51eSKate Stone     RegularExpression &regex, uint32_t start_line, uint32_t end_line,
600b9c1b51eSKate Stone     std::vector<uint32_t> &match_lines) {
601969795f1SJim Ingham   match_lines.clear();
602969795f1SJim Ingham 
603b9c1b51eSKate Stone   if (!LineIsValid(start_line) ||
604b9c1b51eSKate Stone       (end_line != UINT32_MAX && !LineIsValid(end_line)))
605969795f1SJim Ingham     return;
606969795f1SJim Ingham   if (start_line > end_line)
607969795f1SJim Ingham     return;
608969795f1SJim Ingham 
609b9c1b51eSKate Stone   for (uint32_t line_no = start_line; line_no < end_line; line_no++) {
610969795f1SJim Ingham     std::string buffer;
611969795f1SJim Ingham     if (!GetLine(line_no, buffer))
612969795f1SJim Ingham       break;
61395eae423SZachary Turner     if (regex.Execute(buffer)) {
614969795f1SJim Ingham       match_lines.push_back(line_no);
615969795f1SJim Ingham     }
616969795f1SJim Ingham   }
617969795f1SJim Ingham }
618969795f1SJim Ingham 
619b9c1b51eSKate Stone bool SourceManager::File::FileSpecMatches(const FileSpec &file_spec) {
620644247c1SGreg Clayton   return FileSpec::Equal(m_file_spec, file_spec, false);
62130fdc8d8SChris Lattner }
62230fdc8d8SChris Lattner 
623b9c1b51eSKate Stone bool lldb_private::operator==(const SourceManager::File &lhs,
624b9c1b51eSKate Stone                               const SourceManager::File &rhs) {
6253dc342ebSPavel Labath   if (lhs.m_file_spec != rhs.m_file_spec)
6263dc342ebSPavel Labath     return false;
627e37d605eSJim Ingham   return lhs.m_mod_time == rhs.m_mod_time;
628e37d605eSJim Ingham }
62930fdc8d8SChris Lattner 
630b9c1b51eSKate Stone bool SourceManager::File::CalculateLineOffsets(uint32_t line) {
631b9c1b51eSKate Stone   line =
632b9c1b51eSKate Stone       UINT32_MAX; // TODO: take this line out when we support partial indexing
633b9c1b51eSKate Stone   if (line == UINT32_MAX) {
63430fdc8d8SChris Lattner     // Already done?
63530fdc8d8SChris Lattner     if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
63630fdc8d8SChris Lattner       return true;
63730fdc8d8SChris Lattner 
638b9c1b51eSKate Stone     if (m_offsets.empty()) {
63930fdc8d8SChris Lattner       if (m_data_sp.get() == NULL)
64030fdc8d8SChris Lattner         return false;
64130fdc8d8SChris Lattner 
64230fdc8d8SChris Lattner       const char *start = (char *)m_data_sp->GetBytes();
643b9c1b51eSKate Stone       if (start) {
64430fdc8d8SChris Lattner         const char *end = start + m_data_sp->GetByteSize();
64530fdc8d8SChris Lattner 
64630fdc8d8SChris Lattner         // Calculate all line offsets from scratch
64730fdc8d8SChris Lattner 
648b9c1b51eSKate Stone         // Push a 1 at index zero to indicate the file has been completely
649b9c1b51eSKate Stone         // indexed.
65030fdc8d8SChris Lattner         m_offsets.push_back(UINT32_MAX);
6512490f5c9SEric Christopher         const char *s;
652b9c1b51eSKate Stone         for (s = start; s < end; ++s) {
6532490f5c9SEric Christopher           char curr_ch = *s;
654b9c1b51eSKate Stone           if (is_newline_char(curr_ch)) {
655b9c1b51eSKate Stone             if (s + 1 < end) {
6562490f5c9SEric Christopher               char next_ch = s[1];
657b9c1b51eSKate Stone               if (is_newline_char(next_ch)) {
65830fdc8d8SChris Lattner                 if (curr_ch != next_ch)
65930fdc8d8SChris Lattner                   ++s;
66030fdc8d8SChris Lattner               }
661f6cdd126SGreg Clayton             }
66230fdc8d8SChris Lattner             m_offsets.push_back(s + 1 - start);
66330fdc8d8SChris Lattner           }
66430fdc8d8SChris Lattner         }
665b9c1b51eSKate Stone         if (!m_offsets.empty()) {
6665a8ad459SZachary Turner           if (m_offsets.back() < size_t(end - start))
66730fdc8d8SChris Lattner             m_offsets.push_back(end - start);
66830fdc8d8SChris Lattner         }
66930fdc8d8SChris Lattner         return true;
67030fdc8d8SChris Lattner       }
671b9c1b51eSKate Stone     } else {
67230fdc8d8SChris Lattner       // Some lines have been populated, start where we last left off
67303439a87SStephane Sezer       assert("Not implemented yet" && false);
67430fdc8d8SChris Lattner     }
67530fdc8d8SChris Lattner 
676b9c1b51eSKate Stone   } else {
67730fdc8d8SChris Lattner     // Calculate all line offsets up to "line"
67803439a87SStephane Sezer     assert("Not implemented yet" && false);
67930fdc8d8SChris Lattner   }
68030fdc8d8SChris Lattner   return false;
68130fdc8d8SChris Lattner }
682e37d605eSJim Ingham 
683b9c1b51eSKate Stone bool SourceManager::File::GetLine(uint32_t line_no, std::string &buffer) {
684969795f1SJim Ingham   if (!LineIsValid(line_no))
685969795f1SJim Ingham     return false;
686969795f1SJim Ingham 
687c7bece56SGreg Clayton   size_t start_offset = GetLineOffset(line_no);
688c7bece56SGreg Clayton   size_t end_offset = GetLineOffset(line_no + 1);
689b9c1b51eSKate Stone   if (end_offset == UINT32_MAX) {
690969795f1SJim Ingham     end_offset = m_data_sp->GetByteSize();
691969795f1SJim Ingham   }
692b9c1b51eSKate Stone   buffer.assign((char *)m_data_sp->GetBytes() + start_offset,
693b9c1b51eSKate Stone                 end_offset - start_offset);
694969795f1SJim Ingham 
695969795f1SJim Ingham   return true;
696969795f1SJim Ingham }
697969795f1SJim Ingham 
698b9c1b51eSKate Stone void SourceManager::SourceFileCache::AddSourceFile(const FileSP &file_sp) {
699e37d605eSJim Ingham   FileSpec file_spec;
700e37d605eSJim Ingham   FileCache::iterator pos = m_file_cache.find(file_spec);
701e37d605eSJim Ingham   if (pos == m_file_cache.end())
702e37d605eSJim Ingham     m_file_cache[file_spec] = file_sp;
703b9c1b51eSKate Stone   else {
704e37d605eSJim Ingham     if (file_sp != pos->second)
705e37d605eSJim Ingham       m_file_cache[file_spec] = file_sp;
706e37d605eSJim Ingham   }
707e37d605eSJim Ingham }
708e37d605eSJim Ingham 
709b9c1b51eSKate Stone SourceManager::FileSP SourceManager::SourceFileCache::FindSourceFile(
710b9c1b51eSKate Stone     const FileSpec &file_spec) const {
711e37d605eSJim Ingham   FileSP file_sp;
712e37d605eSJim Ingham   FileCache::const_iterator pos = m_file_cache.find(file_spec);
713e37d605eSJim Ingham   if (pos != m_file_cache.end())
714e37d605eSJim Ingham     file_sp = pos->second;
715e37d605eSJim Ingham   return file_sp;
716e37d605eSJim Ingham }
717