diff options
Diffstat (limited to 'source/Interpreter')
28 files changed, 471 insertions, 459 deletions
diff --git a/source/Interpreter/CommandAlias.cpp b/source/Interpreter/CommandAlias.cpp index 8c40574ee50ef..5139c53a47b33 100644 --- a/source/Interpreter/CommandAlias.cpp +++ b/source/Interpreter/CommandAlias.cpp @@ -64,8 +64,8 @@ static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP &cmd_obj_sp, option_arg_vector->emplace_back("<argument>", -1, options_string); else { for (auto &entry : args.entries()) { - if (!entry.ref.empty()) - option_arg_vector->emplace_back("<argument>", -1, entry.ref); + if (!entry.ref().empty()) + option_arg_vector->emplace_back("<argument>", -1, entry.ref()); } } } @@ -115,18 +115,16 @@ bool CommandAlias::WantsCompletion() { return false; } -int CommandAlias::HandleCompletion(CompletionRequest &request) { +void CommandAlias::HandleCompletion(CompletionRequest &request) { if (IsValid()) - return m_underlying_command_sp->HandleCompletion(request); - return -1; + m_underlying_command_sp->HandleCompletion(request); } -int CommandAlias::HandleArgumentCompletion( +void CommandAlias::HandleArgumentCompletion( CompletionRequest &request, OptionElementVector &opt_element_vector) { if (IsValid()) - return m_underlying_command_sp->HandleArgumentCompletion( - request, opt_element_vector); - return -1; + m_underlying_command_sp->HandleArgumentCompletion(request, + opt_element_vector); } Options *CommandAlias::GetOptions() { diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp index 8948037a6307b..0c059096c6cdb 100644 --- a/source/Interpreter/CommandInterpreter.cpp +++ b/source/Interpreter/CommandInterpreter.cpp @@ -16,7 +16,6 @@ #include "Commands/CommandObjectApropos.h" #include "Commands/CommandObjectBreakpoint.h" -#include "Commands/CommandObjectBugreport.h" #include "Commands/CommandObjectCommands.h" #include "Commands/CommandObjectDisassemble.h" #include "Commands/CommandObjectExpression.h" @@ -64,11 +63,14 @@ #include "lldb/Utility/Args.h" #include "lldb/Target/Process.h" +#include "lldb/Target/StopInfo.h" #include "lldb/Target/TargetList.h" #include "lldb/Target/Thread.h" +#include "lldb/Target/UnixSignals.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/FormatAdapters.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" @@ -77,10 +79,6 @@ using namespace lldb_private; static const char *k_white_space = " \t\v"; -static constexpr bool NoGlobalSetting = true; -static constexpr uintptr_t DefaultValueTrue = true; -static constexpr uintptr_t DefaultValueFalse = false; -static constexpr const char *NoCStrDefault = nullptr; static constexpr const char *InitFileWarning = "There is a .lldbinit file in the current directory which is not being " "read.\n" @@ -93,38 +91,12 @@ static constexpr const char *InitFileWarning = "and\n" "accept the security risk."; -static constexpr PropertyDefinition g_properties[] = { - {"expand-regex-aliases", OptionValue::eTypeBoolean, NoGlobalSetting, - DefaultValueFalse, NoCStrDefault, {}, - "If true, regular expression alias commands will show the " - "expanded command that will be executed. This can be used to " - "debug new regular expression alias commands."}, - {"prompt-on-quit", OptionValue::eTypeBoolean, NoGlobalSetting, - DefaultValueTrue, NoCStrDefault, {}, - "If true, LLDB will prompt you before quitting if there are any live " - "processes being debugged. If false, LLDB will quit without asking in any " - "case."}, - {"stop-command-source-on-error", OptionValue::eTypeBoolean, NoGlobalSetting, - DefaultValueTrue, NoCStrDefault, {}, - "If true, LLDB will stop running a 'command source' " - "script upon encountering an error."}, - {"space-repl-prompts", OptionValue::eTypeBoolean, NoGlobalSetting, - DefaultValueFalse, NoCStrDefault, {}, - "If true, blank lines will be printed between between REPL submissions."}, - {"echo-commands", OptionValue::eTypeBoolean, NoGlobalSetting, - DefaultValueTrue, NoCStrDefault, {}, - "If true, commands will be echoed before they are evaluated."}, - {"echo-comment-commands", OptionValue::eTypeBoolean, NoGlobalSetting, - DefaultValueTrue, NoCStrDefault, {}, - "If true, commands will be echoed even if they are pure comment lines."}}; +#define LLDB_PROPERTIES_interpreter +#include "InterpreterProperties.inc" enum { - ePropertyExpandRegexAliases = 0, - ePropertyPromptOnQuit = 1, - ePropertyStopCmdSourceOnError = 2, - eSpaceReplPrompts = 3, - eEchoCommands = 4, - eEchoCommentCommands = 5 +#define LLDB_PROPERTIES_interpreter +#include "InterpreterPropertiesEnum.inc" }; ConstString &CommandInterpreter::GetStaticBroadcasterClass() { @@ -139,7 +111,7 @@ CommandInterpreter::CommandInterpreter(Debugger &debugger, Properties(OptionValuePropertiesSP( new OptionValueProperties(ConstString("interpreter")))), IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand), - m_debugger(debugger), m_synchronous_execution(synchronous_execution), + m_debugger(debugger), m_synchronous_execution(true), m_skip_lldbinit_files(false), m_skip_app_init_files(false), m_command_io_handler_sp(), m_comment_char('#'), m_batch_command_mode(false), m_truncation_warning(eNoTruncation), @@ -148,20 +120,21 @@ CommandInterpreter::CommandInterpreter(Debugger &debugger, SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit"); SetEventName(eBroadcastBitResetPrompt, "reset-prompt"); SetEventName(eBroadcastBitQuitCommandReceived, "quit"); + SetSynchronous(synchronous_execution); CheckInWithManager(); - m_collection_sp->Initialize(g_properties); + m_collection_sp->Initialize(g_interpreter_properties); } bool CommandInterpreter::GetExpandRegexAliases() const { const uint32_t idx = ePropertyExpandRegexAliases; return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_properties[idx].default_uint_value != 0); + nullptr, 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_properties[idx].default_uint_value != 0); + nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); } void CommandInterpreter::SetPromptOnQuit(bool b) { @@ -170,24 +143,24 @@ void CommandInterpreter::SetPromptOnQuit(bool b) { } bool CommandInterpreter::GetEchoCommands() const { - const uint32_t idx = eEchoCommands; + const uint32_t idx = ePropertyEchoCommands; return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_properties[idx].default_uint_value != 0); + nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); } void CommandInterpreter::SetEchoCommands(bool b) { - const uint32_t idx = eEchoCommands; + const uint32_t idx = ePropertyEchoCommands; m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } bool CommandInterpreter::GetEchoCommentCommands() const { - const uint32_t idx = eEchoCommentCommands; + const uint32_t idx = ePropertyEchoCommentCommands; return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_properties[idx].default_uint_value != 0); + nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); } void CommandInterpreter::SetEchoCommentCommands(bool b) { - const uint32_t idx = eEchoCommentCommands; + const uint32_t idx = ePropertyEchoCommentCommands; m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } @@ -223,13 +196,13 @@ void CommandInterpreter::ResolveCommand(const char *command_line, bool CommandInterpreter::GetStopCmdSourceOnError() const { const uint32_t idx = ePropertyStopCmdSourceOnError; return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_properties[idx].default_uint_value != 0); + nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); } bool CommandInterpreter::GetSpaceReplPrompts() const { - const uint32_t idx = eSpaceReplPrompts; + const uint32_t idx = ePropertySpaceReplPrompts; return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_properties[idx].default_uint_value != 0); + nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); } void CommandInterpreter::Initialize() { @@ -473,8 +446,6 @@ void CommandInterpreter::LoadCommandDictionary() { m_command_dict["apropos"] = CommandObjectSP(new CommandObjectApropos(*this)); m_command_dict["breakpoint"] = CommandObjectSP(new CommandObjectMultiwordBreakpoint(*this)); - m_command_dict["bugreport"] = - CommandObjectSP(new CommandObjectMultiwordBugreport(*this)); m_command_dict["command"] = CommandObjectSP(new CommandObjectMultiwordCommands(*this)); m_command_dict["disassemble"] = @@ -1628,8 +1599,7 @@ bool CommandInterpreter::HandleCommand(const char *command_line, llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")", command_line); - if (log) - log->Printf("Processing command: %s", command_line); + LLDB_LOGF(log, "Processing command: %s", command_line); static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "Handling command: %s.", command_line); @@ -1735,13 +1705,13 @@ bool CommandInterpreter::HandleCommand(const char *command_line, // "br s -n main", command_string is now "breakpoint set -n main". if (log) { llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>"; - log->Printf("HandleCommand, cmd_obj : '%s'", command_name.str().c_str()); - log->Printf("HandleCommand, (revised) command_string: '%s'", - command_string.c_str()); + LLDB_LOGF(log, "HandleCommand, cmd_obj : '%s'", command_name.str().c_str()); + LLDB_LOGF(log, "HandleCommand, (revised) command_string: '%s'", + command_string.c_str()); const bool wants_raw_input = (cmd_obj != nullptr) ? cmd_obj->WantsRawCommandString() : false; - log->Printf("HandleCommand, wants_raw_input:'%s'", - wants_raw_input ? "True" : "False"); + LLDB_LOGF(log, "HandleCommand, wants_raw_input:'%s'", + wants_raw_input ? "True" : "False"); } // Phase 2. @@ -1771,34 +1741,30 @@ bool CommandInterpreter::HandleCommand(const char *command_line, if (pos != 0 && pos != std::string::npos) remainder.erase(0, pos); - if (log) - log->Printf( - "HandleCommand, command line after removing command name(s): '%s'", - remainder.c_str()); + LLDB_LOGF( + log, "HandleCommand, command line after removing command name(s): '%s'", + remainder.c_str()); cmd_obj->Execute(remainder.c_str(), result); } - if (log) - log->Printf("HandleCommand, command %s", - (result.Succeeded() ? "succeeded" : "did not succeed")); + LLDB_LOGF(log, "HandleCommand, command %s", + (result.Succeeded() ? "succeeded" : "did not succeed")); return result.Succeeded(); } -int CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) { - int num_command_matches = 0; +void CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) { bool look_for_subcommand = false; // For any of the command completions a unique match will be a complete word. - request.SetWordComplete(true); - if (request.GetCursorIndex() == -1) { + if (request.GetParsedLine().GetArgumentCount() == 0) { // We got nothing on the command line, so return the list of commands bool include_aliases = true; StringList new_matches, descriptions; - num_command_matches = GetCommandNamesMatchingPartialString( - "", include_aliases, new_matches, descriptions); + GetCommandNamesMatchingPartialString("", include_aliases, new_matches, + descriptions); request.AddCompletions(new_matches, descriptions); } else if (request.GetCursorIndex() == 0) { // The cursor is in the first argument, so just do a lookup in the @@ -1808,24 +1774,18 @@ int CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) { GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0), &new_matches, &new_descriptions); - if (num_command_matches == 1 && cmd_obj && cmd_obj->IsMultiwordObject() && + if (new_matches.GetSize() && cmd_obj && cmd_obj->IsMultiwordObject() && new_matches.GetStringAtIndex(0) != nullptr && strcmp(request.GetParsedLine().GetArgumentAtIndex(0), new_matches.GetStringAtIndex(0)) == 0) { - if (request.GetParsedLine().GetArgumentCount() == 1) { - request.SetWordComplete(true); - } else { + if (request.GetParsedLine().GetArgumentCount() != 1) { look_for_subcommand = true; - num_command_matches = 0; new_matches.DeleteStringAtIndex(0); new_descriptions.DeleteStringAtIndex(0); - request.GetParsedLine().AppendArgument(llvm::StringRef()); - request.SetCursorIndex(request.GetCursorIndex() + 1); - request.SetCursorCharPosition(0); + request.AppendEmptyArgument(); } } request.AddCompletions(new_matches, new_descriptions); - num_command_matches = request.GetNumberOfMatches(); } if (request.GetCursorIndex() > 0 || look_for_subcommand) { @@ -1834,81 +1794,31 @@ int CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) { // matching initial command: CommandObject *command_object = GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0)); - if (command_object == nullptr) { - return 0; - } else { - request.GetParsedLine().Shift(); - request.SetCursorIndex(request.GetCursorIndex() - 1); - num_command_matches = command_object->HandleCompletion(request); + if (command_object) { + request.ShiftArguments(); + command_object->HandleCompletion(request); } } - - return num_command_matches; } -int CommandInterpreter::HandleCompletion( - const char *current_line, const char *cursor, const char *last_char, - int match_start_point, int max_return_elements, StringList &matches, - StringList &descriptions) { +void CommandInterpreter::HandleCompletion(CompletionRequest &request) { - llvm::StringRef command_line(current_line, last_char - current_line); - CompletionResult result; - CompletionRequest request(command_line, cursor - current_line, - match_start_point, max_return_elements, result); // Don't complete comments, and if the line we are completing is just the // history repeat character, substitute the appropriate history line. - const char *first_arg = request.GetParsedLine().GetArgumentAtIndex(0); - if (first_arg) { - if (first_arg[0] == m_comment_char) - return 0; - else if (first_arg[0] == CommandHistory::g_repeat_char) { - if (auto hist_str = m_command_history.FindString(first_arg)) { - matches.InsertStringAtIndex(0, *hist_str); - descriptions.InsertStringAtIndex(0, "Previous command history event"); - return -2; - } else - return 0; - } - } - - // Only max_return_elements == -1 is supported at present: - lldbassert(max_return_elements == -1); - - int num_command_matches = HandleCompletionMatches(request); - result.GetMatches(matches); - result.GetDescriptions(descriptions); + llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0); - if (num_command_matches <= 0) - return num_command_matches; - - if (request.GetParsedLine().GetArgumentCount() == 0) { - // If we got an empty string, insert nothing. - matches.InsertStringAtIndex(0, ""); - descriptions.InsertStringAtIndex(0, ""); - } else { - // Now figure out if there is a common substring, and if so put that in - // element 0, otherwise put an empty string in element 0. - std::string command_partial_str = request.GetCursorArgumentPrefix().str(); - - std::string common_prefix; - matches.LongestCommonPrefix(common_prefix); - const size_t partial_name_len = command_partial_str.size(); - common_prefix.erase(0, partial_name_len); - - // If we matched a unique single command, add a space... Only do this if - // the completer told us this was a complete word, however... - if (num_command_matches == 1 && request.GetWordComplete()) { - char quote_char = request.GetParsedLine()[request.GetCursorIndex()].quote; - common_prefix = - Args::EscapeLLDBCommandArgument(common_prefix, quote_char); - if (quote_char != '\0') - common_prefix.push_back(quote_char); - common_prefix.push_back(' '); + if (!first_arg.empty()) { + if (first_arg.front() == m_comment_char) + return; + if (first_arg.front() == CommandHistory::g_repeat_char) { + if (auto hist_str = m_command_history.FindString(first_arg)) + request.AddCompletion(*hist_str, "Previous command history event", + CompletionMode::RewriteLine); + return; } - matches.InsertStringAtIndex(0, common_prefix.c_str()); - descriptions.InsertStringAtIndex(0, ""); } - return num_command_matches; + + HandleCompletionMatches(request); } CommandInterpreter::~CommandInterpreter() {} @@ -2051,7 +1961,7 @@ void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj, for (auto entry : llvm::enumerate(cmd_args.entries())) { if (!used[entry.index()] && !wants_raw_input) - new_args.AppendArgument(entry.value().ref); + new_args.AppendArgument(entry.value().ref()); } cmd_args.Clear(); @@ -2231,6 +2141,45 @@ PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) { return platform_sp; } +bool CommandInterpreter::DidProcessStopAbnormally() const { + TargetSP target_sp = m_debugger.GetTargetList().GetSelectedTarget(); + if (!target_sp) + return false; + + ProcessSP process_sp(target_sp->GetProcessSP()); + if (!process_sp) + return false; + + if (eStateStopped != process_sp->GetState()) + return false; + + for (const auto &thread_sp : process_sp->GetThreadList().Threads()) { + StopInfoSP stop_info = thread_sp->GetStopInfo(); + if (!stop_info) + return false; + + const StopReason reason = stop_info->GetStopReason(); + if (reason == eStopReasonException || reason == eStopReasonInstrumentation) + return true; + + if (reason == eStopReasonSignal) { + const auto stop_signal = static_cast<int32_t>(stop_info->GetValue()); + UnixSignalsSP signals_sp = process_sp->GetUnixSignals(); + if (!signals_sp || !signals_sp->SignalIsValid(stop_signal)) + // The signal is unknown, treat it as abnormal. + return true; + + const auto sigint_num = signals_sp->GetSignalNumberFromName("SIGINT"); + const auto sigstop_num = signals_sp->GetSignalNumberFromName("SIGSTOP"); + if ((stop_signal != sigint_num) && (stop_signal != sigstop_num)) + // The signal very likely implies a crash. + return true; + } + } + + return false; +} + void CommandInterpreter::HandleCommands(const StringList &commands, ExecutionContext *override_context, CommandInterpreterRunOptions &options, @@ -2341,38 +2290,22 @@ void CommandInterpreter::HandleCommands(const StringList &commands, } // Also check for "stop on crash here: - bool should_stop = false; - if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash()) { - TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget()); - if (target_sp) { - ProcessSP process_sp(target_sp->GetProcessSP()); - if (process_sp) { - for (ThreadSP thread_sp : process_sp->GetThreadList().Threads()) { - StopReason reason = thread_sp->GetStopReason(); - if (reason == eStopReasonSignal || reason == eStopReasonException || - reason == eStopReasonInstrumentation) { - should_stop = true; - break; - } - } - } - } - if (should_stop) { - if (idx != num_lines - 1) - result.AppendErrorWithFormat( - "Aborting reading of commands after command #%" PRIu64 - ": '%s' stopped with a signal or exception.\n", - (uint64_t)idx + 1, cmd); - else - result.AppendMessageWithFormat( - "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n", - (uint64_t)idx + 1, cmd); + if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash() && + DidProcessStopAbnormally()) { + if (idx != num_lines - 1) + result.AppendErrorWithFormat( + "Aborting reading of commands after command #%" PRIu64 + ": '%s' stopped with a signal or exception.\n", + (uint64_t)idx + 1, cmd); + else + result.AppendMessageWithFormat( + "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n", + (uint64_t)idx + 1, cmd); - result.SetStatus(tmp_result.GetStatus()); - m_debugger.SetAsyncExecution(old_async_execution); + result.SetStatus(tmp_result.GetStatus()); + m_debugger.SetAsyncExecution(old_async_execution); - return; - } + return; } } @@ -2405,18 +2338,18 @@ void CommandInterpreter::HandleCommandsFromFile( return; } - StreamFileSP input_file_sp(new StreamFile()); std::string cmd_file_path = cmd_file.GetPath(); - Status error = FileSystem::Instance().Open(input_file_sp->GetFile(), cmd_file, - File::eOpenOptionRead); - - if (error.Fail()) { - result.AppendErrorWithFormat( - "error: an error occurred read file '%s': %s\n", cmd_file_path.c_str(), - error.AsCString()); + auto input_file_up = + FileSystem::Instance().Open(cmd_file, File::eOpenOptionRead); + if (!input_file_up) { + std::string error = llvm::toString(input_file_up.takeError()); + result.AppendErrorWithFormatv( + "error: an error occurred read file '{0}': {1}\n", cmd_file_path, + llvm::fmt_consume(input_file_up.takeError())); result.SetStatus(eReturnStatusFailed); return; } + FileSP input_file_sp = FileSP(std::move(input_file_up.get())); Debugger &debugger = GetDebugger(); @@ -2502,8 +2435,8 @@ void CommandInterpreter::HandleCommandsFromFile( } if (flags & eHandleCommandFlagPrintResult) { - debugger.GetOutputFile()->Printf("Executing commands in '%s'.\n", - cmd_file_path.c_str()); + debugger.GetOutputFile().Printf("Executing commands in '%s'.\n", + cmd_file_path.c_str()); } // Used for inheriting the right settings when "command source" might @@ -2541,6 +2474,9 @@ void CommandInterpreter::HandleCommandsFromFile( bool CommandInterpreter::GetSynchronous() { return m_synchronous_execution; } void CommandInterpreter::SetSynchronous(bool value) { + // Asynchronous mode is not supported during reproducer replay. + if (repro::Reproducer::Instance().GetLoader()) + return; m_synchronous_execution = value; } @@ -2701,32 +2637,14 @@ void CommandInterpreter::UpdateExecutionContext( } } -size_t CommandInterpreter::GetProcessOutput() { - // The process has stuff waiting for stderr; get it and write it out to the - // appropriate place. - char stdio_buffer[1024]; - size_t len; - size_t total_bytes = 0; - Status error; +void CommandInterpreter::GetProcessOutput() { TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget()); - if (target_sp) { - ProcessSP process_sp(target_sp->GetProcessSP()); - if (process_sp) { - while ((len = process_sp->GetSTDOUT(stdio_buffer, sizeof(stdio_buffer), - error)) > 0) { - size_t bytes_written = len; - m_debugger.GetOutputFile()->Write(stdio_buffer, bytes_written); - total_bytes += len; - } - while ((len = process_sp->GetSTDERR(stdio_buffer, sizeof(stdio_buffer), - error)) > 0) { - size_t bytes_written = len; - m_debugger.GetErrorFile()->Write(stdio_buffer, bytes_written); - total_bytes += len; - } - } - } - return total_bytes; + if (!target_sp) + return; + + if (ProcessSP process_sp = target_sp->GetProcessSP()) + m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true, + /*flush_stderr*/ true); } void CommandInterpreter::StartHandlingCommand() { @@ -2818,8 +2736,8 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, // from a file) we need to echo the command out so we don't just see the // command output and no command... if (EchoCommandNonInteractive(line, io_handler.GetFlags())) - io_handler.GetOutputStreamFile()->Printf("%s%s\n", io_handler.GetPrompt(), - line.c_str()); + io_handler.GetOutputStreamFileSP()->Printf( + "%s%s\n", io_handler.GetPrompt(), line.c_str()); } StartHandlingCommand(); @@ -2836,13 +2754,13 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, if (!result.GetImmediateOutputStream()) { llvm::StringRef output = result.GetOutputData(); - PrintCommandOutput(*io_handler.GetOutputStreamFile(), output); + PrintCommandOutput(*io_handler.GetOutputStreamFileSP(), output); } // Now emit the command error text from the command we just executed if (!result.GetImmediateErrorStream()) { llvm::StringRef error = result.GetErrorData(); - PrintCommandOutput(*io_handler.GetErrorStreamFile(), error); + PrintCommandOutput(*io_handler.GetErrorStreamFileSP(), error); } } @@ -2875,27 +2793,10 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, // Finally, if we're going to stop on crash, check that here: if (!m_quit_requested && result.GetDidChangeProcessState() && - io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash)) { - bool should_stop = false; - TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget()); - if (target_sp) { - ProcessSP process_sp(target_sp->GetProcessSP()); - if (process_sp) { - for (ThreadSP thread_sp : process_sp->GetThreadList().Threads()) { - StopReason reason = thread_sp->GetStopReason(); - if ((reason == eStopReasonSignal || reason == eStopReasonException || - reason == eStopReasonInstrumentation) && - !result.GetAbnormalStopWasExpected()) { - should_stop = true; - break; - } - } - } - } - if (should_stop) { - io_handler.SetIsDone(true); - m_stopped_for_crash = true; - } + io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash) && + DidProcessStopAbnormally()) { + io_handler.SetIsDone(true); + m_stopped_for_crash = true; } } @@ -3009,8 +2910,8 @@ CommandInterpreter::GetIOHandler(bool force_create, m_command_io_handler_sp = std::make_shared<IOHandlerEditline>( m_debugger, IOHandler::Type::CommandInterpreter, - m_debugger.GetInputFile(), m_debugger.GetOutputFile(), - m_debugger.GetErrorFile(), flags, "lldb", m_debugger.GetPrompt(), + m_debugger.GetInputFileSP(), m_debugger.GetOutputStreamSP(), + m_debugger.GetErrorStreamSP(), flags, "lldb", m_debugger.GetPrompt(), llvm::StringRef(), // Continuation prompt false, // Don't enable multiple line input, just single line commands m_debugger.GetUseColor(), diff --git a/source/Interpreter/CommandObject.cpp b/source/Interpreter/CommandObject.cpp index 8e493c7a326f0..d666852ee68c3 100644 --- a/source/Interpreter/CommandObject.cpp +++ b/source/Interpreter/CommandObject.cpp @@ -257,14 +257,14 @@ void CommandObject::Cleanup() { m_api_locker.unlock(); } -int CommandObject::HandleCompletion(CompletionRequest &request) { +void CommandObject::HandleCompletion(CompletionRequest &request) { // Default implementation of WantsCompletion() is !WantsRawCommandString(). // Subclasses who want raw command string but desire, for example, argument // completion should override WantsCompletion() to return true, instead. if (WantsRawCommandString() && !WantsCompletion()) { // FIXME: Abstract telling the completion to insert the completion // character. - return -1; + return; } else { // Can we do anything generic with the options? Options *cur_options = GetOptions(); @@ -278,11 +278,11 @@ int CommandObject::HandleCompletion(CompletionRequest &request) { bool handled_by_options = cur_options->HandleOptionCompletion( request, opt_element_vector, GetCommandInterpreter()); if (handled_by_options) - return request.GetNumberOfMatches(); + return; } // If we got here, the last word is not an option or an option argument. - return HandleArgumentCompletion(request, opt_element_vector); + HandleArgumentCompletion(request, opt_element_vector); } } @@ -917,12 +917,21 @@ const char *CommandObject::GetArgumentDescriptionAsCString( return g_arguments_data[arg_type].help_text; } -Target *CommandObject::GetDummyTarget() { - return m_interpreter.GetDebugger().GetDummyTarget(); +Target &CommandObject::GetDummyTarget() { + return *m_interpreter.GetDebugger().GetDummyTarget(); +} + +Target &CommandObject::GetSelectedOrDummyTarget(bool prefer_dummy) { + return *m_interpreter.GetDebugger().GetSelectedOrDummyTarget(prefer_dummy); } -Target *CommandObject::GetSelectedOrDummyTarget(bool prefer_dummy) { - return m_interpreter.GetDebugger().GetSelectedOrDummyTarget(prefer_dummy); +Target &CommandObject::GetSelectedTarget() { + assert(m_flags.AnySet(eCommandRequiresTarget | eCommandProcessMustBePaused | + eCommandProcessMustBeLaunched | eCommandRequiresFrame | + eCommandRequiresThread | eCommandRequiresProcess | + eCommandRequiresRegContext) && + "GetSelectedTarget called from object that may have no target"); + return *m_interpreter.GetDebugger().GetSelectedTarget(); } Thread *CommandObject::GetDefaultThread() { @@ -958,7 +967,7 @@ bool CommandObjectParsed::Execute(const char *args_string, } if (!handled) { for (auto entry : llvm::enumerate(cmd_args.entries())) { - if (!entry.value().ref.empty() && entry.value().ref.front() == '`') { + if (!entry.value().ref().empty() && entry.value().ref().front() == '`') { cmd_args.ReplaceArgumentAtIndex( entry.index(), m_interpreter.ProcessEmbeddedScriptCommands(entry.value().c_str())); @@ -1064,7 +1073,7 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = { { eArgTypePythonScript, "python-script", CommandCompletions::eNoCompletion, { nullptr, false }, "Source code written in Python." }, { eArgTypeQueueName, "queue-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of the thread queue." }, { eArgTypeRegisterName, "register-name", CommandCompletions::eNoCompletion, { RegisterNameHelpTextCallback, true }, nullptr }, - { eArgTypeRegularExpression, "regular-expression", CommandCompletions::eNoCompletion, { nullptr, false }, "A regular expression." }, + { eArgTypeRegularExpression, "regular-expression", CommandCompletions::eNoCompletion, { nullptr, false }, "A POSIX-compliant extended regular expression." }, { eArgTypeRunArgs, "run-args", CommandCompletions::eNoCompletion, { nullptr, false }, "Arguments to be passed to the target program when it starts executing." }, { eArgTypeRunMode, "run-mode", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." }, { eArgTypeScriptedCommandSynchronicity, "script-cmd-synchronicity", CommandCompletions::eNoCompletion, { nullptr, false }, "The synchronicity to use to run scripted commands with regard to LLDB event system." }, diff --git a/source/Interpreter/CommandObjectRegexCommand.cpp b/source/Interpreter/CommandObjectRegexCommand.cpp index 19335b95ca3af..693d18ce7bdf8 100644 --- a/source/Interpreter/CommandObjectRegexCommand.cpp +++ b/source/Interpreter/CommandObjectRegexCommand.cpp @@ -30,15 +30,14 @@ bool CommandObjectRegexCommand::DoExecute(llvm::StringRef command, CommandReturnObject &result) { EntryCollection::const_iterator pos, end = m_entries.end(); for (pos = m_entries.begin(); pos != end; ++pos) { - RegularExpression::Match regex_match(m_max_matches); - - if (pos->regex.Execute(command, ®ex_match)) { + llvm::SmallVector<llvm::StringRef, 4> matches; + if (pos->regex.Execute(command, &matches)) { std::string new_command(pos->command); - std::string match_str; char percent_var[8]; size_t idx, percent_var_idx; for (uint32_t match_idx = 1; match_idx <= m_max_matches; ++match_idx) { - if (regex_match.GetMatchAtIndex(command, match_idx, match_str)) { + if (match_idx < matches.size()) { + const std::string match_str = matches[match_idx].str(); const int percent_var_len = ::snprintf(percent_var, sizeof(percent_var), "%%%u", match_idx); for (idx = 0; (percent_var_idx = new_command.find( @@ -74,8 +73,9 @@ bool CommandObjectRegexCommand::AddRegexCommand(const char *re_cstr, const char *command_cstr) { m_entries.resize(m_entries.size() + 1); // Only add the regular expression if it compiles - if (m_entries.back().regex.Compile( - llvm::StringRef::withNullAsEmpty(re_cstr))) { + m_entries.back().regex = + RegularExpression(llvm::StringRef::withNullAsEmpty(re_cstr)); + if (m_entries.back().regex.IsValid()) { m_entries.back().command.assign(command_cstr); return true; } @@ -84,13 +84,9 @@ bool CommandObjectRegexCommand::AddRegexCommand(const char *re_cstr, return false; } -int CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) { +void CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) { if (m_completion_type_mask) { CommandCompletions::InvokeCommonCompletionCallbacks( GetCommandInterpreter(), m_completion_type_mask, request, nullptr); - return request.GetNumberOfMatches(); - } else { - request.SetWordComplete(false); } - return 0; } diff --git a/source/Interpreter/CommandReturnObject.cpp b/source/Interpreter/CommandReturnObject.cpp index 3a7a8755d9755..c17390be7311d 100644 --- a/source/Interpreter/CommandReturnObject.cpp +++ b/source/Interpreter/CommandReturnObject.cpp @@ -33,8 +33,7 @@ static void DumpStringToStreamWithNewline(Stream &strm, const std::string &s, CommandReturnObject::CommandReturnObject() : m_out_stream(), m_err_stream(), m_status(eReturnStatusStarted), - m_did_change_process_state(false), m_interactive(true), - m_abnormal_stop_was_expected(false) {} + m_did_change_process_state(false), m_interactive(true) {} CommandReturnObject::~CommandReturnObject() {} diff --git a/source/Interpreter/InterpreterProperties.td b/source/Interpreter/InterpreterProperties.td new file mode 100644 index 0000000000000..600c1e3edb9b8 --- /dev/null +++ b/source/Interpreter/InterpreterProperties.td @@ -0,0 +1,28 @@ +include "../../include/lldb/Core/PropertiesBase.td" + +let Definition = "interpreter" in { + def ExpandRegexAliases: Property<"expand-regex-aliases", "Boolean">, + Global, + DefaultFalse, + Desc<"If true, regular expression alias commands will show the expanded command that will be executed. This can be used to debug new regular expression alias commands.">; + def PromptOnQuit: Property<"prompt-on-quit", "Boolean">, + Global, + DefaultTrue, + Desc<"If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case.">; + def StopCmdSourceOnError: Property<"stop-command-source-on-error", "Boolean">, + Global, + DefaultTrue, + Desc<"If true, LLDB will stop running a 'command source' script upon encountering an error.">; + def SpaceReplPrompts: Property<"space-repl-prompts", "Boolean">, + Global, + DefaultFalse, + Desc<"If true, blank lines will be printed between between REPL submissions.">; + def EchoCommands: Property<"echo-commands", "Boolean">, + Global, + DefaultTrue, + Desc<"If true, commands will be echoed before they are evaluated.">; + def EchoCommentCommands: Property<"echo-comment-commands", "Boolean">, + Global, + DefaultTrue, + Desc<"If true, commands will be echoed even if they are pure comment lines.">; +} diff --git a/source/Interpreter/OptionArgParser.cpp b/source/Interpreter/OptionArgParser.cpp index efaac0720fd0c..14b81cd7b3d29 100644 --- a/source/Interpreter/OptionArgParser.cpp +++ b/source/Interpreter/OptionArgParser.cpp @@ -211,29 +211,21 @@ lldb::addr_t OptionArgParser::ToAddress(const ExecutionContext *exe_ctx, // pointer types. static RegularExpression g_symbol_plus_offset_regex( "^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$"); - RegularExpression::Match regex_match(3); - if (g_symbol_plus_offset_regex.Execute(sref, ®ex_match)) { + + llvm::SmallVector<llvm::StringRef, 4> matches; + if (g_symbol_plus_offset_regex.Execute(sref, &matches)) { uint64_t offset = 0; - bool add = true; - std::string name; - std::string str; - if (regex_match.GetMatchAtIndex(s, 1, name)) { - if (regex_match.GetMatchAtIndex(s, 2, str)) { - add = str[0] == '+'; - - if (regex_match.GetMatchAtIndex(s, 3, str)) { - if (!llvm::StringRef(str).getAsInteger(0, offset)) { - Status error; - addr = ToAddress(exe_ctx, name.c_str(), LLDB_INVALID_ADDRESS, - &error); - if (addr != LLDB_INVALID_ADDRESS) { - if (add) - return addr + offset; - else - return addr - offset; - } - } - } + std::string name = matches[1].str(); + std::string sign = matches[2].str(); + std::string str_offset = matches[3].str(); + if (!llvm::StringRef(str_offset).getAsInteger(0, offset)) { + Status error; + addr = ToAddress(exe_ctx, name.c_str(), LLDB_INVALID_ADDRESS, &error); + if (addr != LLDB_INVALID_ADDRESS) { + if (sign[0] == '+') + return addr + offset; + else + return addr - offset; } } } diff --git a/source/Interpreter/OptionGroupArchitecture.cpp b/source/Interpreter/OptionGroupArchitecture.cpp index 2ee1a9c7cf846..11f786c52c098 100644 --- a/source/Interpreter/OptionGroupArchitecture.cpp +++ b/source/Interpreter/OptionGroupArchitecture.cpp @@ -46,8 +46,7 @@ OptionGroupArchitecture::SetOptionValue(uint32_t option_idx, break; default: - error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; + llvm_unreachable("Unimplemented option"); } return error; diff --git a/source/Interpreter/OptionGroupFormat.cpp b/source/Interpreter/OptionGroupFormat.cpp index d9acfd663dd1e..c25e35f845172 100644 --- a/source/Interpreter/OptionGroupFormat.cpp +++ b/source/Interpreter/OptionGroupFormat.cpp @@ -160,8 +160,7 @@ Status OptionGroupFormat::SetOptionValue(uint32_t option_idx, } break; default: - error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; + llvm_unreachable("Unimplemented option"); } return error; diff --git a/source/Interpreter/OptionGroupOutputFile.cpp b/source/Interpreter/OptionGroupOutputFile.cpp index ccb99a8fce4a6..3df75cf86b85b 100644 --- a/source/Interpreter/OptionGroupOutputFile.cpp +++ b/source/Interpreter/OptionGroupOutputFile.cpp @@ -50,8 +50,7 @@ OptionGroupOutputFile::SetOptionValue(uint32_t option_idx, break; default: - error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; + llvm_unreachable("Unimplemented option"); } return error; diff --git a/source/Interpreter/OptionGroupPlatform.cpp b/source/Interpreter/OptionGroupPlatform.cpp index 6dc2996bb78a4..6ddbbf0e3abb9 100644 --- a/source/Interpreter/OptionGroupPlatform.cpp +++ b/source/Interpreter/OptionGroupPlatform.cpp @@ -113,8 +113,7 @@ OptionGroupPlatform::SetOptionValue(uint32_t option_idx, break; default: - error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; + llvm_unreachable("Unimplemented option"); } return error; } diff --git a/source/Interpreter/OptionGroupPythonClassWithDict.cpp b/source/Interpreter/OptionGroupPythonClassWithDict.cpp new file mode 100644 index 0000000000000..9a893ec536258 --- /dev/null +++ b/source/Interpreter/OptionGroupPythonClassWithDict.cpp @@ -0,0 +1,123 @@ +//===-- OptionGroupPythonClassWithDict.cpp ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h" + +#include "lldb/Host/OptionParser.h" + +using namespace lldb; +using namespace lldb_private; + +OptionGroupPythonClassWithDict::OptionGroupPythonClassWithDict + (const char *class_use, + int class_option, + int key_option, + int value_option, + const char *class_long_option, + const char *key_long_option, + const char *value_long_option, + bool required) { + m_key_usage_text.assign("The key for a key/value pair passed to the class" + " that implements a "); + m_key_usage_text.append(class_use); + m_key_usage_text.append(". Pairs can be specified more than once."); + + m_value_usage_text.assign("The value for a previous key in the pair passed to" + " the class that implements a "); + m_value_usage_text.append(class_use); + m_value_usage_text.append(". Pairs can be specified more than once."); + + m_class_usage_text.assign("The name of the class that will manage a "); + m_class_usage_text.append(class_use); + m_class_usage_text.append("."); + + m_option_definition[0].usage_mask = LLDB_OPT_SET_1; + m_option_definition[0].required = required; + m_option_definition[0].long_option = class_long_option; + m_option_definition[0].short_option = class_option; + m_option_definition[0].validator = nullptr; + m_option_definition[0].option_has_arg = OptionParser::eRequiredArgument; + m_option_definition[0].enum_values = {}; + m_option_definition[0].completion_type = 0; + m_option_definition[0].argument_type = eArgTypePythonClass; + m_option_definition[0].usage_text = m_class_usage_text.data(); + + m_option_definition[1].usage_mask = LLDB_OPT_SET_1; + m_option_definition[1].required = required; + m_option_definition[1].long_option = key_long_option; + m_option_definition[1].short_option = key_option; + m_option_definition[1].validator = nullptr; + m_option_definition[1].option_has_arg = OptionParser::eRequiredArgument; + m_option_definition[1].enum_values = {}; + m_option_definition[1].completion_type = 0; + m_option_definition[1].argument_type = eArgTypeNone; + m_option_definition[1].usage_text = m_key_usage_text.data(); + + m_option_definition[2].usage_mask = LLDB_OPT_SET_1; + m_option_definition[2].required = required; + m_option_definition[2].long_option = value_long_option; + m_option_definition[2].short_option = value_option; + m_option_definition[2].validator = nullptr; + m_option_definition[2].option_has_arg = OptionParser::eRequiredArgument; + m_option_definition[2].enum_values = {}; + m_option_definition[2].completion_type = 0; + m_option_definition[2].argument_type = eArgTypeNone; + m_option_definition[2].usage_text = m_value_usage_text.data(); +} + +OptionGroupPythonClassWithDict::~OptionGroupPythonClassWithDict() {} + +Status OptionGroupPythonClassWithDict::SetOptionValue( + uint32_t option_idx, + llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + switch (option_idx) { + case 0: { + m_class_name.assign(option_arg); + } break; + case 1: { + if (m_current_key.empty()) + m_current_key.assign(option_arg); + else + error.SetErrorStringWithFormat("Key: \"%s\" missing value.", + m_current_key.c_str()); + + } break; + case 2: { + if (!m_current_key.empty()) { + m_dict_sp->AddStringItem(m_current_key, option_arg); + m_current_key.clear(); + } + else + error.SetErrorStringWithFormat("Value: \"%s\" missing matching key.", + option_arg.str().c_str()); + } break; + default: + llvm_unreachable("Unimplemented option"); + } + return error; +} + +void OptionGroupPythonClassWithDict::OptionParsingStarting( + ExecutionContext *execution_context) { + m_current_key.erase(); + m_dict_sp = std::make_shared<StructuredData::Dictionary>(); +} + +Status OptionGroupPythonClassWithDict::OptionParsingFinished( + ExecutionContext *execution_context) { + Status error; + // If we get here and there's contents in the m_current_key, somebody must + // have provided a key but no value. + if (!m_current_key.empty()) + error.SetErrorStringWithFormat("Key: \"%s\" missing value.", + m_current_key.c_str()); + return error; +} + diff --git a/source/Interpreter/OptionGroupUUID.cpp b/source/Interpreter/OptionGroupUUID.cpp index e32673bc52af6..8fc330a89391e 100644 --- a/source/Interpreter/OptionGroupUUID.cpp +++ b/source/Interpreter/OptionGroupUUID.cpp @@ -40,8 +40,7 @@ Status OptionGroupUUID::SetOptionValue(uint32_t option_idx, break; default: - error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; + llvm_unreachable("Unimplemented option"); } return error; diff --git a/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/source/Interpreter/OptionGroupValueObjectDisplay.cpp index 4e5463a4de00f..81c10a6c762e5 100644 --- a/source/Interpreter/OptionGroupValueObjectDisplay.cpp +++ b/source/Interpreter/OptionGroupValueObjectDisplay.cpp @@ -152,8 +152,7 @@ Status OptionGroupValueObjectDisplay::SetOptionValue( break; default: - error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; + llvm_unreachable("Unimplemented option"); } return error; diff --git a/source/Interpreter/OptionGroupVariable.cpp b/source/Interpreter/OptionGroupVariable.cpp index d703c3dedcd97..a9004bf03cd2e 100644 --- a/source/Interpreter/OptionGroupVariable.cpp +++ b/source/Interpreter/OptionGroupVariable.cpp @@ -109,9 +109,7 @@ OptionGroupVariable::SetOptionValue(uint32_t option_idx, error = summary_string.SetCurrentValue(option_arg); break; default: - error.SetErrorStringWithFormat("unrecognized short option '%c'", - short_option); - break; + llvm_unreachable("Unimplemented option"); } return error; diff --git a/source/Interpreter/OptionGroupWatchpoint.cpp b/source/Interpreter/OptionGroupWatchpoint.cpp index 28e6b817fcc5a..682f99b8c5cce 100644 --- a/source/Interpreter/OptionGroupWatchpoint.cpp +++ b/source/Interpreter/OptionGroupWatchpoint.cpp @@ -16,16 +16,45 @@ using namespace lldb; using namespace lldb_private; static constexpr OptionEnumValueElement g_watch_type[] = { - {OptionGroupWatchpoint::eWatchRead, "read", "Watch for read"}, - {OptionGroupWatchpoint::eWatchWrite, "write", "Watch for write"}, - {OptionGroupWatchpoint::eWatchReadWrite, "read_write", - "Watch for read/write"} }; + { + OptionGroupWatchpoint::eWatchRead, + "read", + "Watch for read", + }, + { + OptionGroupWatchpoint::eWatchWrite, + "write", + "Watch for write", + }, + { + OptionGroupWatchpoint::eWatchReadWrite, + "read_write", + "Watch for read/write", + }, +}; static constexpr OptionEnumValueElement g_watch_size[] = { - {1, "1", "Watch for byte size of 1"}, - {2, "2", "Watch for byte size of 2"}, - {4, "4", "Watch for byte size of 4"}, - {8, "8", "Watch for byte size of 8"} }; + { + 1, + "1", + "Watch for byte size of 1", + }, + { + 2, + "2", + "Watch for byte size of 2", + }, + { + 4, + "4", + "Watch for byte size of 4", + }, + { + 8, + "8", + "Watch for byte size of 8", + }, +}; static constexpr OptionDefinition g_option_table[] = { {LLDB_OPT_SET_1, false, "watch", 'w', OptionParser::eRequiredArgument, @@ -72,9 +101,7 @@ OptionGroupWatchpoint::SetOptionValue(uint32_t option_idx, break; default: - error.SetErrorStringWithFormat("unrecognized short option '%c'", - short_option); - break; + llvm_unreachable("Unimplemented option"); } return error; diff --git a/source/Interpreter/OptionValue.cpp b/source/Interpreter/OptionValue.cpp index 00c8642595b72..bc929aa9dabf5 100644 --- a/source/Interpreter/OptionValue.cpp +++ b/source/Interpreter/OptionValue.cpp @@ -565,11 +565,8 @@ bool OptionValue::DumpQualifiedName(Stream &strm) const { return dumped_something; } -size_t OptionValue::AutoComplete(CommandInterpreter &interpreter, - CompletionRequest &request) { - request.SetWordComplete(false); - return request.GetNumberOfMatches(); -} +void OptionValue::AutoComplete(CommandInterpreter &interpreter, + CompletionRequest &request) {} Status OptionValue::SetValueFromString(llvm::StringRef value, VarSetOperationType op) { diff --git a/source/Interpreter/OptionValueArch.cpp b/source/Interpreter/OptionValueArch.cpp index 92dc45d092bee..7271c1471f90e 100644 --- a/source/Interpreter/OptionValueArch.cpp +++ b/source/Interpreter/OptionValueArch.cpp @@ -68,11 +68,9 @@ lldb::OptionValueSP OptionValueArch::DeepCopy() const { return OptionValueSP(new OptionValueArch(*this)); } -size_t OptionValueArch::AutoComplete(CommandInterpreter &interpreter, - CompletionRequest &request) { - request.SetWordComplete(false); +void OptionValueArch::AutoComplete(CommandInterpreter &interpreter, + CompletionRequest &request) { CommandCompletions::InvokeCommonCompletionCallbacks( interpreter, CommandCompletions::eArchitectureCompletion, request, nullptr); - return request.GetNumberOfMatches(); } diff --git a/source/Interpreter/OptionValueBoolean.cpp b/source/Interpreter/OptionValueBoolean.cpp index 8be8220fb3066..6f893a94e863f 100644 --- a/source/Interpreter/OptionValueBoolean.cpp +++ b/source/Interpreter/OptionValueBoolean.cpp @@ -71,21 +71,17 @@ lldb::OptionValueSP OptionValueBoolean::DeepCopy() const { return OptionValueSP(new OptionValueBoolean(*this)); } -size_t OptionValueBoolean::AutoComplete(CommandInterpreter &interpreter, - CompletionRequest &request) { - request.SetWordComplete(false); - static const llvm::StringRef g_autocomplete_entries[] = { - "true", "false", "on", "off", "yes", "no", "1", "0"}; +void OptionValueBoolean::AutoComplete(CommandInterpreter &interpreter, + CompletionRequest &request) { + llvm::StringRef autocomplete_entries[] = {"true", "false", "on", "off", + "yes", "no", "1", "0"}; - auto entries = llvm::makeArrayRef(g_autocomplete_entries); + auto entries = llvm::makeArrayRef(autocomplete_entries); // only suggest "true" or "false" by default if (request.GetCursorArgumentPrefix().empty()) entries = entries.take_front(2); - for (auto entry : entries) { - if (entry.startswith_lower(request.GetCursorArgumentPrefix())) - request.AddCompletion(entry); - } - return request.GetNumberOfMatches(); + for (auto entry : entries) + request.TryCompleteCurrentArg(entry); } diff --git a/source/Interpreter/OptionValueDictionary.cpp b/source/Interpreter/OptionValueDictionary.cpp index eb66c485bfd17..a4022288fccb7 100644 --- a/source/Interpreter/OptionValueDictionary.cpp +++ b/source/Interpreter/OptionValueDictionary.cpp @@ -111,18 +111,18 @@ Status OptionValueDictionary::SetArgs(const Args &args, return error; } for (const auto &entry : args) { - if (entry.ref.empty()) { + if (entry.ref().empty()) { error.SetErrorString("empty argument"); return error; } - if (!entry.ref.contains('=')) { + if (!entry.ref().contains('=')) { error.SetErrorString( "assign operation takes one or more key=value arguments"); return error; } llvm::StringRef key, value; - std::tie(key, value) = entry.ref.split('='); + std::tie(key, value) = entry.ref().split('='); bool key_valid = false; if (key.empty()) { error.SetErrorString("empty dictionary key"); diff --git a/source/Interpreter/OptionValueEnumeration.cpp b/source/Interpreter/OptionValueEnumeration.cpp index 0b76bd0601aaf..26933aa782404 100644 --- a/source/Interpreter/OptionValueEnumeration.cpp +++ b/source/Interpreter/OptionValueEnumeration.cpp @@ -102,21 +102,16 @@ lldb::OptionValueSP OptionValueEnumeration::DeepCopy() const { return OptionValueSP(new OptionValueEnumeration(*this)); } -size_t OptionValueEnumeration::AutoComplete(CommandInterpreter &interpreter, - CompletionRequest &request) { - request.SetWordComplete(false); - +void OptionValueEnumeration::AutoComplete(CommandInterpreter &interpreter, + CompletionRequest &request) { const uint32_t num_enumerators = m_enumerations.GetSize(); if (!request.GetCursorArgumentPrefix().empty()) { for (size_t i = 0; i < num_enumerators; ++i) { llvm::StringRef name = m_enumerations.GetCStringAtIndex(i).GetStringRef(); - if (name.startswith(request.GetCursorArgumentPrefix())) - request.AddCompletion(name); + request.TryCompleteCurrentArg(name); } - } else { - // only suggest "true" or "false" by default + return; + } for (size_t i = 0; i < num_enumerators; ++i) request.AddCompletion(m_enumerations.GetCStringAtIndex(i).GetStringRef()); - } - return request.GetNumberOfMatches(); } diff --git a/source/Interpreter/OptionValueFileSpec.cpp b/source/Interpreter/OptionValueFileSpec.cpp index 062d7ccdf2aa1..20d3d4e68e337 100644 --- a/source/Interpreter/OptionValueFileSpec.cpp +++ b/source/Interpreter/OptionValueFileSpec.cpp @@ -99,12 +99,10 @@ lldb::OptionValueSP OptionValueFileSpec::DeepCopy() const { return OptionValueSP(new OptionValueFileSpec(*this)); } -size_t OptionValueFileSpec::AutoComplete(CommandInterpreter &interpreter, - CompletionRequest &request) { - request.SetWordComplete(false); +void OptionValueFileSpec::AutoComplete(CommandInterpreter &interpreter, + CompletionRequest &request) { CommandCompletions::InvokeCommonCompletionCallbacks( interpreter, m_completion_mask, request, nullptr); - return request.GetNumberOfMatches(); } const lldb::DataBufferSP &OptionValueFileSpec::GetFileContents() { diff --git a/source/Interpreter/OptionValueFileSpecLIst.cpp b/source/Interpreter/OptionValueFileSpecList.cpp index a95188870f0b2..1a9d3c9ecb870 100644 --- a/source/Interpreter/OptionValueFileSpecLIst.cpp +++ b/source/Interpreter/OptionValueFileSpecList.cpp @@ -1,4 +1,4 @@ -//===-- OptionValueFileSpecLIst.cpp -----------------------------*- C++ -*-===// +//===-- OptionValueFileSpecList.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/source/Interpreter/OptionValueFormatEntity.cpp b/source/Interpreter/OptionValueFormatEntity.cpp index 1bb8c9f6955ab..8dc52650a3318 100644 --- a/source/Interpreter/OptionValueFormatEntity.cpp +++ b/source/Interpreter/OptionValueFormatEntity.cpp @@ -116,7 +116,7 @@ lldb::OptionValueSP OptionValueFormatEntity::DeepCopy() const { return OptionValueSP(new OptionValueFormatEntity(*this)); } -size_t OptionValueFormatEntity::AutoComplete(CommandInterpreter &interpreter, - CompletionRequest &request) { - return FormatEntity::AutoComplete(request); +void OptionValueFormatEntity::AutoComplete(CommandInterpreter &interpreter, + CompletionRequest &request) { + FormatEntity::AutoComplete(request); } diff --git a/source/Interpreter/OptionValueLanguage.cpp b/source/Interpreter/OptionValueLanguage.cpp index d935d5e23496d..1d7e18868b6fd 100644 --- a/source/Interpreter/OptionValueLanguage.cpp +++ b/source/Interpreter/OptionValueLanguage.cpp @@ -10,6 +10,7 @@ #include "lldb/DataFormatters/FormatManager.h" #include "lldb/Target/Language.h" +#include "lldb/Symbol/TypeSystem.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/Stream.h" @@ -39,23 +40,20 @@ Status OptionValueLanguage::SetValueFromString(llvm::StringRef value, case eVarSetOperationReplace: case eVarSetOperationAssign: { ConstString lang_name(value.trim()); - std::set<lldb::LanguageType> languages_for_types; - std::set<lldb::LanguageType> languages_for_expressions; - Language::GetLanguagesSupportingTypeSystems(languages_for_types, - languages_for_expressions); - + LanguageSet languages_for_types = Language::GetLanguagesSupportingTypeSystems(); LanguageType new_type = Language::GetLanguageTypeFromString(lang_name.GetStringRef()); - if (new_type && languages_for_types.count(new_type)) { + if (new_type && languages_for_types[new_type]) { m_value_was_set = true; m_current_value = new_type; } else { StreamString error_strm; error_strm.Printf("invalid language type '%s', ", value.str().c_str()); error_strm.Printf("valid values are:\n"); - for (lldb::LanguageType language : languages_for_types) { - error_strm.Printf("%s%s%s", " ", - Language::GetNameForLanguageType(language), "\n"); + for (int bit : languages_for_types.bitvector.set_bits()) { + auto language = (LanguageType)bit; + error_strm.Printf(" %s\n", + Language::GetNameForLanguageType(language)); } error.SetErrorString(error_strm.GetString()); } diff --git a/source/Interpreter/OptionValueRegex.cpp b/source/Interpreter/OptionValueRegex.cpp index bbe3fa7150199..cf806fb550f9b 100644 --- a/source/Interpreter/OptionValueRegex.cpp +++ b/source/Interpreter/OptionValueRegex.cpp @@ -46,16 +46,14 @@ Status OptionValueRegex::SetValueFromString(llvm::StringRef value, case eVarSetOperationReplace: case eVarSetOperationAssign: - if (m_regex.Compile(value)) { + m_regex = RegularExpression(value); + if (m_regex.IsValid()) { m_value_was_set = true; NotifyValueChanged(); + } else if (llvm::Error err = m_regex.GetError()) { + error.SetErrorString(llvm::toString(std::move(err))); } else { - char regex_error[1024]; - if (m_regex.GetErrorAsCString(regex_error, sizeof(regex_error))) - error.SetErrorString(regex_error); - else - error.SetErrorStringWithFormat("regex error %u", - m_regex.GetErrorCode()); + error.SetErrorString("regex error"); } break; } diff --git a/source/Interpreter/OptionValueUUID.cpp b/source/Interpreter/OptionValueUUID.cpp index f39b66b77bb0f..7a6bc65b25a40 100644 --- a/source/Interpreter/OptionValueUUID.cpp +++ b/source/Interpreter/OptionValueUUID.cpp @@ -62,30 +62,24 @@ lldb::OptionValueSP OptionValueUUID::DeepCopy() const { return OptionValueSP(new OptionValueUUID(*this)); } -size_t OptionValueUUID::AutoComplete(CommandInterpreter &interpreter, - CompletionRequest &request) { - request.SetWordComplete(false); +void OptionValueUUID::AutoComplete(CommandInterpreter &interpreter, + CompletionRequest &request) { ExecutionContext exe_ctx(interpreter.GetExecutionContext()); Target *target = exe_ctx.GetTargetPtr(); - if (target) { - auto prefix = request.GetCursorArgumentPrefix(); - llvm::SmallVector<uint8_t, 20> uuid_bytes; - if (UUID::DecodeUUIDBytesFromString(prefix, uuid_bytes).empty()) { - const size_t num_modules = target->GetImages().GetSize(); - for (size_t i = 0; i < num_modules; ++i) { - ModuleSP module_sp(target->GetImages().GetModuleAtIndex(i)); - if (module_sp) { - const UUID &module_uuid = module_sp->GetUUID(); - if (module_uuid.IsValid()) { - llvm::ArrayRef<uint8_t> module_bytes = module_uuid.GetBytes(); - if (module_bytes.size() >= uuid_bytes.size() && - module_bytes.take_front(uuid_bytes.size()).equals(uuid_bytes)) { - request.AddCompletion(module_uuid.GetAsString()); - } - } - } - } - } + if (!target) + return; + auto prefix = request.GetCursorArgumentPrefix(); + llvm::SmallVector<uint8_t, 20> uuid_bytes; + if (!UUID::DecodeUUIDBytesFromString(prefix, uuid_bytes).empty()) + return; + const size_t num_modules = target->GetImages().GetSize(); + for (size_t i = 0; i < num_modules; ++i) { + ModuleSP module_sp(target->GetImages().GetModuleAtIndex(i)); + if (!module_sp) + continue; + const UUID &module_uuid = module_sp->GetUUID(); + if (!module_uuid.IsValid()) + continue; + request.TryCompleteCurrentArg(module_uuid.GetAsString()); } - return request.GetNumberOfMatches(); } diff --git a/source/Interpreter/Options.cpp b/source/Interpreter/Options.cpp index ba15c020f2daa..0bceea14269d0 100644 --- a/source/Interpreter/Options.cpp +++ b/source/Interpreter/Options.cpp @@ -645,8 +645,6 @@ bool Options::VerifyPartialOptions(CommandReturnObject &result) { bool Options::HandleOptionCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector, CommandInterpreter &interpreter) { - request.SetWordComplete(true); - // For now we just scan the completions to see if the cursor position is in // an option or its argument. Otherwise we'll call HandleArgumentCompletion. // In the future we can use completion to validate options as well if we @@ -654,12 +652,11 @@ bool Options::HandleOptionCompletion(CompletionRequest &request, auto opt_defs = GetDefinitions(); - std::string cur_opt_std_str = request.GetCursorArgumentPrefix().str(); - const char *cur_opt_str = cur_opt_std_str.c_str(); + llvm::StringRef cur_opt_str = request.GetCursorArgumentPrefix(); for (size_t i = 0; i < opt_element_vector.size(); i++) { - int opt_pos = opt_element_vector[i].opt_pos; - int opt_arg_pos = opt_element_vector[i].opt_arg_pos; + size_t opt_pos = static_cast<size_t>(opt_element_vector[i].opt_pos); + size_t opt_arg_pos = static_cast<size_t>(opt_element_vector[i].opt_arg_pos); int opt_defs_index = opt_element_vector[i].opt_defs_index; if (opt_pos == request.GetCursorIndex()) { // We're completing the option itself. @@ -669,13 +666,13 @@ bool Options::HandleOptionCompletion(CompletionRequest &request, // FIXME: We should scan the other options provided and only complete // options // within the option group they belong to. - char opt_str[3] = {'-', 'a', '\0'}; + std::string opt_str = "-a"; for (auto &def : opt_defs) { if (!def.short_option) continue; opt_str[1] = def.short_option; - request.AddCompletion(opt_str); + request.AddCompletion(opt_str, def.usage_text); } return true; @@ -687,7 +684,7 @@ bool Options::HandleOptionCompletion(CompletionRequest &request, full_name.erase(full_name.begin() + 2, full_name.end()); full_name.append(def.long_option); - request.AddCompletion(full_name.c_str()); + request.AddCompletion(full_name, def.usage_text); } return true; } else if (opt_defs_index != OptionArgElement::eUnrecognizedArg) { @@ -695,17 +692,14 @@ bool Options::HandleOptionCompletion(CompletionRequest &request, // anyway (getopt_long_only is happy with shortest unique string, but // it's still a nice thing to do.) Otherwise return The string so the // upper level code will know this is a full match and add the " ". - if (cur_opt_str && strlen(cur_opt_str) > 2 && cur_opt_str[0] == '-' && - cur_opt_str[1] == '-' && - strcmp(opt_defs[opt_defs_index].long_option, cur_opt_str) != 0) { - std::string full_name("--"); - full_name.append(opt_defs[opt_defs_index].long_option); - request.AddCompletion(full_name.c_str()); - return true; - } else { - request.AddCompletion(request.GetCursorArgument()); + const OptionDefinition &opt = opt_defs[opt_defs_index]; + llvm::StringRef long_option = opt.long_option; + if (cur_opt_str.startswith("--") && cur_opt_str != long_option) { + request.AddCompletion("--" + long_option.str(), opt.usage_text); return true; - } + } else + request.AddCompletion(request.GetCursorArgumentPrefix()); + return true; } else { // FIXME - not handling wrong options yet: // Check to see if they are writing a long option & complete it. @@ -713,18 +707,11 @@ bool Options::HandleOptionCompletion(CompletionRequest &request, // elements // that are not unique up to this point. getopt_long_only does // shortest unique match for long options already. - - if (cur_opt_str && strlen(cur_opt_str) > 2 && cur_opt_str[0] == '-' && - cur_opt_str[1] == '-') { + if (cur_opt_str.consume_front("--")) { for (auto &def : opt_defs) { - if (!def.long_option) - continue; - - if (strstr(def.long_option, cur_opt_str + 2) == def.long_option) { - std::string full_name("--"); - full_name.append(def.long_option); - request.AddCompletion(full_name.c_str()); - } + llvm::StringRef long_option(def.long_option); + if (long_option.startswith(cur_opt_str)) + request.AddCompletion("--" + long_option.str(), def.usage_text); } } return true; @@ -733,13 +720,9 @@ bool Options::HandleOptionCompletion(CompletionRequest &request, } else if (opt_arg_pos == request.GetCursorIndex()) { // Okay the cursor is on the completion of an argument. See if it has a // completion, otherwise return no matches. - - CompletionRequest subrequest = request; - subrequest.SetCursorCharPosition(subrequest.GetCursorArgument().size()); if (opt_defs_index != -1) { - HandleOptionArgumentCompletion(subrequest, opt_element_vector, i, + HandleOptionArgumentCompletion(request, opt_element_vector, i, interpreter); - request.SetWordComplete(subrequest.GetWordComplete()); return true; } else { // No completion callback means no completions... @@ -754,34 +737,20 @@ bool Options::HandleOptionCompletion(CompletionRequest &request, return false; } -bool Options::HandleOptionArgumentCompletion( +void Options::HandleOptionArgumentCompletion( CompletionRequest &request, OptionElementVector &opt_element_vector, int opt_element_index, CommandInterpreter &interpreter) { auto opt_defs = GetDefinitions(); std::unique_ptr<SearchFilter> filter_up; - int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos; int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; // See if this is an enumeration type option, and if so complete it here: const auto &enum_values = opt_defs[opt_defs_index].enum_values; - if (!enum_values.empty()) { - bool return_value = false; - std::string match_string( - request.GetParsedLine().GetArgumentAtIndex(opt_arg_pos), - request.GetParsedLine().GetArgumentAtIndex(opt_arg_pos) + - request.GetCursorCharPosition()); - - for (const auto &enum_value : enum_values) { - if (strstr(enum_value.string_value, match_string.c_str()) == - enum_value.string_value) { - request.AddCompletion(enum_value.string_value); - return_value = true; - } - } - return return_value; - } + if (!enum_values.empty()) + for (const auto &enum_value : enum_values) + request.TryCompleteCurrentArg(enum_value.string_value); // If this is a source file or symbol type completion, and there is a -shlib // option somewhere in the supplied arguments, then make a search filter for @@ -836,7 +805,7 @@ bool Options::HandleOptionArgumentCompletion( } } - return CommandCompletions::InvokeCommonCompletionCallbacks( + CommandCompletions::InvokeCommonCompletionCallbacks( interpreter, completion_mask, request, filter_up.get()); } @@ -954,7 +923,7 @@ static Args ReconstituteArgsAfterParsing(llvm::ArrayRef<char *> parsed, for (const char *arg : parsed) { auto pos = FindOriginalIter(arg, original); assert(pos != original.end()); - result.AppendArgument(pos->ref, pos->quote); + result.AppendArgument(pos->ref(), pos->GetQuoteChar()); } return result; } @@ -965,8 +934,8 @@ static size_t FindArgumentIndexForOption(const Args &args, std::string long_opt = llvm::formatv("--{0}", long_option.definition->long_option); for (const auto &entry : llvm::enumerate(args)) { - if (entry.value().ref.startswith(short_opt) || - entry.value().ref.startswith(long_opt)) + if (entry.value().ref().startswith(short_opt) || + entry.value().ref().startswith(long_opt)) return entry.index(); } @@ -1105,7 +1074,7 @@ llvm::Expected<Args> Options::ParseAlias(const Args &args, continue; if (!input_line.empty()) { - auto tmp_arg = args_copy[idx].ref; + auto tmp_arg = args_copy[idx].ref(); size_t pos = input_line.find(tmp_arg); if (pos != std::string::npos) input_line.erase(pos, tmp_arg.size()); @@ -1115,9 +1084,9 @@ llvm::Expected<Args> Options::ParseAlias(const Args &args, OptionParser::eNoArgument) && (OptionParser::GetOptionArgument() != nullptr) && (idx < args_copy.GetArgumentCount()) && - (args_copy[idx].ref == OptionParser::GetOptionArgument())) { + (args_copy[idx].ref() == OptionParser::GetOptionArgument())) { if (input_line.size() > 0) { - auto tmp_arg = args_copy[idx].ref; + auto tmp_arg = args_copy[idx].ref(); size_t pos = input_line.find(tmp_arg); if (pos != std::string::npos) input_line.erase(pos, tmp_arg.size()); @@ -1308,7 +1277,7 @@ OptionElementVector Options::ParseForCompletion(const Args &args, const Args::ArgEntry &cursor = args[cursor_index]; if ((static_cast<int32_t>(dash_dash_pos) == -1 || cursor_index < dash_dash_pos) && - !cursor.IsQuoted() && cursor.ref == "-") { + !cursor.IsQuoted() && cursor.ref() == "-") { option_element_vector.push_back( OptionArgElement(OptionArgElement::eBareDash, cursor_index, OptionArgElement::eBareDash)); @@ -1411,6 +1380,10 @@ llvm::Expected<Args> Options::Parse(const Args &args, ? nullptr : OptionParser::GetOptionArgument(), execution_context); + // If the Option setting returned an error, we should stop parsing + // and return the error. + if (error.Fail()) + break; } else { error.SetErrorStringWithFormat("invalid option with value '%i'", val); } |