1ac7ddfbfSEd Maste //===-- SourceManager.cpp ---------------------------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste // The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste
10ac7ddfbfSEd Maste #include "lldb/Core/SourceManager.h"
11ac7ddfbfSEd Maste
12*b5893f02SDimitry Andric #include "lldb/Core/Address.h"
13*b5893f02SDimitry Andric #include "lldb/Core/AddressRange.h"
14ac7ddfbfSEd Maste #include "lldb/Core/Debugger.h"
15*b5893f02SDimitry Andric #include "lldb/Core/FormatEntity.h"
16*b5893f02SDimitry Andric #include "lldb/Core/Highlighter.h"
17ac7ddfbfSEd Maste #include "lldb/Core/Module.h"
18*b5893f02SDimitry Andric #include "lldb/Core/ModuleList.h"
19435933ddSDimitry Andric #include "lldb/Host/FileSystem.h"
20ac7ddfbfSEd Maste #include "lldb/Symbol/CompileUnit.h"
21ac7ddfbfSEd Maste #include "lldb/Symbol/Function.h"
22*b5893f02SDimitry Andric #include "lldb/Symbol/LineEntry.h"
23ac7ddfbfSEd Maste #include "lldb/Symbol/SymbolContext.h"
24*b5893f02SDimitry Andric #include "lldb/Target/PathMappingList.h"
25ac7ddfbfSEd Maste #include "lldb/Target/Target.h"
26*b5893f02SDimitry Andric #include "lldb/Utility/ConstString.h"
27f678e45dSDimitry Andric #include "lldb/Utility/DataBuffer.h"
28f678e45dSDimitry Andric #include "lldb/Utility/DataBufferLLVM.h"
29f678e45dSDimitry Andric #include "lldb/Utility/RegularExpression.h"
30f678e45dSDimitry Andric #include "lldb/Utility/Stream.h"
31*b5893f02SDimitry Andric #include "lldb/lldb-enumerations.h"
32f678e45dSDimitry Andric
33*b5893f02SDimitry Andric #include "llvm/ADT/Twine.h"
34f678e45dSDimitry Andric
35f678e45dSDimitry Andric #include <memory>
36*b5893f02SDimitry Andric #include <utility>
37f678e45dSDimitry Andric
38*b5893f02SDimitry Andric #include <assert.h>
39*b5893f02SDimitry Andric #include <stdio.h>
40f678e45dSDimitry Andric
41f678e45dSDimitry Andric namespace lldb_private {
42f678e45dSDimitry Andric class ExecutionContext;
43f678e45dSDimitry Andric }
44f678e45dSDimitry Andric namespace lldb_private {
45f678e45dSDimitry Andric class ValueObject;
46f678e45dSDimitry Andric }
47ac7ddfbfSEd Maste
48ac7ddfbfSEd Maste using namespace lldb;
49ac7ddfbfSEd Maste using namespace lldb_private;
50ac7ddfbfSEd Maste
is_newline_char(char ch)51435933ddSDimitry Andric static inline bool is_newline_char(char ch) { return ch == '\n' || ch == '\r'; }
52ac7ddfbfSEd Maste
53ac7ddfbfSEd Maste //----------------------------------------------------------------------
54ac7ddfbfSEd Maste // SourceManager constructor
55ac7ddfbfSEd Maste //----------------------------------------------------------------------
SourceManager(const TargetSP & target_sp)56435933ddSDimitry Andric SourceManager::SourceManager(const TargetSP &target_sp)
57435933ddSDimitry Andric : m_last_file_sp(), m_last_line(0), m_last_count(0), m_default_set(false),
58ac7ddfbfSEd Maste m_target_wp(target_sp),
59435933ddSDimitry Andric m_debugger_wp(target_sp->GetDebugger().shared_from_this()) {}
60ac7ddfbfSEd Maste
SourceManager(const DebuggerSP & debugger_sp)61435933ddSDimitry Andric SourceManager::SourceManager(const DebuggerSP &debugger_sp)
62435933ddSDimitry Andric : m_last_file_sp(), m_last_line(0), m_last_count(0), m_default_set(false),
63435933ddSDimitry Andric m_target_wp(), m_debugger_wp(debugger_sp) {}
64ac7ddfbfSEd Maste
65ac7ddfbfSEd Maste //----------------------------------------------------------------------
66ac7ddfbfSEd Maste // Destructor
67ac7ddfbfSEd Maste //----------------------------------------------------------------------
~SourceManager()68435933ddSDimitry Andric SourceManager::~SourceManager() {}
69ac7ddfbfSEd Maste
GetFile(const FileSpec & file_spec)70435933ddSDimitry Andric SourceManager::FileSP SourceManager::GetFile(const FileSpec &file_spec) {
71435933ddSDimitry Andric bool same_as_previous =
72435933ddSDimitry Andric m_last_file_sp && m_last_file_sp->FileSpecMatches(file_spec);
73ac7ddfbfSEd Maste
74ac7ddfbfSEd Maste DebuggerSP debugger_sp(m_debugger_wp.lock());
75ac7ddfbfSEd Maste FileSP file_sp;
76ac7ddfbfSEd Maste if (same_as_previous)
77ac7ddfbfSEd Maste file_sp = m_last_file_sp;
78ac7ddfbfSEd Maste else if (debugger_sp)
79ac7ddfbfSEd Maste file_sp = debugger_sp->GetSourceFileCache().FindSourceFile(file_spec);
80ac7ddfbfSEd Maste
81ac7ddfbfSEd Maste TargetSP target_sp(m_target_wp.lock());
82ac7ddfbfSEd Maste
83ac7ddfbfSEd Maste // It the target source path map has been updated, get this file again so we
84ac7ddfbfSEd Maste // can successfully remap the source file
85435933ddSDimitry Andric if (target_sp && file_sp &&
86435933ddSDimitry Andric file_sp->GetSourceMapModificationID() !=
87435933ddSDimitry Andric target_sp->GetSourcePathMap().GetModificationID())
88ac7ddfbfSEd Maste file_sp.reset();
89ac7ddfbfSEd Maste
909f2f44ceSEd Maste // Update the file contents if needed if we found a file
919f2f44ceSEd Maste if (file_sp)
929f2f44ceSEd Maste file_sp->UpdateIfNeeded();
939f2f44ceSEd Maste
94ac7ddfbfSEd Maste // If file_sp is no good or it points to a non-existent file, reset it.
95*b5893f02SDimitry Andric if (!file_sp || !FileSystem::Instance().Exists(file_sp->GetFileSpec())) {
96435933ddSDimitry Andric if (target_sp)
97f678e45dSDimitry Andric file_sp = std::make_shared<File>(file_spec, target_sp.get());
98435933ddSDimitry Andric else
99f678e45dSDimitry Andric file_sp = std::make_shared<File>(file_spec, debugger_sp);
100ac7ddfbfSEd Maste
101ac7ddfbfSEd Maste if (debugger_sp)
102ac7ddfbfSEd Maste debugger_sp->GetSourceFileCache().AddSourceFile(file_sp);
103ac7ddfbfSEd Maste }
104ac7ddfbfSEd Maste return file_sp;
105ac7ddfbfSEd Maste }
106ac7ddfbfSEd Maste
should_highlight_source(DebuggerSP debugger_sp)107*b5893f02SDimitry Andric static bool should_highlight_source(DebuggerSP debugger_sp) {
108*b5893f02SDimitry Andric if (!debugger_sp)
109*b5893f02SDimitry Andric return false;
110*b5893f02SDimitry Andric
111*b5893f02SDimitry Andric // We don't use ANSI stop column formatting if the debugger doesn't think it
112*b5893f02SDimitry Andric // should be using color.
113*b5893f02SDimitry Andric if (!debugger_sp->GetUseColor())
114*b5893f02SDimitry Andric return false;
115*b5893f02SDimitry Andric
116*b5893f02SDimitry Andric return debugger_sp->GetHighlightSource();
117*b5893f02SDimitry Andric }
118*b5893f02SDimitry Andric
should_show_stop_column_with_ansi(DebuggerSP debugger_sp)119435933ddSDimitry Andric static bool should_show_stop_column_with_ansi(DebuggerSP debugger_sp) {
120435933ddSDimitry Andric // We don't use ANSI stop column formatting if we can't lookup values from
121435933ddSDimitry Andric // the debugger.
122435933ddSDimitry Andric if (!debugger_sp)
123435933ddSDimitry Andric return false;
124435933ddSDimitry Andric
1254ba319b5SDimitry Andric // We don't use ANSI stop column formatting if the debugger doesn't think it
1264ba319b5SDimitry Andric // should be using color.
127435933ddSDimitry Andric if (!debugger_sp->GetUseColor())
128435933ddSDimitry Andric return false;
129435933ddSDimitry Andric
130435933ddSDimitry Andric // We only use ANSI stop column formatting if we're either supposed to show
131435933ddSDimitry Andric // ANSI where available (which we know we have when we get to this point), or
132435933ddSDimitry Andric // if we're only supposed to use ANSI.
133435933ddSDimitry Andric const auto value = debugger_sp->GetStopShowColumn();
134435933ddSDimitry Andric return ((value == eStopShowColumnAnsiOrCaret) ||
135435933ddSDimitry Andric (value == eStopShowColumnAnsi));
136435933ddSDimitry Andric }
137435933ddSDimitry Andric
should_show_stop_column_with_caret(DebuggerSP debugger_sp)138435933ddSDimitry Andric static bool should_show_stop_column_with_caret(DebuggerSP debugger_sp) {
139435933ddSDimitry Andric // We don't use text-based stop column formatting if we can't lookup values
140435933ddSDimitry Andric // from the debugger.
141435933ddSDimitry Andric if (!debugger_sp)
142435933ddSDimitry Andric return false;
143435933ddSDimitry Andric
1444ba319b5SDimitry Andric // If we're asked to show the first available of ANSI or caret, then we do
1454ba319b5SDimitry Andric // show the caret when ANSI is not available.
146435933ddSDimitry Andric const auto value = debugger_sp->GetStopShowColumn();
147435933ddSDimitry Andric if ((value == eStopShowColumnAnsiOrCaret) && !debugger_sp->GetUseColor())
148435933ddSDimitry Andric return true;
149435933ddSDimitry Andric
150435933ddSDimitry Andric // The only other time we use caret is if we're explicitly asked to show
151435933ddSDimitry Andric // caret.
152435933ddSDimitry Andric return value == eStopShowColumnCaret;
153435933ddSDimitry Andric }
154435933ddSDimitry Andric
DisplaySourceLinesWithLineNumbersUsingLastFile(uint32_t start_line,uint32_t count,uint32_t curr_line,uint32_t column,const char * current_line_cstr,Stream * s,const SymbolContextList * bp_locs)155435933ddSDimitry Andric size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile(
156435933ddSDimitry Andric uint32_t start_line, uint32_t count, uint32_t curr_line, uint32_t column,
157435933ddSDimitry Andric const char *current_line_cstr, Stream *s,
158435933ddSDimitry Andric const SymbolContextList *bp_locs) {
159ac7ddfbfSEd Maste if (count == 0)
160ac7ddfbfSEd Maste return 0;
161*b5893f02SDimitry Andric
162*b5893f02SDimitry Andric Stream::ByteDelta delta(*s);
163*b5893f02SDimitry Andric
164435933ddSDimitry Andric if (start_line == 0) {
165ac7ddfbfSEd Maste if (m_last_line != 0 && m_last_line != UINT32_MAX)
166ac7ddfbfSEd Maste start_line = m_last_line + m_last_count;
167ac7ddfbfSEd Maste else
168ac7ddfbfSEd Maste start_line = 1;
169ac7ddfbfSEd Maste }
170ac7ddfbfSEd Maste
171435933ddSDimitry Andric if (!m_default_set) {
172ac7ddfbfSEd Maste FileSpec tmp_spec;
173ac7ddfbfSEd Maste uint32_t tmp_line;
174ac7ddfbfSEd Maste GetDefaultFileAndLine(tmp_spec, tmp_line);
175ac7ddfbfSEd Maste }
176ac7ddfbfSEd Maste
177ac7ddfbfSEd Maste m_last_line = start_line;
178ac7ddfbfSEd Maste m_last_count = count;
179ac7ddfbfSEd Maste
180435933ddSDimitry Andric if (m_last_file_sp.get()) {
181ac7ddfbfSEd Maste const uint32_t end_line = start_line + count - 1;
182435933ddSDimitry Andric for (uint32_t line = start_line; line <= end_line; ++line) {
183435933ddSDimitry Andric if (!m_last_file_sp->LineIsValid(line)) {
184ac7ddfbfSEd Maste m_last_line = UINT32_MAX;
185ac7ddfbfSEd Maste break;
186ac7ddfbfSEd Maste }
187ac7ddfbfSEd Maste
188ac7ddfbfSEd Maste char prefix[32] = "";
189435933ddSDimitry Andric if (bp_locs) {
190ac7ddfbfSEd Maste uint32_t bp_count = bp_locs->NumLineEntriesWithLine(line);
191ac7ddfbfSEd Maste
192ac7ddfbfSEd Maste if (bp_count > 0)
193ac7ddfbfSEd Maste ::snprintf(prefix, sizeof(prefix), "[%u] ", bp_count);
194ac7ddfbfSEd Maste else
195ac7ddfbfSEd Maste ::snprintf(prefix, sizeof(prefix), " ");
196ac7ddfbfSEd Maste }
197ac7ddfbfSEd Maste
198435933ddSDimitry Andric s->Printf("%s%2.2s %-4u\t", prefix,
199435933ddSDimitry Andric line == curr_line ? current_line_cstr : "", line);
200*b5893f02SDimitry Andric
201*b5893f02SDimitry Andric // So far we treated column 0 as a special 'no column value', but
202*b5893f02SDimitry Andric // DisplaySourceLines starts counting columns from 0 (and no column is
203*b5893f02SDimitry Andric // expressed by passing an empty optional).
204*b5893f02SDimitry Andric llvm::Optional<size_t> columnToHighlight;
205*b5893f02SDimitry Andric if (line == curr_line && column)
206*b5893f02SDimitry Andric columnToHighlight = column - 1;
207*b5893f02SDimitry Andric
208*b5893f02SDimitry Andric size_t this_line_size =
209*b5893f02SDimitry Andric m_last_file_sp->DisplaySourceLines(line, columnToHighlight, 0, 0, s);
210435933ddSDimitry Andric if (column != 0 && line == curr_line &&
211435933ddSDimitry Andric should_show_stop_column_with_caret(m_debugger_wp.lock())) {
212435933ddSDimitry Andric // Display caret cursor.
213435933ddSDimitry Andric std::string src_line;
214435933ddSDimitry Andric m_last_file_sp->GetLine(line, src_line);
215*b5893f02SDimitry Andric s->Printf(" \t");
216435933ddSDimitry Andric // Insert a space for every non-tab character in the source line.
217435933ddSDimitry Andric for (size_t i = 0; i + 1 < column && i < src_line.length(); ++i)
218*b5893f02SDimitry Andric s->PutChar(src_line[i] == '\t' ? '\t' : ' ');
219435933ddSDimitry Andric // Now add the caret.
220*b5893f02SDimitry Andric s->Printf("^\n");
221435933ddSDimitry Andric }
222435933ddSDimitry Andric if (this_line_size == 0) {
223ac7ddfbfSEd Maste m_last_line = UINT32_MAX;
224ac7ddfbfSEd Maste break;
225ac7ddfbfSEd Maste }
226ac7ddfbfSEd Maste }
227*b5893f02SDimitry Andric }
228*b5893f02SDimitry Andric return *delta;
229ac7ddfbfSEd Maste }
230ac7ddfbfSEd Maste
DisplaySourceLinesWithLineNumbers(const FileSpec & file_spec,uint32_t line,uint32_t column,uint32_t context_before,uint32_t context_after,const char * current_line_cstr,Stream * s,const SymbolContextList * bp_locs)231435933ddSDimitry Andric size_t SourceManager::DisplaySourceLinesWithLineNumbers(
232435933ddSDimitry Andric const FileSpec &file_spec, uint32_t line, uint32_t column,
233435933ddSDimitry Andric uint32_t context_before, uint32_t context_after,
234435933ddSDimitry Andric const char *current_line_cstr, Stream *s,
235435933ddSDimitry Andric const SymbolContextList *bp_locs) {
236ac7ddfbfSEd Maste FileSP file_sp(GetFile(file_spec));
237ac7ddfbfSEd Maste
238ac7ddfbfSEd Maste uint32_t start_line;
239ac7ddfbfSEd Maste uint32_t count = context_before + context_after + 1;
240ac7ddfbfSEd Maste if (line > context_before)
241ac7ddfbfSEd Maste start_line = line - context_before;
242ac7ddfbfSEd Maste else
243ac7ddfbfSEd Maste start_line = 1;
244ac7ddfbfSEd Maste
245435933ddSDimitry Andric if (m_last_file_sp.get() != file_sp.get()) {
246ac7ddfbfSEd Maste if (line == 0)
247ac7ddfbfSEd Maste m_last_line = 0;
248ac7ddfbfSEd Maste m_last_file_sp = file_sp;
249ac7ddfbfSEd Maste }
250435933ddSDimitry Andric return DisplaySourceLinesWithLineNumbersUsingLastFile(
251435933ddSDimitry Andric start_line, count, line, column, current_line_cstr, s, bp_locs);
252ac7ddfbfSEd Maste }
253ac7ddfbfSEd Maste
DisplayMoreWithLineNumbers(Stream * s,uint32_t count,bool reverse,const SymbolContextList * bp_locs)254435933ddSDimitry Andric size_t SourceManager::DisplayMoreWithLineNumbers(
255435933ddSDimitry Andric Stream *s, uint32_t count, bool reverse, const SymbolContextList *bp_locs) {
256435933ddSDimitry Andric // If we get called before anybody has set a default file and line, then try
257435933ddSDimitry Andric // to figure it out here.
258ac7ddfbfSEd Maste const bool have_default_file_line = m_last_file_sp && m_last_line > 0;
259435933ddSDimitry Andric if (!m_default_set) {
260ac7ddfbfSEd Maste FileSpec tmp_spec;
261ac7ddfbfSEd Maste uint32_t tmp_line;
262ac7ddfbfSEd Maste GetDefaultFileAndLine(tmp_spec, tmp_line);
263ac7ddfbfSEd Maste }
264ac7ddfbfSEd Maste
265435933ddSDimitry Andric if (m_last_file_sp) {
266ac7ddfbfSEd Maste if (m_last_line == UINT32_MAX)
267ac7ddfbfSEd Maste return 0;
268ac7ddfbfSEd Maste
269ac7ddfbfSEd Maste if (reverse && m_last_line == 1)
270ac7ddfbfSEd Maste return 0;
271ac7ddfbfSEd Maste
272ac7ddfbfSEd Maste if (count > 0)
273ac7ddfbfSEd Maste m_last_count = count;
274ac7ddfbfSEd Maste else if (m_last_count == 0)
275ac7ddfbfSEd Maste m_last_count = 10;
276ac7ddfbfSEd Maste
277435933ddSDimitry Andric if (m_last_line > 0) {
278435933ddSDimitry Andric if (reverse) {
2794ba319b5SDimitry Andric // If this is the first time we've done a reverse, then back up one
2804ba319b5SDimitry Andric // more time so we end up showing the chunk before the last one we've
2814ba319b5SDimitry Andric // shown:
282ac7ddfbfSEd Maste if (m_last_line > m_last_count)
283ac7ddfbfSEd Maste m_last_line -= m_last_count;
284ac7ddfbfSEd Maste else
285ac7ddfbfSEd Maste m_last_line = 1;
286435933ddSDimitry Andric } else if (have_default_file_line)
287ac7ddfbfSEd Maste m_last_line += m_last_count;
288435933ddSDimitry Andric } else
289ac7ddfbfSEd Maste m_last_line = 1;
290ac7ddfbfSEd Maste
291435933ddSDimitry Andric const uint32_t column = 0;
292435933ddSDimitry Andric return DisplaySourceLinesWithLineNumbersUsingLastFile(
293435933ddSDimitry Andric m_last_line, m_last_count, UINT32_MAX, column, "", s, bp_locs);
294ac7ddfbfSEd Maste }
295ac7ddfbfSEd Maste return 0;
296ac7ddfbfSEd Maste }
297ac7ddfbfSEd Maste
SetDefaultFileAndLine(const FileSpec & file_spec,uint32_t line)298435933ddSDimitry Andric bool SourceManager::SetDefaultFileAndLine(const FileSpec &file_spec,
299435933ddSDimitry Andric uint32_t line) {
300ac7ddfbfSEd Maste FileSP old_file_sp = m_last_file_sp;
301ac7ddfbfSEd Maste m_last_file_sp = GetFile(file_spec);
302ac7ddfbfSEd Maste
303ac7ddfbfSEd Maste m_default_set = true;
304435933ddSDimitry Andric if (m_last_file_sp) {
305ac7ddfbfSEd Maste m_last_line = line;
306ac7ddfbfSEd Maste return true;
307435933ddSDimitry Andric } else {
308ac7ddfbfSEd Maste m_last_file_sp = old_file_sp;
309ac7ddfbfSEd Maste return false;
310ac7ddfbfSEd Maste }
311ac7ddfbfSEd Maste }
312ac7ddfbfSEd Maste
GetDefaultFileAndLine(FileSpec & file_spec,uint32_t & line)313435933ddSDimitry Andric bool SourceManager::GetDefaultFileAndLine(FileSpec &file_spec, uint32_t &line) {
314435933ddSDimitry Andric if (m_last_file_sp) {
315ac7ddfbfSEd Maste file_spec = m_last_file_sp->GetFileSpec();
316ac7ddfbfSEd Maste line = m_last_line;
317ac7ddfbfSEd Maste return true;
318435933ddSDimitry Andric } else if (!m_default_set) {
319ac7ddfbfSEd Maste TargetSP target_sp(m_target_wp.lock());
320ac7ddfbfSEd Maste
321435933ddSDimitry Andric if (target_sp) {
322435933ddSDimitry Andric // If nobody has set the default file and line then try here. If there's
3234ba319b5SDimitry Andric // no executable, then we will try again later when there is one.
3244ba319b5SDimitry Andric // Otherwise, if we can't find it we won't look again, somebody will have
3254ba319b5SDimitry Andric // to set it (for instance when we stop somewhere...)
326ac7ddfbfSEd Maste Module *executable_ptr = target_sp->GetExecutableModulePointer();
327435933ddSDimitry Andric if (executable_ptr) {
328ac7ddfbfSEd Maste SymbolContextList sc_list;
329ac7ddfbfSEd Maste ConstString main_name("main");
330ac7ddfbfSEd Maste bool symbols_okay = false; // Force it to be a debug symbol.
331ac7ddfbfSEd Maste bool inlines_okay = true;
332ac7ddfbfSEd Maste bool append = false;
333435933ddSDimitry Andric size_t num_matches = executable_ptr->FindFunctions(
334435933ddSDimitry Andric main_name, NULL, lldb::eFunctionNameTypeBase, inlines_okay,
335435933ddSDimitry Andric symbols_okay, append, sc_list);
336435933ddSDimitry Andric for (size_t idx = 0; idx < num_matches; idx++) {
337ac7ddfbfSEd Maste SymbolContext sc;
338ac7ddfbfSEd Maste sc_list.GetContextAtIndex(idx, sc);
339435933ddSDimitry Andric if (sc.function) {
340ac7ddfbfSEd Maste lldb_private::LineEntry line_entry;
341435933ddSDimitry Andric if (sc.function->GetAddressRange()
342435933ddSDimitry Andric .GetBaseAddress()
343435933ddSDimitry Andric .CalculateSymbolContextLineEntry(line_entry)) {
344435933ddSDimitry Andric SetDefaultFileAndLine(line_entry.file, line_entry.line);
345ac7ddfbfSEd Maste file_spec = m_last_file_sp->GetFileSpec();
346ac7ddfbfSEd Maste line = m_last_line;
347ac7ddfbfSEd Maste return true;
348ac7ddfbfSEd Maste }
349ac7ddfbfSEd Maste }
350ac7ddfbfSEd Maste }
351ac7ddfbfSEd Maste }
352ac7ddfbfSEd Maste }
353ac7ddfbfSEd Maste }
354ac7ddfbfSEd Maste return false;
355ac7ddfbfSEd Maste }
356ac7ddfbfSEd Maste
FindLinesMatchingRegex(FileSpec & file_spec,RegularExpression & regex,uint32_t start_line,uint32_t end_line,std::vector<uint32_t> & match_lines)357435933ddSDimitry Andric void SourceManager::FindLinesMatchingRegex(FileSpec &file_spec,
358ac7ddfbfSEd Maste RegularExpression ®ex,
359ac7ddfbfSEd Maste uint32_t start_line,
360ac7ddfbfSEd Maste uint32_t end_line,
361435933ddSDimitry Andric std::vector<uint32_t> &match_lines) {
362ac7ddfbfSEd Maste match_lines.clear();
363ac7ddfbfSEd Maste FileSP file_sp = GetFile(file_spec);
364ac7ddfbfSEd Maste if (!file_sp)
365ac7ddfbfSEd Maste return;
366435933ddSDimitry Andric return file_sp->FindLinesMatchingRegex(regex, start_line, end_line,
367435933ddSDimitry Andric match_lines);
368ac7ddfbfSEd Maste }
369ac7ddfbfSEd Maste
File(const FileSpec & file_spec,lldb::DebuggerSP debugger_sp)370435933ddSDimitry Andric SourceManager::File::File(const FileSpec &file_spec,
371435933ddSDimitry Andric lldb::DebuggerSP debugger_sp)
372435933ddSDimitry Andric : m_file_spec_orig(file_spec), m_file_spec(file_spec),
373*b5893f02SDimitry Andric m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
374435933ddSDimitry Andric m_debugger_wp(debugger_sp) {
375435933ddSDimitry Andric CommonInitializer(file_spec, nullptr);
376435933ddSDimitry Andric }
377435933ddSDimitry Andric
File(const FileSpec & file_spec,Target * target)378435933ddSDimitry Andric SourceManager::File::File(const FileSpec &file_spec, Target *target)
379435933ddSDimitry Andric : m_file_spec_orig(file_spec), m_file_spec(file_spec),
380*b5893f02SDimitry Andric m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
381435933ddSDimitry Andric m_debugger_wp(target ? target->GetDebugger().shared_from_this()
382435933ddSDimitry Andric : DebuggerSP()) {
383435933ddSDimitry Andric CommonInitializer(file_spec, target);
384435933ddSDimitry Andric }
385435933ddSDimitry Andric
CommonInitializer(const FileSpec & file_spec,Target * target)386435933ddSDimitry Andric void SourceManager::File::CommonInitializer(const FileSpec &file_spec,
387435933ddSDimitry Andric Target *target) {
388435933ddSDimitry Andric if (m_mod_time == llvm::sys::TimePoint<>()) {
389435933ddSDimitry Andric if (target) {
390ac7ddfbfSEd Maste m_source_map_mod_id = target->GetSourcePathMap().GetModificationID();
391ac7ddfbfSEd Maste
392435933ddSDimitry Andric if (!file_spec.GetDirectory() && file_spec.GetFilename()) {
393435933ddSDimitry Andric // If this is just a file name, lets see if we can find it in the
394435933ddSDimitry Andric // target:
395ac7ddfbfSEd Maste bool check_inlines = false;
396ac7ddfbfSEd Maste SymbolContextList sc_list;
397435933ddSDimitry Andric size_t num_matches =
398435933ddSDimitry Andric target->GetImages().ResolveSymbolContextForFilePath(
399435933ddSDimitry Andric file_spec.GetFilename().AsCString(), 0, check_inlines,
400*b5893f02SDimitry Andric SymbolContextItem(eSymbolContextModule |
401*b5893f02SDimitry Andric eSymbolContextCompUnit),
402ac7ddfbfSEd Maste sc_list);
403ac7ddfbfSEd Maste bool got_multiple = false;
404435933ddSDimitry Andric if (num_matches != 0) {
405435933ddSDimitry Andric if (num_matches > 1) {
406ac7ddfbfSEd Maste SymbolContext sc;
407ac7ddfbfSEd Maste FileSpec *test_cu_spec = NULL;
408ac7ddfbfSEd Maste
409435933ddSDimitry Andric for (unsigned i = 0; i < num_matches; i++) {
410ac7ddfbfSEd Maste sc_list.GetContextAtIndex(i, sc);
411435933ddSDimitry Andric if (sc.comp_unit) {
412435933ddSDimitry Andric if (test_cu_spec) {
413ac7ddfbfSEd Maste if (test_cu_spec != static_cast<FileSpec *>(sc.comp_unit))
414ac7ddfbfSEd Maste got_multiple = true;
415ac7ddfbfSEd Maste break;
416435933ddSDimitry Andric } else
417ac7ddfbfSEd Maste test_cu_spec = sc.comp_unit;
418ac7ddfbfSEd Maste }
419ac7ddfbfSEd Maste }
420ac7ddfbfSEd Maste }
421435933ddSDimitry Andric if (!got_multiple) {
422ac7ddfbfSEd Maste SymbolContext sc;
423ac7ddfbfSEd Maste sc_list.GetContextAtIndex(0, sc);
424ac7ddfbfSEd Maste m_file_spec = sc.comp_unit;
425*b5893f02SDimitry Andric m_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec);
426ac7ddfbfSEd Maste }
427ac7ddfbfSEd Maste }
428ac7ddfbfSEd Maste }
429ac7ddfbfSEd Maste // Try remapping if m_file_spec does not correspond to an existing file.
430*b5893f02SDimitry Andric if (!FileSystem::Instance().Exists(m_file_spec)) {
431ac7ddfbfSEd Maste FileSpec new_file_spec;
432ac7ddfbfSEd Maste // Check target specific source remappings first, then fall back to
433435933ddSDimitry Andric // modules objects can have individual path remappings that were
4344ba319b5SDimitry Andric // detected when the debug info for a module was found. then
435ac7ddfbfSEd Maste if (target->GetSourcePathMap().FindFile(m_file_spec, new_file_spec) ||
436435933ddSDimitry Andric target->GetImages().FindSourceFile(m_file_spec, new_file_spec)) {
437ac7ddfbfSEd Maste m_file_spec = new_file_spec;
438*b5893f02SDimitry Andric m_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec);
439ac7ddfbfSEd Maste }
440ac7ddfbfSEd Maste }
441ac7ddfbfSEd Maste }
442ac7ddfbfSEd Maste }
443ac7ddfbfSEd Maste
444435933ddSDimitry Andric if (m_mod_time != llvm::sys::TimePoint<>())
445*b5893f02SDimitry Andric m_data_sp = FileSystem::Instance().CreateDataBuffer(m_file_spec);
446ac7ddfbfSEd Maste }
447ac7ddfbfSEd Maste
GetLineOffset(uint32_t line)448435933ddSDimitry Andric uint32_t SourceManager::File::GetLineOffset(uint32_t line) {
449ac7ddfbfSEd Maste if (line == 0)
450ac7ddfbfSEd Maste return UINT32_MAX;
451ac7ddfbfSEd Maste
452ac7ddfbfSEd Maste if (line == 1)
453ac7ddfbfSEd Maste return 0;
454ac7ddfbfSEd Maste
455435933ddSDimitry Andric if (CalculateLineOffsets(line)) {
456ac7ddfbfSEd Maste if (line < m_offsets.size())
457ac7ddfbfSEd Maste return m_offsets[line - 1]; // yes we want "line - 1" in the index
458ac7ddfbfSEd Maste }
459ac7ddfbfSEd Maste return UINT32_MAX;
460ac7ddfbfSEd Maste }
461ac7ddfbfSEd Maste
GetNumLines()462435933ddSDimitry Andric uint32_t SourceManager::File::GetNumLines() {
46312b93ac6SEd Maste CalculateLineOffsets();
46412b93ac6SEd Maste return m_offsets.size();
46512b93ac6SEd Maste }
46612b93ac6SEd Maste
PeekLineData(uint32_t line)467435933ddSDimitry Andric const char *SourceManager::File::PeekLineData(uint32_t line) {
46812b93ac6SEd Maste if (!LineIsValid(line))
46912b93ac6SEd Maste return NULL;
47012b93ac6SEd Maste
47112b93ac6SEd Maste size_t line_offset = GetLineOffset(line);
47212b93ac6SEd Maste if (line_offset < m_data_sp->GetByteSize())
47312b93ac6SEd Maste return (const char *)m_data_sp->GetBytes() + line_offset;
47412b93ac6SEd Maste return NULL;
47512b93ac6SEd Maste }
47612b93ac6SEd Maste
GetLineLength(uint32_t line,bool include_newline_chars)477435933ddSDimitry Andric uint32_t SourceManager::File::GetLineLength(uint32_t line,
478435933ddSDimitry Andric bool include_newline_chars) {
47912b93ac6SEd Maste if (!LineIsValid(line))
48012b93ac6SEd Maste return false;
48112b93ac6SEd Maste
48212b93ac6SEd Maste size_t start_offset = GetLineOffset(line);
48312b93ac6SEd Maste size_t end_offset = GetLineOffset(line + 1);
48412b93ac6SEd Maste if (end_offset == UINT32_MAX)
48512b93ac6SEd Maste end_offset = m_data_sp->GetByteSize();
48612b93ac6SEd Maste
487435933ddSDimitry Andric if (end_offset > start_offset) {
48812b93ac6SEd Maste uint32_t length = end_offset - start_offset;
489*b5893f02SDimitry Andric if (!include_newline_chars) {
490435933ddSDimitry Andric const char *line_start =
491435933ddSDimitry Andric (const char *)m_data_sp->GetBytes() + start_offset;
492435933ddSDimitry Andric while (length > 0) {
49312b93ac6SEd Maste const char last_char = line_start[length - 1];
49412b93ac6SEd Maste if ((last_char == '\r') || (last_char == '\n'))
49512b93ac6SEd Maste --length;
49612b93ac6SEd Maste else
49712b93ac6SEd Maste break;
49812b93ac6SEd Maste }
49912b93ac6SEd Maste }
50012b93ac6SEd Maste return length;
50112b93ac6SEd Maste }
50212b93ac6SEd Maste return 0;
50312b93ac6SEd Maste }
50412b93ac6SEd Maste
LineIsValid(uint32_t line)505435933ddSDimitry Andric bool SourceManager::File::LineIsValid(uint32_t line) {
506ac7ddfbfSEd Maste if (line == 0)
507ac7ddfbfSEd Maste return false;
508ac7ddfbfSEd Maste
509ac7ddfbfSEd Maste if (CalculateLineOffsets(line))
510ac7ddfbfSEd Maste return line < m_offsets.size();
511ac7ddfbfSEd Maste return false;
512ac7ddfbfSEd Maste }
513ac7ddfbfSEd Maste
UpdateIfNeeded()514435933ddSDimitry Andric void SourceManager::File::UpdateIfNeeded() {
515ac7ddfbfSEd Maste // TODO: use host API to sign up for file modifications to anything in our
516ac7ddfbfSEd Maste // source cache and only update when we determine a file has been updated.
517ac7ddfbfSEd Maste // For now we check each time we want to display info for the file.
518*b5893f02SDimitry Andric auto curr_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec);
519ac7ddfbfSEd Maste
520435933ddSDimitry Andric if (curr_mod_time != llvm::sys::TimePoint<>() &&
521435933ddSDimitry Andric m_mod_time != curr_mod_time) {
522ac7ddfbfSEd Maste m_mod_time = curr_mod_time;
523*b5893f02SDimitry Andric m_data_sp = FileSystem::Instance().CreateDataBuffer(m_file_spec);
524ac7ddfbfSEd Maste m_offsets.clear();
525ac7ddfbfSEd Maste }
5269f2f44ceSEd Maste }
527ac7ddfbfSEd Maste
DisplaySourceLines(uint32_t line,llvm::Optional<size_t> column,uint32_t context_before,uint32_t context_after,Stream * s)528*b5893f02SDimitry Andric size_t SourceManager::File::DisplaySourceLines(uint32_t line,
529*b5893f02SDimitry Andric llvm::Optional<size_t> column,
530435933ddSDimitry Andric uint32_t context_before,
531435933ddSDimitry Andric uint32_t context_after,
532435933ddSDimitry Andric Stream *s) {
533435933ddSDimitry Andric // Nothing to write if there's no stream.
534435933ddSDimitry Andric if (!s)
535435933ddSDimitry Andric return 0;
536435933ddSDimitry Andric
537ac7ddfbfSEd Maste // Sanity check m_data_sp before proceeding.
538ac7ddfbfSEd Maste if (!m_data_sp)
539ac7ddfbfSEd Maste return 0;
540ac7ddfbfSEd Maste
541*b5893f02SDimitry Andric size_t bytes_written = s->GetWrittenBytes();
542*b5893f02SDimitry Andric
543*b5893f02SDimitry Andric auto debugger_sp = m_debugger_wp.lock();
544*b5893f02SDimitry Andric
545*b5893f02SDimitry Andric HighlightStyle style;
546*b5893f02SDimitry Andric // Use the default Vim style if source highlighting is enabled.
547*b5893f02SDimitry Andric if (should_highlight_source(debugger_sp))
548*b5893f02SDimitry Andric style = HighlightStyle::MakeVimStyle();
549*b5893f02SDimitry Andric
550*b5893f02SDimitry Andric // If we should mark the stop column with color codes, then copy the prefix
551*b5893f02SDimitry Andric // and suffix to our color style.
552*b5893f02SDimitry Andric if (should_show_stop_column_with_ansi(debugger_sp))
553*b5893f02SDimitry Andric style.selected.Set(debugger_sp->GetStopShowColumnAnsiPrefix(),
554*b5893f02SDimitry Andric debugger_sp->GetStopShowColumnAnsiSuffix());
555*b5893f02SDimitry Andric
556*b5893f02SDimitry Andric HighlighterManager mgr;
557*b5893f02SDimitry Andric std::string path = GetFileSpec().GetPath(/*denormalize*/ false);
558*b5893f02SDimitry Andric // FIXME: Find a way to get the definitive language this file was written in
559*b5893f02SDimitry Andric // and pass it to the highlighter.
560*b5893f02SDimitry Andric const auto &h = mgr.getHighlighterFor(lldb::eLanguageTypeUnknown, path);
561*b5893f02SDimitry Andric
562435933ddSDimitry Andric const uint32_t start_line =
563435933ddSDimitry Andric line <= context_before ? 1 : line - context_before;
564ac7ddfbfSEd Maste const uint32_t start_line_offset = GetLineOffset(start_line);
565435933ddSDimitry Andric if (start_line_offset != UINT32_MAX) {
566ac7ddfbfSEd Maste const uint32_t end_line = line + context_after;
567ac7ddfbfSEd Maste uint32_t end_line_offset = GetLineOffset(end_line + 1);
568ac7ddfbfSEd Maste if (end_line_offset == UINT32_MAX)
569ac7ddfbfSEd Maste end_line_offset = m_data_sp->GetByteSize();
570ac7ddfbfSEd Maste
571ac7ddfbfSEd Maste assert(start_line_offset <= end_line_offset);
572435933ddSDimitry Andric if (start_line_offset < end_line_offset) {
573ac7ddfbfSEd Maste size_t count = end_line_offset - start_line_offset;
574ac7ddfbfSEd Maste const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
575435933ddSDimitry Andric
576*b5893f02SDimitry Andric auto ref = llvm::StringRef(reinterpret_cast<const char *>(cstr), count);
577435933ddSDimitry Andric
578*b5893f02SDimitry Andric h.Highlight(style, ref, column, "", *s);
579435933ddSDimitry Andric
580435933ddSDimitry Andric // Ensure we get an end of line character one way or another.
581*b5893f02SDimitry Andric if (!is_newline_char(ref.back()))
582*b5893f02SDimitry Andric s->EOL();
583ac7ddfbfSEd Maste }
584ac7ddfbfSEd Maste }
585*b5893f02SDimitry Andric return s->GetWrittenBytes() - bytes_written;
586ac7ddfbfSEd Maste }
587ac7ddfbfSEd Maste
FindLinesMatchingRegex(RegularExpression & regex,uint32_t start_line,uint32_t end_line,std::vector<uint32_t> & match_lines)588435933ddSDimitry Andric void SourceManager::File::FindLinesMatchingRegex(
589435933ddSDimitry Andric RegularExpression ®ex, uint32_t start_line, uint32_t end_line,
590435933ddSDimitry Andric std::vector<uint32_t> &match_lines) {
591ac7ddfbfSEd Maste match_lines.clear();
592ac7ddfbfSEd Maste
593435933ddSDimitry Andric if (!LineIsValid(start_line) ||
594435933ddSDimitry Andric (end_line != UINT32_MAX && !LineIsValid(end_line)))
595ac7ddfbfSEd Maste return;
596ac7ddfbfSEd Maste if (start_line > end_line)
597ac7ddfbfSEd Maste return;
598ac7ddfbfSEd Maste
599435933ddSDimitry Andric for (uint32_t line_no = start_line; line_no < end_line; line_no++) {
600ac7ddfbfSEd Maste std::string buffer;
601ac7ddfbfSEd Maste if (!GetLine(line_no, buffer))
602ac7ddfbfSEd Maste break;
603435933ddSDimitry Andric if (regex.Execute(buffer)) {
604ac7ddfbfSEd Maste match_lines.push_back(line_no);
605ac7ddfbfSEd Maste }
606ac7ddfbfSEd Maste }
607ac7ddfbfSEd Maste }
608ac7ddfbfSEd Maste
FileSpecMatches(const FileSpec & file_spec)609435933ddSDimitry Andric bool SourceManager::File::FileSpecMatches(const FileSpec &file_spec) {
610ac7ddfbfSEd Maste return FileSpec::Equal(m_file_spec, file_spec, false);
611ac7ddfbfSEd Maste }
612ac7ddfbfSEd Maste
operator ==(const SourceManager::File & lhs,const SourceManager::File & rhs)613435933ddSDimitry Andric bool lldb_private::operator==(const SourceManager::File &lhs,
614435933ddSDimitry Andric const SourceManager::File &rhs) {
615435933ddSDimitry Andric if (lhs.m_file_spec != rhs.m_file_spec)
616435933ddSDimitry Andric return false;
617ac7ddfbfSEd Maste return lhs.m_mod_time == rhs.m_mod_time;
618ac7ddfbfSEd Maste }
619ac7ddfbfSEd Maste
CalculateLineOffsets(uint32_t line)620435933ddSDimitry Andric bool SourceManager::File::CalculateLineOffsets(uint32_t line) {
621435933ddSDimitry Andric line =
622435933ddSDimitry Andric UINT32_MAX; // TODO: take this line out when we support partial indexing
623435933ddSDimitry Andric if (line == UINT32_MAX) {
624ac7ddfbfSEd Maste // Already done?
625ac7ddfbfSEd Maste if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
626ac7ddfbfSEd Maste return true;
627ac7ddfbfSEd Maste
628435933ddSDimitry Andric if (m_offsets.empty()) {
629ac7ddfbfSEd Maste if (m_data_sp.get() == NULL)
630ac7ddfbfSEd Maste return false;
631ac7ddfbfSEd Maste
632ac7ddfbfSEd Maste const char *start = (char *)m_data_sp->GetBytes();
633435933ddSDimitry Andric if (start) {
634ac7ddfbfSEd Maste const char *end = start + m_data_sp->GetByteSize();
635ac7ddfbfSEd Maste
636ac7ddfbfSEd Maste // Calculate all line offsets from scratch
637ac7ddfbfSEd Maste
638435933ddSDimitry Andric // Push a 1 at index zero to indicate the file has been completely
639435933ddSDimitry Andric // indexed.
640ac7ddfbfSEd Maste m_offsets.push_back(UINT32_MAX);
64135617911SEd Maste const char *s;
642435933ddSDimitry Andric for (s = start; s < end; ++s) {
64335617911SEd Maste char curr_ch = *s;
644435933ddSDimitry Andric if (is_newline_char(curr_ch)) {
645435933ddSDimitry Andric if (s + 1 < end) {
64635617911SEd Maste char next_ch = s[1];
647435933ddSDimitry Andric if (is_newline_char(next_ch)) {
648ac7ddfbfSEd Maste if (curr_ch != next_ch)
649ac7ddfbfSEd Maste ++s;
650ac7ddfbfSEd Maste }
651ac7ddfbfSEd Maste }
652ac7ddfbfSEd Maste m_offsets.push_back(s + 1 - start);
653ac7ddfbfSEd Maste }
654ac7ddfbfSEd Maste }
655435933ddSDimitry Andric if (!m_offsets.empty()) {
656435933ddSDimitry Andric if (m_offsets.back() < size_t(end - start))
657ac7ddfbfSEd Maste m_offsets.push_back(end - start);
658ac7ddfbfSEd Maste }
659ac7ddfbfSEd Maste return true;
660ac7ddfbfSEd Maste }
661435933ddSDimitry Andric } else {
662ac7ddfbfSEd Maste // Some lines have been populated, start where we last left off
6639f2f44ceSEd Maste assert("Not implemented yet" && false);
664ac7ddfbfSEd Maste }
665ac7ddfbfSEd Maste
666435933ddSDimitry Andric } else {
667ac7ddfbfSEd Maste // Calculate all line offsets up to "line"
6689f2f44ceSEd Maste assert("Not implemented yet" && false);
669ac7ddfbfSEd Maste }
670ac7ddfbfSEd Maste return false;
671ac7ddfbfSEd Maste }
672ac7ddfbfSEd Maste
GetLine(uint32_t line_no,std::string & buffer)673435933ddSDimitry Andric bool SourceManager::File::GetLine(uint32_t line_no, std::string &buffer) {
674ac7ddfbfSEd Maste if (!LineIsValid(line_no))
675ac7ddfbfSEd Maste return false;
676ac7ddfbfSEd Maste
677ac7ddfbfSEd Maste size_t start_offset = GetLineOffset(line_no);
678ac7ddfbfSEd Maste size_t end_offset = GetLineOffset(line_no + 1);
679435933ddSDimitry Andric if (end_offset == UINT32_MAX) {
680ac7ddfbfSEd Maste end_offset = m_data_sp->GetByteSize();
681ac7ddfbfSEd Maste }
682435933ddSDimitry Andric buffer.assign((char *)m_data_sp->GetBytes() + start_offset,
683435933ddSDimitry Andric end_offset - start_offset);
684ac7ddfbfSEd Maste
685ac7ddfbfSEd Maste return true;
686ac7ddfbfSEd Maste }
687ac7ddfbfSEd Maste
AddSourceFile(const FileSP & file_sp)688435933ddSDimitry Andric void SourceManager::SourceFileCache::AddSourceFile(const FileSP &file_sp) {
689ac7ddfbfSEd Maste FileSpec file_spec;
690ac7ddfbfSEd Maste FileCache::iterator pos = m_file_cache.find(file_spec);
691ac7ddfbfSEd Maste if (pos == m_file_cache.end())
692ac7ddfbfSEd Maste m_file_cache[file_spec] = file_sp;
693435933ddSDimitry Andric else {
694ac7ddfbfSEd Maste if (file_sp != pos->second)
695ac7ddfbfSEd Maste m_file_cache[file_spec] = file_sp;
696ac7ddfbfSEd Maste }
697ac7ddfbfSEd Maste }
698ac7ddfbfSEd Maste
FindSourceFile(const FileSpec & file_spec) const699435933ddSDimitry Andric SourceManager::FileSP SourceManager::SourceFileCache::FindSourceFile(
700435933ddSDimitry Andric const FileSpec &file_spec) const {
701ac7ddfbfSEd Maste FileSP file_sp;
702ac7ddfbfSEd Maste FileCache::const_iterator pos = m_file_cache.find(file_spec);
703ac7ddfbfSEd Maste if (pos != m_file_cache.end())
704ac7ddfbfSEd Maste file_sp = pos->second;
705ac7ddfbfSEd Maste return file_sp;
706ac7ddfbfSEd Maste }
707