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 //===----------------------------------------------------------------------===//
12 // Other libraries and framework includes
14 #include "lldb/Expression/REPL.h"
15 #include "lldb/Core/Debugger.h"
16 #include "lldb/Core/PluginManager.h"
17 #include "lldb/Core/StreamFile.h"
18 #include "lldb/Expression/ExpressionVariable.h"
19 #include "lldb/Expression/UserExpression.h"
20 #include "lldb/Host/HostInfo.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 #include "lldb/Interpreter/CommandReturnObject.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Target/Thread.h"
25 #include "lldb/Utility/AnsiTerminal.h"
27 using namespace lldb_private;
29 REPL::REPL(LLVMCastKind kind, Target &target) : m_target(target), m_kind(kind) {
30 // Make sure all option values have sane defaults
31 Debugger &debugger = m_target.GetDebugger();
32 auto exe_ctx = debugger.GetCommandInterpreter().GetExecutionContext();
33 m_format_options.OptionParsingStarting(&exe_ctx);
34 m_varobj_options.OptionParsingStarting(&exe_ctx);
35 m_command_options.OptionParsingStarting(&exe_ctx);
37 // Default certain settings for REPL regardless of the global settings.
38 m_command_options.unwind_on_error = false;
39 m_command_options.ignore_breakpoints = false;
40 m_command_options.debug = false;
43 REPL::~REPL() = default;
45 lldb::REPLSP REPL::Create(Error &err, lldb::LanguageType language,
46 Debugger *debugger, Target *target,
47 const char *repl_options) {
51 while (REPLCreateInstance create_instance =
52 PluginManager::GetREPLCreateCallbackAtIndex(idx++)) {
53 ret = (*create_instance)(err, language, debugger, target, repl_options);
62 std::string REPL::GetSourcePath() {
63 ConstString file_basename = GetSourceFileBasename();
65 FileSpec tmpdir_file_spec;
66 if (HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir,
68 tmpdir_file_spec.GetFilename().SetCString(file_basename.AsCString());
69 m_repl_source_path = tmpdir_file_spec.GetPath();
71 tmpdir_file_spec = FileSpec("/tmp", false);
72 tmpdir_file_spec.AppendPathComponent(file_basename.AsCString());
75 return tmpdir_file_spec.GetPath();
78 lldb::IOHandlerSP REPL::GetIOHandler() {
79 if (!m_io_handler_sp) {
80 Debugger &debugger = m_target.GetDebugger();
81 m_io_handler_sp.reset(
82 new IOHandlerEditline(debugger, IOHandler::Type::REPL,
83 "lldb-repl", // Name of input reader for history
84 llvm::StringRef("> "), // prompt
85 llvm::StringRef(". "), // Continuation prompt
87 true, // The REPL prompt is always colored
91 // Don't exit if CTRL+C is pressed
92 static_cast<IOHandlerEditline *>(m_io_handler_sp.get())
93 ->SetInterruptExits(false);
95 if (m_io_handler_sp->GetIsInteractive() &&
96 m_io_handler_sp->GetIsRealTerminal()) {
97 m_indent_str.assign(debugger.GetTabSize(), ' ');
98 m_enable_auto_indent = debugger.GetAutoIndent();
100 m_indent_str.clear();
101 m_enable_auto_indent = false;
104 return m_io_handler_sp;
107 void REPL::IOHandlerActivated(IOHandler &io_handler) {
108 lldb::ProcessSP process_sp = m_target.GetProcessSP();
109 if (process_sp && process_sp->IsAlive())
111 lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
112 error_sp->Printf("REPL requires a running target process.\n");
113 io_handler.SetIsDone(true);
116 bool REPL::IOHandlerInterrupt(IOHandler &io_handler) { return false; }
118 void REPL::IOHandlerInputInterrupted(IOHandler &io_handler, std::string &line) {
121 const char *REPL::IOHandlerGetFixIndentationCharacters() {
122 return (m_enable_auto_indent ? GetAutoIndentCharacters() : nullptr);
125 ConstString REPL::IOHandlerGetControlSequence(char ch) {
127 return ConstString(":quit\n");
128 return ConstString();
131 const char *REPL::IOHandlerGetCommandPrefix() { return ":"; }
133 const char *REPL::IOHandlerGetHelpPrologue() {
134 return "\nThe REPL (Read-Eval-Print-Loop) acts like an interpreter. "
135 "Valid statements, expressions, and declarations are immediately "
136 "compiled and executed.\n\n"
137 "The complete set of LLDB debugging commands are also available as "
138 "described below. Commands "
139 "must be prefixed with a colon at the REPL prompt (:quit for "
140 "example.) Typing just a colon "
141 "followed by return will switch to the LLDB prompt.\n\n";
144 bool REPL::IOHandlerIsInputComplete(IOHandler &io_handler, StringList &lines) {
145 // Check for meta command
146 const size_t num_lines = lines.GetSize();
147 if (num_lines == 1) {
148 const char *first_line = lines.GetStringAtIndex(0);
149 if (first_line[0] == ':')
150 return true; // Meta command is a single line where that starts with ':'
153 // Check if REPL input is done
154 std::string source_string(lines.CopyList());
155 return SourceIsComplete(source_string);
158 int REPL::CalculateActualIndentation(const StringList &lines) {
159 std::string last_line = lines[lines.GetSize() - 1];
161 int actual_indent = 0;
162 for (char &ch : last_line) {
168 return actual_indent;
171 int REPL::IOHandlerFixIndentation(IOHandler &io_handler,
172 const StringList &lines,
173 int cursor_position) {
174 if (!m_enable_auto_indent)
177 if (!lines.GetSize()) {
181 int tab_size = io_handler.GetDebugger().GetTabSize();
183 lldb::offset_t desired_indent =
184 GetDesiredIndentation(lines, cursor_position, tab_size);
186 int actual_indent = REPL::CalculateActualIndentation(lines);
188 if (desired_indent == LLDB_INVALID_OFFSET)
191 return (int)desired_indent - actual_indent;
194 void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
195 lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFile());
196 lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
197 bool extra_line = false;
198 bool did_quit = false;
201 m_code.AppendString("");
202 static_cast<IOHandlerEditline &>(io_handler)
203 .SetBaseLineNumber(m_code.GetSize() + 1);
205 Debugger &debugger = m_target.GetDebugger();
206 CommandInterpreter &ci = debugger.GetCommandInterpreter();
207 extra_line = ci.GetSpaceReplPrompts();
209 ExecutionContext exe_ctx(m_target.GetProcessSP()
215 lldb::ProcessSP process_sp(exe_ctx.GetProcessSP());
217 if (code[0] == ':') {
221 if (Args::StripSpaces(code)) {
222 // "lldb" was followed by arguments, so just execute the command dump
225 // Turn off prompt on quit in case the user types ":quit"
226 const bool saved_prompt_on_quit = ci.GetPromptOnQuit();
227 if (saved_prompt_on_quit)
228 ci.SetPromptOnQuit(false);
230 // Execute the command
231 CommandReturnObject result;
232 result.SetImmediateOutputStream(output_sp);
233 result.SetImmediateErrorStream(error_sp);
234 ci.HandleCommand(code.c_str(), eLazyBoolNo, result);
236 if (saved_prompt_on_quit)
237 ci.SetPromptOnQuit(true);
239 if (result.GetStatus() == lldb::eReturnStatusQuit) {
241 io_handler.SetIsDone(true);
242 if (debugger.CheckTopIOHandlerTypes(
243 IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) {
244 // We typed "quit" or an alias to quit so we need to check if the
245 // command interpreter is above us and tell it that it is done as
247 // so we don't drop back into the command interpreter if we have
250 lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
252 io_handler_sp->SetIsDone(true);
256 // ":" was followed by no arguments, so push the LLDB command prompt
257 if (debugger.CheckTopIOHandlerTypes(
258 IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) {
259 // If the user wants to get back to the command interpreter and the
260 // command interpreter is what launched the REPL, then just let the
261 // REPL exit and fall back to the command interpreter.
262 io_handler.SetIsDone(true);
264 // The REPL wasn't launched the by the command interpreter, it is the
265 // base IOHandler, so we need to get the command interpreter and
266 lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
268 io_handler_sp->SetIsDone(false);
269 debugger.PushIOHandler(ci.GetIOHandler());
274 // Unwind any expression we might have been running in case our REPL
275 // expression crashed and the user was looking around
276 if (m_dedicated_repl_mode) {
277 Thread *thread = exe_ctx.GetThreadPtr();
278 if (thread && thread->UnwindInnermostExpression().Success()) {
279 thread->SetSelectedFrameByIndex(0, false);
280 exe_ctx.SetFrameSP(thread->GetSelectedFrame());
284 const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();
286 EvaluateExpressionOptions expr_options;
287 expr_options.SetCoerceToId(m_varobj_options.use_objc);
288 expr_options.SetUnwindOnError(m_command_options.unwind_on_error);
289 expr_options.SetIgnoreBreakpoints(m_command_options.ignore_breakpoints);
290 expr_options.SetKeepInMemory(true);
291 expr_options.SetUseDynamic(m_varobj_options.use_dynamic);
292 expr_options.SetTryAllThreads(m_command_options.try_all_threads);
293 expr_options.SetGenerateDebugInfo(true);
294 expr_options.SetREPLEnabled(true);
295 expr_options.SetColorizeErrors(colorize_err);
296 expr_options.SetPoundLine(m_repl_source_path.c_str(),
297 m_code.GetSize() + 1);
298 if (m_command_options.timeout > 0)
299 expr_options.SetTimeout(std::chrono::microseconds(m_command_options.timeout));
301 expr_options.SetTimeout(llvm::None);
303 expr_options.SetLanguage(GetLanguage());
305 PersistentExpressionState *persistent_state =
306 m_target.GetPersistentExpressionStateForLanguage(GetLanguage());
308 const size_t var_count_before = persistent_state->GetSize();
310 const char *expr_prefix = nullptr;
311 lldb::ValueObjectSP result_valobj_sp;
313 lldb::ModuleSP jit_module_sp;
314 lldb::ExpressionResults execution_results =
315 UserExpression::Evaluate(exe_ctx, expr_options, code.c_str(),
316 expr_prefix, result_valobj_sp, error,
318 nullptr, // Fixed Expression
321 // CommandInterpreter &ci = debugger.GetCommandInterpreter();
323 if (process_sp && process_sp->IsAlive()) {
324 bool add_to_code = true;
325 bool handled = false;
326 if (result_valobj_sp) {
327 lldb::Format format = m_format_options.GetFormat();
329 if (result_valobj_sp->GetError().Success()) {
330 handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp);
331 } else if (result_valobj_sp->GetError().GetError() ==
332 UserExpression::kNoResult) {
333 if (format != lldb::eFormatVoid && debugger.GetNotifyVoid()) {
334 error_sp->PutCString("(void)\n");
340 if (debugger.GetPrintDecls()) {
341 for (size_t vi = var_count_before, ve = persistent_state->GetSize();
343 lldb::ExpressionVariableSP persistent_var_sp =
344 persistent_state->GetVariableAtIndex(vi);
345 lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject();
347 PrintOneVariable(debugger, output_sp, valobj_sp,
348 persistent_var_sp.get());
353 bool useColors = error_sp->GetFile().GetIsTerminalWithColors();
354 switch (execution_results) {
355 case lldb::eExpressionSetupError:
356 case lldb::eExpressionParseError:
359 case lldb::eExpressionDiscarded:
360 error_sp->Printf("%s\n", error.AsCString());
363 case lldb::eExpressionCompleted:
365 case lldb::eExpressionInterrupted:
367 error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
368 error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
370 error_sp->Printf("Execution interrupted. ");
372 error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
373 error_sp->Printf("Enter code to recover and continue.\nEnter LLDB "
374 "commands to investigate (type :help for "
378 case lldb::eExpressionHitBreakpoint:
379 // Breakpoint was hit, drop into LLDB command interpreter
381 error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
382 error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
384 output_sp->Printf("Execution stopped at breakpoint. ");
386 error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
387 output_sp->Printf("Enter LLDB commands to investigate (type help "
388 "for assistance.)\n");
390 lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
392 io_handler_sp->SetIsDone(false);
393 debugger.PushIOHandler(ci.GetIOHandler());
398 case lldb::eExpressionTimedOut:
399 error_sp->Printf("error: timeout\n");
400 if (error.AsCString())
401 error_sp->Printf("error: %s\n", error.AsCString());
403 case lldb::eExpressionResultUnavailable:
404 // Shoulnd't happen???
405 error_sp->Printf("error: could not fetch result -- %s\n",
408 case lldb::eExpressionStoppedForDebug:
409 // Shoulnd't happen???
410 error_sp->Printf("error: stopped for debug -- %s\n",
417 const uint32_t new_default_line = m_code.GetSize() + 1;
419 m_code.SplitIntoLines(code);
421 // Update our code on disk
422 if (!m_repl_source_path.empty()) {
423 lldb_private::File file(m_repl_source_path.c_str(),
424 File::eOpenOptionWrite |
425 File::eOpenOptionTruncate |
426 File::eOpenOptionCanCreate,
427 lldb::eFilePermissionsFileDefault);
428 std::string code(m_code.CopyList());
429 code.append(1, '\n');
430 size_t bytes_written = code.size();
431 file.Write(code.c_str(), bytes_written);
434 // Now set the default file and line to the REPL source file
435 m_target.GetSourceManager().SetDefaultFileAndLine(
436 FileSpec(m_repl_source_path, false), new_default_line);
438 static_cast<IOHandlerEditline &>(io_handler)
439 .SetBaseLineNumber(m_code.GetSize() + 1);
442 fprintf(output_sp->GetFile().GetStream(), "\n");
447 // Don't complain about the REPL process going away if we are in the process
449 if (!did_quit && (!process_sp || !process_sp->IsAlive())) {
451 "error: REPL process is no longer alive, exiting REPL\n");
452 io_handler.SetIsDone(true);
457 int REPL::IOHandlerComplete(IOHandler &io_handler, const char *current_line,
458 const char *cursor, const char *last_char,
459 int skip_first_n_matches, int max_matches,
460 StringList &matches) {
463 llvm::StringRef line(current_line, cursor - current_line);
465 // Complete an LLDB command if the first character is a colon...
466 if (!line.empty() && line[0] == ':') {
467 Debugger &debugger = m_target.GetDebugger();
469 // auto complete LLDB commands
470 const char *lldb_current_line = line.substr(1).data();
471 return debugger.GetCommandInterpreter().HandleCompletion(
472 lldb_current_line, cursor, last_char, skip_first_n_matches, max_matches,
476 // Strip spaces from the line and see if we had only spaces
479 // Only spaces on this line, so just indent
480 matches.AppendString(m_indent_str);
484 std::string current_code;
485 current_code.append(m_code.CopyList());
487 IOHandlerEditline &editline = static_cast<IOHandlerEditline &>(io_handler);
488 const StringList *current_lines = editline.GetCurrentLines();
490 const uint32_t current_line_idx = editline.GetCurrentLineIndex();
492 if (current_line_idx < current_lines->GetSize()) {
493 for (uint32_t i = 0; i < current_line_idx; ++i) {
494 const char *line_cstr = current_lines->GetStringAtIndex(i);
496 current_code.append("\n");
497 current_code.append(line_cstr);
503 if (cursor > current_line) {
504 current_code.append("\n");
505 current_code.append(current_line, cursor - current_line);
508 return CompleteCode(current_code, matches);
511 bool QuitCommandOverrideCallback(void *baton, const char **argv) {
512 Target *target = (Target *)baton;
513 lldb::ProcessSP process_sp(target->GetProcessSP());
515 process_sp->Destroy(false);
516 process_sp->GetTarget().GetDebugger().ClearIOHandlers();
521 Error REPL::RunLoop() {
524 error = DoInitialization();
525 m_repl_source_path = GetSourcePath();
527 if (!error.Success())
530 Debugger &debugger = m_target.GetDebugger();
532 lldb::IOHandlerSP io_handler_sp(GetIOHandler());
534 FileSpec save_default_file;
535 uint32_t save_default_line = 0;
537 if (!m_repl_source_path.empty()) {
538 // Save the current default file and line
539 m_target.GetSourceManager().GetDefaultFileAndLine(save_default_file,
543 debugger.PushIOHandler(io_handler_sp);
545 // Check if we are in dedicated REPL mode where LLDB was start with the
547 // from the command line. Currently we know this by checking if the debugger
549 // has a IOHandler thread.
550 if (!debugger.HasIOHandlerThread()) {
551 // The debugger doesn't have an existing IOHandler thread, so this must be
552 // dedicated REPL mode...
553 m_dedicated_repl_mode = true;
554 debugger.StartIOHandlerThread();
555 llvm::StringRef command_name_str("quit");
556 CommandObject *cmd_obj =
557 debugger.GetCommandInterpreter().GetCommandObjectForCommand(
560 assert(command_name_str.empty());
561 cmd_obj->SetOverrideCallback(QuitCommandOverrideCallback, &m_target);
565 // Wait for the REPL command interpreter to get popped
566 io_handler_sp->WaitForPop();
568 if (m_dedicated_repl_mode) {
569 // If we were in dedicated REPL mode we would have started the
570 // IOHandler thread, and we should kill our process
571 lldb::ProcessSP process_sp = m_target.GetProcessSP();
572 if (process_sp && process_sp->IsAlive())
573 process_sp->Destroy(false);
575 // Wait for the IO handler thread to exit (TODO: don't do this if the IO
576 // handler thread already exists...)
577 debugger.JoinIOHandlerThread();
580 // Restore the default file and line
581 if (save_default_file && save_default_line != 0)
582 m_target.GetSourceManager().SetDefaultFileAndLine(save_default_file,