diff options
author | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
---|---|---|
committer | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
commit | b9c1b51e45b845debb76d8658edabca70ca56079 (patch) | |
tree | dfcb5a13ef2b014202340f47036da383eaee74aa /lldb/source/Expression/REPL.cpp | |
parent | d5aa73376966339caad04013510626ec2e42c760 (diff) | |
download | llvm-b9c1b51e45b845debb76d8658edabca70ca56079.zip llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.gz llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.bz2 |
*** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style. This kind of mass change has
*** two obvious implications:
Firstly, merging this particular commit into a downstream fork may be a huge
effort. Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit. The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):
find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;
The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.
Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit. There are alternatives available that will attempt
to look through this change and find the appropriate prior commit. YMMV.
llvm-svn: 280751
Diffstat (limited to 'lldb/source/Expression/REPL.cpp')
-rw-r--r-- | lldb/source/Expression/REPL.cpp | 1083 |
1 files changed, 509 insertions, 574 deletions
diff --git a/lldb/source/Expression/REPL.cpp b/lldb/source/Expression/REPL.cpp index 5d28c43..4685b26 100644 --- a/lldb/source/Expression/REPL.cpp +++ b/lldb/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(); - 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(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 + "> ", // 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; } - 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.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; } + } } - - // 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.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"); + } + } } - - 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(); + 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); + } + } + + // 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; } |