]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Expression/REPL.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Expression / REPL.cpp
1 //===-- REPL.cpp ------------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "lldb/Expression/REPL.h"
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Core/PluginManager.h"
13 #include "lldb/Core/StreamFile.h"
14 #include "lldb/Expression/ExpressionVariable.h"
15 #include "lldb/Expression/UserExpression.h"
16 #include "lldb/Host/HostInfo.h"
17 #include "lldb/Interpreter/CommandInterpreter.h"
18 #include "lldb/Interpreter/CommandReturnObject.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Target/Thread.h"
21 #include "lldb/Utility/AnsiTerminal.h"
22
23 using namespace lldb_private;
24
25 REPL::REPL(LLVMCastKind kind, Target &target) : m_target(target), m_kind(kind) {
26   // Make sure all option values have sane defaults
27   Debugger &debugger = m_target.GetDebugger();
28   auto exe_ctx = debugger.GetCommandInterpreter().GetExecutionContext();
29   m_format_options.OptionParsingStarting(&exe_ctx);
30   m_varobj_options.OptionParsingStarting(&exe_ctx);
31   m_command_options.OptionParsingStarting(&exe_ctx);
32
33   // Default certain settings for REPL regardless of the global settings.
34   m_command_options.unwind_on_error = false;
35   m_command_options.ignore_breakpoints = false;
36   m_command_options.debug = false;
37 }
38
39 REPL::~REPL() = default;
40
41 lldb::REPLSP REPL::Create(Status &err, lldb::LanguageType language,
42                           Debugger *debugger, Target *target,
43                           const char *repl_options) {
44   uint32_t idx = 0;
45   lldb::REPLSP ret;
46
47   while (REPLCreateInstance create_instance =
48              PluginManager::GetREPLCreateCallbackAtIndex(idx++)) {
49     ret = (*create_instance)(err, language, debugger, target, repl_options);
50     if (ret) {
51       break;
52     }
53   }
54
55   return ret;
56 }
57
58 std::string REPL::GetSourcePath() {
59   ConstString file_basename = GetSourceFileBasename();
60   FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir();
61   if (tmpdir_file_spec) {
62     tmpdir_file_spec.GetFilename().SetCString(file_basename.AsCString());
63     m_repl_source_path = tmpdir_file_spec.GetPath();
64   } else {
65     tmpdir_file_spec = FileSpec("/tmp");
66     tmpdir_file_spec.AppendPathComponent(file_basename.AsCString());
67   }
68
69   return tmpdir_file_spec.GetPath();
70 }
71
72 lldb::IOHandlerSP REPL::GetIOHandler() {
73   if (!m_io_handler_sp) {
74     Debugger &debugger = m_target.GetDebugger();
75     m_io_handler_sp.reset(
76         new IOHandlerEditline(debugger, IOHandler::Type::REPL,
77                               "lldb-repl", // Name of input reader for history
78                               llvm::StringRef("> "), // prompt
79                               llvm::StringRef(". "), // Continuation prompt
80                               true,                  // Multi-line
81                               true, // The REPL prompt is always colored
82                               1,    // Line number
83                               *this));
84
85     // Don't exit if CTRL+C is pressed
86     static_cast<IOHandlerEditline *>(m_io_handler_sp.get())
87         ->SetInterruptExits(false);
88
89     if (m_io_handler_sp->GetIsInteractive() &&
90         m_io_handler_sp->GetIsRealTerminal()) {
91       m_indent_str.assign(debugger.GetTabSize(), ' ');
92       m_enable_auto_indent = debugger.GetAutoIndent();
93     } else {
94       m_indent_str.clear();
95       m_enable_auto_indent = false;
96     }
97   }
98   return m_io_handler_sp;
99 }
100
101 void REPL::IOHandlerActivated(IOHandler &io_handler) {
102   lldb::ProcessSP process_sp = m_target.GetProcessSP();
103   if (process_sp && process_sp->IsAlive())
104     return;
105   lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
106   error_sp->Printf("REPL requires a running target process.\n");
107   io_handler.SetIsDone(true);
108 }
109
110 bool REPL::IOHandlerInterrupt(IOHandler &io_handler) { return false; }
111
112 void REPL::IOHandlerInputInterrupted(IOHandler &io_handler, std::string &line) {
113 }
114
115 const char *REPL::IOHandlerGetFixIndentationCharacters() {
116   return (m_enable_auto_indent ? GetAutoIndentCharacters() : nullptr);
117 }
118
119 ConstString REPL::IOHandlerGetControlSequence(char ch) {
120   if (ch == 'd')
121     return ConstString(":quit\n");
122   return ConstString();
123 }
124
125 const char *REPL::IOHandlerGetCommandPrefix() { return ":"; }
126
127 const char *REPL::IOHandlerGetHelpPrologue() {
128   return "\nThe REPL (Read-Eval-Print-Loop) acts like an interpreter.  "
129          "Valid statements, expressions, and declarations are immediately "
130          "compiled and executed.\n\n"
131          "The complete set of LLDB debugging commands are also available as "
132          "described below.  Commands "
133          "must be prefixed with a colon at the REPL prompt (:quit for "
134          "example.)  Typing just a colon "
135          "followed by return will switch to the LLDB prompt.\n\n";
136 }
137
138 bool REPL::IOHandlerIsInputComplete(IOHandler &io_handler, StringList &lines) {
139   // Check for meta command
140   const size_t num_lines = lines.GetSize();
141   if (num_lines == 1) {
142     const char *first_line = lines.GetStringAtIndex(0);
143     if (first_line[0] == ':')
144       return true; // Meta command is a single line where that starts with ':'
145   }
146
147   // Check if REPL input is done
148   std::string source_string(lines.CopyList());
149   return SourceIsComplete(source_string);
150 }
151
152 int REPL::CalculateActualIndentation(const StringList &lines) {
153   std::string last_line = lines[lines.GetSize() - 1];
154
155   int actual_indent = 0;
156   for (char &ch : last_line) {
157     if (ch != ' ')
158       break;
159     ++actual_indent;
160   }
161
162   return actual_indent;
163 }
164
165 int REPL::IOHandlerFixIndentation(IOHandler &io_handler,
166                                   const StringList &lines,
167                                   int cursor_position) {
168   if (!m_enable_auto_indent)
169     return 0;
170
171   if (!lines.GetSize()) {
172     return 0;
173   }
174
175   int tab_size = io_handler.GetDebugger().GetTabSize();
176
177   lldb::offset_t desired_indent =
178       GetDesiredIndentation(lines, cursor_position, tab_size);
179
180   int actual_indent = REPL::CalculateActualIndentation(lines);
181
182   if (desired_indent == LLDB_INVALID_OFFSET)
183     return 0;
184
185   return (int)desired_indent - actual_indent;
186 }
187
188 void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
189   lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFile());
190   lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
191   bool extra_line = false;
192   bool did_quit = false;
193
194   if (code.empty()) {
195     m_code.AppendString("");
196     static_cast<IOHandlerEditline &>(io_handler)
197         .SetBaseLineNumber(m_code.GetSize() + 1);
198   } else {
199     Debugger &debugger = m_target.GetDebugger();
200     CommandInterpreter &ci = debugger.GetCommandInterpreter();
201     extra_line = ci.GetSpaceReplPrompts();
202
203     ExecutionContext exe_ctx(m_target.GetProcessSP()
204                                  ->GetThreadList()
205                                  .GetSelectedThread()
206                                  ->GetSelectedFrame()
207                                  .get());
208
209     lldb::ProcessSP process_sp(exe_ctx.GetProcessSP());
210
211     if (code[0] == ':') {
212       // Meta command
213       // Strip the ':'
214       code.erase(0, 1);
215       if (Args::StripSpaces(code)) {
216         // "lldb" was followed by arguments, so just execute the command dump
217         // the results
218
219         // Turn off prompt on quit in case the user types ":quit"
220         const bool saved_prompt_on_quit = ci.GetPromptOnQuit();
221         if (saved_prompt_on_quit)
222           ci.SetPromptOnQuit(false);
223
224         // Execute the command
225         CommandReturnObject result;
226         result.SetImmediateOutputStream(output_sp);
227         result.SetImmediateErrorStream(error_sp);
228         ci.HandleCommand(code.c_str(), eLazyBoolNo, result);
229
230         if (saved_prompt_on_quit)
231           ci.SetPromptOnQuit(true);
232
233         if (result.GetStatus() == lldb::eReturnStatusQuit) {
234           did_quit = true;
235           io_handler.SetIsDone(true);
236           if (debugger.CheckTopIOHandlerTypes(
237                   IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) {
238             // We typed "quit" or an alias to quit so we need to check if the
239             // command interpreter is above us and tell it that it is done as
240             // well so we don't drop back into the command interpreter if we
241             // have already quit
242             lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
243             if (io_handler_sp)
244               io_handler_sp->SetIsDone(true);
245           }
246         }
247       } else {
248         // ":" was followed by no arguments, so push the LLDB command prompt
249         if (debugger.CheckTopIOHandlerTypes(
250                 IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) {
251           // If the user wants to get back to the command interpreter and the
252           // command interpreter is what launched the REPL, then just let the
253           // REPL exit and fall back to the command interpreter.
254           io_handler.SetIsDone(true);
255         } else {
256           // The REPL wasn't launched the by the command interpreter, it is the
257           // base IOHandler, so we need to get the command interpreter and
258           lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
259           if (io_handler_sp) {
260             io_handler_sp->SetIsDone(false);
261             debugger.PushIOHandler(ci.GetIOHandler());
262           }
263         }
264       }
265     } else {
266       // Unwind any expression we might have been running in case our REPL
267       // expression crashed and the user was looking around
268       if (m_dedicated_repl_mode) {
269         Thread *thread = exe_ctx.GetThreadPtr();
270         if (thread && thread->UnwindInnermostExpression().Success()) {
271           thread->SetSelectedFrameByIndex(0, false);
272           exe_ctx.SetFrameSP(thread->GetSelectedFrame());
273         }
274       }
275
276       const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();
277
278       EvaluateExpressionOptions expr_options;
279       expr_options.SetCoerceToId(m_varobj_options.use_objc);
280       expr_options.SetUnwindOnError(m_command_options.unwind_on_error);
281       expr_options.SetIgnoreBreakpoints(m_command_options.ignore_breakpoints);
282       expr_options.SetKeepInMemory(true);
283       expr_options.SetUseDynamic(m_varobj_options.use_dynamic);
284       expr_options.SetTryAllThreads(m_command_options.try_all_threads);
285       expr_options.SetGenerateDebugInfo(true);
286       expr_options.SetREPLEnabled(true);
287       expr_options.SetColorizeErrors(colorize_err);
288       expr_options.SetPoundLine(m_repl_source_path.c_str(),
289                                 m_code.GetSize() + 1);
290       if (m_command_options.timeout > 0)
291         expr_options.SetTimeout(std::chrono::microseconds(m_command_options.timeout));
292       else
293         expr_options.SetTimeout(llvm::None);
294
295       expr_options.SetLanguage(GetLanguage());
296
297       PersistentExpressionState *persistent_state =
298           m_target.GetPersistentExpressionStateForLanguage(GetLanguage());
299
300       const size_t var_count_before = persistent_state->GetSize();
301
302       const char *expr_prefix = nullptr;
303       lldb::ValueObjectSP result_valobj_sp;
304       Status error;
305       lldb::ModuleSP jit_module_sp;
306       lldb::ExpressionResults execution_results =
307           UserExpression::Evaluate(exe_ctx, expr_options, code.c_str(),
308                                    expr_prefix, result_valobj_sp, error,
309                                    0,       // Line offset
310                                    nullptr, // Fixed Expression
311                                    &jit_module_sp);
312
313       // CommandInterpreter &ci = debugger.GetCommandInterpreter();
314
315       if (process_sp && process_sp->IsAlive()) {
316         bool add_to_code = true;
317         bool handled = false;
318         if (result_valobj_sp) {
319           lldb::Format format = m_format_options.GetFormat();
320
321           if (result_valobj_sp->GetError().Success()) {
322             handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp);
323           } else if (result_valobj_sp->GetError().GetError() ==
324                      UserExpression::kNoResult) {
325             if (format != lldb::eFormatVoid && debugger.GetNotifyVoid()) {
326               error_sp->PutCString("(void)\n");
327               handled = true;
328             }
329           }
330         }
331
332         if (debugger.GetPrintDecls()) {
333           for (size_t vi = var_count_before, ve = persistent_state->GetSize();
334                vi != ve; ++vi) {
335             lldb::ExpressionVariableSP persistent_var_sp =
336                 persistent_state->GetVariableAtIndex(vi);
337             lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject();
338
339             PrintOneVariable(debugger, output_sp, valobj_sp,
340                              persistent_var_sp.get());
341           }
342         }
343
344         if (!handled) {
345           bool useColors = error_sp->GetFile().GetIsTerminalWithColors();
346           switch (execution_results) {
347           case lldb::eExpressionSetupError:
348           case lldb::eExpressionParseError:
349             add_to_code = false;
350             LLVM_FALLTHROUGH;
351           case lldb::eExpressionDiscarded:
352             error_sp->Printf("%s\n", error.AsCString());
353             break;
354
355           case lldb::eExpressionCompleted:
356             break;
357           case lldb::eExpressionInterrupted:
358             if (useColors) {
359               error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
360               error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
361             }
362             error_sp->Printf("Execution interrupted. ");
363             if (useColors)
364               error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
365             error_sp->Printf("Enter code to recover and continue.\nEnter LLDB "
366                              "commands to investigate (type :help for "
367                              "assistance.)\n");
368             break;
369
370           case lldb::eExpressionHitBreakpoint:
371             // Breakpoint was hit, drop into LLDB command interpreter
372             if (useColors) {
373               error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
374               error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
375             }
376             output_sp->Printf("Execution stopped at breakpoint.  ");
377             if (useColors)
378               error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
379             output_sp->Printf("Enter LLDB commands to investigate (type help "
380                               "for assistance.)\n");
381             {
382               lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
383               if (io_handler_sp) {
384                 io_handler_sp->SetIsDone(false);
385                 debugger.PushIOHandler(ci.GetIOHandler());
386               }
387             }
388             break;
389
390           case lldb::eExpressionTimedOut:
391             error_sp->Printf("error: timeout\n");
392             if (error.AsCString())
393               error_sp->Printf("error: %s\n", error.AsCString());
394             break;
395           case lldb::eExpressionResultUnavailable:
396             // Shoulnd't happen???
397             error_sp->Printf("error: could not fetch result -- %s\n",
398                              error.AsCString());
399             break;
400           case lldb::eExpressionStoppedForDebug:
401             // Shoulnd't happen???
402             error_sp->Printf("error: stopped for debug -- %s\n",
403                              error.AsCString());
404             break;
405           }
406         }
407
408         if (add_to_code) {
409           const uint32_t new_default_line = m_code.GetSize() + 1;
410
411           m_code.SplitIntoLines(code);
412
413           // Update our code on disk
414           if (!m_repl_source_path.empty()) {
415             lldb_private::File file;
416             FileSystem::Instance().Open(file, FileSpec(m_repl_source_path),
417                                         File::eOpenOptionWrite |
418                                             File::eOpenOptionTruncate |
419                                             File::eOpenOptionCanCreate,
420                                         lldb::eFilePermissionsFileDefault);
421             std::string code(m_code.CopyList());
422             code.append(1, '\n');
423             size_t bytes_written = code.size();
424             file.Write(code.c_str(), bytes_written);
425             file.Close();
426
427             // Now set the default file and line to the REPL source file
428             m_target.GetSourceManager().SetDefaultFileAndLine(
429                 FileSpec(m_repl_source_path), new_default_line);
430           }
431           static_cast<IOHandlerEditline &>(io_handler)
432               .SetBaseLineNumber(m_code.GetSize() + 1);
433         }
434         if (extra_line) {
435           fprintf(output_sp->GetFile().GetStream(), "\n");
436         }
437       }
438     }
439
440     // Don't complain about the REPL process going away if we are in the
441     // process of quitting.
442     if (!did_quit && (!process_sp || !process_sp->IsAlive())) {
443       error_sp->Printf(
444           "error: REPL process is no longer alive, exiting REPL\n");
445       io_handler.SetIsDone(true);
446     }
447   }
448 }
449
450 int REPL::IOHandlerComplete(IOHandler &io_handler, const char *current_line,
451                             const char *cursor, const char *last_char,
452                             int skip_first_n_matches, int max_matches,
453                             StringList &matches, StringList &descriptions) {
454   matches.Clear();
455
456   llvm::StringRef line(current_line, cursor - current_line);
457
458   // Complete an LLDB command if the first character is a colon...
459   if (!line.empty() && line[0] == ':') {
460     Debugger &debugger = m_target.GetDebugger();
461
462     // auto complete LLDB commands
463     const char *lldb_current_line = line.substr(1).data();
464     return debugger.GetCommandInterpreter().HandleCompletion(
465         lldb_current_line, cursor, last_char, skip_first_n_matches, max_matches,
466         matches, descriptions);
467   }
468
469   // Strip spaces from the line and see if we had only spaces
470   line = line.ltrim();
471   if (line.empty()) {
472     // Only spaces on this line, so just indent
473     matches.AppendString(m_indent_str);
474     return 1;
475   }
476
477   std::string current_code;
478   current_code.append(m_code.CopyList());
479
480   IOHandlerEditline &editline = static_cast<IOHandlerEditline &>(io_handler);
481   const StringList *current_lines = editline.GetCurrentLines();
482   if (current_lines) {
483     const uint32_t current_line_idx = editline.GetCurrentLineIndex();
484
485     if (current_line_idx < current_lines->GetSize()) {
486       for (uint32_t i = 0; i < current_line_idx; ++i) {
487         const char *line_cstr = current_lines->GetStringAtIndex(i);
488         if (line_cstr) {
489           current_code.append("\n");
490           current_code.append(line_cstr);
491         }
492       }
493     }
494   }
495
496   if (cursor > current_line) {
497     current_code.append("\n");
498     current_code.append(current_line, cursor - current_line);
499   }
500
501   return CompleteCode(current_code, matches);
502 }
503
504 bool QuitCommandOverrideCallback(void *baton, const char **argv) {
505   Target *target = (Target *)baton;
506   lldb::ProcessSP process_sp(target->GetProcessSP());
507   if (process_sp) {
508     process_sp->Destroy(false);
509     process_sp->GetTarget().GetDebugger().ClearIOHandlers();
510   }
511   return false;
512 }
513
514 Status REPL::RunLoop() {
515   Status error;
516
517   error = DoInitialization();
518   m_repl_source_path = GetSourcePath();
519
520   if (!error.Success())
521     return error;
522
523   Debugger &debugger = m_target.GetDebugger();
524
525   lldb::IOHandlerSP io_handler_sp(GetIOHandler());
526
527   FileSpec save_default_file;
528   uint32_t save_default_line = 0;
529
530   if (!m_repl_source_path.empty()) {
531     // Save the current default file and line
532     m_target.GetSourceManager().GetDefaultFileAndLine(save_default_file,
533                                                       save_default_line);
534   }
535
536   debugger.PushIOHandler(io_handler_sp);
537
538   // Check if we are in dedicated REPL mode where LLDB was start with the "--
539   // repl" option from the command line. Currently we know this by checking if
540   // the debugger already has a IOHandler thread.
541   if (!debugger.HasIOHandlerThread()) {
542     // The debugger doesn't have an existing IOHandler thread, so this must be
543     // dedicated REPL mode...
544     m_dedicated_repl_mode = true;
545     debugger.StartIOHandlerThread();
546     llvm::StringRef command_name_str("quit");
547     CommandObject *cmd_obj =
548         debugger.GetCommandInterpreter().GetCommandObjectForCommand(
549             command_name_str);
550     if (cmd_obj) {
551       assert(command_name_str.empty());
552       cmd_obj->SetOverrideCallback(QuitCommandOverrideCallback, &m_target);
553     }
554   }
555
556   // Wait for the REPL command interpreter to get popped
557   io_handler_sp->WaitForPop();
558
559   if (m_dedicated_repl_mode) {
560     // If we were in dedicated REPL mode we would have started the IOHandler
561     // thread, and we should kill our process
562     lldb::ProcessSP process_sp = m_target.GetProcessSP();
563     if (process_sp && process_sp->IsAlive())
564       process_sp->Destroy(false);
565
566     // Wait for the IO handler thread to exit (TODO: don't do this if the IO
567     // handler thread already exists...)
568     debugger.JoinIOHandlerThread();
569   }
570
571   // Restore the default file and line
572   if (save_default_file && save_default_line != 0)
573     m_target.GetSourceManager().SetDefaultFileAndLine(save_default_file,
574                                                       save_default_line);
575   return error;
576 }