aboutsummaryrefslogtreecommitdiff
path: root/source/Expression/REPL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Expression/REPL.cpp')
-rw-r--r--source/Expression/REPL.cpp1083
1 files changed, 509 insertions, 574 deletions
diff --git a/source/Expression/REPL.cpp b/source/Expression/REPL.cpp
index 30f256002fc8..e404537562b7 100644
--- a/source/Expression/REPL.cpp
+++ b/source/Expression/REPL.cpp
@@ -11,11 +11,11 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "lldb/Expression/REPL.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Expression/ExpressionVariable.h"
-#include "lldb/Expression/REPL.h"
#include "lldb/Expression/UserExpression.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -26,625 +26,560 @@
using namespace lldb_private;
-REPL::REPL(LLVMCastKind kind, Target &target) :
- m_target(target),
- m_kind(kind)
-{
- // Make sure all option values have sane defaults
- Debugger &debugger = m_target.GetDebugger();
- CommandInterpreter &ci = debugger.GetCommandInterpreter();
- m_format_options.OptionParsingStarting(ci);
- m_varobj_options.OptionParsingStarting(ci);
- m_command_options.OptionParsingStarting(ci);
-
- // Default certain settings for REPL regardless of the global settings.
- m_command_options.unwind_on_error = false;
- m_command_options.ignore_breakpoints = false;
- m_command_options.debug = false;
+REPL::REPL(LLVMCastKind kind, Target &target) : m_target(target), m_kind(kind) {
+ // Make sure all option values have sane defaults
+ Debugger &debugger = m_target.GetDebugger();
+ auto exe_ctx = debugger.GetCommandInterpreter().GetExecutionContext();
+ m_format_options.OptionParsingStarting(&exe_ctx);
+ m_varobj_options.OptionParsingStarting(&exe_ctx);
+ m_command_options.OptionParsingStarting(&exe_ctx);
+
+ // Default certain settings for REPL regardless of the global settings.
+ m_command_options.unwind_on_error = false;
+ m_command_options.ignore_breakpoints = false;
+ m_command_options.debug = false;
}
REPL::~REPL() = default;
-lldb::REPLSP
-REPL::Create(Error &err, lldb::LanguageType language, Debugger *debugger, Target *target, const char *repl_options)
-{
- uint32_t idx = 0;
- lldb::REPLSP ret;
-
- while (REPLCreateInstance create_instance = PluginManager::GetREPLCreateCallbackAtIndex(idx++))
- {
- ret = (*create_instance)(err, language, debugger, target, repl_options);
- if (ret)
- {
- break;
- }
+lldb::REPLSP REPL::Create(Error &err, lldb::LanguageType language,
+ Debugger *debugger, Target *target,
+ const char *repl_options) {
+ uint32_t idx = 0;
+ lldb::REPLSP ret;
+
+ while (REPLCreateInstance create_instance =
+ PluginManager::GetREPLCreateCallbackAtIndex(idx++)) {
+ ret = (*create_instance)(err, language, debugger, target, repl_options);
+ if (ret) {
+ break;
}
-
- return ret;
+ }
+
+ return ret;
}
-std::string
-REPL::GetSourcePath()
-{
- ConstString file_basename = GetSourceFileBasename();
-
- FileSpec tmpdir_file_spec;
- if (HostInfo::GetLLDBPath (lldb::ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
- {
- tmpdir_file_spec.GetFilename().SetCString(file_basename.AsCString());
- m_repl_source_path = tmpdir_file_spec.GetPath();
- }
- else
- {
- tmpdir_file_spec = FileSpec("/tmp", false);
- tmpdir_file_spec.AppendPathComponent(file_basename.AsCString());
- }
-
- return tmpdir_file_spec.GetPath();
+std::string REPL::GetSourcePath() {
+ ConstString file_basename = GetSourceFileBasename();
+
+ FileSpec tmpdir_file_spec;
+ if (HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir,
+ tmpdir_file_spec)) {
+ tmpdir_file_spec.GetFilename().SetCString(file_basename.AsCString());
+ m_repl_source_path = tmpdir_file_spec.GetPath();
+ } else {
+ tmpdir_file_spec = FileSpec("/tmp", false);
+ tmpdir_file_spec.AppendPathComponent(file_basename.AsCString());
+ }
+
+ return tmpdir_file_spec.GetPath();
}
-lldb::IOHandlerSP
-REPL::GetIOHandler()
-{
- if (!m_io_handler_sp)
- {
- Debugger &debugger = m_target.GetDebugger();
- m_io_handler_sp.reset (new IOHandlerEditline (debugger,
- IOHandler::Type::REPL,
- "lldb-repl", // Name of input reader for history
- "> ", // prompt
- ". ", // Continuation prompt
- true, // Multi-line
- true, // The REPL prompt is always colored
- 1, // Line number
- *this));
-
- // Don't exit if CTRL+C is pressed
- static_cast<IOHandlerEditline *>(m_io_handler_sp.get())->SetInterruptExits(false);
-
- if (m_io_handler_sp->GetIsInteractive() && m_io_handler_sp->GetIsRealTerminal())
- {
- m_indent_str.assign (debugger.GetTabSize(), ' ');
- m_enable_auto_indent = debugger.GetAutoIndent();
- }
- else
- {
- m_indent_str.clear();
- m_enable_auto_indent = false;
- }
-
+lldb::IOHandlerSP REPL::GetIOHandler() {
+ if (!m_io_handler_sp) {
+ Debugger &debugger = m_target.GetDebugger();
+ m_io_handler_sp.reset(
+ new IOHandlerEditline(debugger, IOHandler::Type::REPL,
+ "lldb-repl", // Name of input reader for history
+ llvm::StringRef("> "), // prompt
+ llvm::StringRef(". "), // Continuation prompt
+ true, // Multi-line
+ true, // The REPL prompt is always colored
+ 1, // Line number
+ *this));
+
+ // Don't exit if CTRL+C is pressed
+ static_cast<IOHandlerEditline *>(m_io_handler_sp.get())
+ ->SetInterruptExits(false);
+
+ if (m_io_handler_sp->GetIsInteractive() &&
+ m_io_handler_sp->GetIsRealTerminal()) {
+ m_indent_str.assign(debugger.GetTabSize(), ' ');
+ m_enable_auto_indent = debugger.GetAutoIndent();
+ } else {
+ m_indent_str.clear();
+ m_enable_auto_indent = false;
}
- return m_io_handler_sp;
+ }
+ return m_io_handler_sp;
}
-void
-REPL::IOHandlerActivated (IOHandler &io_handler)
-{
- lldb::ProcessSP process_sp = m_target.GetProcessSP();
- if (process_sp && process_sp->IsAlive())
- return;
- lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
- error_sp->Printf("REPL requires a running target process.\n");
- io_handler.SetIsDone(true);
+void REPL::IOHandlerActivated(IOHandler &io_handler) {
+ lldb::ProcessSP process_sp = m_target.GetProcessSP();
+ if (process_sp && process_sp->IsAlive())
+ return;
+ lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
+ error_sp->Printf("REPL requires a running target process.\n");
+ io_handler.SetIsDone(true);
}
-bool
-REPL::IOHandlerInterrupt (IOHandler &io_handler)
-{
- return false;
-}
+bool REPL::IOHandlerInterrupt(IOHandler &io_handler) { return false; }
-void
-REPL::IOHandlerInputInterrupted (IOHandler &io_handler,
- std::string &line)
-{
+void REPL::IOHandlerInputInterrupted(IOHandler &io_handler, std::string &line) {
}
-const char *
-REPL::IOHandlerGetFixIndentationCharacters()
-{
- return (m_enable_auto_indent ? GetAutoIndentCharacters() : nullptr);
+const char *REPL::IOHandlerGetFixIndentationCharacters() {
+ return (m_enable_auto_indent ? GetAutoIndentCharacters() : nullptr);
}
-ConstString
-REPL::IOHandlerGetControlSequence (char ch)
-{
- if (ch == 'd')
- return ConstString(":quit\n");
- return ConstString();
+ConstString REPL::IOHandlerGetControlSequence(char ch) {
+ if (ch == 'd')
+ return ConstString(":quit\n");
+ return ConstString();
}
-const char *
-REPL::IOHandlerGetCommandPrefix ()
-{
- return ":";
-}
+const char *REPL::IOHandlerGetCommandPrefix() { return ":"; }
-const char *
-REPL::IOHandlerGetHelpPrologue ()
-{
- return "\nThe REPL (Read-Eval-Print-Loop) acts like an interpreter. "
- "Valid statements, expressions, and declarations are immediately compiled and executed.\n\n"
- "The complete set of LLDB debugging commands are also available as described below. Commands "
- "must be prefixed with a colon at the REPL prompt (:quit for example.) Typing just a colon "
- "followed by return will switch to the LLDB prompt.\n\n";
+const char *REPL::IOHandlerGetHelpPrologue() {
+ return "\nThe REPL (Read-Eval-Print-Loop) acts like an interpreter. "
+ "Valid statements, expressions, and declarations are immediately "
+ "compiled and executed.\n\n"
+ "The complete set of LLDB debugging commands are also available as "
+ "described below. Commands "
+ "must be prefixed with a colon at the REPL prompt (:quit for "
+ "example.) Typing just a colon "
+ "followed by return will switch to the LLDB prompt.\n\n";
}
-bool
-REPL::IOHandlerIsInputComplete (IOHandler &io_handler,
- StringList &lines)
-{
- // Check for meta command
- const size_t num_lines = lines.GetSize();
- if (num_lines == 1)
- {
- const char *first_line = lines.GetStringAtIndex(0);
- if (first_line[0] == ':')
- return true; // Meta command is a single line where that starts with ':'
- }
-
- // Check if REPL input is done
- std::string source_string (lines.CopyList());
- return SourceIsComplete(source_string);
+bool REPL::IOHandlerIsInputComplete(IOHandler &io_handler, StringList &lines) {
+ // Check for meta command
+ const size_t num_lines = lines.GetSize();
+ if (num_lines == 1) {
+ const char *first_line = lines.GetStringAtIndex(0);
+ if (first_line[0] == ':')
+ return true; // Meta command is a single line where that starts with ':'
+ }
+
+ // Check if REPL input is done
+ std::string source_string(lines.CopyList());
+ return SourceIsComplete(source_string);
}
-int
-REPL::CalculateActualIndentation (const StringList &lines)
-{
- std::string last_line = lines[lines.GetSize() - 1];
+int REPL::CalculateActualIndentation(const StringList &lines) {
+ std::string last_line = lines[lines.GetSize() - 1];
- int actual_indent = 0;
- for (char &ch : last_line)
- {
- if (ch != ' ') break;
- ++actual_indent;
- }
-
- return actual_indent;
+ int actual_indent = 0;
+ for (char &ch : last_line) {
+ if (ch != ' ')
+ break;
+ ++actual_indent;
+ }
+
+ return actual_indent;
}
-int
-REPL::IOHandlerFixIndentation (IOHandler &io_handler,
- const StringList &lines,
- int cursor_position)
-{
- if (!m_enable_auto_indent) return 0;
-
- if (!lines.GetSize())
- {
- return 0;
- }
-
- int tab_size = io_handler.GetDebugger().GetTabSize();
-
- lldb::offset_t desired_indent = GetDesiredIndentation(lines,
- cursor_position,
- tab_size);
-
- int actual_indent = REPL::CalculateActualIndentation(lines);
-
- if (desired_indent == LLDB_INVALID_OFFSET)
- return 0;
-
- return (int)desired_indent - actual_indent;
+int REPL::IOHandlerFixIndentation(IOHandler &io_handler,
+ const StringList &lines,
+ int cursor_position) {
+ if (!m_enable_auto_indent)
+ return 0;
+
+ if (!lines.GetSize()) {
+ return 0;
+ }
+
+ int tab_size = io_handler.GetDebugger().GetTabSize();
+
+ lldb::offset_t desired_indent =
+ GetDesiredIndentation(lines, cursor_position, tab_size);
+
+ int actual_indent = REPL::CalculateActualIndentation(lines);
+
+ if (desired_indent == LLDB_INVALID_OFFSET)
+ return 0;
+
+ return (int)desired_indent - actual_indent;
}
-void
-REPL::IOHandlerInputComplete (IOHandler &io_handler, std::string &code)
-{
- lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFile());
- lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
- bool extra_line = false;
- bool did_quit = false;
-
- if (code.empty())
- {
- m_code.AppendString("");
- static_cast<IOHandlerEditline &>(io_handler).SetBaseLineNumber(m_code.GetSize()+1);
- }
- else
- {
- Debugger &debugger = m_target.GetDebugger();
- CommandInterpreter &ci = debugger.GetCommandInterpreter();
- extra_line = ci.GetSpaceReplPrompts();
-
- ExecutionContext exe_ctx (m_target.GetProcessSP()->GetThreadList().GetSelectedThread()->GetSelectedFrame().get());
-
- lldb::ProcessSP process_sp(exe_ctx.GetProcessSP());
-
- if (code[0] == ':')
- {
- // Meta command
- // Strip the ':'
- code.erase(0, 1);
- if (Args::StripSpaces (code))
- {
- // "lldb" was followed by arguments, so just execute the command dump the results
-
- // Turn off prompt on quit in case the user types ":quit"
- const bool saved_prompt_on_quit = ci.GetPromptOnQuit();
- if (saved_prompt_on_quit)
- ci.SetPromptOnQuit(false);
-
- // Execute the command
- CommandReturnObject result;
- result.SetImmediateOutputStream(output_sp);
- result.SetImmediateErrorStream(error_sp);
- ci.HandleCommand(code.c_str(), eLazyBoolNo, result);
-
- if (saved_prompt_on_quit)
- ci.SetPromptOnQuit(true);
-
- if (result.GetStatus() == lldb::eReturnStatusQuit)
- {
- did_quit = true;
- io_handler.SetIsDone(true);
- if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter))
- {
- // We typed "quit" or an alias to quit so we need to check if the
- // command interpreter is above us and tell it that it is done as well
- // so we don't drop back into the command interpreter if we have already
- // quit
- lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler());
- if (io_handler_sp)
- io_handler_sp->SetIsDone(true);
- }
- }
- }
- else
- {
- // ":" was followed by no arguments, so push the LLDB command prompt
- if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter))
- {
- // If the user wants to get back to the command interpreter and the
- // command interpreter is what launched the REPL, then just let the
- // REPL exit and fall back to the command interpreter.
- io_handler.SetIsDone(true);
- }
- else
- {
- // The REPL wasn't launched the by the command interpreter, it is the
- // base IOHandler, so we need to get the command interpreter and
- lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler());
- if (io_handler_sp)
- {
- io_handler_sp->SetIsDone(false);
- debugger.PushIOHandler(ci.GetIOHandler());
- }
- }
- }
+void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
+ lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFile());
+ lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
+ bool extra_line = false;
+ bool did_quit = false;
+
+ if (code.empty()) {
+ m_code.AppendString("");
+ static_cast<IOHandlerEditline &>(io_handler)
+ .SetBaseLineNumber(m_code.GetSize() + 1);
+ } else {
+ Debugger &debugger = m_target.GetDebugger();
+ CommandInterpreter &ci = debugger.GetCommandInterpreter();
+ extra_line = ci.GetSpaceReplPrompts();
+
+ ExecutionContext exe_ctx(m_target.GetProcessSP()
+ ->GetThreadList()
+ .GetSelectedThread()
+ ->GetSelectedFrame()
+ .get());
+
+ lldb::ProcessSP process_sp(exe_ctx.GetProcessSP());
+
+ if (code[0] == ':') {
+ // Meta command
+ // Strip the ':'
+ code.erase(0, 1);
+ if (Args::StripSpaces(code)) {
+ // "lldb" was followed by arguments, so just execute the command dump
+ // the results
+
+ // Turn off prompt on quit in case the user types ":quit"
+ const bool saved_prompt_on_quit = ci.GetPromptOnQuit();
+ if (saved_prompt_on_quit)
+ ci.SetPromptOnQuit(false);
+
+ // Execute the command
+ CommandReturnObject result;
+ result.SetImmediateOutputStream(output_sp);
+ result.SetImmediateErrorStream(error_sp);
+ ci.HandleCommand(code.c_str(), eLazyBoolNo, result);
+
+ if (saved_prompt_on_quit)
+ ci.SetPromptOnQuit(true);
+
+ if (result.GetStatus() == lldb::eReturnStatusQuit) {
+ did_quit = true;
+ io_handler.SetIsDone(true);
+ if (debugger.CheckTopIOHandlerTypes(
+ IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) {
+ // We typed "quit" or an alias to quit so we need to check if the
+ // command interpreter is above us and tell it that it is done as
+ // well
+ // so we don't drop back into the command interpreter if we have
+ // already
+ // quit
+ lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
+ if (io_handler_sp)
+ io_handler_sp->SetIsDone(true);
+ }
}
- else
- {
- // Unwind any expression we might have been running in case our REPL
- // expression crashed and the user was looking around
- if (m_dedicated_repl_mode)
- {
- Thread *thread = exe_ctx.GetThreadPtr();
- if (thread && thread->UnwindInnermostExpression().Success())
- {
- thread->SetSelectedFrameByIndex(0, false);
- exe_ctx.SetFrameSP(thread->GetSelectedFrame());
- }
- }
-
- const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();
-
- EvaluateExpressionOptions expr_options;
- expr_options.SetCoerceToId(m_varobj_options.use_objc);
- expr_options.SetUnwindOnError(m_command_options.unwind_on_error);
- expr_options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints);
- expr_options.SetKeepInMemory(true);
- expr_options.SetUseDynamic(m_varobj_options.use_dynamic);
- expr_options.SetTryAllThreads(m_command_options.try_all_threads);
- expr_options.SetGenerateDebugInfo(true);
- expr_options.SetREPLEnabled (true);
- expr_options.SetColorizeErrors(colorize_err);
- expr_options.SetPoundLine(m_repl_source_path.c_str(), m_code.GetSize() + 1);
- if (m_command_options.timeout > 0)
- expr_options.SetTimeoutUsec(m_command_options.timeout);
- else
- expr_options.SetTimeoutUsec(0);
-
- expr_options.SetLanguage(GetLanguage());
-
- PersistentExpressionState *persistent_state = m_target.GetPersistentExpressionStateForLanguage(GetLanguage());
-
- const size_t var_count_before = persistent_state->GetSize();
-
- const char *expr_prefix = nullptr;
- lldb::ValueObjectSP result_valobj_sp;
- Error error;
- lldb::ModuleSP jit_module_sp;
- lldb::ExpressionResults execution_results = UserExpression::Evaluate (exe_ctx,
- expr_options,
- code.c_str(),
- expr_prefix,
- result_valobj_sp,
- error,
- 0, // Line offset
- nullptr, // Fixed Expression
- &jit_module_sp);
-
- //CommandInterpreter &ci = debugger.GetCommandInterpreter();
-
- if (process_sp && process_sp->IsAlive())
- {
- bool add_to_code = true;
- bool handled = false;
- if (result_valobj_sp)
- {
- lldb::Format format = m_format_options.GetFormat();
-
- if (result_valobj_sp->GetError().Success())
- {
- handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp);
- }
- else if (result_valobj_sp->GetError().GetError() == UserExpression::kNoResult)
- {
- if (format != lldb::eFormatVoid && debugger.GetNotifyVoid())
- {
- error_sp->PutCString("(void)\n");
- handled = true;
- }
- }
- }
-
- if (debugger.GetPrintDecls())
- {
- for (size_t vi = var_count_before, ve = persistent_state->GetSize();
- vi != ve;
- ++vi)
- {
- lldb::ExpressionVariableSP persistent_var_sp = persistent_state->GetVariableAtIndex(vi);
- lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject();
-
- PrintOneVariable(debugger, output_sp, valobj_sp, persistent_var_sp.get());
- }
- }
-
- if (!handled)
- {
- bool useColors = error_sp->GetFile().GetIsTerminalWithColors();
- switch (execution_results)
- {
- case lldb::eExpressionSetupError:
- case lldb::eExpressionParseError:
- add_to_code = false;
- LLVM_FALLTHROUGH;
- case lldb::eExpressionDiscarded:
- error_sp->Printf("%s\n", error.AsCString());
- break;
-
- case lldb::eExpressionCompleted:
- break;
- case lldb::eExpressionInterrupted:
- if (useColors) {
- error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
- error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
- }
- error_sp->Printf("Execution interrupted. ");
- if (useColors) error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
- error_sp->Printf("Enter code to recover and continue.\nEnter LLDB commands to investigate (type :help for assistance.)\n");
- break;
-
- case lldb::eExpressionHitBreakpoint:
- // Breakpoint was hit, drop into LLDB command interpreter
- if (useColors) {
- error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
- error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
- }
- output_sp->Printf("Execution stopped at breakpoint. ");
- if (useColors) error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
- output_sp->Printf("Enter LLDB commands to investigate (type help for assistance.)\n");
- {
- lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler());
- if (io_handler_sp)
- {
- io_handler_sp->SetIsDone(false);
- debugger.PushIOHandler(ci.GetIOHandler());
- }
- }
- break;
-
- case lldb::eExpressionTimedOut:
- error_sp->Printf("error: timeout\n");
- if (error.AsCString())
- error_sp->Printf("error: %s\n", error.AsCString());
- break;
- case lldb::eExpressionResultUnavailable:
- // Shoulnd't happen???
- error_sp->Printf("error: could not fetch result -- %s\n", error.AsCString());
- break;
- case lldb::eExpressionStoppedForDebug:
- // Shoulnd't happen???
- error_sp->Printf("error: stopped for debug -- %s\n", error.AsCString());
- break;
- }
- }
-
- if (add_to_code)
- {
- const uint32_t new_default_line = m_code.GetSize() + 1;
-
- m_code.SplitIntoLines(code);
-
- // Update our code on disk
- if (!m_repl_source_path.empty())
- {
- lldb_private::File file (m_repl_source_path.c_str(),
- File::eOpenOptionWrite | File::eOpenOptionTruncate | File::eOpenOptionCanCreate,
- lldb::eFilePermissionsFileDefault);
- std::string code (m_code.CopyList());
- code.append(1, '\n');
- size_t bytes_written = code.size();
- file.Write(code.c_str(), bytes_written);
- file.Close();
-
- // Now set the default file and line to the REPL source file
- m_target.GetSourceManager().SetDefaultFileAndLine(FileSpec(m_repl_source_path.c_str(), false), new_default_line);
- }
- static_cast<IOHandlerEditline &>(io_handler).SetBaseLineNumber(m_code.GetSize()+1);
- }
- if (extra_line)
- {
- fprintf(output_sp->GetFile().GetStream(), "\n");
- }
+ } else {
+ // ":" was followed by no arguments, so push the LLDB command prompt
+ if (debugger.CheckTopIOHandlerTypes(
+ IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) {
+ // If the user wants to get back to the command interpreter and the
+ // command interpreter is what launched the REPL, then just let the
+ // REPL exit and fall back to the command interpreter.
+ io_handler.SetIsDone(true);
+ } else {
+ // The REPL wasn't launched the by the command interpreter, it is the
+ // base IOHandler, so we need to get the command interpreter and
+ lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
+ if (io_handler_sp) {
+ io_handler_sp->SetIsDone(false);
+ debugger.PushIOHandler(ci.GetIOHandler());
+ }
+ }
+ }
+ } else {
+ // Unwind any expression we might have been running in case our REPL
+ // expression crashed and the user was looking around
+ if (m_dedicated_repl_mode) {
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (thread && thread->UnwindInnermostExpression().Success()) {
+ thread->SetSelectedFrameByIndex(0, false);
+ exe_ctx.SetFrameSP(thread->GetSelectedFrame());
+ }
+ }
+
+ const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();
+
+ EvaluateExpressionOptions expr_options;
+ expr_options.SetCoerceToId(m_varobj_options.use_objc);
+ expr_options.SetUnwindOnError(m_command_options.unwind_on_error);
+ expr_options.SetIgnoreBreakpoints(m_command_options.ignore_breakpoints);
+ expr_options.SetKeepInMemory(true);
+ expr_options.SetUseDynamic(m_varobj_options.use_dynamic);
+ expr_options.SetTryAllThreads(m_command_options.try_all_threads);
+ expr_options.SetGenerateDebugInfo(true);
+ expr_options.SetREPLEnabled(true);
+ expr_options.SetColorizeErrors(colorize_err);
+ expr_options.SetPoundLine(m_repl_source_path.c_str(),
+ m_code.GetSize() + 1);
+ if (m_command_options.timeout > 0)
+ expr_options.SetTimeout(std::chrono::microseconds(m_command_options.timeout));
+ else
+ expr_options.SetTimeout(llvm::None);
+
+ expr_options.SetLanguage(GetLanguage());
+
+ PersistentExpressionState *persistent_state =
+ m_target.GetPersistentExpressionStateForLanguage(GetLanguage());
+
+ const size_t var_count_before = persistent_state->GetSize();
+
+ const char *expr_prefix = nullptr;
+ lldb::ValueObjectSP result_valobj_sp;
+ Error error;
+ lldb::ModuleSP jit_module_sp;
+ lldb::ExpressionResults execution_results =
+ UserExpression::Evaluate(exe_ctx, expr_options, code.c_str(),
+ expr_prefix, result_valobj_sp, error,
+ 0, // Line offset
+ nullptr, // Fixed Expression
+ &jit_module_sp);
+
+ // CommandInterpreter &ci = debugger.GetCommandInterpreter();
+
+ if (process_sp && process_sp->IsAlive()) {
+ bool add_to_code = true;
+ bool handled = false;
+ if (result_valobj_sp) {
+ lldb::Format format = m_format_options.GetFormat();
+
+ if (result_valobj_sp->GetError().Success()) {
+ handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp);
+ } else if (result_valobj_sp->GetError().GetError() ==
+ UserExpression::kNoResult) {
+ if (format != lldb::eFormatVoid && debugger.GetNotifyVoid()) {
+ error_sp->PutCString("(void)\n");
+ handled = true;
}
+ }
}
-
- // Don't complain about the REPL process going away if we are in the process of quitting.
- if (!did_quit && (!process_sp || !process_sp->IsAlive()))
- {
- error_sp->Printf("error: REPL process is no longer alive, exiting REPL\n");
- io_handler.SetIsDone(true);
+
+ if (debugger.GetPrintDecls()) {
+ for (size_t vi = var_count_before, ve = persistent_state->GetSize();
+ vi != ve; ++vi) {
+ lldb::ExpressionVariableSP persistent_var_sp =
+ persistent_state->GetVariableAtIndex(vi);
+ lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject();
+
+ PrintOneVariable(debugger, output_sp, valobj_sp,
+ persistent_var_sp.get());
+ }
}
- }
-}
-int
-REPL::IOHandlerComplete (IOHandler &io_handler,
- const char *current_line,
- const char *cursor,
- const char *last_char,
- int skip_first_n_matches,
- int max_matches,
- StringList &matches)
-{
- matches.Clear();
-
- llvm::StringRef line (current_line, cursor - current_line);
-
- // Complete an LLDB command if the first character is a colon...
- if (!line.empty() && line[0] == ':')
- {
- Debugger &debugger = m_target.GetDebugger();
-
- // auto complete LLDB commands
- const char *lldb_current_line = line.substr(1).data();
- return debugger.GetCommandInterpreter().HandleCompletion (lldb_current_line,
- cursor,
- last_char,
- skip_first_n_matches,
- max_matches,
- matches);
- }
-
- // Strip spaces from the line and see if we had only spaces
- line = line.ltrim();
- if (line.empty())
- {
- // Only spaces on this line, so just indent
- matches.AppendString(m_indent_str);
- return 1;
- }
-
- std::string current_code;
- current_code.append(m_code.CopyList());
-
- IOHandlerEditline &editline = static_cast<IOHandlerEditline &>(io_handler);
- const StringList *current_lines = editline.GetCurrentLines();
- if (current_lines)
- {
- const uint32_t current_line_idx = editline.GetCurrentLineIndex();
-
- if (current_line_idx < current_lines->GetSize())
- {
- for (uint32_t i=0; i<current_line_idx; ++i)
+ if (!handled) {
+ bool useColors = error_sp->GetFile().GetIsTerminalWithColors();
+ switch (execution_results) {
+ case lldb::eExpressionSetupError:
+ case lldb::eExpressionParseError:
+ add_to_code = false;
+ LLVM_FALLTHROUGH;
+ case lldb::eExpressionDiscarded:
+ error_sp->Printf("%s\n", error.AsCString());
+ break;
+
+ case lldb::eExpressionCompleted:
+ break;
+ case lldb::eExpressionInterrupted:
+ if (useColors) {
+ error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
+ error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
+ }
+ error_sp->Printf("Execution interrupted. ");
+ if (useColors)
+ error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
+ error_sp->Printf("Enter code to recover and continue.\nEnter LLDB "
+ "commands to investigate (type :help for "
+ "assistance.)\n");
+ break;
+
+ case lldb::eExpressionHitBreakpoint:
+ // Breakpoint was hit, drop into LLDB command interpreter
+ if (useColors) {
+ error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
+ error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
+ }
+ output_sp->Printf("Execution stopped at breakpoint. ");
+ if (useColors)
+ error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
+ output_sp->Printf("Enter LLDB commands to investigate (type help "
+ "for assistance.)\n");
{
- const char *line_cstr = current_lines->GetStringAtIndex(i);
- if (line_cstr)
- {
- current_code.append("\n");
- current_code.append (line_cstr);
- }
+ lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
+ if (io_handler_sp) {
+ io_handler_sp->SetIsDone(false);
+ debugger.PushIOHandler(ci.GetIOHandler());
+ }
}
+ break;
+
+ case lldb::eExpressionTimedOut:
+ error_sp->Printf("error: timeout\n");
+ if (error.AsCString())
+ error_sp->Printf("error: %s\n", error.AsCString());
+ break;
+ case lldb::eExpressionResultUnavailable:
+ // Shoulnd't happen???
+ error_sp->Printf("error: could not fetch result -- %s\n",
+ error.AsCString());
+ break;
+ case lldb::eExpressionStoppedForDebug:
+ // Shoulnd't happen???
+ error_sp->Printf("error: stopped for debug -- %s\n",
+ error.AsCString());
+ break;
+ }
}
+
+ if (add_to_code) {
+ const uint32_t new_default_line = m_code.GetSize() + 1;
+
+ m_code.SplitIntoLines(code);
+
+ // Update our code on disk
+ if (!m_repl_source_path.empty()) {
+ lldb_private::File file(m_repl_source_path.c_str(),
+ File::eOpenOptionWrite |
+ File::eOpenOptionTruncate |
+ File::eOpenOptionCanCreate,
+ lldb::eFilePermissionsFileDefault);
+ std::string code(m_code.CopyList());
+ code.append(1, '\n');
+ size_t bytes_written = code.size();
+ file.Write(code.c_str(), bytes_written);
+ file.Close();
+
+ // Now set the default file and line to the REPL source file
+ m_target.GetSourceManager().SetDefaultFileAndLine(
+ FileSpec(m_repl_source_path, false), new_default_line);
+ }
+ static_cast<IOHandlerEditline &>(io_handler)
+ .SetBaseLineNumber(m_code.GetSize() + 1);
+ }
+ if (extra_line) {
+ fprintf(output_sp->GetFile().GetStream(), "\n");
+ }
+ }
}
-
- if (cursor > current_line)
- {
- current_code.append("\n");
- current_code.append(current_line, cursor - current_line);
- }
-
- return CompleteCode(current_code, matches);
-}
-bool
-QuitCommandOverrideCallback(void *baton, const char **argv)
-{
- Target *target = (Target *)baton;
- lldb::ProcessSP process_sp (target->GetProcessSP());
- if (process_sp)
- {
- process_sp->Destroy(false);
- process_sp->GetTarget().GetDebugger().ClearIOHandlers();
+ // Don't complain about the REPL process going away if we are in the process
+ // of quitting.
+ if (!did_quit && (!process_sp || !process_sp->IsAlive())) {
+ error_sp->Printf(
+ "error: REPL process is no longer alive, exiting REPL\n");
+ io_handler.SetIsDone(true);
}
- return false;
+ }
}
-Error
-REPL::RunLoop ()
-{
- Error error;
-
- error = DoInitialization();
- m_repl_source_path = GetSourcePath();
-
- if (!error.Success())
- return error;
-
+int REPL::IOHandlerComplete(IOHandler &io_handler, const char *current_line,
+ const char *cursor, const char *last_char,
+ int skip_first_n_matches, int max_matches,
+ StringList &matches) {
+ matches.Clear();
+
+ llvm::StringRef line(current_line, cursor - current_line);
+
+ // Complete an LLDB command if the first character is a colon...
+ if (!line.empty() && line[0] == ':') {
Debugger &debugger = m_target.GetDebugger();
-
- lldb::IOHandlerSP io_handler_sp (GetIOHandler());
-
- FileSpec save_default_file;
- uint32_t save_default_line = 0;
-
- if (!m_repl_source_path.empty())
- {
- // Save the current default file and line
- m_target.GetSourceManager().GetDefaultFileAndLine(save_default_file, save_default_line);
- }
-
- debugger.PushIOHandler(io_handler_sp);
-
- // Check if we are in dedicated REPL mode where LLDB was start with the "--repl" option
- // from the command line. Currently we know this by checking if the debugger already
- // has a IOHandler thread.
- if (!debugger.HasIOHandlerThread())
- {
- // The debugger doesn't have an existing IOHandler thread, so this must be
- // dedicated REPL mode...
- m_dedicated_repl_mode = true;
- debugger.StartIOHandlerThread();
- std::string command_name_str ("quit");
- CommandObject *cmd_obj = debugger.GetCommandInterpreter().GetCommandObjectForCommand(command_name_str);
- if (cmd_obj)
- {
- assert(command_name_str.empty());
- cmd_obj->SetOverrideCallback (QuitCommandOverrideCallback, &m_target);
+
+ // auto complete LLDB commands
+ const char *lldb_current_line = line.substr(1).data();
+ return debugger.GetCommandInterpreter().HandleCompletion(
+ lldb_current_line, cursor, last_char, skip_first_n_matches, max_matches,
+ matches);
+ }
+
+ // Strip spaces from the line and see if we had only spaces
+ line = line.ltrim();
+ if (line.empty()) {
+ // Only spaces on this line, so just indent
+ matches.AppendString(m_indent_str);
+ return 1;
+ }
+
+ std::string current_code;
+ current_code.append(m_code.CopyList());
+
+ IOHandlerEditline &editline = static_cast<IOHandlerEditline &>(io_handler);
+ const StringList *current_lines = editline.GetCurrentLines();
+ if (current_lines) {
+ const uint32_t current_line_idx = editline.GetCurrentLineIndex();
+
+ if (current_line_idx < current_lines->GetSize()) {
+ for (uint32_t i = 0; i < current_line_idx; ++i) {
+ const char *line_cstr = current_lines->GetStringAtIndex(i);
+ if (line_cstr) {
+ current_code.append("\n");
+ current_code.append(line_cstr);
}
+ }
}
-
- // Wait for the REPL command interpreter to get popped
- io_handler_sp->WaitForPop();
-
- if (m_dedicated_repl_mode)
- {
- // If we were in dedicated REPL mode we would have started the
- // IOHandler thread, and we should kill our process
- lldb::ProcessSP process_sp = m_target.GetProcessSP();
- if (process_sp && process_sp->IsAlive())
- process_sp->Destroy(false);
-
- // Wait for the IO handler thread to exit (TODO: don't do this if the IO handler thread already exists...)
- debugger.JoinIOHandlerThread();
- }
-
- // Restore the default file and line
- if (save_default_file && save_default_line != 0)
- m_target.GetSourceManager().SetDefaultFileAndLine(save_default_file, save_default_line);
+ }
+
+ if (cursor > current_line) {
+ current_code.append("\n");
+ current_code.append(current_line, cursor - current_line);
+ }
+
+ return CompleteCode(current_code, matches);
+}
+
+bool QuitCommandOverrideCallback(void *baton, const char **argv) {
+ Target *target = (Target *)baton;
+ lldb::ProcessSP process_sp(target->GetProcessSP());
+ if (process_sp) {
+ process_sp->Destroy(false);
+ process_sp->GetTarget().GetDebugger().ClearIOHandlers();
+ }
+ return false;
+}
+
+Error REPL::RunLoop() {
+ Error error;
+
+ error = DoInitialization();
+ m_repl_source_path = GetSourcePath();
+
+ if (!error.Success())
return error;
+
+ Debugger &debugger = m_target.GetDebugger();
+
+ lldb::IOHandlerSP io_handler_sp(GetIOHandler());
+
+ FileSpec save_default_file;
+ uint32_t save_default_line = 0;
+
+ if (!m_repl_source_path.empty()) {
+ // Save the current default file and line
+ m_target.GetSourceManager().GetDefaultFileAndLine(save_default_file,
+ save_default_line);
+ }
+
+ debugger.PushIOHandler(io_handler_sp);
+
+ // Check if we are in dedicated REPL mode where LLDB was start with the
+ // "--repl" option
+ // from the command line. Currently we know this by checking if the debugger
+ // already
+ // has a IOHandler thread.
+ if (!debugger.HasIOHandlerThread()) {
+ // The debugger doesn't have an existing IOHandler thread, so this must be
+ // dedicated REPL mode...
+ m_dedicated_repl_mode = true;
+ debugger.StartIOHandlerThread();
+ llvm::StringRef command_name_str("quit");
+ CommandObject *cmd_obj =
+ debugger.GetCommandInterpreter().GetCommandObjectForCommand(
+ command_name_str);
+ if (cmd_obj) {
+ assert(command_name_str.empty());
+ cmd_obj->SetOverrideCallback(QuitCommandOverrideCallback, &m_target);
+ }
+ }
+
+ // Wait for the REPL command interpreter to get popped
+ io_handler_sp->WaitForPop();
+
+ if (m_dedicated_repl_mode) {
+ // If we were in dedicated REPL mode we would have started the
+ // IOHandler thread, and we should kill our process
+ lldb::ProcessSP process_sp = m_target.GetProcessSP();
+ if (process_sp && process_sp->IsAlive())
+ process_sp->Destroy(false);
+
+ // Wait for the IO handler thread to exit (TODO: don't do this if the IO
+ // handler thread already exists...)
+ debugger.JoinIOHandlerThread();
+ }
+
+ // Restore the default file and line
+ if (save_default_file && save_default_line != 0)
+ m_target.GetSourceManager().SetDefaultFileAndLine(save_default_file,
+ save_default_line);
+ return error;
}