diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp')
-rw-r--r-- | contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp | 371 |
1 files changed, 202 insertions, 169 deletions
diff --git a/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp b/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp index 8b24c72d7733..f78fc728c898 100644 --- a/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp @@ -146,73 +146,73 @@ CommandInterpreter::CommandInterpreter(Debugger &debugger, bool CommandInterpreter::GetExpandRegexAliases() const { const uint32_t idx = ePropertyExpandRegexAliases; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_interpreter_properties[idx].default_uint_value != 0); } bool CommandInterpreter::GetPromptOnQuit() const { const uint32_t idx = ePropertyPromptOnQuit; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_interpreter_properties[idx].default_uint_value != 0); } void CommandInterpreter::SetPromptOnQuit(bool enable) { const uint32_t idx = ePropertyPromptOnQuit; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable); + SetPropertyAtIndex(idx, enable); } bool CommandInterpreter::GetSaveSessionOnQuit() const { const uint32_t idx = ePropertySaveSessionOnQuit; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_interpreter_properties[idx].default_uint_value != 0); } void CommandInterpreter::SetSaveSessionOnQuit(bool enable) { const uint32_t idx = ePropertySaveSessionOnQuit; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable); + SetPropertyAtIndex(idx, enable); } bool CommandInterpreter::GetOpenTranscriptInEditor() const { const uint32_t idx = ePropertyOpenTranscriptInEditor; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_interpreter_properties[idx].default_uint_value != 0); } void CommandInterpreter::SetOpenTranscriptInEditor(bool enable) { const uint32_t idx = ePropertyOpenTranscriptInEditor; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable); + SetPropertyAtIndex(idx, enable); } FileSpec CommandInterpreter::GetSaveSessionDirectory() const { const uint32_t idx = ePropertySaveSessionDirectory; - return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); + return GetPropertyAtIndexAs<FileSpec>(idx, {}); } void CommandInterpreter::SetSaveSessionDirectory(llvm::StringRef path) { const uint32_t idx = ePropertySaveSessionDirectory; - m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, path); + SetPropertyAtIndex(idx, path); } bool CommandInterpreter::GetEchoCommands() const { const uint32_t idx = ePropertyEchoCommands; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_interpreter_properties[idx].default_uint_value != 0); } void CommandInterpreter::SetEchoCommands(bool enable) { const uint32_t idx = ePropertyEchoCommands; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable); + SetPropertyAtIndex(idx, enable); } bool CommandInterpreter::GetEchoCommentCommands() const { const uint32_t idx = ePropertyEchoCommentCommands; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_interpreter_properties[idx].default_uint_value != 0); } void CommandInterpreter::SetEchoCommentCommands(bool enable) { const uint32_t idx = ePropertyEchoCommentCommands; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable); + SetPropertyAtIndex(idx, enable); } void CommandInterpreter::AllowExitCodeOnQuit(bool allow) { @@ -246,26 +246,26 @@ void CommandInterpreter::ResolveCommand(const char *command_line, bool CommandInterpreter::GetStopCmdSourceOnError() const { const uint32_t idx = ePropertyStopCmdSourceOnError; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_interpreter_properties[idx].default_uint_value != 0); } bool CommandInterpreter::GetSpaceReplPrompts() const { const uint32_t idx = ePropertySpaceReplPrompts; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_interpreter_properties[idx].default_uint_value != 0); } bool CommandInterpreter::GetRepeatPreviousCommand() const { const uint32_t idx = ePropertyRepeatPreviousCommand; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_interpreter_properties[idx].default_uint_value != 0); } bool CommandInterpreter::GetRequireCommandOverwrite() const { const uint32_t idx = ePropertyRequireCommandOverwrite; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); + return GetPropertyAtIndexAs<bool>( + idx, g_interpreter_properties[idx].default_uint_value != 0); } void CommandInterpreter::Initialize() { @@ -413,17 +413,21 @@ void CommandInterpreter::Initialize() { alias_arguments_vector_sp = std::make_shared<OptionArgVector>(); - cmd_obj_sp = GetCommandSPExact("expression"); + cmd_obj_sp = GetCommandSPExact("dwim-print"); if (cmd_obj_sp) { AddAlias("p", cmd_obj_sp, "--")->SetHelpLong(""); AddAlias("print", cmd_obj_sp, "--")->SetHelpLong(""); - AddAlias("call", cmd_obj_sp, "--")->SetHelpLong(""); if (auto *po = AddAlias("po", cmd_obj_sp, "-O --")) { po->SetHelp("Evaluate an expression on the current thread. Displays any " "returned value with formatting " "controlled by the type's author."); po->SetHelpLong(""); } + } + + cmd_obj_sp = GetCommandSPExact("expression"); + if (cmd_obj_sp) { + AddAlias("call", cmd_obj_sp, "--")->SetHelpLong(""); CommandAlias *parray_alias = AddAlias("parray", cmd_obj_sp, "--element-count %1 --"); if (parray_alias) { @@ -612,10 +616,7 @@ void CommandInterpreter::LoadCommandDictionary() { "current file\n" " // containing text 'break " "here'.\n", - 3, - CommandCompletions::eSymbolCompletion | - CommandCompletions::eSourceFileCompletion, - false)); + lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false)); if (break_regex_cmd_up) { bool success = true; @@ -666,10 +667,7 @@ void CommandInterpreter::LoadCommandDictionary() { "current file\n" " // containing text 'break " "here'.\n", - 2, - CommandCompletions::eSymbolCompletion | - CommandCompletions::eSourceFileCompletion, - false)); + lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false)); if (tbreak_regex_cmd_up) { bool success = true; @@ -694,7 +692,7 @@ void CommandInterpreter::LoadCommandDictionary() { std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up( new CommandObjectRegexCommand( *this, "_regexp-attach", "Attach to process by ID or name.", - "_regexp-attach <pid> | <process-name>", 2, 0, false)); + "_regexp-attach <pid> | <process-name>", 0, false)); if (attach_regex_cmd_up) { if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$", "process attach --pid %1") && @@ -716,7 +714,7 @@ void CommandInterpreter::LoadCommandDictionary() { "Select a newer stack frame. Defaults to " "moving one frame, a numeric argument can " "specify an arbitrary number.", - "_regexp-down [<count>]", 2, 0, false)); + "_regexp-down [<count>]", 0, false)); if (down_regex_cmd_up) { if (down_regex_cmd_up->AddRegexCommand("^$", "frame select -r -1") && down_regex_cmd_up->AddRegexCommand("^([0-9]+)$", @@ -732,7 +730,7 @@ void CommandInterpreter::LoadCommandDictionary() { *this, "_regexp-up", "Select an older stack frame. Defaults to moving one " "frame, a numeric argument can specify an arbitrary number.", - "_regexp-up [<count>]", 2, 0, false)); + "_regexp-up [<count>]", 0, false)); if (up_regex_cmd_up) { if (up_regex_cmd_up->AddRegexCommand("^$", "frame select -r 1") && up_regex_cmd_up->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) { @@ -746,7 +744,7 @@ void CommandInterpreter::LoadCommandDictionary() { new CommandObjectRegexCommand( *this, "_regexp-display", "Evaluate an expression at every stop (see 'help target stop-hook'.)", - "_regexp-display expression", 2, 0, false)); + "_regexp-display expression", 0, false)); if (display_regex_cmd_up) { if (display_regex_cmd_up->AddRegexCommand( "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) { @@ -760,7 +758,7 @@ void CommandInterpreter::LoadCommandDictionary() { new CommandObjectRegexCommand(*this, "_regexp-undisplay", "Stop displaying expression at every " "stop (specified by stop-hook index.)", - "_regexp-undisplay stop-hook-number", 2, 0, + "_regexp-undisplay stop-hook-number", 0, false)); if (undisplay_regex_cmd_up) { if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$", @@ -778,7 +776,7 @@ void CommandInterpreter::LoadCommandDictionary() { "If no host is specifed, localhost is assumed.\n" "gdb-remote is an abbreviation for 'process connect --plugin " "gdb-remote connect://<hostname>:<port>'\n", - "gdb-remote [<hostname>:]<portnum>", 2, 0, false)); + "gdb-remote [<hostname>:]<portnum>", 0, false)); if (connect_gdb_remote_cmd_up) { if (connect_gdb_remote_cmd_up->AddRegexCommand( "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$", @@ -798,7 +796,7 @@ void CommandInterpreter::LoadCommandDictionary() { "If no UDP port is specified, port 41139 is assumed.\n" "kdp-remote is an abbreviation for 'process connect --plugin " "kdp-remote udp://<hostname>:<port>'\n", - "kdp-remote <hostname>[:<portnum>]", 2, 0, false)); + "kdp-remote <hostname>[:<portnum>]", 0, false)); if (connect_kdp_remote_cmd_up) { if (connect_kdp_remote_cmd_up->AddRegexCommand( "^([^:]+:[[:digit:]]+)$", @@ -818,7 +816,7 @@ void CommandInterpreter::LoadCommandDictionary() { "frames. The argument 'all' displays all threads. Use 'settings" " set frame-format' to customize the printing of individual frames " "and 'settings set thread-format' to customize the thread header.", - "bt [<digit> | all]", 2, 0, false)); + "bt [<digit> | all]", 0, false)); if (bt_regex_cmd_up) { // accept but don't document "bt -c <number>" -- before bt was a regex // command if you wanted to backtrace three frames you would do "bt -c 3" @@ -847,7 +845,7 @@ void CommandInterpreter::LoadCommandDictionary() { "_regexp-list 0x<address> // List around specified address\n" "_regexp-list -[<count>] // List previous <count> lines\n" "_regexp-list // List subsequent lines", - 2, CommandCompletions::eSourceFileCompletion, false)); + lldb::eSourceFileCompletion, false)); if (list_regex_cmd_up) { if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$", "source list --line %1") && @@ -879,7 +877,7 @@ void CommandInterpreter::LoadCommandDictionary() { "\n" "_regexp-env // Show environment\n" "_regexp-env <name>=<value> // Set an environment variable", - 2, 0, false)); + 0, false)); if (env_regex_cmd_up) { if (env_regex_cmd_up->AddRegexCommand("^$", "settings show target.env-vars") && @@ -899,7 +897,7 @@ void CommandInterpreter::LoadCommandDictionary() { "_regexp-jump +<line-offset> | -<line-offset>\n" "_regexp-jump <file>:<line>\n" "_regexp-jump *<addr>\n", - 2, 0, false)); + 0, false)); if (jump_regex_cmd_up) { if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$", "thread jump --addr %1") && @@ -1372,11 +1370,12 @@ bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) { return false; } -bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd) { +bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd, bool force) { auto pos = m_command_dict.find(std::string(cmd)); if (pos != m_command_dict.end()) { - if (pos->second->IsRemovable()) { - // Only regular expression objects or python commands are removable + if (force || pos->second->IsRemovable()) { + // Only regular expression objects or python commands are removable under + // normal circumstances. m_command_dict.erase(pos); return true; } @@ -1687,20 +1686,19 @@ CommandObject *CommandInterpreter::BuildAliasResult( return nullptr; } llvm::StringRef arg_text = entry.ref(); - if (strpos - start_fudge + arg_text.size() + len_fudge - > raw_input_string.size()) { + if (strpos - start_fudge + arg_text.size() + len_fudge > + raw_input_string.size()) { result.AppendError("Unmatched quote at command end."); - return nullptr; + return nullptr; } raw_input_string = raw_input_string.erase( - strpos - start_fudge, + strpos - start_fudge, strlen(cmd_args.GetArgumentAtIndex(index)) + len_fudge); } if (quote_char == '\0') result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index)); else - result_str.Printf("%c%s%c", quote_char, - entry.c_str(), quote_char); + result_str.Printf("%c%s%c", quote_char, entry.c_str(), quote_char); } } @@ -1748,112 +1746,124 @@ Status CommandInterpreter::PreprocessCommand(std::string &command) { std::string expr_str(command, expr_content_start, end_backtick - expr_content_start); + error = PreprocessToken(expr_str); + // We always stop at the first error: + if (error.Fail()) + break; - ExecutionContext exe_ctx(GetExecutionContext()); + command.erase(start_backtick, end_backtick - start_backtick + 1); + command.insert(start_backtick, std::string(expr_str)); + pos = start_backtick + expr_str.size(); + } + return error; +} - // Get a dummy target to allow for calculator mode while processing - // backticks. This also helps break the infinite loop caused when target is - // null. - Target *exe_target = exe_ctx.GetTargetPtr(); - Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget(); - - ValueObjectSP expr_result_valobj_sp; - - EvaluateExpressionOptions options; - options.SetCoerceToId(false); - options.SetUnwindOnError(true); - options.SetIgnoreBreakpoints(true); - options.SetKeepInMemory(false); - options.SetTryAllThreads(true); - options.SetTimeout(std::nullopt); - - ExpressionResults expr_result = - target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(), - expr_result_valobj_sp, options); - - if (expr_result == eExpressionCompleted) { - Scalar scalar; - if (expr_result_valobj_sp) - expr_result_valobj_sp = - expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable( - expr_result_valobj_sp->GetDynamicValueType(), true); - if (expr_result_valobj_sp->ResolveValue(scalar)) { - command.erase(start_backtick, end_backtick - start_backtick + 1); - StreamString value_strm; - const bool show_type = false; - scalar.GetValue(&value_strm, show_type); - size_t value_string_size = value_strm.GetSize(); - if (value_string_size) { - command.insert(start_backtick, std::string(value_strm.GetString())); - pos = start_backtick + value_string_size; - continue; - } else { - error.SetErrorStringWithFormat("expression value didn't result " - "in a scalar value for the " - "expression '%s'", - expr_str.c_str()); - break; - } - } else { - error.SetErrorStringWithFormat("expression value didn't result " - "in a scalar value for the " - "expression '%s'", - expr_str.c_str()); - break; - } +Status +CommandInterpreter::PreprocessToken(std::string &expr_str) { + Status error; + ExecutionContext exe_ctx(GetExecutionContext()); - continue; - } + // Get a dummy target to allow for calculator mode while processing + // backticks. This also helps break the infinite loop caused when target is + // null. + Target *exe_target = exe_ctx.GetTargetPtr(); + Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget(); - if (expr_result_valobj_sp) - error = expr_result_valobj_sp->GetError(); + ValueObjectSP expr_result_valobj_sp; - if (error.Success()) { - switch (expr_result) { - case eExpressionSetupError: - error.SetErrorStringWithFormat( - "expression setup error for the expression '%s'", expr_str.c_str()); - break; - case eExpressionParseError: - error.SetErrorStringWithFormat( - "expression parse error for the expression '%s'", expr_str.c_str()); - break; - case eExpressionResultUnavailable: - error.SetErrorStringWithFormat( - "expression error fetching result for the expression '%s'", - expr_str.c_str()); - break; - case eExpressionCompleted: - break; - case eExpressionDiscarded: - error.SetErrorStringWithFormat( - "expression discarded for the expression '%s'", expr_str.c_str()); - break; - case eExpressionInterrupted: - error.SetErrorStringWithFormat( - "expression interrupted for the expression '%s'", expr_str.c_str()); - break; - case eExpressionHitBreakpoint: - error.SetErrorStringWithFormat( - "expression hit breakpoint for the expression '%s'", - expr_str.c_str()); - break; - case eExpressionTimedOut: - error.SetErrorStringWithFormat( - "expression timed out for the expression '%s'", expr_str.c_str()); - break; - case eExpressionStoppedForDebug: - error.SetErrorStringWithFormat("expression stop at entry point " - "for debugging for the " + EvaluateExpressionOptions options; + options.SetCoerceToId(false); + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetKeepInMemory(false); + options.SetTryAllThreads(true); + options.SetTimeout(std::nullopt); + + ExpressionResults expr_result = + target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(), + expr_result_valobj_sp, options); + + if (expr_result == eExpressionCompleted) { + Scalar scalar; + if (expr_result_valobj_sp) + expr_result_valobj_sp = + expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable( + expr_result_valobj_sp->GetDynamicValueType(), true); + if (expr_result_valobj_sp->ResolveValue(scalar)) { + + StreamString value_strm; + const bool show_type = false; + scalar.GetValue(&value_strm, show_type); + size_t value_string_size = value_strm.GetSize(); + if (value_string_size) { + expr_str = value_strm.GetData(); + } else { + error.SetErrorStringWithFormat("expression value didn't result " + "in a scalar value for the " "expression '%s'", expr_str.c_str()); - break; - case eExpressionThreadVanished: - error.SetErrorStringWithFormat( - "expression thread vanished for the expression '%s'", - expr_str.c_str()); - break; } + } else { + error.SetErrorStringWithFormat("expression value didn't result " + "in a scalar value for the " + "expression '%s'", + expr_str.c_str()); + } + return error; + } + + // If we have an error from the expression evaluation it will be in the + // ValueObject error, which won't be success and we will just report it. + // But if for some reason we didn't get a value object at all, then we will + // make up some helpful errors from the expression result. + if (expr_result_valobj_sp) + error = expr_result_valobj_sp->GetError(); + + if (error.Success()) { + switch (expr_result) { + case eExpressionSetupError: + error.SetErrorStringWithFormat( + "expression setup error for the expression '%s'", expr_str.c_str()); + break; + case eExpressionParseError: + error.SetErrorStringWithFormat( + "expression parse error for the expression '%s'", expr_str.c_str()); + break; + case eExpressionResultUnavailable: + error.SetErrorStringWithFormat( + "expression error fetching result for the expression '%s'", + expr_str.c_str()); + break; + case eExpressionCompleted: + break; + case eExpressionDiscarded: + error.SetErrorStringWithFormat( + "expression discarded for the expression '%s'", expr_str.c_str()); + break; + case eExpressionInterrupted: + error.SetErrorStringWithFormat( + "expression interrupted for the expression '%s'", expr_str.c_str()); + break; + case eExpressionHitBreakpoint: + error.SetErrorStringWithFormat( + "expression hit breakpoint for the expression '%s'", + expr_str.c_str()); + break; + case eExpressionTimedOut: + error.SetErrorStringWithFormat( + "expression timed out for the expression '%s'", expr_str.c_str()); + break; + case eExpressionStoppedForDebug: + error.SetErrorStringWithFormat("expression stop at entry point " + "for debugging for the " + "expression '%s'", + expr_str.c_str()); + break; + case eExpressionThreadVanished: + error.SetErrorStringWithFormat( + "expression thread vanished for the expression '%s'", + expr_str.c_str()); + break; } } return error; @@ -1872,8 +1882,8 @@ bool CommandInterpreter::HandleCommand(const char *command_line, bool CommandInterpreter::HandleCommand(const char *command_line, LazyBool lazy_add_to_history, - CommandReturnObject &result) { - + CommandReturnObject &result, + bool force_repeat_command) { std::string command_string(command_line); std::string original_command_string(command_line); @@ -1884,8 +1894,8 @@ bool CommandInterpreter::HandleCommand(const char *command_line, LLDB_LOGF(log, "Processing command: %s", command_line); LLDB_SCOPED_TIMERF("Processing command: %s.", command_line); - if (WasInterrupted()) { - result.AppendError("interrupted"); + if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted initiating command")) { + result.AppendError("... Interrupted"); return false; } @@ -1968,11 +1978,11 @@ bool CommandInterpreter::HandleCommand(const char *command_line, CommandObject *cmd_obj = ResolveCommandImpl(command_string, result); - // We have to preprocess the whole command string for Raw commands, since we + // We have to preprocess the whole command string for Raw commands, since we // don't know the structure of the command. For parsed commands, we only // treat backticks as quote characters specially. // FIXME: We probably want to have raw commands do their own preprocessing. - // For instance, I don't think people expect substitution in expr expressions. + // For instance, I don't think people expect substitution in expr expressions. if (cmd_obj && cmd_obj->WantsRawCommandString()) { Status error(PreprocessCommand(command_string)); @@ -2002,17 +2012,26 @@ bool CommandInterpreter::HandleCommand(const char *command_line, // arguments. if (cmd_obj != nullptr) { + bool generate_repeat_command = add_to_history; // If we got here when empty_command was true, then this command is a // stored "repeat command" which we should give a chance to produce it's // repeat command, even though we don't add repeat commands to the history. - if (add_to_history || empty_command) { + generate_repeat_command |= empty_command; + // For `command regex`, the regex command (ex `bt`) is added to history, but + // the resolved command (ex `thread backtrace`) is _not_ added to history. + // However, the resolved command must be given the opportunity to provide a + // repeat command. `force_repeat_command` supports this case. + generate_repeat_command |= force_repeat_command; + if (generate_repeat_command) { Args command_args(command_string); std::optional<std::string> repeat_command = cmd_obj->GetRepeatCommand(command_args, 0); - if (repeat_command) + if (repeat_command) { + LLDB_LOGF(log, "Repeat command: %s", repeat_command->data()); m_repeat_command.assign(*repeat_command); - else + } else { m_repeat_command.assign(original_command_string); + } } if (add_to_history) @@ -2544,7 +2563,7 @@ void CommandInterpreter::HandleCommands(const StringList &commands, m_debugger.SetAsyncExecution(false); } - for (size_t idx = 0; idx < num_lines && !WasInterrupted(); idx++) { + for (size_t idx = 0; idx < num_lines; idx++) { const char *cmd = commands.GetStringAtIndex(idx); if (cmd[0] == '\0') continue; @@ -3024,6 +3043,9 @@ bool CommandInterpreter::InterruptCommand() { } bool CommandInterpreter::WasInterrupted() const { + if (!m_debugger.IsIOHandlerThreadCurrentThread()) + return false; + bool was_interrupted = (m_command_state == CommandHandlingState::eInterrupted); lldbassert(!was_interrupted || m_iohandler_nesting_level > 0); @@ -3037,7 +3059,8 @@ void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler, lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP() : io_handler.GetErrorStreamFileSP(); // Split the output into lines and poll for interrupt requests - while (!str.empty() && !WasInterrupted()) { + bool had_output = !str.empty(); + while (!str.empty()) { llvm::StringRef line; std::tie(line, str) = str.split('\n'); { @@ -3048,7 +3071,8 @@ void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler, } std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex()); - if (!str.empty()) + if (had_output && INTERRUPT_REQUESTED(GetDebugger(), + "Interrupted dumping command output")) stream->Printf("\n... Interrupted.\n"); stream->Flush(); } @@ -3243,8 +3267,11 @@ bool CommandInterpreter::SaveTranscript( if (GetOpenTranscriptInEditor() && Host::IsInteractiveGraphicSession()) { const FileSpec file_spec; error = file->GetFileSpec(const_cast<FileSpec &>(file_spec)); - if (error.Success()) - Host::OpenFileInExternalEditor(file_spec, 1); + if (error.Success()) { + if (llvm::Error e = Host::OpenFileInExternalEditor( + m_debugger.GetExternalEditor(), file_spec, 1)) + result.AppendError(llvm::toString(std::move(e))); + } } return true; @@ -3361,7 +3388,13 @@ CommandInterpreterRunResult CommandInterpreter::RunCommandInterpreter( if (options.GetSpawnThread()) { m_debugger.StartIOHandlerThread(); } else { + // If the current thread is not managed by a host thread, we won't detect + // that this IS the CommandInterpreter IOHandler thread, so make it so: + HostThread new_io_handler_thread(Host::GetCurrentThread()); + HostThread old_io_handler_thread = + m_debugger.SetIOHandlerThread(new_io_handler_thread); m_debugger.RunIOHandlers(); + m_debugger.SetIOHandlerThread(old_io_handler_thread); if (options.GetAutoHandleEvents()) m_debugger.StopEventHandlerThread(); |