1 //===-- REPL.cpp ------------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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"
23 using namespace lldb_private;
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);
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;
39 REPL::~REPL() = default;
41 lldb::REPLSP REPL::Create(Status &err, lldb::LanguageType language,
42 Debugger *debugger, Target *target,
43 const char *repl_options) {
47 while (REPLCreateInstance create_instance =
48 PluginManager::GetREPLCreateCallbackAtIndex(idx++)) {
49 ret = (*create_instance)(err, language, debugger, target, repl_options);
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();
65 tmpdir_file_spec = FileSpec("/tmp");
66 tmpdir_file_spec.AppendPathComponent(file_basename.AsCString());
69 return tmpdir_file_spec.GetPath();
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
81 true, // The REPL prompt is always colored
85 // Don't exit if CTRL+C is pressed
86 static_cast<IOHandlerEditline *>(m_io_handler_sp.get())
87 ->SetInterruptExits(false);
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();
95 m_enable_auto_indent = false;
98 return m_io_handler_sp;
101 void REPL::IOHandlerActivated(IOHandler &io_handler) {
102 lldb::ProcessSP process_sp = m_target.GetProcessSP();
103 if (process_sp && process_sp->IsAlive())
105 lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
106 error_sp->Printf("REPL requires a running target process.\n");
107 io_handler.SetIsDone(true);
110 bool REPL::IOHandlerInterrupt(IOHandler &io_handler) { return false; }
112 void REPL::IOHandlerInputInterrupted(IOHandler &io_handler, std::string &line) {
115 const char *REPL::IOHandlerGetFixIndentationCharacters() {
116 return (m_enable_auto_indent ? GetAutoIndentCharacters() : nullptr);
119 ConstString REPL::IOHandlerGetControlSequence(char ch) {
121 return ConstString(":quit\n");
122 return ConstString();
125 const char *REPL::IOHandlerGetCommandPrefix() { return ":"; }
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";
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 ':'
147 // Check if REPL input is done
148 std::string source_string(lines.CopyList());
149 return SourceIsComplete(source_string);
152 int REPL::CalculateActualIndentation(const StringList &lines) {
153 std::string last_line = lines[lines.GetSize() - 1];
155 int actual_indent = 0;
156 for (char &ch : last_line) {
162 return actual_indent;
165 int REPL::IOHandlerFixIndentation(IOHandler &io_handler,
166 const StringList &lines,
167 int cursor_position) {
168 if (!m_enable_auto_indent)
171 if (!lines.GetSize()) {
175 int tab_size = io_handler.GetDebugger().GetTabSize();
177 lldb::offset_t desired_indent =
178 GetDesiredIndentation(lines, cursor_position, tab_size);
180 int actual_indent = REPL::CalculateActualIndentation(lines);
182 if (desired_indent == LLDB_INVALID_OFFSET)
185 return (int)desired_indent - actual_indent;
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;
195 m_code.AppendString("");
196 static_cast<IOHandlerEditline &>(io_handler)
197 .SetBaseLineNumber(m_code.GetSize() + 1);
199 Debugger &debugger = m_target.GetDebugger();
200 CommandInterpreter &ci = debugger.GetCommandInterpreter();
201 extra_line = ci.GetSpaceReplPrompts();
203 ExecutionContext exe_ctx(m_target.GetProcessSP()
209 lldb::ProcessSP process_sp(exe_ctx.GetProcessSP());
211 if (code[0] == ':') {
215 if (Args::StripSpaces(code)) {
216 // "lldb" was followed by arguments, so just execute the command dump
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);
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);
230 if (saved_prompt_on_quit)
231 ci.SetPromptOnQuit(true);
233 if (result.GetStatus() == lldb::eReturnStatusQuit) {
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
242 lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
244 io_handler_sp->SetIsDone(true);
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);
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());
260 io_handler_sp->SetIsDone(false);
261 debugger.PushIOHandler(ci.GetIOHandler());
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());
276 const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();
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));
293 expr_options.SetTimeout(llvm::None);
295 expr_options.SetLanguage(GetLanguage());
297 PersistentExpressionState *persistent_state =
298 m_target.GetPersistentExpressionStateForLanguage(GetLanguage());
300 const size_t var_count_before = persistent_state->GetSize();
302 const char *expr_prefix = nullptr;
303 lldb::ValueObjectSP result_valobj_sp;
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,
310 nullptr, // Fixed Expression
313 // CommandInterpreter &ci = debugger.GetCommandInterpreter();
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();
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");
332 if (debugger.GetPrintDecls()) {
333 for (size_t vi = var_count_before, ve = persistent_state->GetSize();
335 lldb::ExpressionVariableSP persistent_var_sp =
336 persistent_state->GetVariableAtIndex(vi);
337 lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject();
339 PrintOneVariable(debugger, output_sp, valobj_sp,
340 persistent_var_sp.get());
345 bool useColors = error_sp->GetFile().GetIsTerminalWithColors();
346 switch (execution_results) {
347 case lldb::eExpressionSetupError:
348 case lldb::eExpressionParseError:
351 case lldb::eExpressionDiscarded:
352 error_sp->Printf("%s\n", error.AsCString());
355 case lldb::eExpressionCompleted:
357 case lldb::eExpressionInterrupted:
359 error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
360 error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
362 error_sp->Printf("Execution interrupted. ");
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 "
370 case lldb::eExpressionHitBreakpoint:
371 // Breakpoint was hit, drop into LLDB command interpreter
373 error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
374 error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
376 output_sp->Printf("Execution stopped at breakpoint. ");
378 error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
379 output_sp->Printf("Enter LLDB commands to investigate (type help "
380 "for assistance.)\n");
382 lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
384 io_handler_sp->SetIsDone(false);
385 debugger.PushIOHandler(ci.GetIOHandler());
390 case lldb::eExpressionTimedOut:
391 error_sp->Printf("error: timeout\n");
392 if (error.AsCString())
393 error_sp->Printf("error: %s\n", error.AsCString());
395 case lldb::eExpressionResultUnavailable:
396 // Shoulnd't happen???
397 error_sp->Printf("error: could not fetch result -- %s\n",
400 case lldb::eExpressionStoppedForDebug:
401 // Shoulnd't happen???
402 error_sp->Printf("error: stopped for debug -- %s\n",
409 const uint32_t new_default_line = m_code.GetSize() + 1;
411 m_code.SplitIntoLines(code);
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);
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);
431 static_cast<IOHandlerEditline &>(io_handler)
432 .SetBaseLineNumber(m_code.GetSize() + 1);
435 fprintf(output_sp->GetFile().GetStream(), "\n");
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())) {
444 "error: REPL process is no longer alive, exiting REPL\n");
445 io_handler.SetIsDone(true);
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) {
456 llvm::StringRef line(current_line, cursor - current_line);
458 // Complete an LLDB command if the first character is a colon...
459 if (!line.empty() && line[0] == ':') {
460 Debugger &debugger = m_target.GetDebugger();
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);
469 // Strip spaces from the line and see if we had only spaces
472 // Only spaces on this line, so just indent
473 matches.AppendString(m_indent_str);
477 std::string current_code;
478 current_code.append(m_code.CopyList());
480 IOHandlerEditline &editline = static_cast<IOHandlerEditline &>(io_handler);
481 const StringList *current_lines = editline.GetCurrentLines();
483 const uint32_t current_line_idx = editline.GetCurrentLineIndex();
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);
489 current_code.append("\n");
490 current_code.append(line_cstr);
496 if (cursor > current_line) {
497 current_code.append("\n");
498 current_code.append(current_line, cursor - current_line);
501 return CompleteCode(current_code, matches);
504 bool QuitCommandOverrideCallback(void *baton, const char **argv) {
505 Target *target = (Target *)baton;
506 lldb::ProcessSP process_sp(target->GetProcessSP());
508 process_sp->Destroy(false);
509 process_sp->GetTarget().GetDebugger().ClearIOHandlers();
514 Status REPL::RunLoop() {
517 error = DoInitialization();
518 m_repl_source_path = GetSourcePath();
520 if (!error.Success())
523 Debugger &debugger = m_target.GetDebugger();
525 lldb::IOHandlerSP io_handler_sp(GetIOHandler());
527 FileSpec save_default_file;
528 uint32_t save_default_line = 0;
530 if (!m_repl_source_path.empty()) {
531 // Save the current default file and line
532 m_target.GetSourceManager().GetDefaultFileAndLine(save_default_file,
536 debugger.PushIOHandler(io_handler_sp);
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(
551 assert(command_name_str.empty());
552 cmd_obj->SetOverrideCallback(QuitCommandOverrideCallback, &m_target);
556 // Wait for the REPL command interpreter to get popped
557 io_handler_sp->WaitForPop();
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);
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();
571 // Restore the default file and line
572 if (save_default_file && save_default_line != 0)
573 m_target.GetSourceManager().SetDefaultFileAndLine(save_default_file,