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 
122f3df613SZachary Turner #include "lldb/Core/Address.h"      // for Address
132f3df613SZachary Turner #include "lldb/Core/AddressRange.h" // for AddressRange
14e37d605eSJim Ingham #include "lldb/Core/Debugger.h"
152f3df613SZachary Turner #include "lldb/Core/FormatEntity.h" // for FormatEntity
16566afa0aSRaphael Isemann #include "lldb/Core/Highlighter.h"
171f746071SGreg Clayton #include "lldb/Core/Module.h"
182f3df613SZachary Turner #include "lldb/Core/ModuleList.h" // for ModuleList
191408bf72SPavel Labath #include "lldb/Host/FileSystem.h"
201f746071SGreg Clayton #include "lldb/Symbol/CompileUnit.h"
211f746071SGreg Clayton #include "lldb/Symbol/Function.h"
222f3df613SZachary Turner #include "lldb/Symbol/LineEntry.h" // for LineEntry
23176761e5SGreg Clayton #include "lldb/Symbol/SymbolContext.h"
242f3df613SZachary Turner #include "lldb/Target/PathMappingList.h" // for PathMappingList
257e14f91dSGreg Clayton #include "lldb/Target/Target.h"
262f3df613SZachary Turner #include "lldb/Utility/ConstString.h" // for ConstString
27666cc0b2SZachary Turner #include "lldb/Utility/DataBuffer.h"
287f6a7a37SZachary Turner #include "lldb/Utility/DataBufferLLVM.h"
29bf9a7730SZachary Turner #include "lldb/Utility/RegularExpression.h"
30bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
312f3df613SZachary Turner #include "lldb/lldb-enumerations.h" // for StopShowColumn::eStopSho...
322f3df613SZachary Turner 
332f3df613SZachary Turner #include "llvm/ADT/Twine.h" // for Twine
342f3df613SZachary Turner 
352f3df613SZachary Turner #include <memory>
362f3df613SZachary Turner #include <utility> // for pair
372f3df613SZachary Turner 
382f3df613SZachary Turner #include <assert.h> // for assert
392f3df613SZachary Turner #include <stdio.h>  // for size_t, NULL, snprintf
402f3df613SZachary Turner 
412f3df613SZachary Turner namespace lldb_private {
422f3df613SZachary Turner class ExecutionContext;
432f3df613SZachary Turner }
442f3df613SZachary Turner namespace lldb_private {
452f3df613SZachary Turner class ValueObject;
462f3df613SZachary Turner }
4730fdc8d8SChris Lattner 
489585fbfcSGreg Clayton using namespace lldb;
4930fdc8d8SChris Lattner using namespace lldb_private;
5030fdc8d8SChris Lattner 
51b9c1b51eSKate Stone static inline bool is_newline_char(char ch) { return ch == '\n' || ch == '\r'; }
5230fdc8d8SChris Lattner 
5330fdc8d8SChris Lattner //----------------------------------------------------------------------
5430fdc8d8SChris Lattner // SourceManager constructor
5530fdc8d8SChris Lattner //----------------------------------------------------------------------
56b9c1b51eSKate Stone SourceManager::SourceManager(const TargetSP &target_sp)
57b9c1b51eSKate Stone     : m_last_file_sp(), m_last_line(0), m_last_count(0), m_default_set(false),
589585fbfcSGreg Clayton       m_target_wp(target_sp),
59b9c1b51eSKate Stone       m_debugger_wp(target_sp->GetDebugger().shared_from_this()) {}
60e37d605eSJim Ingham 
61b9c1b51eSKate Stone SourceManager::SourceManager(const DebuggerSP &debugger_sp)
62b9c1b51eSKate Stone     : m_last_file_sp(), m_last_line(0), m_last_count(0), m_default_set(false),
63b9c1b51eSKate Stone       m_target_wp(), m_debugger_wp(debugger_sp) {}
6430fdc8d8SChris Lattner 
6530fdc8d8SChris Lattner //----------------------------------------------------------------------
6630fdc8d8SChris Lattner // Destructor
6730fdc8d8SChris Lattner //----------------------------------------------------------------------
68b9c1b51eSKate Stone SourceManager::~SourceManager() {}
6930fdc8d8SChris Lattner 
70b9c1b51eSKate Stone SourceManager::FileSP SourceManager::GetFile(const FileSpec &file_spec) {
71b9c1b51eSKate Stone   bool same_as_previous =
72b9c1b51eSKate Stone       m_last_file_sp && m_last_file_sp->FileSpecMatches(file_spec);
734a89501fSGreg Clayton 
749585fbfcSGreg Clayton   DebuggerSP debugger_sp(m_debugger_wp.lock());
7530fdc8d8SChris Lattner   FileSP file_sp;
764a89501fSGreg Clayton   if (same_as_previous)
774a89501fSGreg Clayton     file_sp = m_last_file_sp;
789585fbfcSGreg Clayton   else if (debugger_sp)
799585fbfcSGreg Clayton     file_sp = debugger_sp->GetSourceFileCache().FindSourceFile(file_spec);
809585fbfcSGreg Clayton 
819585fbfcSGreg Clayton   TargetSP target_sp(m_target_wp.lock());
824a89501fSGreg Clayton 
834a89501fSGreg Clayton   // It the target source path map has been updated, get this file again so we
844a89501fSGreg Clayton   // can successfully remap the source file
85b9c1b51eSKate Stone   if (target_sp && file_sp &&
86b9c1b51eSKate Stone       file_sp->GetSourceMapModificationID() !=
87b9c1b51eSKate Stone           target_sp->GetSourcePathMap().GetModificationID())
884a89501fSGreg Clayton     file_sp.reset();
894a89501fSGreg Clayton 
900d5b0a8aSGreg Clayton   // Update the file contents if needed if we found a file
910d5b0a8aSGreg Clayton   if (file_sp)
920d5b0a8aSGreg Clayton     file_sp->UpdateIfNeeded();
930d5b0a8aSGreg Clayton 
9464bab489SJohnny Chen   // If file_sp is no good or it points to a non-existent file, reset it.
95*dbd7fabaSJonas Devlieghere   if (!file_sp || !FileSystem::Instance().Exists(file_sp->GetFileSpec())) {
969666ba75STodd Fiala     if (target_sp)
972f3df613SZachary Turner       file_sp = std::make_shared<File>(file_spec, target_sp.get());
989666ba75STodd Fiala     else
992f3df613SZachary Turner       file_sp = std::make_shared<File>(file_spec, debugger_sp);
100e37d605eSJim Ingham 
1019585fbfcSGreg Clayton     if (debugger_sp)
1029585fbfcSGreg Clayton       debugger_sp->GetSourceFileCache().AddSourceFile(file_sp);
10330fdc8d8SChris Lattner   }
10430fdc8d8SChris Lattner   return file_sp;
10530fdc8d8SChris Lattner }
10630fdc8d8SChris Lattner 
107566afa0aSRaphael Isemann static bool should_highlight_source(DebuggerSP debugger_sp) {
108566afa0aSRaphael Isemann   if (!debugger_sp)
109566afa0aSRaphael Isemann     return false;
110566afa0aSRaphael Isemann 
111566afa0aSRaphael Isemann   // We don't use ANSI stop column formatting if the debugger doesn't think it
112566afa0aSRaphael Isemann   // should be using color.
113566afa0aSRaphael Isemann   if (!debugger_sp->GetUseColor())
114566afa0aSRaphael Isemann     return false;
115566afa0aSRaphael Isemann 
116566afa0aSRaphael Isemann   return debugger_sp->GetHighlightSource();
117566afa0aSRaphael Isemann }
118566afa0aSRaphael Isemann 
1199666ba75STodd Fiala static bool should_show_stop_column_with_ansi(DebuggerSP debugger_sp) {
1209666ba75STodd Fiala   // We don't use ANSI stop column formatting if we can't lookup values from
1219666ba75STodd Fiala   // the debugger.
1229666ba75STodd Fiala   if (!debugger_sp)
1239666ba75STodd Fiala     return false;
1249666ba75STodd Fiala 
12505097246SAdrian Prantl   // We don't use ANSI stop column formatting if the debugger doesn't think it
12605097246SAdrian Prantl   // should be using color.
1279666ba75STodd Fiala   if (!debugger_sp->GetUseColor())
1289666ba75STodd Fiala     return false;
1299666ba75STodd Fiala 
1309666ba75STodd Fiala   // We only use ANSI stop column formatting if we're either supposed to show
1319666ba75STodd Fiala   // ANSI where available (which we know we have when we get to this point), or
1329666ba75STodd Fiala   // if we're only supposed to use ANSI.
1339666ba75STodd Fiala   const auto value = debugger_sp->GetStopShowColumn();
1349666ba75STodd Fiala   return ((value == eStopShowColumnAnsiOrCaret) ||
1359666ba75STodd Fiala           (value == eStopShowColumnAnsi));
1369666ba75STodd Fiala }
1379666ba75STodd Fiala 
1389666ba75STodd Fiala static bool should_show_stop_column_with_caret(DebuggerSP debugger_sp) {
1399666ba75STodd Fiala   // We don't use text-based stop column formatting if we can't lookup values
1409666ba75STodd Fiala   // from the debugger.
1419666ba75STodd Fiala   if (!debugger_sp)
1429666ba75STodd Fiala     return false;
1439666ba75STodd Fiala 
14405097246SAdrian Prantl   // If we're asked to show the first available of ANSI or caret, then we do
14505097246SAdrian Prantl   // show the caret when ANSI is not available.
1469666ba75STodd Fiala   const auto value = debugger_sp->GetStopShowColumn();
1479666ba75STodd Fiala   if ((value == eStopShowColumnAnsiOrCaret) && !debugger_sp->GetUseColor())
1489666ba75STodd Fiala     return true;
1499666ba75STodd Fiala 
1509666ba75STodd Fiala   // The only other time we use caret is if we're explicitly asked to show
1519666ba75STodd Fiala   // caret.
1529666ba75STodd Fiala   return value == eStopShowColumnCaret;
1539666ba75STodd Fiala }
1549666ba75STodd Fiala 
155b9c1b51eSKate Stone size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile(
1569666ba75STodd Fiala     uint32_t start_line, uint32_t count, uint32_t curr_line, uint32_t column,
157b9c1b51eSKate Stone     const char *current_line_cstr, Stream *s,
158b9c1b51eSKate Stone     const SymbolContextList *bp_locs) {
159e4ca515aSGreg Clayton   if (count == 0)
160e4ca515aSGreg Clayton     return 0;
1617e9649b8SRaphael Isemann 
1627e9649b8SRaphael Isemann   Stream::ByteDelta delta(*s);
1637e9649b8SRaphael Isemann 
164b9c1b51eSKate Stone   if (start_line == 0) {
165e4ca515aSGreg Clayton     if (m_last_line != 0 && m_last_line != UINT32_MAX)
166e4ca515aSGreg Clayton       start_line = m_last_line + m_last_count;
16730fdc8d8SChris Lattner     else
168e4ca515aSGreg Clayton       start_line = 1;
16930fdc8d8SChris Lattner   }
17030fdc8d8SChris Lattner 
171b9c1b51eSKate Stone   if (!m_default_set) {
172e4ca515aSGreg Clayton     FileSpec tmp_spec;
173e4ca515aSGreg Clayton     uint32_t tmp_line;
174e4ca515aSGreg Clayton     GetDefaultFileAndLine(tmp_spec, tmp_line);
175e4ca515aSGreg Clayton   }
17630fdc8d8SChris Lattner 
177e4ca515aSGreg Clayton   m_last_line = start_line;
178e4ca515aSGreg Clayton   m_last_count = count;
17930fdc8d8SChris Lattner 
180b9c1b51eSKate Stone   if (m_last_file_sp.get()) {
181e4ca515aSGreg Clayton     const uint32_t end_line = start_line + count - 1;
182b9c1b51eSKate Stone     for (uint32_t line = start_line; line <= end_line; ++line) {
183b9c1b51eSKate Stone       if (!m_last_file_sp->LineIsValid(line)) {
184e4ca515aSGreg Clayton         m_last_line = UINT32_MAX;
18530fdc8d8SChris Lattner         break;
18630fdc8d8SChris Lattner       }
18730fdc8d8SChris Lattner 
188176761e5SGreg Clayton       char prefix[32] = "";
189b9c1b51eSKate Stone       if (bp_locs) {
190e4ca515aSGreg Clayton         uint32_t bp_count = bp_locs->NumLineEntriesWithLine(line);
191176761e5SGreg Clayton 
192176761e5SGreg Clayton         if (bp_count > 0)
193176761e5SGreg Clayton           ::snprintf(prefix, sizeof(prefix), "[%u] ", bp_count);
194176761e5SGreg Clayton         else
195176761e5SGreg Clayton           ::snprintf(prefix, sizeof(prefix), "    ");
196176761e5SGreg Clayton       }
197176761e5SGreg Clayton 
198b9c1b51eSKate Stone       s->Printf("%s%2.2s %-4u\t", prefix,
199b9c1b51eSKate Stone                 line == curr_line ? current_line_cstr : "", line);
20020786326SRaphael Isemann 
20120786326SRaphael Isemann       // So far we treated column 0 as a special 'no column value', but
20220786326SRaphael Isemann       // DisplaySourceLines starts counting columns from 0 (and no column is
20320786326SRaphael Isemann       // expressed by passing an empty optional).
20420786326SRaphael Isemann       llvm::Optional<size_t> columnToHighlight;
20520786326SRaphael Isemann       if (line == curr_line && column)
20620786326SRaphael Isemann         columnToHighlight = column - 1;
20720786326SRaphael Isemann 
20820786326SRaphael Isemann       size_t this_line_size =
20920786326SRaphael Isemann           m_last_file_sp->DisplaySourceLines(line, columnToHighlight, 0, 0, s);
2109666ba75STodd Fiala       if (column != 0 && line == curr_line &&
2119666ba75STodd Fiala           should_show_stop_column_with_caret(m_debugger_wp.lock())) {
2129666ba75STodd Fiala         // Display caret cursor.
2139666ba75STodd Fiala         std::string src_line;
2149666ba75STodd Fiala         m_last_file_sp->GetLine(line, src_line);
2157e9649b8SRaphael Isemann         s->Printf("    \t");
2169666ba75STodd Fiala         // Insert a space for every non-tab character in the source line.
21705092039SEd Maste         for (size_t i = 0; i + 1 < column && i < src_line.length(); ++i)
2187e9649b8SRaphael Isemann           s->PutChar(src_line[i] == '\t' ? '\t' : ' ');
2199666ba75STodd Fiala         // Now add the caret.
2207e9649b8SRaphael Isemann         s->Printf("^\n");
2219666ba75STodd Fiala       }
222b9c1b51eSKate Stone       if (this_line_size == 0) {
223e4ca515aSGreg Clayton         m_last_line = UINT32_MAX;
22430fdc8d8SChris Lattner         break;
22530fdc8d8SChris Lattner       }
22630fdc8d8SChris Lattner     }
2277e9649b8SRaphael Isemann   }
2287e9649b8SRaphael Isemann   return *delta;
22930fdc8d8SChris Lattner }
23030fdc8d8SChris Lattner 
231b9c1b51eSKate Stone size_t SourceManager::DisplaySourceLinesWithLineNumbers(
2329666ba75STodd Fiala     const FileSpec &file_spec, uint32_t line, uint32_t column,
2339666ba75STodd Fiala     uint32_t context_before, uint32_t context_after,
2349666ba75STodd Fiala     const char *current_line_cstr, Stream *s,
235b9c1b51eSKate Stone     const SymbolContextList *bp_locs) {
2364a89501fSGreg Clayton   FileSP file_sp(GetFile(file_spec));
23730fdc8d8SChris Lattner 
238e4ca515aSGreg Clayton   uint32_t start_line;
239e4ca515aSGreg Clayton   uint32_t count = context_before + context_after + 1;
240e4ca515aSGreg Clayton   if (line > context_before)
241e4ca515aSGreg Clayton     start_line = line - context_before;
242e4ca515aSGreg Clayton   else
243e4ca515aSGreg Clayton     start_line = 1;
244e4ca515aSGreg Clayton 
245b9c1b51eSKate Stone   if (m_last_file_sp.get() != file_sp.get()) {
2464a89501fSGreg Clayton     if (line == 0)
247e4ca515aSGreg Clayton       m_last_line = 0;
2484a89501fSGreg Clayton     m_last_file_sp = file_sp;
24930fdc8d8SChris Lattner   }
250b9c1b51eSKate Stone   return DisplaySourceLinesWithLineNumbersUsingLastFile(
2519666ba75STodd Fiala       start_line, count, line, column, current_line_cstr, s, bp_locs);
25230fdc8d8SChris Lattner }
25330fdc8d8SChris Lattner 
254b9c1b51eSKate Stone size_t SourceManager::DisplayMoreWithLineNumbers(
255b9c1b51eSKate Stone     Stream *s, uint32_t count, bool reverse, const SymbolContextList *bp_locs) {
256b9c1b51eSKate Stone   // If we get called before anybody has set a default file and line, then try
257b9c1b51eSKate Stone   // to figure it out here.
2589585fbfcSGreg Clayton   const bool have_default_file_line = m_last_file_sp && m_last_line > 0;
259b9c1b51eSKate Stone   if (!m_default_set) {
260196bbc25SJim Ingham     FileSpec tmp_spec;
261196bbc25SJim Ingham     uint32_t tmp_line;
262196bbc25SJim Ingham     GetDefaultFileAndLine(tmp_spec, tmp_line);
263196bbc25SJim Ingham   }
264196bbc25SJim Ingham 
265b9c1b51eSKate Stone   if (m_last_file_sp) {
266e4ca515aSGreg Clayton     if (m_last_line == UINT32_MAX)
26730fdc8d8SChris Lattner       return 0;
268196bbc25SJim Ingham 
269e4ca515aSGreg Clayton     if (reverse && m_last_line == 1)
270196bbc25SJim Ingham       return 0;
271196bbc25SJim Ingham 
272e4ca515aSGreg Clayton     if (count > 0)
273e4ca515aSGreg Clayton       m_last_count = count;
274e4ca515aSGreg Clayton     else if (m_last_count == 0)
275e4ca515aSGreg Clayton       m_last_count = 10;
276196bbc25SJim Ingham 
277b9c1b51eSKate Stone     if (m_last_line > 0) {
278b9c1b51eSKate Stone       if (reverse) {
27905097246SAdrian Prantl         // If this is the first time we've done a reverse, then back up one
28005097246SAdrian Prantl         // more time so we end up showing the chunk before the last one we've
28105097246SAdrian Prantl         // shown:
282e4ca515aSGreg Clayton         if (m_last_line > m_last_count)
283e4ca515aSGreg Clayton           m_last_line -= m_last_count;
284e4ca515aSGreg Clayton         else
285e4ca515aSGreg Clayton           m_last_line = 1;
286b9c1b51eSKate Stone       } else if (have_default_file_line)
287e4ca515aSGreg Clayton         m_last_line += m_last_count;
288b9c1b51eSKate Stone     } else
289e4ca515aSGreg Clayton       m_last_line = 1;
290196bbc25SJim Ingham 
2919666ba75STodd Fiala     const uint32_t column = 0;
292b9c1b51eSKate Stone     return DisplaySourceLinesWithLineNumbersUsingLastFile(
2939666ba75STodd Fiala         m_last_line, m_last_count, UINT32_MAX, column, "", s, bp_locs);
29430fdc8d8SChris Lattner   }
29530fdc8d8SChris Lattner   return 0;
29630fdc8d8SChris Lattner }
29730fdc8d8SChris Lattner 
298b9c1b51eSKate Stone bool SourceManager::SetDefaultFileAndLine(const FileSpec &file_spec,
299b9c1b51eSKate Stone                                           uint32_t line) {
300b7f6b2faSJim Ingham   FileSP old_file_sp = m_last_file_sp;
301b7f6b2faSJim Ingham   m_last_file_sp = GetFile(file_spec);
302f3277750SJim Ingham 
303f3277750SJim Ingham   m_default_set = true;
304b9c1b51eSKate Stone   if (m_last_file_sp) {
305e4ca515aSGreg Clayton     m_last_line = line;
306b7f6b2faSJim Ingham     return true;
307b9c1b51eSKate Stone   } else {
308b7f6b2faSJim Ingham     m_last_file_sp = old_file_sp;
309b7f6b2faSJim Ingham     return false;
310b7f6b2faSJim Ingham   }
311b7f6b2faSJim Ingham }
312b7f6b2faSJim Ingham 
313b9c1b51eSKate Stone bool SourceManager::GetDefaultFileAndLine(FileSpec &file_spec, uint32_t &line) {
314b9c1b51eSKate Stone   if (m_last_file_sp) {
315b7f6b2faSJim Ingham     file_spec = m_last_file_sp->GetFileSpec();
316e4ca515aSGreg Clayton     line = m_last_line;
317b7f6b2faSJim Ingham     return true;
318b9c1b51eSKate Stone   } else if (!m_default_set) {
3199585fbfcSGreg Clayton     TargetSP target_sp(m_target_wp.lock());
3209585fbfcSGreg Clayton 
321b9c1b51eSKate Stone     if (target_sp) {
322b9c1b51eSKate Stone       // If nobody has set the default file and line then try here.  If there's
32305097246SAdrian Prantl       // no executable, then we will try again later when there is one.
32405097246SAdrian Prantl       // Otherwise, if we can't find it we won't look again, somebody will have
32505097246SAdrian Prantl       // to set it (for instance when we stop somewhere...)
3269585fbfcSGreg Clayton       Module *executable_ptr = target_sp->GetExecutableModulePointer();
327b9c1b51eSKate Stone       if (executable_ptr) {
328f3277750SJim Ingham         SymbolContextList sc_list;
329f3277750SJim Ingham         ConstString main_name("main");
330f3277750SJim Ingham         bool symbols_okay = false; // Force it to be a debug symbol.
3319df05fbbSSean Callanan         bool inlines_okay = true;
332f3277750SJim Ingham         bool append = false;
333b9c1b51eSKate Stone         size_t num_matches = executable_ptr->FindFunctions(
334b9c1b51eSKate Stone             main_name, NULL, lldb::eFunctionNameTypeBase, inlines_okay,
335b9c1b51eSKate Stone             symbols_okay, append, sc_list);
336b9c1b51eSKate Stone         for (size_t idx = 0; idx < num_matches; idx++) {
337f3277750SJim Ingham           SymbolContext sc;
338f3277750SJim Ingham           sc_list.GetContextAtIndex(idx, sc);
339b9c1b51eSKate Stone           if (sc.function) {
3406f6bf26aSGreg Clayton             lldb_private::LineEntry line_entry;
341b9c1b51eSKate Stone             if (sc.function->GetAddressRange()
342b9c1b51eSKate Stone                     .GetBaseAddress()
343b9c1b51eSKate Stone                     .CalculateSymbolContextLineEntry(line_entry)) {
344b9c1b51eSKate Stone               SetDefaultFileAndLine(line_entry.file, line_entry.line);
3456f6bf26aSGreg Clayton               file_spec = m_last_file_sp->GetFileSpec();
346e4ca515aSGreg Clayton               line = m_last_line;
3476f6bf26aSGreg Clayton               return true;
348f3277750SJim Ingham             }
349f3277750SJim Ingham           }
350f3277750SJim Ingham         }
351f3277750SJim Ingham       }
3526f6bf26aSGreg Clayton     }
3539585fbfcSGreg Clayton   }
354b7f6b2faSJim Ingham   return false;
355b7f6b2faSJim Ingham }
35630fdc8d8SChris Lattner 
357b9c1b51eSKate Stone void SourceManager::FindLinesMatchingRegex(FileSpec &file_spec,
358969795f1SJim Ingham                                            RegularExpression &regex,
359969795f1SJim Ingham                                            uint32_t start_line,
360969795f1SJim Ingham                                            uint32_t end_line,
361b9c1b51eSKate Stone                                            std::vector<uint32_t> &match_lines) {
362969795f1SJim Ingham   match_lines.clear();
363969795f1SJim Ingham   FileSP file_sp = GetFile(file_spec);
364969795f1SJim Ingham   if (!file_sp)
365969795f1SJim Ingham     return;
366b9c1b51eSKate Stone   return file_sp->FindLinesMatchingRegex(regex, start_line, end_line,
367b9c1b51eSKate Stone                                          match_lines);
368969795f1SJim Ingham }
36930fdc8d8SChris Lattner 
3709666ba75STodd Fiala SourceManager::File::File(const FileSpec &file_spec,
3719666ba75STodd Fiala                           lldb::DebuggerSP debugger_sp)
3729666ba75STodd Fiala     : m_file_spec_orig(file_spec), m_file_spec(file_spec),
37346376966SJonas Devlieghere       m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
3741408bf72SPavel Labath       m_debugger_wp(debugger_sp) {
3759666ba75STodd Fiala   CommonInitializer(file_spec, nullptr);
3769666ba75STodd Fiala }
3779666ba75STodd Fiala 
378b9c1b51eSKate Stone SourceManager::File::File(const FileSpec &file_spec, Target *target)
379b9c1b51eSKate Stone     : m_file_spec_orig(file_spec), m_file_spec(file_spec),
38046376966SJonas Devlieghere       m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
3819666ba75STodd Fiala       m_debugger_wp(target ? target->GetDebugger().shared_from_this()
3829666ba75STodd Fiala                            : DebuggerSP()) {
3839666ba75STodd Fiala   CommonInitializer(file_spec, target);
3849666ba75STodd Fiala }
3859666ba75STodd Fiala 
3869666ba75STodd Fiala void SourceManager::File::CommonInitializer(const FileSpec &file_spec,
3879666ba75STodd Fiala                                             Target *target) {
3883dc342ebSPavel Labath   if (m_mod_time == llvm::sys::TimePoint<>()) {
389b9c1b51eSKate Stone     if (target) {
3904a89501fSGreg Clayton       m_source_map_mod_id = target->GetSourcePathMap().GetModificationID();
3914a89501fSGreg Clayton 
392b9c1b51eSKate Stone       if (!file_spec.GetDirectory() && file_spec.GetFilename()) {
393b9c1b51eSKate Stone         // If this is just a file name, lets see if we can find it in the
394b9c1b51eSKate Stone         // target:
395e37d605eSJim Ingham         bool check_inlines = false;
396e37d605eSJim Ingham         SymbolContextList sc_list;
397b9c1b51eSKate Stone         size_t num_matches =
398b9c1b51eSKate Stone             target->GetImages().ResolveSymbolContextForFilePath(
399b9c1b51eSKate Stone                 file_spec.GetFilename().AsCString(), 0, check_inlines,
400991e4453SZachary Turner                 SymbolContextItem(eSymbolContextModule |
401991e4453SZachary Turner                                   eSymbolContextCompUnit),
402e37d605eSJim Ingham                 sc_list);
403e37d605eSJim Ingham         bool got_multiple = false;
404b9c1b51eSKate Stone         if (num_matches != 0) {
405b9c1b51eSKate Stone           if (num_matches > 1) {
406e37d605eSJim Ingham             SymbolContext sc;
407e37d605eSJim Ingham             FileSpec *test_cu_spec = NULL;
408e37d605eSJim Ingham 
409b9c1b51eSKate Stone             for (unsigned i = 0; i < num_matches; i++) {
410e37d605eSJim Ingham               sc_list.GetContextAtIndex(i, sc);
411b9c1b51eSKate Stone               if (sc.comp_unit) {
412b9c1b51eSKate Stone                 if (test_cu_spec) {
413e37d605eSJim Ingham                   if (test_cu_spec != static_cast<FileSpec *>(sc.comp_unit))
414e37d605eSJim Ingham                     got_multiple = true;
415e37d605eSJim Ingham                   break;
416b9c1b51eSKate Stone                 } else
417e37d605eSJim Ingham                   test_cu_spec = sc.comp_unit;
418e37d605eSJim Ingham               }
419e37d605eSJim Ingham             }
420e37d605eSJim Ingham           }
421b9c1b51eSKate Stone           if (!got_multiple) {
422e37d605eSJim Ingham             SymbolContext sc;
423e37d605eSJim Ingham             sc_list.GetContextAtIndex(0, sc);
424d804d285SGreg Clayton             m_file_spec = sc.comp_unit;
42546376966SJonas Devlieghere             m_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec);
426e37d605eSJim Ingham           }
427e37d605eSJim Ingham         }
428e37d605eSJim Ingham       }
42964bab489SJohnny Chen       // Try remapping if m_file_spec does not correspond to an existing file.
430*dbd7fabaSJonas Devlieghere       if (!FileSystem::Instance().Exists(m_file_spec)) {
431d804d285SGreg Clayton         FileSpec new_file_spec;
432d804d285SGreg Clayton         // Check target specific source remappings first, then fall back to
433b9c1b51eSKate Stone         // modules objects can have individual path remappings that were
43405097246SAdrian Prantl         // detected when the debug info for a module was found. then
435d804d285SGreg Clayton         if (target->GetSourcePathMap().FindFile(m_file_spec, new_file_spec) ||
436b9c1b51eSKate Stone             target->GetImages().FindSourceFile(m_file_spec, new_file_spec)) {
437d804d285SGreg Clayton           m_file_spec = new_file_spec;
43846376966SJonas Devlieghere           m_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec);
43964bab489SJohnny Chen         }
4407e14f91dSGreg Clayton       }
441e37d605eSJim Ingham     }
442e37d605eSJim Ingham   }
4437e14f91dSGreg Clayton 
4443dc342ebSPavel Labath   if (m_mod_time != llvm::sys::TimePoint<>())
4457f6a7a37SZachary Turner     m_data_sp = DataBufferLLVM::CreateFromPath(m_file_spec.GetPath());
44630fdc8d8SChris Lattner }
44730fdc8d8SChris Lattner 
448b9c1b51eSKate Stone uint32_t SourceManager::File::GetLineOffset(uint32_t line) {
44930fdc8d8SChris Lattner   if (line == 0)
45030fdc8d8SChris Lattner     return UINT32_MAX;
45130fdc8d8SChris Lattner 
45230fdc8d8SChris Lattner   if (line == 1)
45330fdc8d8SChris Lattner     return 0;
45430fdc8d8SChris Lattner 
455b9c1b51eSKate Stone   if (CalculateLineOffsets(line)) {
45630fdc8d8SChris Lattner     if (line < m_offsets.size())
45730fdc8d8SChris Lattner       return m_offsets[line - 1]; // yes we want "line - 1" in the index
45830fdc8d8SChris Lattner   }
45930fdc8d8SChris Lattner   return UINT32_MAX;
46030fdc8d8SChris Lattner }
46130fdc8d8SChris Lattner 
462b9c1b51eSKate Stone uint32_t SourceManager::File::GetNumLines() {
46344d93782SGreg Clayton   CalculateLineOffsets();
46444d93782SGreg Clayton   return m_offsets.size();
46544d93782SGreg Clayton }
46644d93782SGreg Clayton 
467b9c1b51eSKate Stone const char *SourceManager::File::PeekLineData(uint32_t line) {
46844d93782SGreg Clayton   if (!LineIsValid(line))
46944d93782SGreg Clayton     return NULL;
47044d93782SGreg Clayton 
47144d93782SGreg Clayton   size_t line_offset = GetLineOffset(line);
47244d93782SGreg Clayton   if (line_offset < m_data_sp->GetByteSize())
47344d93782SGreg Clayton     return (const char *)m_data_sp->GetBytes() + line_offset;
47444d93782SGreg Clayton   return NULL;
47544d93782SGreg Clayton }
47644d93782SGreg Clayton 
477b9c1b51eSKate Stone uint32_t SourceManager::File::GetLineLength(uint32_t line,
478b9c1b51eSKate Stone                                             bool include_newline_chars) {
47944d93782SGreg Clayton   if (!LineIsValid(line))
48044d93782SGreg Clayton     return false;
48144d93782SGreg Clayton 
48244d93782SGreg Clayton   size_t start_offset = GetLineOffset(line);
48344d93782SGreg Clayton   size_t end_offset = GetLineOffset(line + 1);
48444d93782SGreg Clayton   if (end_offset == UINT32_MAX)
48544d93782SGreg Clayton     end_offset = m_data_sp->GetByteSize();
48644d93782SGreg Clayton 
487b9c1b51eSKate Stone   if (end_offset > start_offset) {
48844d93782SGreg Clayton     uint32_t length = end_offset - start_offset;
489b9c1b51eSKate Stone     if (include_newline_chars == false) {
490b9c1b51eSKate Stone       const char *line_start =
491b9c1b51eSKate Stone           (const char *)m_data_sp->GetBytes() + start_offset;
492b9c1b51eSKate Stone       while (length > 0) {
49344d93782SGreg Clayton         const char last_char = line_start[length - 1];
49444d93782SGreg Clayton         if ((last_char == '\r') || (last_char == '\n'))
49544d93782SGreg Clayton           --length;
49644d93782SGreg Clayton         else
49744d93782SGreg Clayton           break;
49844d93782SGreg Clayton       }
49944d93782SGreg Clayton     }
50044d93782SGreg Clayton     return length;
50144d93782SGreg Clayton   }
50244d93782SGreg Clayton   return 0;
50344d93782SGreg Clayton }
50444d93782SGreg Clayton 
505b9c1b51eSKate Stone bool SourceManager::File::LineIsValid(uint32_t line) {
50630fdc8d8SChris Lattner   if (line == 0)
50730fdc8d8SChris Lattner     return false;
50830fdc8d8SChris Lattner 
50930fdc8d8SChris Lattner   if (CalculateLineOffsets(line))
51030fdc8d8SChris Lattner     return line < m_offsets.size();
51130fdc8d8SChris Lattner   return false;
51230fdc8d8SChris Lattner }
51330fdc8d8SChris Lattner 
514b9c1b51eSKate Stone void SourceManager::File::UpdateIfNeeded() {
5159625d08cSGreg Clayton   // TODO: use host API to sign up for file modifications to anything in our
5169625d08cSGreg Clayton   // source cache and only update when we determine a file has been updated.
5179625d08cSGreg Clayton   // For now we check each time we want to display info for the file.
51846376966SJonas Devlieghere   auto curr_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec);
51964bab489SJohnny Chen 
5203dc342ebSPavel Labath   if (curr_mod_time != llvm::sys::TimePoint<>() &&
5213dc342ebSPavel Labath       m_mod_time != curr_mod_time) {
5229625d08cSGreg Clayton     m_mod_time = curr_mod_time;
5237f6a7a37SZachary Turner     m_data_sp = DataBufferLLVM::CreateFromPath(m_file_spec.GetPath());
5249625d08cSGreg Clayton     m_offsets.clear();
5259625d08cSGreg Clayton   }
5260d5b0a8aSGreg Clayton }
5279625d08cSGreg Clayton 
52820786326SRaphael Isemann size_t SourceManager::File::DisplaySourceLines(uint32_t line,
52920786326SRaphael Isemann                                                llvm::Optional<size_t> column,
530b9c1b51eSKate Stone                                                uint32_t context_before,
531b9c1b51eSKate Stone                                                uint32_t context_after,
532b9c1b51eSKate Stone                                                Stream *s) {
5339666ba75STodd Fiala   // Nothing to write if there's no stream.
5349666ba75STodd Fiala   if (!s)
5359666ba75STodd Fiala     return 0;
5369666ba75STodd Fiala 
53764bab489SJohnny Chen   // Sanity check m_data_sp before proceeding.
53864bab489SJohnny Chen   if (!m_data_sp)
53964bab489SJohnny Chen     return 0;
54064bab489SJohnny Chen 
5412d437f6bSRaphael Isemann   size_t bytes_written = s->GetWrittenBytes();
5422d437f6bSRaphael Isemann 
54320786326SRaphael Isemann   auto debugger_sp = m_debugger_wp.lock();
544566afa0aSRaphael Isemann 
54520786326SRaphael Isemann   HighlightStyle style;
54620786326SRaphael Isemann   // Use the default Vim style if source highlighting is enabled.
54720786326SRaphael Isemann   if (should_highlight_source(debugger_sp))
54820786326SRaphael Isemann     style = HighlightStyle::MakeVimStyle();
54920786326SRaphael Isemann 
55020786326SRaphael Isemann   // If we should mark the stop column with color codes, then copy the prefix
55120786326SRaphael Isemann   // and suffix to our color style.
55220786326SRaphael Isemann   if (should_show_stop_column_with_ansi(debugger_sp))
55320786326SRaphael Isemann     style.selected.Set(debugger_sp->GetStopShowColumnAnsiPrefix(),
55420786326SRaphael Isemann                        debugger_sp->GetStopShowColumnAnsiSuffix());
55520786326SRaphael Isemann 
556566afa0aSRaphael Isemann   HighlighterManager mgr;
557566afa0aSRaphael Isemann   std::string path = GetFileSpec().GetPath(/*denormalize*/ false);
558566afa0aSRaphael Isemann   // FIXME: Find a way to get the definitive language this file was written in
559566afa0aSRaphael Isemann   // and pass it to the highlighter.
56020786326SRaphael Isemann   const auto &h = mgr.getHighlighterFor(lldb::eLanguageTypeUnknown, path);
561566afa0aSRaphael Isemann 
562b9c1b51eSKate Stone   const uint32_t start_line =
563b9c1b51eSKate Stone       line <= context_before ? 1 : line - context_before;
56430fdc8d8SChris Lattner   const uint32_t start_line_offset = GetLineOffset(start_line);
565b9c1b51eSKate Stone   if (start_line_offset != UINT32_MAX) {
56630fdc8d8SChris Lattner     const uint32_t end_line = line + context_after;
56730fdc8d8SChris Lattner     uint32_t end_line_offset = GetLineOffset(end_line + 1);
56830fdc8d8SChris Lattner     if (end_line_offset == UINT32_MAX)
56930fdc8d8SChris Lattner       end_line_offset = m_data_sp->GetByteSize();
57030fdc8d8SChris Lattner 
57130fdc8d8SChris Lattner     assert(start_line_offset <= end_line_offset);
572b9c1b51eSKate Stone     if (start_line_offset < end_line_offset) {
57330fdc8d8SChris Lattner       size_t count = end_line_offset - start_line_offset;
57430fdc8d8SChris Lattner       const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
5759666ba75STodd Fiala 
576566afa0aSRaphael Isemann       auto ref = llvm::StringRef(reinterpret_cast<const char *>(cstr), count);
5779666ba75STodd Fiala 
57820786326SRaphael Isemann       h.Highlight(style, ref, column, "", *s);
5799666ba75STodd Fiala 
5809666ba75STodd Fiala       // Ensure we get an end of line character one way or another.
581566afa0aSRaphael Isemann       if (!is_newline_char(ref.back()))
5822d437f6bSRaphael Isemann         s->EOL();
58330fdc8d8SChris Lattner     }
58430fdc8d8SChris Lattner   }
5852d437f6bSRaphael Isemann   return s->GetWrittenBytes() - bytes_written;
58630fdc8d8SChris Lattner }
58730fdc8d8SChris Lattner 
588b9c1b51eSKate Stone void SourceManager::File::FindLinesMatchingRegex(
589b9c1b51eSKate Stone     RegularExpression &regex, uint32_t start_line, uint32_t end_line,
590b9c1b51eSKate Stone     std::vector<uint32_t> &match_lines) {
591969795f1SJim Ingham   match_lines.clear();
592969795f1SJim Ingham 
593b9c1b51eSKate Stone   if (!LineIsValid(start_line) ||
594b9c1b51eSKate Stone       (end_line != UINT32_MAX && !LineIsValid(end_line)))
595969795f1SJim Ingham     return;
596969795f1SJim Ingham   if (start_line > end_line)
597969795f1SJim Ingham     return;
598969795f1SJim Ingham 
599b9c1b51eSKate Stone   for (uint32_t line_no = start_line; line_no < end_line; line_no++) {
600969795f1SJim Ingham     std::string buffer;
601969795f1SJim Ingham     if (!GetLine(line_no, buffer))
602969795f1SJim Ingham       break;
60395eae423SZachary Turner     if (regex.Execute(buffer)) {
604969795f1SJim Ingham       match_lines.push_back(line_no);
605969795f1SJim Ingham     }
606969795f1SJim Ingham   }
607969795f1SJim Ingham }
608969795f1SJim Ingham 
609b9c1b51eSKate Stone bool SourceManager::File::FileSpecMatches(const FileSpec &file_spec) {
610644247c1SGreg Clayton   return FileSpec::Equal(m_file_spec, file_spec, false);
61130fdc8d8SChris Lattner }
61230fdc8d8SChris Lattner 
613b9c1b51eSKate Stone bool lldb_private::operator==(const SourceManager::File &lhs,
614b9c1b51eSKate Stone                               const SourceManager::File &rhs) {
6153dc342ebSPavel Labath   if (lhs.m_file_spec != rhs.m_file_spec)
6163dc342ebSPavel Labath     return false;
617e37d605eSJim Ingham   return lhs.m_mod_time == rhs.m_mod_time;
618e37d605eSJim Ingham }
61930fdc8d8SChris Lattner 
620b9c1b51eSKate Stone bool SourceManager::File::CalculateLineOffsets(uint32_t line) {
621b9c1b51eSKate Stone   line =
622b9c1b51eSKate Stone       UINT32_MAX; // TODO: take this line out when we support partial indexing
623b9c1b51eSKate Stone   if (line == UINT32_MAX) {
62430fdc8d8SChris Lattner     // Already done?
62530fdc8d8SChris Lattner     if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
62630fdc8d8SChris Lattner       return true;
62730fdc8d8SChris Lattner 
628b9c1b51eSKate Stone     if (m_offsets.empty()) {
62930fdc8d8SChris Lattner       if (m_data_sp.get() == NULL)
63030fdc8d8SChris Lattner         return false;
63130fdc8d8SChris Lattner 
63230fdc8d8SChris Lattner       const char *start = (char *)m_data_sp->GetBytes();
633b9c1b51eSKate Stone       if (start) {
63430fdc8d8SChris Lattner         const char *end = start + m_data_sp->GetByteSize();
63530fdc8d8SChris Lattner 
63630fdc8d8SChris Lattner         // Calculate all line offsets from scratch
63730fdc8d8SChris Lattner 
638b9c1b51eSKate Stone         // Push a 1 at index zero to indicate the file has been completely
639b9c1b51eSKate Stone         // indexed.
64030fdc8d8SChris Lattner         m_offsets.push_back(UINT32_MAX);
6412490f5c9SEric Christopher         const char *s;
642b9c1b51eSKate Stone         for (s = start; s < end; ++s) {
6432490f5c9SEric Christopher           char curr_ch = *s;
644b9c1b51eSKate Stone           if (is_newline_char(curr_ch)) {
645b9c1b51eSKate Stone             if (s + 1 < end) {
6462490f5c9SEric Christopher               char next_ch = s[1];
647b9c1b51eSKate Stone               if (is_newline_char(next_ch)) {
64830fdc8d8SChris Lattner                 if (curr_ch != next_ch)
64930fdc8d8SChris Lattner                   ++s;
65030fdc8d8SChris Lattner               }
651f6cdd126SGreg Clayton             }
65230fdc8d8SChris Lattner             m_offsets.push_back(s + 1 - start);
65330fdc8d8SChris Lattner           }
65430fdc8d8SChris Lattner         }
655b9c1b51eSKate Stone         if (!m_offsets.empty()) {
6565a8ad459SZachary Turner           if (m_offsets.back() < size_t(end - start))
65730fdc8d8SChris Lattner             m_offsets.push_back(end - start);
65830fdc8d8SChris Lattner         }
65930fdc8d8SChris Lattner         return true;
66030fdc8d8SChris Lattner       }
661b9c1b51eSKate Stone     } else {
66230fdc8d8SChris Lattner       // Some lines have been populated, start where we last left off
66303439a87SStephane Sezer       assert("Not implemented yet" && false);
66430fdc8d8SChris Lattner     }
66530fdc8d8SChris Lattner 
666b9c1b51eSKate Stone   } else {
66730fdc8d8SChris Lattner     // Calculate all line offsets up to "line"
66803439a87SStephane Sezer     assert("Not implemented yet" && false);
66930fdc8d8SChris Lattner   }
67030fdc8d8SChris Lattner   return false;
67130fdc8d8SChris Lattner }
672e37d605eSJim Ingham 
673b9c1b51eSKate Stone bool SourceManager::File::GetLine(uint32_t line_no, std::string &buffer) {
674969795f1SJim Ingham   if (!LineIsValid(line_no))
675969795f1SJim Ingham     return false;
676969795f1SJim Ingham 
677c7bece56SGreg Clayton   size_t start_offset = GetLineOffset(line_no);
678c7bece56SGreg Clayton   size_t end_offset = GetLineOffset(line_no + 1);
679b9c1b51eSKate Stone   if (end_offset == UINT32_MAX) {
680969795f1SJim Ingham     end_offset = m_data_sp->GetByteSize();
681969795f1SJim Ingham   }
682b9c1b51eSKate Stone   buffer.assign((char *)m_data_sp->GetBytes() + start_offset,
683b9c1b51eSKate Stone                 end_offset - start_offset);
684969795f1SJim Ingham 
685969795f1SJim Ingham   return true;
686969795f1SJim Ingham }
687969795f1SJim Ingham 
688b9c1b51eSKate Stone void SourceManager::SourceFileCache::AddSourceFile(const FileSP &file_sp) {
689e37d605eSJim Ingham   FileSpec file_spec;
690e37d605eSJim Ingham   FileCache::iterator pos = m_file_cache.find(file_spec);
691e37d605eSJim Ingham   if (pos == m_file_cache.end())
692e37d605eSJim Ingham     m_file_cache[file_spec] = file_sp;
693b9c1b51eSKate Stone   else {
694e37d605eSJim Ingham     if (file_sp != pos->second)
695e37d605eSJim Ingham       m_file_cache[file_spec] = file_sp;
696e37d605eSJim Ingham   }
697e37d605eSJim Ingham }
698e37d605eSJim Ingham 
699b9c1b51eSKate Stone SourceManager::FileSP SourceManager::SourceFileCache::FindSourceFile(
700b9c1b51eSKate Stone     const FileSpec &file_spec) const {
701e37d605eSJim Ingham   FileSP file_sp;
702e37d605eSJim Ingham   FileCache::const_iterator pos = m_file_cache.find(file_spec);
703e37d605eSJim Ingham   if (pos != m_file_cache.end())
704e37d605eSJim Ingham     file_sp = pos->second;
705e37d605eSJim Ingham   return file_sp;
706e37d605eSJim Ingham }
707