aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Interpreter
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Interpreter')
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/CommandAlias.cpp250
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/CommandHistory.cpp106
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp3583
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/CommandObject.cpp854
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/CommandOptionValidators.cpp36
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/CommandReturnObject.cpp175
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/InterpreterProperties.td51
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionArgParser.cpp320
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupArchitecture.cpp54
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupBoolean.cpp54
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupFile.cpp75
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupFormat.cpp283
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupMemoryTag.cpp60
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupOutputFile.cpp60
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupPlatform.cpp148
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp156
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupString.cpp45
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupUInt64.cpp45
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupUUID.cpp48
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp223
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupVariable.cpp141
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionGroupWatchpoint.cpp113
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValue.cpp643
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueArch.cpp71
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueArgs.cpp21
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueArray.cpp320
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueBoolean.cpp83
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueChar.cpp59
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueDictionary.cpp347
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueEnumeration.cpp110
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueFileColonLine.cpp137
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueFileSpec.cpp101
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueFileSpecList.cpp166
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueFormat.cpp62
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueFormatEntity.cpp122
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueLanguage.cpp73
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValuePathMappings.cpp196
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueProperties.cpp491
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueRegex.cpp61
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueSInt64.cpp70
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueString.cpp143
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueUInt64.cpp75
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/OptionValueUUID.cpp81
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/Options.cpp1364
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/Property.cpp309
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/ScriptInterpreter.cpp276
-rw-r--r--contrib/llvm-project/lldb/source/Interpreter/embedded_interpreter.py136
47 files changed, 12397 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Interpreter/CommandAlias.cpp b/contrib/llvm-project/lldb/source/Interpreter/CommandAlias.cpp
new file mode 100644
index 000000000000..c5971b52f837
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/CommandAlias.cpp
@@ -0,0 +1,250 @@
+//===-- CommandAlias.cpp --------------------------------------------------===//
+//
+// 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/CommandAlias.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP &cmd_obj_sp,
+ llvm::StringRef options_args,
+ OptionArgVectorSP &option_arg_vector_sp) {
+ bool success = true;
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+
+ if (options_args.size() < 1)
+ return true;
+
+ Args args(options_args);
+ std::string options_string(options_args);
+ // TODO: Find a way to propagate errors in this CommandReturnObject up the
+ // stack.
+ CommandReturnObject result(false);
+ // Check to see if the command being aliased can take any command options.
+ Options *options = cmd_obj_sp->GetOptions();
+ if (options) {
+ // See if any options were specified as part of the alias; if so, handle
+ // them appropriately.
+ ExecutionContext exe_ctx =
+ cmd_obj_sp->GetCommandInterpreter().GetExecutionContext();
+ options->NotifyOptionParsingStarting(&exe_ctx);
+
+ llvm::Expected<Args> args_or =
+ options->ParseAlias(args, option_arg_vector, options_string);
+ if (!args_or) {
+ result.AppendError(toString(args_or.takeError()));
+ result.AppendError("Unable to create requested alias.\n");
+ return false;
+ }
+ args = std::move(*args_or);
+ options->VerifyPartialOptions(result);
+ if (!result.Succeeded() &&
+ result.GetStatus() != lldb::eReturnStatusStarted) {
+ result.AppendError("Unable to create requested alias.\n");
+ return false;
+ }
+ }
+
+ if (!options_string.empty()) {
+ if (cmd_obj_sp->WantsRawCommandString())
+ option_arg_vector->emplace_back(CommandInterpreter::g_argument,
+ -1, options_string);
+ else {
+ for (auto &entry : args.entries()) {
+ if (!entry.ref().empty())
+ option_arg_vector->emplace_back(std::string(CommandInterpreter::g_argument), -1,
+ std::string(entry.ref()));
+ }
+ }
+ }
+
+ return success;
+}
+
+CommandAlias::CommandAlias(CommandInterpreter &interpreter,
+ lldb::CommandObjectSP cmd_sp,
+ llvm::StringRef options_args, llvm::StringRef name,
+ llvm::StringRef help, llvm::StringRef syntax,
+ uint32_t flags)
+ : CommandObject(interpreter, name, help, syntax, flags),
+ m_option_string(std::string(options_args)),
+ m_option_args_sp(new OptionArgVector),
+ m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false),
+ m_did_set_help_long(false) {
+ if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) {
+ m_underlying_command_sp = cmd_sp;
+ for (int i = 0;
+ auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i);
+ i++) {
+ m_arguments.push_back(*cmd_entry);
+ }
+ if (!help.empty()) {
+ StreamString sstr;
+ StreamString translation_and_help;
+ GetAliasExpansion(sstr);
+
+ translation_and_help.Printf(
+ "(%s) %s", sstr.GetData(),
+ GetUnderlyingCommand()->GetHelp().str().c_str());
+ SetHelp(translation_and_help.GetString());
+ }
+ }
+}
+
+bool CommandAlias::WantsRawCommandString() {
+ if (IsValid())
+ return m_underlying_command_sp->WantsRawCommandString();
+ return false;
+}
+
+bool CommandAlias::WantsCompletion() {
+ if (IsValid())
+ return m_underlying_command_sp->WantsCompletion();
+ return false;
+}
+
+void CommandAlias::HandleCompletion(CompletionRequest &request) {
+ if (IsValid())
+ m_underlying_command_sp->HandleCompletion(request);
+}
+
+void CommandAlias::HandleArgumentCompletion(
+ CompletionRequest &request, OptionElementVector &opt_element_vector) {
+ if (IsValid())
+ m_underlying_command_sp->HandleArgumentCompletion(request,
+ opt_element_vector);
+}
+
+Options *CommandAlias::GetOptions() {
+ if (IsValid())
+ return m_underlying_command_sp->GetOptions();
+ return nullptr;
+}
+
+void CommandAlias::Execute(const char *args_string,
+ CommandReturnObject &result) {
+ llvm_unreachable("CommandAlias::Execute is not to be called");
+}
+
+void CommandAlias::GetAliasExpansion(StreamString &help_string) const {
+ llvm::StringRef command_name = m_underlying_command_sp->GetCommandName();
+ help_string.Printf("'%*s", (int)command_name.size(), command_name.data());
+
+ if (!m_option_args_sp) {
+ help_string.Printf("'");
+ return;
+ }
+
+ OptionArgVector *options = m_option_args_sp.get();
+ std::string opt;
+ std::string value;
+
+ for (const auto &opt_entry : *options) {
+ std::tie(opt, std::ignore, value) = opt_entry;
+ if (opt == CommandInterpreter::g_argument) {
+ help_string.Printf(" %s", value.c_str());
+ } else {
+ help_string.Printf(" %s", opt.c_str());
+ if ((value != CommandInterpreter::g_no_argument)
+ && (value != CommandInterpreter::g_need_argument)) {
+ help_string.Printf(" %s", value.c_str());
+ }
+ }
+ }
+
+ help_string.Printf("'");
+}
+
+bool CommandAlias::IsDashDashCommand() {
+ if (m_is_dashdash_alias != eLazyBoolCalculate)
+ return (m_is_dashdash_alias == eLazyBoolYes);
+ m_is_dashdash_alias = eLazyBoolNo;
+ if (!IsValid())
+ return false;
+
+ std::string opt;
+ std::string value;
+
+ for (const auto &opt_entry : *GetOptionArguments()) {
+ std::tie(opt, std::ignore, value) = opt_entry;
+ if (opt == CommandInterpreter::g_argument && !value.empty() &&
+ llvm::StringRef(value).ends_with("--")) {
+ m_is_dashdash_alias = eLazyBoolYes;
+ break;
+ }
+ }
+
+ // if this is a nested alias, it may be adding arguments on top of an already
+ // dash-dash alias
+ if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias())
+ m_is_dashdash_alias =
+ (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes
+ : eLazyBoolNo);
+ return (m_is_dashdash_alias == eLazyBoolYes);
+}
+
+bool CommandAlias::IsNestedAlias() {
+ if (GetUnderlyingCommand())
+ return GetUnderlyingCommand()->IsAlias();
+ return false;
+}
+
+std::pair<lldb::CommandObjectSP, OptionArgVectorSP> CommandAlias::Desugar() {
+ auto underlying = GetUnderlyingCommand();
+ if (!underlying)
+ return {nullptr, nullptr};
+
+ if (underlying->IsAlias()) {
+ // FIXME: This doesn't work if the original alias fills a slot in the
+ // underlying alias, since this just appends the two lists.
+ auto desugared = ((CommandAlias *)underlying.get())->Desugar();
+ OptionArgVectorSP options = std::make_shared<OptionArgVector>();
+ llvm::append_range(*options, *desugared.second);
+ llvm::append_range(*options, *GetOptionArguments());
+ return {desugared.first, options};
+ }
+
+ return {underlying, GetOptionArguments()};
+}
+
+// allow CommandAlias objects to provide their own help, but fallback to the
+// info for the underlying command if no customization has been provided
+void CommandAlias::SetHelp(llvm::StringRef str) {
+ this->CommandObject::SetHelp(str);
+ m_did_set_help = true;
+}
+
+void CommandAlias::SetHelpLong(llvm::StringRef str) {
+ this->CommandObject::SetHelpLong(str);
+ m_did_set_help_long = true;
+}
+
+llvm::StringRef CommandAlias::GetHelp() {
+ if (!m_cmd_help_short.empty() || m_did_set_help)
+ return m_cmd_help_short;
+ if (IsValid())
+ return m_underlying_command_sp->GetHelp();
+ return llvm::StringRef();
+}
+
+llvm::StringRef CommandAlias::GetHelpLong() {
+ if (!m_cmd_help_long.empty() || m_did_set_help_long)
+ return m_cmd_help_long;
+ if (IsValid())
+ return m_underlying_command_sp->GetHelpLong();
+ return llvm::StringRef();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/CommandHistory.cpp b/contrib/llvm-project/lldb/source/Interpreter/CommandHistory.cpp
new file mode 100644
index 000000000000..f5dbcb675030
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/CommandHistory.cpp
@@ -0,0 +1,106 @@
+//===-- CommandHistory.cpp ------------------------------------------------===//
+//
+// 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 <cinttypes>
+#include <optional>
+
+#include "lldb/Interpreter/CommandHistory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+size_t CommandHistory::GetSize() const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ return m_history.size();
+}
+
+bool CommandHistory::IsEmpty() const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ return m_history.empty();
+}
+
+std::optional<llvm::StringRef>
+CommandHistory::FindString(llvm::StringRef input_str) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (input_str.size() < 2)
+ return std::nullopt;
+
+ if (input_str[0] != g_repeat_char)
+ return std::nullopt;
+
+ if (input_str[1] == g_repeat_char) {
+ if (m_history.empty())
+ return std::nullopt;
+ return llvm::StringRef(m_history.back());
+ }
+
+ input_str = input_str.drop_front();
+
+ size_t idx = 0;
+ if (input_str.front() == '-') {
+ if (input_str.drop_front(1).getAsInteger(0, idx))
+ return std::nullopt;
+ if (idx >= m_history.size())
+ return std::nullopt;
+ idx = m_history.size() - idx;
+ } else {
+ if (input_str.getAsInteger(0, idx))
+ return std::nullopt;
+ if (idx >= m_history.size())
+ return std::nullopt;
+ }
+
+ return llvm::StringRef(m_history[idx]);
+}
+
+llvm::StringRef CommandHistory::GetStringAtIndex(size_t idx) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (idx < m_history.size())
+ return m_history[idx];
+ return "";
+}
+
+llvm::StringRef CommandHistory::operator[](size_t idx) const {
+ return GetStringAtIndex(idx);
+}
+
+llvm::StringRef CommandHistory::GetRecentmostString() const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (m_history.empty())
+ return "";
+ return m_history.back();
+}
+
+void CommandHistory::AppendString(llvm::StringRef str, bool reject_if_dupe) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (reject_if_dupe) {
+ if (!m_history.empty()) {
+ if (str == m_history.back())
+ return;
+ }
+ }
+ m_history.push_back(std::string(str));
+}
+
+void CommandHistory::Clear() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ m_history.clear();
+}
+
+void CommandHistory::Dump(Stream &stream, size_t start_idx,
+ size_t stop_idx) const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ stop_idx = std::min(stop_idx + 1, m_history.size());
+ for (size_t counter = start_idx; counter < stop_idx; counter++) {
+ const std::string hist_item = m_history[counter];
+ if (!hist_item.empty()) {
+ stream.Indent();
+ stream.Printf("%4" PRIu64 ": %s\n", (uint64_t)counter, hist_item.c_str());
+ }
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp b/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp
new file mode 100644
index 000000000000..fc07168b6c0a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -0,0 +1,3583 @@
+//===-- CommandInterpreter.cpp --------------------------------------------===//
+//
+// 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 <chrono>
+#include <cstdlib>
+#include <limits>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "Commands/CommandObjectApropos.h"
+#include "Commands/CommandObjectBreakpoint.h"
+#include "Commands/CommandObjectCommands.h"
+#include "Commands/CommandObjectDWIMPrint.h"
+#include "Commands/CommandObjectDiagnostics.h"
+#include "Commands/CommandObjectDisassemble.h"
+#include "Commands/CommandObjectExpression.h"
+#include "Commands/CommandObjectFrame.h"
+#include "Commands/CommandObjectGUI.h"
+#include "Commands/CommandObjectHelp.h"
+#include "Commands/CommandObjectLanguage.h"
+#include "Commands/CommandObjectLog.h"
+#include "Commands/CommandObjectMemory.h"
+#include "Commands/CommandObjectPlatform.h"
+#include "Commands/CommandObjectPlugin.h"
+#include "Commands/CommandObjectProcess.h"
+#include "Commands/CommandObjectQuit.h"
+#include "Commands/CommandObjectRegexCommand.h"
+#include "Commands/CommandObjectRegister.h"
+#include "Commands/CommandObjectScripting.h"
+#include "Commands/CommandObjectSession.h"
+#include "Commands/CommandObjectSettings.h"
+#include "Commands/CommandObjectSource.h"
+#include "Commands/CommandObjectStats.h"
+#include "Commands/CommandObjectTarget.h"
+#include "Commands/CommandObjectThread.h"
+#include "Commands/CommandObjectTrace.h"
+#include "Commands/CommandObjectType.h"
+#include "Commands/CommandObjectVersion.h"
+#include "Commands/CommandObjectWatchpoint.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/StreamFile.h"
+#include "lldb/Utility/ErrorMessages.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/State.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/Timer.h"
+
+#include "lldb/Host/Config.h"
+#if LLDB_ENABLE_LIBEDIT
+#include "lldb/Host/Editline.h"
+#endif
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileCache.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/Property.h"
+#include "lldb/Utility/Args.h"
+
+#include "lldb/Target/Language.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/ScopeExit.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+#if defined(__APPLE__)
+#include <TargetConditionals.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *k_white_space = " \t\v";
+
+static constexpr const char *InitFileWarning =
+ "There is a .lldbinit file in the current directory which is not being "
+ "read.\n"
+ "To silence this warning without sourcing in the local .lldbinit,\n"
+ "add the following to the lldbinit file in your home directory:\n"
+ " settings set target.load-cwd-lldbinit false\n"
+ "To allow lldb to source .lldbinit files in the current working "
+ "directory,\n"
+ "set the value of this variable to true. Only do so if you understand "
+ "and\n"
+ "accept the security risk.";
+
+const char *CommandInterpreter::g_no_argument = "<no-argument>";
+const char *CommandInterpreter::g_need_argument = "<need-argument>";
+const char *CommandInterpreter::g_argument = "<argument>";
+
+
+#define LLDB_PROPERTIES_interpreter
+#include "InterpreterProperties.inc"
+
+enum {
+#define LLDB_PROPERTIES_interpreter
+#include "InterpreterPropertiesEnum.inc"
+};
+
+llvm::StringRef CommandInterpreter::GetStaticBroadcasterClass() {
+ static constexpr llvm::StringLiteral class_name("lldb.commandInterpreter");
+ return class_name;
+}
+
+CommandInterpreter::CommandInterpreter(Debugger &debugger,
+ bool synchronous_execution)
+ : Broadcaster(debugger.GetBroadcasterManager(),
+ CommandInterpreter::GetStaticBroadcasterClass().str()),
+ Properties(
+ OptionValuePropertiesSP(new OptionValueProperties("interpreter"))),
+ IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand),
+ m_debugger(debugger), m_synchronous_execution(true),
+ m_skip_lldbinit_files(false), m_skip_app_init_files(false),
+ m_comment_char('#'), m_batch_command_mode(false),
+ m_truncation_warning(eNoOmission), m_max_depth_warning(eNoOmission),
+ m_command_source_depth(0) {
+ SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit");
+ SetEventName(eBroadcastBitResetPrompt, "reset-prompt");
+ SetEventName(eBroadcastBitQuitCommandReceived, "quit");
+ SetSynchronous(synchronous_execution);
+ CheckInWithManager();
+ m_collection_sp->Initialize(g_interpreter_properties);
+}
+
+bool CommandInterpreter::GetExpandRegexAliases() const {
+ const uint32_t idx = ePropertyExpandRegexAliases;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
+bool CommandInterpreter::GetPromptOnQuit() const {
+ const uint32_t idx = ePropertyPromptOnQuit;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
+void CommandInterpreter::SetPromptOnQuit(bool enable) {
+ const uint32_t idx = ePropertyPromptOnQuit;
+ SetPropertyAtIndex(idx, enable);
+}
+
+bool CommandInterpreter::GetSaveTranscript() const {
+ const uint32_t idx = ePropertySaveTranscript;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
+void CommandInterpreter::SetSaveTranscript(bool enable) {
+ const uint32_t idx = ePropertySaveTranscript;
+ SetPropertyAtIndex(idx, enable);
+}
+
+bool CommandInterpreter::GetSaveSessionOnQuit() const {
+ const uint32_t idx = ePropertySaveSessionOnQuit;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
+void CommandInterpreter::SetSaveSessionOnQuit(bool enable) {
+ const uint32_t idx = ePropertySaveSessionOnQuit;
+ SetPropertyAtIndex(idx, enable);
+}
+
+bool CommandInterpreter::GetOpenTranscriptInEditor() const {
+ const uint32_t idx = ePropertyOpenTranscriptInEditor;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
+void CommandInterpreter::SetOpenTranscriptInEditor(bool enable) {
+ const uint32_t idx = ePropertyOpenTranscriptInEditor;
+ SetPropertyAtIndex(idx, enable);
+}
+
+FileSpec CommandInterpreter::GetSaveSessionDirectory() const {
+ const uint32_t idx = ePropertySaveSessionDirectory;
+ return GetPropertyAtIndexAs<FileSpec>(idx, {});
+}
+
+void CommandInterpreter::SetSaveSessionDirectory(llvm::StringRef path) {
+ const uint32_t idx = ePropertySaveSessionDirectory;
+ SetPropertyAtIndex(idx, path);
+}
+
+bool CommandInterpreter::GetEchoCommands() const {
+ const uint32_t idx = ePropertyEchoCommands;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
+void CommandInterpreter::SetEchoCommands(bool enable) {
+ const uint32_t idx = ePropertyEchoCommands;
+ SetPropertyAtIndex(idx, enable);
+}
+
+bool CommandInterpreter::GetEchoCommentCommands() const {
+ const uint32_t idx = ePropertyEchoCommentCommands;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
+void CommandInterpreter::SetEchoCommentCommands(bool enable) {
+ const uint32_t idx = ePropertyEchoCommentCommands;
+ SetPropertyAtIndex(idx, enable);
+}
+
+void CommandInterpreter::AllowExitCodeOnQuit(bool allow) {
+ m_allow_exit_code = allow;
+ if (!allow)
+ m_quit_exit_code.reset();
+}
+
+bool CommandInterpreter::SetQuitExitCode(int exit_code) {
+ if (!m_allow_exit_code)
+ return false;
+ m_quit_exit_code = exit_code;
+ return true;
+}
+
+int CommandInterpreter::GetQuitExitCode(bool &exited) const {
+ exited = m_quit_exit_code.has_value();
+ if (exited)
+ return *m_quit_exit_code;
+ return 0;
+}
+
+void CommandInterpreter::ResolveCommand(const char *command_line,
+ CommandReturnObject &result) {
+ std::string command = command_line;
+ if (ResolveCommandImpl(command, result) != nullptr) {
+ result.AppendMessageWithFormat("%s", command.c_str());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+}
+
+bool CommandInterpreter::GetStopCmdSourceOnError() const {
+ const uint32_t idx = ePropertyStopCmdSourceOnError;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
+bool CommandInterpreter::GetSpaceReplPrompts() const {
+ const uint32_t idx = ePropertySpaceReplPrompts;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
+bool CommandInterpreter::GetRepeatPreviousCommand() const {
+ const uint32_t idx = ePropertyRepeatPreviousCommand;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
+bool CommandInterpreter::GetRequireCommandOverwrite() const {
+ const uint32_t idx = ePropertyRequireCommandOverwrite;
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
+void CommandInterpreter::Initialize() {
+ LLDB_SCOPED_TIMER();
+
+ CommandReturnObject result(m_debugger.GetUseColor());
+
+ LoadCommandDictionary();
+
+ // An alias arguments vector to reuse - reset it before use...
+ OptionArgVectorSP alias_arguments_vector_sp(new OptionArgVector);
+
+ // Set up some initial aliases.
+ CommandObjectSP cmd_obj_sp = GetCommandSPExact("quit");
+ if (cmd_obj_sp) {
+ AddAlias("q", cmd_obj_sp);
+ AddAlias("exit", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("_regexp-attach");
+ if (cmd_obj_sp)
+ AddAlias("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+
+ cmd_obj_sp = GetCommandSPExact("process detach");
+ if (cmd_obj_sp) {
+ AddAlias("detach", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("process continue");
+ if (cmd_obj_sp) {
+ AddAlias("c", cmd_obj_sp);
+ AddAlias("continue", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("_regexp-break");
+ if (cmd_obj_sp)
+ AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+
+ cmd_obj_sp = GetCommandSPExact("_regexp-tbreak");
+ if (cmd_obj_sp)
+ AddAlias("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+
+ cmd_obj_sp = GetCommandSPExact("thread step-inst");
+ if (cmd_obj_sp) {
+ AddAlias("stepi", cmd_obj_sp);
+ AddAlias("si", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("thread step-inst-over");
+ if (cmd_obj_sp) {
+ AddAlias("nexti", cmd_obj_sp);
+ AddAlias("ni", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("thread step-in");
+ if (cmd_obj_sp) {
+ AddAlias("s", cmd_obj_sp);
+ AddAlias("step", cmd_obj_sp);
+ CommandAlias *sif_alias = AddAlias(
+ "sif", cmd_obj_sp, "--end-linenumber block --step-in-target %1");
+ if (sif_alias) {
+ sif_alias->SetHelp("Step through the current block, stopping if you step "
+ "directly into a function whose name matches the "
+ "TargetFunctionName.");
+ sif_alias->SetSyntax("sif <TargetFunctionName>");
+ }
+ }
+
+ cmd_obj_sp = GetCommandSPExact("thread step-over");
+ if (cmd_obj_sp) {
+ AddAlias("n", cmd_obj_sp);
+ AddAlias("next", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("thread step-out");
+ if (cmd_obj_sp) {
+ AddAlias("finish", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("frame select");
+ if (cmd_obj_sp) {
+ AddAlias("f", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("thread select");
+ if (cmd_obj_sp) {
+ AddAlias("t", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("_regexp-jump");
+ if (cmd_obj_sp) {
+ AddAlias("j", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+ AddAlias("jump", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+ }
+
+ cmd_obj_sp = GetCommandSPExact("_regexp-list");
+ if (cmd_obj_sp) {
+ AddAlias("l", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+ AddAlias("list", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+ }
+
+ cmd_obj_sp = GetCommandSPExact("_regexp-env");
+ if (cmd_obj_sp)
+ AddAlias("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+
+ cmd_obj_sp = GetCommandSPExact("memory read");
+ if (cmd_obj_sp)
+ AddAlias("x", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact("_regexp-up");
+ if (cmd_obj_sp)
+ AddAlias("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+
+ cmd_obj_sp = GetCommandSPExact("_regexp-down");
+ if (cmd_obj_sp)
+ AddAlias("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+
+ cmd_obj_sp = GetCommandSPExact("_regexp-display");
+ if (cmd_obj_sp)
+ AddAlias("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+
+ cmd_obj_sp = GetCommandSPExact("disassemble");
+ if (cmd_obj_sp)
+ AddAlias("dis", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact("disassemble");
+ if (cmd_obj_sp)
+ AddAlias("di", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact("_regexp-undisplay");
+ if (cmd_obj_sp)
+ AddAlias("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+
+ cmd_obj_sp = GetCommandSPExact("_regexp-bt");
+ if (cmd_obj_sp)
+ AddAlias("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
+
+ cmd_obj_sp = GetCommandSPExact("target create");
+ if (cmd_obj_sp)
+ AddAlias("file", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact("target modules");
+ if (cmd_obj_sp)
+ AddAlias("image", cmd_obj_sp);
+
+ alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
+
+ cmd_obj_sp = GetCommandSPExact("dwim-print");
+ if (cmd_obj_sp) {
+ AddAlias("p", cmd_obj_sp, "--")->SetHelpLong("");
+ AddAlias("print", 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) {
+ parray_alias->SetHelp
+ ("parray <COUNT> <EXPRESSION> -- lldb will evaluate EXPRESSION "
+ "to get a typed-pointer-to-an-array in memory, and will display "
+ "COUNT elements of that type from the array.");
+ parray_alias->SetHelpLong("");
+ }
+ CommandAlias *poarray_alias = AddAlias("poarray", cmd_obj_sp,
+ "--object-description --element-count %1 --");
+ if (poarray_alias) {
+ poarray_alias->SetHelp("poarray <COUNT> <EXPRESSION> -- lldb will "
+ "evaluate EXPRESSION to get the address of an array of COUNT "
+ "objects in memory, and will call po on them.");
+ poarray_alias->SetHelpLong("");
+ }
+ }
+
+ cmd_obj_sp = GetCommandSPExact("platform shell");
+ if (cmd_obj_sp) {
+ CommandAlias *shell_alias = AddAlias("shell", cmd_obj_sp, " --host --");
+ if (shell_alias) {
+ shell_alias->SetHelp("Run a shell command on the host.");
+ shell_alias->SetHelpLong("");
+ shell_alias->SetSyntax("shell <shell-command>");
+ }
+ }
+
+ cmd_obj_sp = GetCommandSPExact("process kill");
+ if (cmd_obj_sp) {
+ AddAlias("kill", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("process launch");
+ if (cmd_obj_sp) {
+ alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
+#if defined(__APPLE__)
+#if TARGET_OS_IPHONE
+ AddAlias("r", cmd_obj_sp, "--");
+ AddAlias("run", cmd_obj_sp, "--");
+#else
+ AddAlias("r", cmd_obj_sp, "--shell-expand-args true --");
+ AddAlias("run", cmd_obj_sp, "--shell-expand-args true --");
+#endif
+#else
+ StreamString defaultshell;
+ defaultshell.Printf("--shell=%s --",
+ HostInfo::GetDefaultShell().GetPath().c_str());
+ AddAlias("r", cmd_obj_sp, defaultshell.GetString());
+ AddAlias("run", cmd_obj_sp, defaultshell.GetString());
+#endif
+ }
+
+ cmd_obj_sp = GetCommandSPExact("target symbols add");
+ if (cmd_obj_sp) {
+ AddAlias("add-dsym", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("breakpoint set");
+ if (cmd_obj_sp) {
+ AddAlias("rbreak", cmd_obj_sp, "--func-regex %1");
+ }
+
+ cmd_obj_sp = GetCommandSPExact("frame variable");
+ if (cmd_obj_sp) {
+ AddAlias("v", cmd_obj_sp);
+ AddAlias("var", cmd_obj_sp);
+ AddAlias("vo", cmd_obj_sp, "--object-description");
+ }
+
+ cmd_obj_sp = GetCommandSPExact("register");
+ if (cmd_obj_sp) {
+ AddAlias("re", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("scripting run");
+ if (cmd_obj_sp) {
+ AddAlias("sc", cmd_obj_sp);
+ AddAlias("scr", cmd_obj_sp);
+ AddAlias("scri", cmd_obj_sp);
+ AddAlias("scrip", cmd_obj_sp);
+ AddAlias("script", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("session history");
+ if (cmd_obj_sp) {
+ AddAlias("history", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact("help");
+ if (cmd_obj_sp) {
+ AddAlias("h", cmd_obj_sp);
+ }
+}
+
+void CommandInterpreter::Clear() {
+ m_command_io_handler_sp.reset();
+}
+
+const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) {
+ // This function has not yet been implemented.
+
+ // Look for any embedded script command
+ // If found,
+ // get interpreter object from the command dictionary,
+ // call execute_one_command on it,
+ // get the results as a string,
+ // substitute that string for current stuff.
+
+ return arg;
+}
+
+#define REGISTER_COMMAND_OBJECT(NAME, CLASS) \
+ m_command_dict[NAME] = std::make_shared<CLASS>(*this);
+
+void CommandInterpreter::LoadCommandDictionary() {
+ LLDB_SCOPED_TIMER();
+
+ REGISTER_COMMAND_OBJECT("apropos", CommandObjectApropos);
+ REGISTER_COMMAND_OBJECT("breakpoint", CommandObjectMultiwordBreakpoint);
+ REGISTER_COMMAND_OBJECT("command", CommandObjectMultiwordCommands);
+ REGISTER_COMMAND_OBJECT("diagnostics", CommandObjectDiagnostics);
+ REGISTER_COMMAND_OBJECT("disassemble", CommandObjectDisassemble);
+ REGISTER_COMMAND_OBJECT("dwim-print", CommandObjectDWIMPrint);
+ REGISTER_COMMAND_OBJECT("expression", CommandObjectExpression);
+ REGISTER_COMMAND_OBJECT("frame", CommandObjectMultiwordFrame);
+ REGISTER_COMMAND_OBJECT("gui", CommandObjectGUI);
+ REGISTER_COMMAND_OBJECT("help", CommandObjectHelp);
+ REGISTER_COMMAND_OBJECT("log", CommandObjectLog);
+ REGISTER_COMMAND_OBJECT("memory", CommandObjectMemory);
+ REGISTER_COMMAND_OBJECT("platform", CommandObjectPlatform);
+ REGISTER_COMMAND_OBJECT("plugin", CommandObjectPlugin);
+ REGISTER_COMMAND_OBJECT("process", CommandObjectMultiwordProcess);
+ REGISTER_COMMAND_OBJECT("quit", CommandObjectQuit);
+ REGISTER_COMMAND_OBJECT("register", CommandObjectRegister);
+ REGISTER_COMMAND_OBJECT("scripting", CommandObjectMultiwordScripting);
+ REGISTER_COMMAND_OBJECT("settings", CommandObjectMultiwordSettings);
+ REGISTER_COMMAND_OBJECT("session", CommandObjectSession);
+ REGISTER_COMMAND_OBJECT("source", CommandObjectMultiwordSource);
+ REGISTER_COMMAND_OBJECT("statistics", CommandObjectStats);
+ REGISTER_COMMAND_OBJECT("target", CommandObjectMultiwordTarget);
+ REGISTER_COMMAND_OBJECT("thread", CommandObjectMultiwordThread);
+ REGISTER_COMMAND_OBJECT("trace", CommandObjectTrace);
+ REGISTER_COMMAND_OBJECT("type", CommandObjectType);
+ REGISTER_COMMAND_OBJECT("version", CommandObjectVersion);
+ REGISTER_COMMAND_OBJECT("watchpoint", CommandObjectMultiwordWatchpoint);
+ REGISTER_COMMAND_OBJECT("language", CommandObjectLanguage);
+
+ // clang-format off
+ const char *break_regexes[][2] = {
+ {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
+ "breakpoint set --file '%1' --line %2 --column %3"},
+ {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
+ "breakpoint set --file '%1' --line %2"},
+ {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
+ {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
+ {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
+ {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$",
+ "breakpoint set --name '%1'"},
+ {"^(-.*)$", "breakpoint set %1"},
+ {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$",
+ "breakpoint set --name '%2' --shlib '%1'"},
+ {"^\\&(.*[^[:space:]])[[:space:]]*$",
+ "breakpoint set --name '%1' --skip-prologue=0"},
+ {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$",
+ "breakpoint set --name '%1'"}};
+ // clang-format on
+
+ size_t num_regexes = std::size(break_regexes);
+
+ std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "_regexp-break",
+ "Set a breakpoint using one of several shorthand formats.",
+ "\n"
+ "_regexp-break <filename>:<linenum>:<colnum>\n"
+ " main.c:12:21 // Break at line 12 and column "
+ "21 of main.c\n\n"
+ "_regexp-break <filename>:<linenum>\n"
+ " main.c:12 // Break at line 12 of "
+ "main.c\n\n"
+ "_regexp-break <linenum>\n"
+ " 12 // Break at line 12 of current "
+ "file\n\n"
+ "_regexp-break 0x<address>\n"
+ " 0x1234000 // Break at address "
+ "0x1234000\n\n"
+ "_regexp-break <name>\n"
+ " main // Break in 'main' after the "
+ "prologue\n\n"
+ "_regexp-break &<name>\n"
+ " &main // Break at first instruction "
+ "in 'main'\n\n"
+ "_regexp-break <module>`<name>\n"
+ " libc.so`malloc // Break in 'malloc' from "
+ "'libc.so'\n\n"
+ "_regexp-break /<source-regex>/\n"
+ " /break here/ // Break on source lines in "
+ "current file\n"
+ " // containing text 'break "
+ "here'.\n",
+ lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false));
+
+ if (break_regex_cmd_up) {
+ bool success = true;
+ for (size_t i = 0; i < num_regexes; i++) {
+ success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0],
+ break_regexes[i][1]);
+ if (!success)
+ break;
+ }
+ success =
+ break_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
+
+ if (success) {
+ CommandObjectSP break_regex_cmd_sp(break_regex_cmd_up.release());
+ m_command_dict[std::string(break_regex_cmd_sp->GetCommandName())] =
+ break_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "_regexp-tbreak",
+ "Set a one-shot breakpoint using one of several shorthand formats.",
+ "\n"
+ "_regexp-break <filename>:<linenum>:<colnum>\n"
+ " main.c:12:21 // Break at line 12 and column "
+ "21 of main.c\n\n"
+ "_regexp-break <filename>:<linenum>\n"
+ " main.c:12 // Break at line 12 of "
+ "main.c\n\n"
+ "_regexp-break <linenum>\n"
+ " 12 // Break at line 12 of current "
+ "file\n\n"
+ "_regexp-break 0x<address>\n"
+ " 0x1234000 // Break at address "
+ "0x1234000\n\n"
+ "_regexp-break <name>\n"
+ " main // Break in 'main' after the "
+ "prologue\n\n"
+ "_regexp-break &<name>\n"
+ " &main // Break at first instruction "
+ "in 'main'\n\n"
+ "_regexp-break <module>`<name>\n"
+ " libc.so`malloc // Break in 'malloc' from "
+ "'libc.so'\n\n"
+ "_regexp-break /<source-regex>/\n"
+ " /break here/ // Break on source lines in "
+ "current file\n"
+ " // containing text 'break "
+ "here'.\n",
+ lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false));
+
+ if (tbreak_regex_cmd_up) {
+ bool success = true;
+ for (size_t i = 0; i < num_regexes; i++) {
+ std::string command = break_regexes[i][1];
+ command += " -o 1";
+ success =
+ tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], command);
+ if (!success)
+ break;
+ }
+ success =
+ tbreak_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
+
+ if (success) {
+ CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_up.release());
+ m_command_dict[std::string(tbreak_regex_cmd_sp->GetCommandName())] =
+ tbreak_regex_cmd_sp;
+ }
+ }
+
+ 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>", 0, false));
+ if (attach_regex_cmd_up) {
+ if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
+ "process attach --pid %1") &&
+ attach_regex_cmd_up->AddRegexCommand(
+ "^(-.*|.* -.*)$", "process attach %1") && // Any options that are
+ // specified get passed to
+ // 'process attach'
+ attach_regex_cmd_up->AddRegexCommand("^(.+)$",
+ "process attach --name '%1'") &&
+ attach_regex_cmd_up->AddRegexCommand("^$", "process attach")) {
+ CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_up.release());
+ m_command_dict[std::string(attach_regex_cmd_sp->GetCommandName())] =
+ attach_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up(
+ new CommandObjectRegexCommand(*this, "_regexp-down",
+ "Select a newer stack frame. Defaults to "
+ "moving one frame, a numeric argument can "
+ "specify an arbitrary number.",
+ "_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]+)$",
+ "frame select -r -%1")) {
+ CommandObjectSP down_regex_cmd_sp(down_regex_cmd_up.release());
+ m_command_dict[std::string(down_regex_cmd_sp->GetCommandName())] =
+ down_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "_regexp-up",
+ "Select an older stack frame. Defaults to moving one "
+ "frame, a numeric argument can specify an arbitrary number.",
+ "_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")) {
+ CommandObjectSP up_regex_cmd_sp(up_regex_cmd_up.release());
+ m_command_dict[std::string(up_regex_cmd_sp->GetCommandName())] =
+ up_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "_regexp-display",
+ "Evaluate an expression at every stop (see 'help target stop-hook'.)",
+ "_regexp-display expression", 0, false));
+ if (display_regex_cmd_up) {
+ if (display_regex_cmd_up->AddRegexCommand(
+ "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) {
+ CommandObjectSP display_regex_cmd_sp(display_regex_cmd_up.release());
+ m_command_dict[std::string(display_regex_cmd_sp->GetCommandName())] =
+ display_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up(
+ new CommandObjectRegexCommand(*this, "_regexp-undisplay",
+ "Stop displaying expression at every "
+ "stop (specified by stop-hook index.)",
+ "_regexp-undisplay stop-hook-number", 0,
+ false));
+ if (undisplay_regex_cmd_up) {
+ if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
+ "target stop-hook delete %1")) {
+ CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release());
+ m_command_dict[std::string(undisplay_regex_cmd_sp->GetCommandName())] =
+ undisplay_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "gdb-remote",
+ "Connect to a process via remote GDB server.\n"
+ "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>", 0, false));
+ if (connect_gdb_remote_cmd_up) {
+ if (connect_gdb_remote_cmd_up->AddRegexCommand(
+ "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
+ "process connect --plugin gdb-remote connect://%1:%2") &&
+ connect_gdb_remote_cmd_up->AddRegexCommand(
+ "^([[:digit:]]+)$",
+ "process connect --plugin gdb-remote connect://localhost:%1")) {
+ CommandObjectSP command_sp(connect_gdb_remote_cmd_up.release());
+ m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "kdp-remote",
+ "Connect to a process via remote KDP server.\n"
+ "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>]", 0, false));
+ if (connect_kdp_remote_cmd_up) {
+ if (connect_kdp_remote_cmd_up->AddRegexCommand(
+ "^([^:]+:[[:digit:]]+)$",
+ "process connect --plugin kdp-remote udp://%1") &&
+ connect_kdp_remote_cmd_up->AddRegexCommand(
+ "^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) {
+ CommandObjectSP command_sp(connect_kdp_remote_cmd_up.release());
+ m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "_regexp-bt",
+ "Show backtrace of the current thread's call stack. Any numeric "
+ "argument displays at most that many 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]", 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"
+ // but the intention is to have this emulate the gdb "bt" command and so
+ // now "bt 3" is the preferred form, in line with gdb.
+ if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$",
+ "thread backtrace -c %1") &&
+ bt_regex_cmd_up->AddRegexCommand("^-c ([[:digit:]]+)[[:space:]]*$",
+ "thread backtrace -c %1") &&
+ bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") &&
+ bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) {
+ CommandObjectSP command_sp(bt_regex_cmd_up.release());
+ m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "_regexp-list",
+ "List relevant source code using one of several shorthand formats.",
+ "\n"
+ "_regexp-list <file>:<line> // List around specific file/line\n"
+ "_regexp-list <line> // List current file around specified "
+ "line\n"
+ "_regexp-list <function-name> // List specified function\n"
+ "_regexp-list 0x<address> // List around specified address\n"
+ "_regexp-list -[<count>] // List previous <count> lines\n"
+ "_regexp-list // List subsequent lines",
+ lldb::eSourceFileCompletion, false));
+ if (list_regex_cmd_up) {
+ if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
+ "source list --line %1") &&
+ list_regex_cmd_up->AddRegexCommand(
+ "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]"
+ "]*$",
+ "source list --file '%1' --line %2") &&
+ list_regex_cmd_up->AddRegexCommand(
+ "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
+ "source list --address %1") &&
+ list_regex_cmd_up->AddRegexCommand("^-[[:space:]]*$",
+ "source list --reverse") &&
+ list_regex_cmd_up->AddRegexCommand(
+ "^-([[:digit:]]+)[[:space:]]*$",
+ "source list --reverse --count %1") &&
+ list_regex_cmd_up->AddRegexCommand("^(.+)$",
+ "source list --name \"%1\"") &&
+ list_regex_cmd_up->AddRegexCommand("^$", "source list")) {
+ CommandObjectSP list_regex_cmd_sp(list_regex_cmd_up.release());
+ m_command_dict[std::string(list_regex_cmd_sp->GetCommandName())] =
+ list_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "_regexp-env",
+ "Shorthand for viewing and setting environment variables.",
+ "\n"
+ "_regexp-env // Show environment\n"
+ "_regexp-env <name>=<value> // Set an environment variable",
+ 0, false));
+ if (env_regex_cmd_up) {
+ if (env_regex_cmd_up->AddRegexCommand("^$",
+ "settings show target.env-vars") &&
+ env_regex_cmd_up->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$",
+ "settings set target.env-vars %1")) {
+ CommandObjectSP env_regex_cmd_sp(env_regex_cmd_up.release());
+ m_command_dict[std::string(env_regex_cmd_sp->GetCommandName())] =
+ env_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "_regexp-jump", "Set the program counter to a new address.",
+ "\n"
+ "_regexp-jump <line>\n"
+ "_regexp-jump +<line-offset> | -<line-offset>\n"
+ "_regexp-jump <file>:<line>\n"
+ "_regexp-jump *<addr>\n",
+ 0, false));
+ if (jump_regex_cmd_up) {
+ if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$",
+ "thread jump --addr %1") &&
+ jump_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
+ "thread jump --line %1") &&
+ jump_regex_cmd_up->AddRegexCommand("^([^:]+):([0-9]+)$",
+ "thread jump --file %1 --line %2") &&
+ jump_regex_cmd_up->AddRegexCommand("^([+\\-][0-9]+)$",
+ "thread jump --by %1")) {
+ CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_up.release());
+ m_command_dict[std::string(jump_regex_cmd_sp->GetCommandName())] =
+ jump_regex_cmd_sp;
+ }
+ }
+}
+
+int CommandInterpreter::GetCommandNamesMatchingPartialString(
+ const char *cmd_str, bool include_aliases, StringList &matches,
+ StringList &descriptions) {
+ AddNamesMatchingPartialString(m_command_dict, cmd_str, matches,
+ &descriptions);
+
+ if (include_aliases) {
+ AddNamesMatchingPartialString(m_alias_dict, cmd_str, matches,
+ &descriptions);
+ }
+
+ return matches.GetSize();
+}
+
+CommandObjectMultiword *CommandInterpreter::VerifyUserMultiwordCmdPath(
+ Args &path, bool leaf_is_command, Status &result) {
+ result.Clear();
+
+ auto get_multi_or_report_error =
+ [&result](CommandObjectSP cmd_sp,
+ const char *name) -> CommandObjectMultiword * {
+ if (!cmd_sp) {
+ result.SetErrorStringWithFormat("Path component: '%s' not found", name);
+ return nullptr;
+ }
+ if (!cmd_sp->IsUserCommand()) {
+ result.SetErrorStringWithFormat("Path component: '%s' is not a user "
+ "command",
+ name);
+ return nullptr;
+ }
+ CommandObjectMultiword *cmd_as_multi = cmd_sp->GetAsMultiwordCommand();
+ if (!cmd_as_multi) {
+ result.SetErrorStringWithFormat("Path component: '%s' is not a container "
+ "command",
+ name);
+ return nullptr;
+ }
+ return cmd_as_multi;
+ };
+
+ size_t num_args = path.GetArgumentCount();
+ if (num_args == 0) {
+ result.SetErrorString("empty command path");
+ return nullptr;
+ }
+
+ if (num_args == 1 && leaf_is_command) {
+ // We just got a leaf command to be added to the root. That's not an error,
+ // just return null for the container.
+ return nullptr;
+ }
+
+ // Start by getting the root command from the interpreter.
+ const char *cur_name = path.GetArgumentAtIndex(0);
+ CommandObjectSP cur_cmd_sp = GetCommandSPExact(cur_name);
+ CommandObjectMultiword *cur_as_multi =
+ get_multi_or_report_error(cur_cmd_sp, cur_name);
+ if (cur_as_multi == nullptr)
+ return nullptr;
+
+ size_t num_path_elements = num_args - (leaf_is_command ? 1 : 0);
+ for (size_t cursor = 1; cursor < num_path_elements && cur_as_multi != nullptr;
+ cursor++) {
+ cur_name = path.GetArgumentAtIndex(cursor);
+ cur_cmd_sp = cur_as_multi->GetSubcommandSPExact(cur_name);
+ cur_as_multi = get_multi_or_report_error(cur_cmd_sp, cur_name);
+ }
+ return cur_as_multi;
+}
+
+CommandObjectSP
+CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases,
+ bool exact, StringList *matches,
+ StringList *descriptions) const {
+ CommandObjectSP command_sp;
+
+ std::string cmd = std::string(cmd_str);
+
+ if (HasCommands()) {
+ auto pos = m_command_dict.find(cmd);
+ if (pos != m_command_dict.end())
+ command_sp = pos->second;
+ }
+
+ if (include_aliases && HasAliases()) {
+ auto alias_pos = m_alias_dict.find(cmd);
+ if (alias_pos != m_alias_dict.end())
+ command_sp = alias_pos->second;
+ }
+
+ if (HasUserCommands()) {
+ auto pos = m_user_dict.find(cmd);
+ if (pos != m_user_dict.end())
+ command_sp = pos->second;
+ }
+
+ if (HasUserMultiwordCommands()) {
+ auto pos = m_user_mw_dict.find(cmd);
+ if (pos != m_user_mw_dict.end())
+ command_sp = pos->second;
+ }
+
+ if (!exact && !command_sp) {
+ // We will only get into here if we didn't find any exact matches.
+
+ CommandObjectSP user_match_sp, user_mw_match_sp, alias_match_sp,
+ real_match_sp;
+
+ StringList local_matches;
+ if (matches == nullptr)
+ matches = &local_matches;
+
+ unsigned int num_cmd_matches = 0;
+ unsigned int num_alias_matches = 0;
+ unsigned int num_user_matches = 0;
+ unsigned int num_user_mw_matches = 0;
+
+ // Look through the command dictionaries one by one, and if we get only one
+ // match from any of them in toto, then return that, otherwise return an
+ // empty CommandObjectSP and the list of matches.
+
+ if (HasCommands()) {
+ num_cmd_matches = AddNamesMatchingPartialString(m_command_dict, cmd_str,
+ *matches, descriptions);
+ }
+
+ if (num_cmd_matches == 1) {
+ cmd.assign(matches->GetStringAtIndex(0));
+ auto pos = m_command_dict.find(cmd);
+ if (pos != m_command_dict.end())
+ real_match_sp = pos->second;
+ }
+
+ if (include_aliases && HasAliases()) {
+ num_alias_matches = AddNamesMatchingPartialString(m_alias_dict, cmd_str,
+ *matches, descriptions);
+ }
+
+ if (num_alias_matches == 1) {
+ cmd.assign(matches->GetStringAtIndex(num_cmd_matches));
+ auto alias_pos = m_alias_dict.find(cmd);
+ if (alias_pos != m_alias_dict.end())
+ alias_match_sp = alias_pos->second;
+ }
+
+ if (HasUserCommands()) {
+ num_user_matches = AddNamesMatchingPartialString(m_user_dict, cmd_str,
+ *matches, descriptions);
+ }
+
+ if (num_user_matches == 1) {
+ cmd.assign(
+ matches->GetStringAtIndex(num_cmd_matches + num_alias_matches));
+
+ auto pos = m_user_dict.find(cmd);
+ if (pos != m_user_dict.end())
+ user_match_sp = pos->second;
+ }
+
+ if (HasUserMultiwordCommands()) {
+ num_user_mw_matches = AddNamesMatchingPartialString(
+ m_user_mw_dict, cmd_str, *matches, descriptions);
+ }
+
+ if (num_user_mw_matches == 1) {
+ cmd.assign(matches->GetStringAtIndex(num_cmd_matches + num_alias_matches +
+ num_user_matches));
+
+ auto pos = m_user_mw_dict.find(cmd);
+ if (pos != m_user_mw_dict.end())
+ user_mw_match_sp = pos->second;
+ }
+
+ // If we got exactly one match, return that, otherwise return the match
+ // list.
+
+ if (num_user_matches + num_user_mw_matches + num_cmd_matches +
+ num_alias_matches ==
+ 1) {
+ if (num_cmd_matches)
+ return real_match_sp;
+ else if (num_alias_matches)
+ return alias_match_sp;
+ else if (num_user_mw_matches)
+ return user_mw_match_sp;
+ else
+ return user_match_sp;
+ }
+ } else if (matches && command_sp) {
+ matches->AppendString(cmd_str);
+ if (descriptions)
+ descriptions->AppendString(command_sp->GetHelp());
+ }
+
+ return command_sp;
+}
+
+bool CommandInterpreter::AddCommand(llvm::StringRef name,
+ const lldb::CommandObjectSP &cmd_sp,
+ bool can_replace) {
+ if (cmd_sp.get())
+ lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
+ "tried to add a CommandObject from a different interpreter");
+
+ if (name.empty())
+ return false;
+
+ cmd_sp->SetIsUserCommand(false);
+
+ std::string name_sstr(name);
+ auto name_iter = m_command_dict.find(name_sstr);
+ if (name_iter != m_command_dict.end()) {
+ if (!can_replace || !name_iter->second->IsRemovable())
+ return false;
+ name_iter->second = cmd_sp;
+ } else {
+ m_command_dict[name_sstr] = cmd_sp;
+ }
+ return true;
+}
+
+Status CommandInterpreter::AddUserCommand(llvm::StringRef name,
+ const lldb::CommandObjectSP &cmd_sp,
+ bool can_replace) {
+ Status result;
+ if (cmd_sp.get())
+ lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
+ "tried to add a CommandObject from a different interpreter");
+ if (name.empty()) {
+ result.SetErrorString("can't use the empty string for a command name");
+ return result;
+ }
+ // do not allow replacement of internal commands
+ if (CommandExists(name)) {
+ result.SetErrorString("can't replace builtin command");
+ return result;
+ }
+
+ if (UserCommandExists(name)) {
+ if (!can_replace) {
+ result.SetErrorStringWithFormatv(
+ "user command \"{0}\" already exists and force replace was not set "
+ "by --overwrite or 'settings set interpreter.require-overwrite "
+ "false'",
+ name);
+ return result;
+ }
+ if (cmd_sp->IsMultiwordObject()) {
+ if (!m_user_mw_dict[std::string(name)]->IsRemovable()) {
+ result.SetErrorString(
+ "can't replace explicitly non-removable multi-word command");
+ return result;
+ }
+ } else {
+ if (!m_user_dict[std::string(name)]->IsRemovable()) {
+ result.SetErrorString("can't replace explicitly non-removable command");
+ return result;
+ }
+ }
+ }
+
+ cmd_sp->SetIsUserCommand(true);
+
+ if (cmd_sp->IsMultiwordObject())
+ m_user_mw_dict[std::string(name)] = cmd_sp;
+ else
+ m_user_dict[std::string(name)] = cmd_sp;
+ return result;
+}
+
+CommandObjectSP
+CommandInterpreter::GetCommandSPExact(llvm::StringRef cmd_str,
+ bool include_aliases) const {
+ // Break up the command string into words, in case it's a multi-word command.
+ Args cmd_words(cmd_str);
+
+ if (cmd_str.empty())
+ return {};
+
+ if (cmd_words.GetArgumentCount() == 1)
+ return GetCommandSP(cmd_str, include_aliases, true);
+
+ // We have a multi-word command (seemingly), so we need to do more work.
+ // First, get the cmd_obj_sp for the first word in the command.
+ CommandObjectSP cmd_obj_sp =
+ GetCommandSP(cmd_words.GetArgumentAtIndex(0), include_aliases, true);
+ if (!cmd_obj_sp)
+ return {};
+
+ // Loop through the rest of the words in the command (everything passed in
+ // was supposed to be part of a command name), and find the appropriate
+ // sub-command SP for each command word....
+ size_t end = cmd_words.GetArgumentCount();
+ for (size_t i = 1; i < end; ++i) {
+ if (!cmd_obj_sp->IsMultiwordObject()) {
+ // We have more words in the command name, but we don't have a
+ // multiword object. Fail and return.
+ return {};
+ }
+
+ cmd_obj_sp = cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(i));
+ if (!cmd_obj_sp) {
+ // The sub-command name was invalid. Fail and return.
+ return {};
+ }
+ }
+
+ // We successfully looped through all the command words and got valid
+ // command objects for them.
+ return cmd_obj_sp;
+}
+
+CommandObject *
+CommandInterpreter::GetCommandObject(llvm::StringRef cmd_str,
+ StringList *matches,
+ StringList *descriptions) const {
+ // Try to find a match among commands and aliases. Allowing inexact matches,
+ // but perferring exact matches.
+ return GetCommandSP(cmd_str, /*include_aliases=*/true, /*exact=*/false,
+ matches, descriptions)
+ .get();
+}
+
+CommandObject *CommandInterpreter::GetUserCommandObject(
+ llvm::StringRef cmd, StringList *matches, StringList *descriptions) const {
+ std::string cmd_str(cmd);
+ auto find_exact = [&](const CommandObject::CommandMap &map) {
+ auto found_elem = map.find(std::string(cmd));
+ if (found_elem == map.end())
+ return (CommandObject *)nullptr;
+ CommandObject *exact_cmd = found_elem->second.get();
+ if (exact_cmd) {
+ if (matches)
+ matches->AppendString(exact_cmd->GetCommandName());
+ if (descriptions)
+ descriptions->AppendString(exact_cmd->GetHelp());
+ return exact_cmd;
+ }
+ return (CommandObject *)nullptr;
+ };
+
+ CommandObject *exact_cmd = find_exact(GetUserCommands());
+ if (exact_cmd)
+ return exact_cmd;
+
+ exact_cmd = find_exact(GetUserMultiwordCommands());
+ if (exact_cmd)
+ return exact_cmd;
+
+ // We didn't have an exact command, so now look for partial matches.
+ StringList tmp_list;
+ StringList *matches_ptr = matches ? matches : &tmp_list;
+ AddNamesMatchingPartialString(GetUserCommands(), cmd_str, *matches_ptr);
+ AddNamesMatchingPartialString(GetUserMultiwordCommands(),
+ cmd_str, *matches_ptr);
+
+ return {};
+}
+
+bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const {
+ return m_command_dict.find(std::string(cmd)) != m_command_dict.end();
+}
+
+bool CommandInterpreter::GetAliasFullName(llvm::StringRef cmd,
+ std::string &full_name) const {
+ bool exact_match =
+ (m_alias_dict.find(std::string(cmd)) != m_alias_dict.end());
+ if (exact_match) {
+ full_name.assign(std::string(cmd));
+ return exact_match;
+ } else {
+ StringList matches;
+ size_t num_alias_matches;
+ num_alias_matches =
+ AddNamesMatchingPartialString(m_alias_dict, cmd, matches);
+ if (num_alias_matches == 1) {
+ // Make sure this isn't shadowing a command in the regular command space:
+ StringList regular_matches;
+ const bool include_aliases = false;
+ const bool exact = false;
+ CommandObjectSP cmd_obj_sp(
+ GetCommandSP(cmd, include_aliases, exact, &regular_matches));
+ if (cmd_obj_sp || regular_matches.GetSize() > 0)
+ return false;
+ else {
+ full_name.assign(matches.GetStringAtIndex(0));
+ return true;
+ }
+ } else
+ return false;
+ }
+}
+
+bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const {
+ return m_alias_dict.find(std::string(cmd)) != m_alias_dict.end();
+}
+
+bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const {
+ return m_user_dict.find(std::string(cmd)) != m_user_dict.end();
+}
+
+bool CommandInterpreter::UserMultiwordCommandExists(llvm::StringRef cmd) const {
+ return m_user_mw_dict.find(std::string(cmd)) != m_user_mw_dict.end();
+}
+
+CommandAlias *
+CommandInterpreter::AddAlias(llvm::StringRef alias_name,
+ lldb::CommandObjectSP &command_obj_sp,
+ llvm::StringRef args_string) {
+ if (command_obj_sp.get())
+ lldbassert((this == &command_obj_sp->GetCommandInterpreter()) &&
+ "tried to add a CommandObject from a different interpreter");
+
+ std::unique_ptr<CommandAlias> command_alias_up(
+ new CommandAlias(*this, command_obj_sp, args_string, alias_name));
+
+ if (command_alias_up && command_alias_up->IsValid()) {
+ m_alias_dict[std::string(alias_name)] =
+ CommandObjectSP(command_alias_up.get());
+ return command_alias_up.release();
+ }
+
+ return nullptr;
+}
+
+bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) {
+ auto pos = m_alias_dict.find(std::string(alias_name));
+ if (pos != m_alias_dict.end()) {
+ m_alias_dict.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd, bool force) {
+ auto pos = m_command_dict.find(std::string(cmd));
+ if (pos != m_command_dict.end()) {
+ if (force || pos->second->IsRemovable()) {
+ // Only regular expression objects or python commands are removable under
+ // normal circumstances.
+ m_command_dict.erase(pos);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CommandInterpreter::RemoveUser(llvm::StringRef user_name) {
+ CommandObject::CommandMap::iterator pos =
+ m_user_dict.find(std::string(user_name));
+ if (pos != m_user_dict.end()) {
+ m_user_dict.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+bool CommandInterpreter::RemoveUserMultiword(llvm::StringRef multi_name) {
+ CommandObject::CommandMap::iterator pos =
+ m_user_mw_dict.find(std::string(multi_name));
+ if (pos != m_user_mw_dict.end()) {
+ m_user_mw_dict.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+void CommandInterpreter::GetHelp(CommandReturnObject &result,
+ uint32_t cmd_types) {
+ llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue());
+ if (!help_prologue.empty()) {
+ OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(),
+ help_prologue);
+ }
+
+ CommandObject::CommandMap::const_iterator pos;
+ size_t max_len = FindLongestCommandWord(m_command_dict);
+
+ if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) {
+ result.AppendMessage("Debugger commands:");
+ result.AppendMessage("");
+
+ for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) {
+ if (!(cmd_types & eCommandTypesHidden) &&
+ (pos->first.compare(0, 1, "_") == 0))
+ continue;
+
+ OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
+ pos->second->GetHelp(), max_len);
+ }
+ result.AppendMessage("");
+ }
+
+ if (!m_alias_dict.empty() &&
+ ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) {
+ result.AppendMessageWithFormat(
+ "Current command abbreviations "
+ "(type '%shelp command alias' for more info):\n",
+ GetCommandPrefix());
+ result.AppendMessage("");
+ max_len = FindLongestCommandWord(m_alias_dict);
+
+ for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end();
+ ++alias_pos) {
+ OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--",
+ alias_pos->second->GetHelp(), max_len);
+ }
+ result.AppendMessage("");
+ }
+
+ if (!m_user_dict.empty() &&
+ ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) {
+ result.AppendMessage("Current user-defined commands:");
+ result.AppendMessage("");
+ max_len = FindLongestCommandWord(m_user_dict);
+ for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) {
+ OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
+ pos->second->GetHelp(), max_len);
+ }
+ result.AppendMessage("");
+ }
+
+ if (!m_user_mw_dict.empty() &&
+ ((cmd_types & eCommandTypesUserMW) == eCommandTypesUserMW)) {
+ result.AppendMessage("Current user-defined container commands:");
+ result.AppendMessage("");
+ max_len = FindLongestCommandWord(m_user_mw_dict);
+ for (pos = m_user_mw_dict.begin(); pos != m_user_mw_dict.end(); ++pos) {
+ OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
+ pos->second->GetHelp(), max_len);
+ }
+ result.AppendMessage("");
+ }
+
+ result.AppendMessageWithFormat(
+ "For more information on any command, type '%shelp <command-name>'.\n",
+ GetCommandPrefix());
+}
+
+CommandObject *CommandInterpreter::GetCommandObjectForCommand(
+ llvm::StringRef &command_string) {
+ // This function finds the final, lowest-level, alias-resolved command object
+ // whose 'Execute' function will eventually be invoked by the given command
+ // line.
+
+ CommandObject *cmd_obj = nullptr;
+ size_t start = command_string.find_first_not_of(k_white_space);
+ size_t end = 0;
+ bool done = false;
+ while (!done) {
+ if (start != std::string::npos) {
+ // Get the next word from command_string.
+ end = command_string.find_first_of(k_white_space, start);
+ if (end == std::string::npos)
+ end = command_string.size();
+ std::string cmd_word =
+ std::string(command_string.substr(start, end - start));
+
+ if (cmd_obj == nullptr)
+ // Since cmd_obj is NULL we are on our first time through this loop.
+ // Check to see if cmd_word is a valid command or alias.
+ cmd_obj = GetCommandObject(cmd_word);
+ else if (cmd_obj->IsMultiwordObject()) {
+ // Our current object is a multi-word object; see if the cmd_word is a
+ // valid sub-command for our object.
+ CommandObject *sub_cmd_obj =
+ cmd_obj->GetSubcommandObject(cmd_word.c_str());
+ if (sub_cmd_obj)
+ cmd_obj = sub_cmd_obj;
+ else // cmd_word was not a valid sub-command word, so we are done
+ done = true;
+ } else
+ // We have a cmd_obj and it is not a multi-word object, so we are done.
+ done = true;
+
+ // If we didn't find a valid command object, or our command object is not
+ // a multi-word object, or we are at the end of the command_string, then
+ // we are done. Otherwise, find the start of the next word.
+
+ if (!cmd_obj || !cmd_obj->IsMultiwordObject() ||
+ end >= command_string.size())
+ done = true;
+ else
+ start = command_string.find_first_not_of(k_white_space, end);
+ } else
+ // Unable to find any more words.
+ done = true;
+ }
+
+ command_string = command_string.substr(end);
+ return cmd_obj;
+}
+
+static const char *k_valid_command_chars =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
+static void StripLeadingSpaces(std::string &s) {
+ if (!s.empty()) {
+ size_t pos = s.find_first_not_of(k_white_space);
+ if (pos == std::string::npos)
+ s.clear();
+ else if (pos == 0)
+ return;
+ s.erase(0, pos);
+ }
+}
+
+static size_t FindArgumentTerminator(const std::string &s) {
+ const size_t s_len = s.size();
+ size_t offset = 0;
+ while (offset < s_len) {
+ size_t pos = s.find("--", offset);
+ if (pos == std::string::npos)
+ break;
+ if (pos > 0) {
+ if (llvm::isSpace(s[pos - 1])) {
+ // Check if the string ends "\s--" (where \s is a space character) or
+ // if we have "\s--\s".
+ if ((pos + 2 >= s_len) || llvm::isSpace(s[pos + 2])) {
+ return pos;
+ }
+ }
+ }
+ offset = pos + 2;
+ }
+ return std::string::npos;
+}
+
+static bool ExtractCommand(std::string &command_string, std::string &command,
+ std::string &suffix, char &quote_char) {
+ command.clear();
+ suffix.clear();
+ StripLeadingSpaces(command_string);
+
+ bool result = false;
+ quote_char = '\0';
+
+ if (!command_string.empty()) {
+ const char first_char = command_string[0];
+ if (first_char == '\'' || first_char == '"') {
+ quote_char = first_char;
+ const size_t end_quote_pos = command_string.find(quote_char, 1);
+ if (end_quote_pos == std::string::npos) {
+ command.swap(command_string);
+ command_string.erase();
+ } else {
+ command.assign(command_string, 1, end_quote_pos - 1);
+ if (end_quote_pos + 1 < command_string.size())
+ command_string.erase(0, command_string.find_first_not_of(
+ k_white_space, end_quote_pos + 1));
+ else
+ command_string.erase();
+ }
+ } else {
+ const size_t first_space_pos =
+ command_string.find_first_of(k_white_space);
+ if (first_space_pos == std::string::npos) {
+ command.swap(command_string);
+ command_string.erase();
+ } else {
+ command.assign(command_string, 0, first_space_pos);
+ command_string.erase(0, command_string.find_first_not_of(
+ k_white_space, first_space_pos));
+ }
+ }
+ result = true;
+ }
+
+ if (!command.empty()) {
+ // actual commands can't start with '-' or '_'
+ if (command[0] != '-' && command[0] != '_') {
+ size_t pos = command.find_first_not_of(k_valid_command_chars);
+ if (pos > 0 && pos != std::string::npos) {
+ suffix.assign(command.begin() + pos, command.end());
+ command.erase(pos);
+ }
+ }
+ }
+
+ return result;
+}
+
+CommandObject *CommandInterpreter::BuildAliasResult(
+ llvm::StringRef alias_name, std::string &raw_input_string,
+ std::string &alias_result, CommandReturnObject &result) {
+ CommandObject *alias_cmd_obj = nullptr;
+ Args cmd_args(raw_input_string);
+ alias_cmd_obj = GetCommandObject(alias_name);
+ StreamString result_str;
+
+ if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) {
+ alias_result.clear();
+ return alias_cmd_obj;
+ }
+ std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
+ ((CommandAlias *)alias_cmd_obj)->Desugar();
+ OptionArgVectorSP option_arg_vector_sp = desugared.second;
+ alias_cmd_obj = desugared.first.get();
+ std::string alias_name_str = std::string(alias_name);
+ if ((cmd_args.GetArgumentCount() == 0) ||
+ (alias_name_str != cmd_args.GetArgumentAtIndex(0)))
+ cmd_args.Unshift(alias_name_str);
+
+ result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str());
+
+ if (!option_arg_vector_sp.get()) {
+ alias_result = std::string(result_str.GetString());
+ return alias_cmd_obj;
+ }
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+
+ int value_type;
+ std::string option;
+ std::string value;
+ for (const auto &entry : *option_arg_vector) {
+ std::tie(option, value_type, value) = entry;
+ if (option == g_argument) {
+ result_str.Printf(" %s", value.c_str());
+ continue;
+ }
+
+ result_str.Printf(" %s", option.c_str());
+ if (value_type == OptionParser::eNoArgument)
+ continue;
+
+ if (value_type != OptionParser::eOptionalArgument)
+ result_str.Printf(" ");
+ int index = GetOptionArgumentPosition(value.c_str());
+ if (index == 0)
+ result_str.Printf("%s", value.c_str());
+ else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
+
+ result.AppendErrorWithFormat("Not enough arguments provided; you "
+ "need at least %d arguments to use "
+ "this alias.\n",
+ index);
+ return nullptr;
+ } else {
+ const Args::ArgEntry &entry = cmd_args[index];
+ size_t strpos = raw_input_string.find(entry.c_str());
+ const char quote_char = entry.GetQuoteChar();
+ if (strpos != std::string::npos) {
+ const size_t start_fudge = quote_char == '\0' ? 0 : 1;
+ const size_t len_fudge = quote_char == '\0' ? 0 : 2;
+
+ // Make sure we aren't going outside the bounds of the cmd string:
+ if (strpos < start_fudge) {
+ result.AppendError("Unmatched quote at command beginning.");
+ return nullptr;
+ }
+ llvm::StringRef arg_text = entry.ref();
+ if (strpos - start_fudge + arg_text.size() + len_fudge >
+ raw_input_string.size()) {
+ result.AppendError("Unmatched quote at command end.");
+ return nullptr;
+ }
+ raw_input_string = raw_input_string.erase(
+ 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);
+ }
+ }
+
+ alias_result = std::string(result_str.GetString());
+ return alias_cmd_obj;
+}
+
+Status CommandInterpreter::PreprocessCommand(std::string &command) {
+ // The command preprocessor needs to do things to the command line before any
+ // parsing of arguments or anything else is done. The only current stuff that
+ // gets preprocessed is anything enclosed in backtick ('`') characters is
+ // evaluated as an expression and the result of the expression must be a
+ // scalar that can be substituted into the command. An example would be:
+ // (lldb) memory read `$rsp + 20`
+ Status error; // Status for any expressions that might not evaluate
+ size_t start_backtick;
+ size_t pos = 0;
+ while ((start_backtick = command.find('`', pos)) != std::string::npos) {
+ // Stop if an error was encountered during the previous iteration.
+ if (error.Fail())
+ break;
+
+ if (start_backtick > 0 && command[start_backtick - 1] == '\\') {
+ // The backtick was preceded by a '\' character, remove the slash and
+ // don't treat the backtick as the start of an expression.
+ command.erase(start_backtick - 1, 1);
+ // No need to add one to start_backtick since we just deleted a char.
+ pos = start_backtick;
+ continue;
+ }
+
+ const size_t expr_content_start = start_backtick + 1;
+ const size_t end_backtick = command.find('`', expr_content_start);
+
+ if (end_backtick == std::string::npos) {
+ // Stop if there's no end backtick.
+ break;
+ }
+
+ if (end_backtick == expr_content_start) {
+ // Skip over empty expression. (two backticks in a row)
+ command.erase(start_backtick, 2);
+ continue;
+ }
+
+ 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;
+
+ 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;
+}
+
+Status
+CommandInterpreter::PreprocessToken(std::string &expr_str) {
+ Status error;
+ ExecutionContext exe_ctx(GetExecutionContext());
+
+ // 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)) {
+
+ 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());
+ }
+ } 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()) {
+ std::string result = lldb_private::toString(expr_result);
+ error.SetErrorString(result + "for the expression '" + expr_str + "'");
+ }
+ return error;
+}
+
+bool CommandInterpreter::HandleCommand(const char *command_line,
+ LazyBool lazy_add_to_history,
+ const ExecutionContext &override_context,
+ CommandReturnObject &result) {
+
+ OverrideExecutionContext(override_context);
+ bool status = HandleCommand(command_line, lazy_add_to_history, result);
+ RestoreExecutionContext();
+ return status;
+}
+
+bool CommandInterpreter::HandleCommand(const char *command_line,
+ LazyBool lazy_add_to_history,
+ CommandReturnObject &result,
+ bool force_repeat_command) {
+ std::string command_string(command_line);
+ std::string original_command_string(command_line);
+
+ Log *log = GetLog(LLDBLog::Commands);
+ llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
+ command_line);
+
+ LLDB_LOGF(log, "Processing command: %s", command_line);
+ LLDB_SCOPED_TIMERF("Processing command: %s.", command_line);
+
+ if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted initiating command")) {
+ result.AppendError("... Interrupted");
+ return false;
+ }
+
+ bool add_to_history;
+ if (lazy_add_to_history == eLazyBoolCalculate)
+ add_to_history = (m_command_source_depth == 0);
+ else
+ add_to_history = (lazy_add_to_history == eLazyBoolYes);
+
+ // The same `transcript_item` will be used below to add output and error of
+ // the command.
+ StructuredData::DictionarySP transcript_item;
+ if (GetSaveTranscript()) {
+ m_transcript_stream << "(lldb) " << command_line << '\n';
+
+ transcript_item = std::make_shared<StructuredData::Dictionary>();
+ transcript_item->AddStringItem("command", command_line);
+ transcript_item->AddIntegerItem(
+ "timestampInEpochSeconds",
+ std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count());
+ m_transcript.AddItem(transcript_item);
+ }
+
+ bool empty_command = false;
+ bool comment_command = false;
+ if (command_string.empty())
+ empty_command = true;
+ else {
+ const char *k_space_characters = "\t\n\v\f\r ";
+
+ size_t non_space = command_string.find_first_not_of(k_space_characters);
+ // Check for empty line or comment line (lines whose first non-space
+ // character is the comment character for this interpreter)
+ if (non_space == std::string::npos)
+ empty_command = true;
+ else if (command_string[non_space] == m_comment_char)
+ comment_command = true;
+ else if (command_string[non_space] == CommandHistory::g_repeat_char) {
+ llvm::StringRef search_str(command_string);
+ search_str = search_str.drop_front(non_space);
+ if (auto hist_str = m_command_history.FindString(search_str)) {
+ add_to_history = false;
+ command_string = std::string(*hist_str);
+ original_command_string = std::string(*hist_str);
+ } else {
+ result.AppendErrorWithFormat("Could not find entry: %s in history",
+ command_string.c_str());
+ return false;
+ }
+ }
+ }
+
+ if (empty_command) {
+ if (!GetRepeatPreviousCommand()) {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ if (m_command_history.IsEmpty()) {
+ result.AppendError("empty command");
+ return false;
+ }
+
+ command_line = m_repeat_command.c_str();
+ command_string = command_line;
+ original_command_string = command_line;
+ if (m_repeat_command.empty()) {
+ result.AppendError("No auto repeat.");
+ return false;
+ }
+
+ add_to_history = false;
+ } else if (comment_command) {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ // Phase 1.
+
+ // Before we do ANY kind of argument processing, we need to figure out what
+ // the real/final command object is for the specified command. This gets
+ // complicated by the fact that the user could have specified an alias, and,
+ // in translating the alias, there may also be command options and/or even
+ // data (including raw text strings) that need to be found and inserted into
+ // the command line as part of the translation. So this first step is plain
+ // look-up and replacement, resulting in:
+ // 1. the command object whose Execute method will actually be called
+ // 2. a revised command string, with all substitutions and replacements
+ // taken care of
+ // From 1 above, we can determine whether the Execute function wants raw
+ // input or not.
+
+ CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
+
+ // 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.
+ if (cmd_obj && cmd_obj->WantsRawCommandString()) {
+ Status error(PreprocessCommand(command_string));
+
+ if (error.Fail()) {
+ result.AppendError(error.AsCString());
+ return false;
+ }
+ }
+
+ // Although the user may have abbreviated the command, the command_string now
+ // has the command expanded to the full name. For example, if the input was
+ // "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>";
+ 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;
+ LLDB_LOGF(log, "HandleCommand, wants_raw_input:'%s'",
+ wants_raw_input ? "True" : "False");
+ }
+
+ // Phase 2.
+ // Take care of things like setting up the history command & calling the
+ // appropriate Execute method on the CommandObject, with the appropriate
+ // arguments.
+ StatsDuration execute_time;
+ 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.
+ 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) {
+ LLDB_LOGF(log, "Repeat command: %s", repeat_command->data());
+ m_repeat_command.assign(*repeat_command);
+ } else {
+ m_repeat_command.assign(original_command_string);
+ }
+ }
+
+ if (add_to_history)
+ m_command_history.AppendString(original_command_string);
+
+ std::string remainder;
+ const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size();
+ if (actual_cmd_name_len < command_string.length())
+ remainder = command_string.substr(actual_cmd_name_len);
+
+ // Remove any initial spaces
+ size_t pos = remainder.find_first_not_of(k_white_space);
+ if (pos != 0 && pos != std::string::npos)
+ remainder.erase(0, pos);
+
+ LLDB_LOGF(
+ log, "HandleCommand, command line after removing command name(s): '%s'",
+ remainder.c_str());
+
+ // To test whether or not transcript should be saved, `transcript_item` is
+ // used instead of `GetSaveTrasncript()`. This is because the latter will
+ // fail when the command is "settings set interpreter.save-transcript true".
+ if (transcript_item) {
+ transcript_item->AddStringItem("commandName", cmd_obj->GetCommandName());
+ transcript_item->AddStringItem("commandArguments", remainder);
+ }
+
+ ElapsedTime elapsed(execute_time);
+ cmd_obj->Execute(remainder.c_str(), result);
+ }
+
+ LLDB_LOGF(log, "HandleCommand, command %s",
+ (result.Succeeded() ? "succeeded" : "did not succeed"));
+
+ // To test whether or not transcript should be saved, `transcript_item` is
+ // used instead of `GetSaveTrasncript()`. This is because the latter will
+ // fail when the command is "settings set interpreter.save-transcript true".
+ if (transcript_item) {
+ m_transcript_stream << result.GetOutputData();
+ m_transcript_stream << result.GetErrorData();
+
+ transcript_item->AddStringItem("output", result.GetOutputData());
+ transcript_item->AddStringItem("error", result.GetErrorData());
+ transcript_item->AddFloatItem("durationInSeconds",
+ execute_time.get().count());
+ }
+
+ return result.Succeeded();
+}
+
+void CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) {
+ bool look_for_subcommand = false;
+
+ // For any of the command completions a unique match will be a complete word.
+
+ 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;
+ 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
+ // dictionary.
+ StringList new_matches, new_descriptions;
+ CommandObject *cmd_obj =
+ GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0),
+ &new_matches, &new_descriptions);
+
+ 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) {
+ look_for_subcommand = true;
+ new_matches.DeleteStringAtIndex(0);
+ new_descriptions.DeleteStringAtIndex(0);
+ request.AppendEmptyArgument();
+ }
+ }
+ request.AddCompletions(new_matches, new_descriptions);
+ }
+
+ if (request.GetCursorIndex() > 0 || look_for_subcommand) {
+ // We are completing further on into a commands arguments, so find the
+ // command and tell it to complete the command. First see if there is a
+ // matching initial command:
+ CommandObject *command_object =
+ GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0));
+ if (command_object) {
+ request.ShiftArguments();
+ command_object->HandleCompletion(request);
+ }
+ }
+}
+
+void CommandInterpreter::HandleCompletion(CompletionRequest &request) {
+
+ // Don't complete comments, and if the line we are completing is just the
+ // history repeat character, substitute the appropriate history line.
+ llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
+
+ 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;
+ }
+ }
+
+ HandleCompletionMatches(request);
+}
+
+std::optional<std::string>
+CommandInterpreter::GetAutoSuggestionForCommand(llvm::StringRef line) {
+ if (line.empty())
+ return std::nullopt;
+ const size_t s = m_command_history.GetSize();
+ for (int i = s - 1; i >= 0; --i) {
+ llvm::StringRef entry = m_command_history.GetStringAtIndex(i);
+ if (entry.consume_front(line))
+ return entry.str();
+ }
+ return std::nullopt;
+}
+
+void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
+ EventSP prompt_change_event_sp(
+ new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
+ ;
+ BroadcastEvent(prompt_change_event_sp);
+ if (m_command_io_handler_sp)
+ m_command_io_handler_sp->SetPrompt(new_prompt);
+}
+
+bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) {
+ // Check AutoConfirm first:
+ if (m_debugger.GetAutoConfirm())
+ return default_answer;
+
+ IOHandlerConfirm *confirm =
+ new IOHandlerConfirm(m_debugger, message, default_answer);
+ IOHandlerSP io_handler_sp(confirm);
+ m_debugger.RunIOHandlerSync(io_handler_sp);
+ return confirm->GetResponse();
+}
+
+const CommandAlias *
+CommandInterpreter::GetAlias(llvm::StringRef alias_name) const {
+ OptionArgVectorSP ret_val;
+
+ auto pos = m_alias_dict.find(std::string(alias_name));
+ if (pos != m_alias_dict.end())
+ return (CommandAlias *)pos->second.get();
+
+ return nullptr;
+}
+
+bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); }
+
+bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); }
+
+bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); }
+
+bool CommandInterpreter::HasUserMultiwordCommands() const {
+ return (!m_user_mw_dict.empty());
+}
+
+bool CommandInterpreter::HasAliasOptions() const { return HasAliases(); }
+
+void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj,
+ const char *alias_name,
+ Args &cmd_args,
+ std::string &raw_input_string,
+ CommandReturnObject &result) {
+ OptionArgVectorSP option_arg_vector_sp =
+ GetAlias(alias_name)->GetOptionArguments();
+
+ bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
+
+ // Make sure that the alias name is the 0th element in cmd_args
+ std::string alias_name_str = alias_name;
+ if (alias_name_str != cmd_args.GetArgumentAtIndex(0))
+ cmd_args.Unshift(alias_name_str);
+
+ Args new_args(alias_cmd_obj->GetCommandName());
+ if (new_args.GetArgumentCount() == 2)
+ new_args.Shift();
+
+ if (option_arg_vector_sp.get()) {
+ if (wants_raw_input) {
+ // We have a command that both has command options and takes raw input.
+ // Make *sure* it has a " -- " in the right place in the
+ // raw_input_string.
+ size_t pos = raw_input_string.find(" -- ");
+ if (pos == std::string::npos) {
+ // None found; assume it goes at the beginning of the raw input string
+ raw_input_string.insert(0, " -- ");
+ }
+ }
+
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+ const size_t old_size = cmd_args.GetArgumentCount();
+ std::vector<bool> used(old_size + 1, false);
+
+ used[0] = true;
+
+ int value_type;
+ std::string option;
+ std::string value;
+ for (const auto &option_entry : *option_arg_vector) {
+ std::tie(option, value_type, value) = option_entry;
+ if (option == g_argument) {
+ if (!wants_raw_input || (value != "--")) {
+ // Since we inserted this above, make sure we don't insert it twice
+ new_args.AppendArgument(value);
+ }
+ continue;
+ }
+
+ if (value_type != OptionParser::eOptionalArgument)
+ new_args.AppendArgument(option);
+
+ if (value == g_no_argument)
+ continue;
+
+ int index = GetOptionArgumentPosition(value.c_str());
+ if (index == 0) {
+ // value was NOT a positional argument; must be a real value
+ if (value_type != OptionParser::eOptionalArgument)
+ new_args.AppendArgument(value);
+ else {
+ new_args.AppendArgument(option + value);
+ }
+
+ } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
+ result.AppendErrorWithFormat("Not enough arguments provided; you "
+ "need at least %d arguments to use "
+ "this alias.\n",
+ index);
+ return;
+ } else {
+ // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
+ size_t strpos =
+ raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
+ if (strpos != std::string::npos) {
+ raw_input_string = raw_input_string.erase(
+ strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
+ }
+
+ if (value_type != OptionParser::eOptionalArgument)
+ new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index));
+ else {
+ new_args.AppendArgument(option + cmd_args.GetArgumentAtIndex(index));
+ }
+ used[index] = true;
+ }
+ }
+
+ for (auto entry : llvm::enumerate(cmd_args.entries())) {
+ if (!used[entry.index()] && !wants_raw_input)
+ new_args.AppendArgument(entry.value().ref());
+ }
+
+ cmd_args.Clear();
+ cmd_args.SetArguments(new_args.GetArgumentCount(),
+ new_args.GetConstArgumentVector());
+ } else {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ // This alias was not created with any options; nothing further needs to be
+ // done, unless it is a command that wants raw input, in which case we need
+ // to clear the rest of the data from cmd_args, since its in the raw input
+ // string.
+ if (wants_raw_input) {
+ cmd_args.Clear();
+ cmd_args.SetArguments(new_args.GetArgumentCount(),
+ new_args.GetConstArgumentVector());
+ }
+ return;
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+}
+
+int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
+ int position = 0; // Any string that isn't an argument position, i.e. '%'
+ // followed by an integer, gets a position
+ // of zero.
+
+ const char *cptr = in_string;
+
+ // Does it start with '%'
+ if (cptr[0] == '%') {
+ ++cptr;
+
+ // Is the rest of it entirely digits?
+ if (isdigit(cptr[0])) {
+ const char *start = cptr;
+ while (isdigit(cptr[0]))
+ ++cptr;
+
+ // We've gotten to the end of the digits; are we at the end of the
+ // string?
+ if (cptr[0] == '\0')
+ position = atoi(start);
+ }
+ }
+
+ return position;
+}
+
+static void GetHomeInitFile(llvm::SmallVectorImpl<char> &init_file,
+ llvm::StringRef suffix = {}) {
+ std::string init_file_name = ".lldbinit";
+ if (!suffix.empty()) {
+ init_file_name.append("-");
+ init_file_name.append(suffix.str());
+ }
+
+ FileSystem::Instance().GetHomeDirectory(init_file);
+ llvm::sys::path::append(init_file, init_file_name);
+
+ FileSystem::Instance().Resolve(init_file);
+}
+
+static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file,
+ LanguageType language) {
+ if (language == eLanguageTypeUnknown) {
+ LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
+ if (auto main_repl_language = repl_languages.GetSingularLanguage())
+ language = *main_repl_language;
+ else
+ return;
+ }
+
+ std::string init_file_name =
+ (llvm::Twine(".lldbinit-") +
+ llvm::Twine(Language::GetNameForLanguageType(language)) +
+ llvm::Twine("-repl"))
+ .str();
+ FileSystem::Instance().GetHomeDirectory(init_file);
+ llvm::sys::path::append(init_file, init_file_name);
+ FileSystem::Instance().Resolve(init_file);
+}
+
+static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) {
+ llvm::StringRef s = ".lldbinit";
+ init_file.assign(s.begin(), s.end());
+ FileSystem::Instance().Resolve(init_file);
+}
+
+void CommandInterpreter::SourceInitFile(FileSpec file,
+ CommandReturnObject &result) {
+ assert(!m_skip_lldbinit_files);
+
+ if (!FileSystem::Instance().Exists(file)) {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return;
+ }
+
+ // Use HandleCommand to 'source' the given file; this will do the actual
+ // broadcasting of the commands back to any appropriate listener (see
+ // CommandObjectSource::Execute for more details).
+ const bool saved_batch = SetBatchCommandMode(true);
+ CommandInterpreterRunOptions options;
+ options.SetSilent(true);
+ options.SetPrintErrors(true);
+ options.SetStopOnError(false);
+ options.SetStopOnContinue(true);
+ HandleCommandsFromFile(file, options, result);
+ SetBatchCommandMode(saved_batch);
+}
+
+void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) {
+ if (m_skip_lldbinit_files) {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return;
+ }
+
+ llvm::SmallString<128> init_file;
+ GetCwdInitFile(init_file);
+ if (!FileSystem::Instance().Exists(init_file)) {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return;
+ }
+
+ LoadCWDlldbinitFile should_load =
+ Target::GetGlobalProperties().GetLoadCWDlldbinitFile();
+
+ switch (should_load) {
+ case eLoadCWDlldbinitFalse:
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ break;
+ case eLoadCWDlldbinitTrue:
+ SourceInitFile(FileSpec(init_file.str()), result);
+ break;
+ case eLoadCWDlldbinitWarn: {
+ llvm::SmallString<128> home_init_file;
+ GetHomeInitFile(home_init_file);
+ if (llvm::sys::path::parent_path(init_file) ==
+ llvm::sys::path::parent_path(home_init_file)) {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ } else {
+ result.AppendError(InitFileWarning);
+ }
+ }
+ }
+}
+
+/// We will first see if there is an application specific ".lldbinit" file
+/// whose name is "~/.lldbinit" followed by a "-" and the name of the program.
+/// If this file doesn't exist, we fall back to the REPL init file or the
+/// default home init file in "~/.lldbinit".
+void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result,
+ bool is_repl) {
+ if (m_skip_lldbinit_files) {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return;
+ }
+
+ llvm::SmallString<128> init_file;
+
+ if (is_repl)
+ GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage());
+
+ if (init_file.empty())
+ GetHomeInitFile(init_file);
+
+ if (!m_skip_app_init_files) {
+ llvm::StringRef program_name =
+ HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
+ llvm::SmallString<128> program_init_file;
+ GetHomeInitFile(program_init_file, program_name);
+ if (FileSystem::Instance().Exists(program_init_file))
+ init_file = program_init_file;
+ }
+
+ SourceInitFile(FileSpec(init_file.str()), result);
+}
+
+void CommandInterpreter::SourceInitFileGlobal(CommandReturnObject &result) {
+#ifdef LLDB_GLOBAL_INIT_DIRECTORY
+ if (!m_skip_lldbinit_files) {
+ FileSpec init_file(LLDB_GLOBAL_INIT_DIRECTORY);
+ if (init_file)
+ init_file.MakeAbsolute(HostInfo::GetShlibDir());
+
+ init_file.AppendPathComponent("lldbinit");
+ SourceInitFile(init_file, result);
+ return;
+ }
+#endif
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+}
+
+const char *CommandInterpreter::GetCommandPrefix() {
+ const char *prefix = GetDebugger().GetIOHandlerCommandPrefix();
+ return prefix == nullptr ? "" : prefix;
+}
+
+PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
+ PlatformSP platform_sp;
+ if (prefer_target_platform) {
+ ExecutionContext exe_ctx(GetExecutionContext());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ platform_sp = target->GetPlatform();
+ }
+
+ if (!platform_sp)
+ platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform();
+ return platform_sp;
+}
+
+bool CommandInterpreter::DidProcessStopAbnormally() const {
+ auto exe_ctx = GetExecutionContext();
+ TargetSP target_sp = exe_ctx.GetTargetSP();
+ 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) {
+ // If there's no stop_info, keep iterating through the other threads;
+ // it's enough that any thread has got a stop_info that indicates
+ // an abnormal stop, to consider the process to be stopped abnormally.
+ continue;
+ }
+
+ const StopReason reason = stop_info->GetStopReason();
+ if (reason == eStopReasonException ||
+ reason == eStopReasonInstrumentation ||
+ reason == eStopReasonProcessorTrace)
+ 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,
+ const ExecutionContext &override_context,
+ const CommandInterpreterRunOptions &options,
+ CommandReturnObject &result) {
+
+ OverrideExecutionContext(override_context);
+ HandleCommands(commands, options, result);
+ RestoreExecutionContext();
+}
+
+void CommandInterpreter::HandleCommands(const StringList &commands,
+ const CommandInterpreterRunOptions &options,
+ CommandReturnObject &result) {
+ size_t num_lines = commands.GetSize();
+
+ // If we are going to continue past a "continue" then we need to run the
+ // commands synchronously. Make sure you reset this value anywhere you return
+ // from the function.
+
+ bool old_async_execution = m_debugger.GetAsyncExecution();
+
+ if (!options.GetStopOnContinue()) {
+ m_debugger.SetAsyncExecution(false);
+ }
+
+ for (size_t idx = 0; idx < num_lines; idx++) {
+ const char *cmd = commands.GetStringAtIndex(idx);
+ if (cmd[0] == '\0')
+ continue;
+
+ if (options.GetEchoCommands()) {
+ // TODO: Add Stream support.
+ result.AppendMessageWithFormat("%s %s\n",
+ m_debugger.GetPrompt().str().c_str(), cmd);
+ }
+
+ CommandReturnObject tmp_result(m_debugger.GetUseColor());
+ tmp_result.SetInteractive(result.GetInteractive());
+ tmp_result.SetSuppressImmediateOutput(true);
+
+ // We might call into a regex or alias command, in which case the
+ // add_to_history will get lost. This m_command_source_depth dingus is the
+ // way we turn off adding to the history in that case, so set it up here.
+ if (!options.GetAddToHistory())
+ m_command_source_depth++;
+ bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result);
+ if (!options.GetAddToHistory())
+ m_command_source_depth--;
+
+ if (options.GetPrintResults()) {
+ if (tmp_result.Succeeded())
+ result.AppendMessage(tmp_result.GetOutputData());
+ }
+
+ if (!success || !tmp_result.Succeeded()) {
+ llvm::StringRef error_msg = tmp_result.GetErrorData();
+ if (error_msg.empty())
+ error_msg = "<unknown error>.\n";
+ if (options.GetStopOnError()) {
+ result.AppendErrorWithFormat(
+ "Aborting reading of commands after command #%" PRIu64
+ ": '%s' failed with %s",
+ (uint64_t)idx, cmd, error_msg.str().c_str());
+ m_debugger.SetAsyncExecution(old_async_execution);
+ return;
+ } else if (options.GetPrintResults()) {
+ result.AppendMessageWithFormat(
+ "Command #%" PRIu64 " '%s' failed with %s", (uint64_t)idx + 1, cmd,
+ error_msg.str().c_str());
+ }
+ }
+
+ if (result.GetImmediateOutputStream())
+ result.GetImmediateOutputStream()->Flush();
+
+ if (result.GetImmediateErrorStream())
+ result.GetImmediateErrorStream()->Flush();
+
+ // N.B. Can't depend on DidChangeProcessState, because the state coming
+ // into the command execution could be running (for instance in Breakpoint
+ // Commands. So we check the return value to see if it is has running in
+ // it.
+ if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
+ (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult)) {
+ if (options.GetStopOnContinue()) {
+ // If we caused the target to proceed, and we're going to stop in that
+ // case, set the status in our real result before returning. This is
+ // an error if the continue was not the last command in the set of
+ // commands to be run.
+ if (idx != num_lines - 1)
+ result.AppendErrorWithFormat(
+ "Aborting reading of commands after command #%" PRIu64
+ ": '%s' continued the target.\n",
+ (uint64_t)idx + 1, cmd);
+ else
+ result.AppendMessageWithFormat("Command #%" PRIu64
+ " '%s' continued the target.\n",
+ (uint64_t)idx + 1, cmd);
+
+ result.SetStatus(tmp_result.GetStatus());
+ m_debugger.SetAsyncExecution(old_async_execution);
+
+ return;
+ }
+ }
+
+ // Also check for "stop on crash here:
+ 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);
+
+ return;
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ m_debugger.SetAsyncExecution(old_async_execution);
+}
+
+// Make flags that we can pass into the IOHandler so our delegates can do the
+// right thing
+enum {
+ eHandleCommandFlagStopOnContinue = (1u << 0),
+ eHandleCommandFlagStopOnError = (1u << 1),
+ eHandleCommandFlagEchoCommand = (1u << 2),
+ eHandleCommandFlagEchoCommentCommand = (1u << 3),
+ eHandleCommandFlagPrintResult = (1u << 4),
+ eHandleCommandFlagPrintErrors = (1u << 5),
+ eHandleCommandFlagStopOnCrash = (1u << 6),
+ eHandleCommandFlagAllowRepeats = (1u << 7)
+};
+
+void CommandInterpreter::HandleCommandsFromFile(
+ FileSpec &cmd_file, const ExecutionContext &context,
+ const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
+ OverrideExecutionContext(context);
+ HandleCommandsFromFile(cmd_file, options, result);
+ RestoreExecutionContext();
+}
+
+void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file,
+ const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
+ if (!FileSystem::Instance().Exists(cmd_file)) {
+ result.AppendErrorWithFormat(
+ "Error reading commands from file %s - file not found.\n",
+ cmd_file.GetFilename().AsCString("<Unknown>"));
+ return;
+ }
+
+ std::string cmd_file_path = cmd_file.GetPath();
+ auto input_file_up =
+ FileSystem::Instance().Open(cmd_file, File::eOpenOptionReadOnly);
+ 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()));
+ return;
+ }
+ FileSP input_file_sp = FileSP(std::move(input_file_up.get()));
+
+ Debugger &debugger = GetDebugger();
+
+ uint32_t flags = 0;
+
+ if (options.m_stop_on_continue == eLazyBoolCalculate) {
+ if (m_command_source_flags.empty()) {
+ // Stop on continue by default
+ flags |= eHandleCommandFlagStopOnContinue;
+ } else if (m_command_source_flags.back() &
+ eHandleCommandFlagStopOnContinue) {
+ flags |= eHandleCommandFlagStopOnContinue;
+ }
+ } else if (options.m_stop_on_continue == eLazyBoolYes) {
+ flags |= eHandleCommandFlagStopOnContinue;
+ }
+
+ if (options.m_stop_on_error == eLazyBoolCalculate) {
+ if (m_command_source_flags.empty()) {
+ if (GetStopCmdSourceOnError())
+ flags |= eHandleCommandFlagStopOnError;
+ } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnError) {
+ flags |= eHandleCommandFlagStopOnError;
+ }
+ } else if (options.m_stop_on_error == eLazyBoolYes) {
+ flags |= eHandleCommandFlagStopOnError;
+ }
+
+ // stop-on-crash can only be set, if it is present in all levels of
+ // pushed flag sets.
+ if (options.GetStopOnCrash()) {
+ if (m_command_source_flags.empty()) {
+ flags |= eHandleCommandFlagStopOnCrash;
+ } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash) {
+ flags |= eHandleCommandFlagStopOnCrash;
+ }
+ }
+
+ if (options.m_echo_commands == eLazyBoolCalculate) {
+ if (m_command_source_flags.empty()) {
+ // Echo command by default
+ flags |= eHandleCommandFlagEchoCommand;
+ } else if (m_command_source_flags.back() & eHandleCommandFlagEchoCommand) {
+ flags |= eHandleCommandFlagEchoCommand;
+ }
+ } else if (options.m_echo_commands == eLazyBoolYes) {
+ flags |= eHandleCommandFlagEchoCommand;
+ }
+
+ // We will only ever ask for this flag, if we echo commands in general.
+ if (options.m_echo_comment_commands == eLazyBoolCalculate) {
+ if (m_command_source_flags.empty()) {
+ // Echo comments by default
+ flags |= eHandleCommandFlagEchoCommentCommand;
+ } else if (m_command_source_flags.back() &
+ eHandleCommandFlagEchoCommentCommand) {
+ flags |= eHandleCommandFlagEchoCommentCommand;
+ }
+ } else if (options.m_echo_comment_commands == eLazyBoolYes) {
+ flags |= eHandleCommandFlagEchoCommentCommand;
+ }
+
+ if (options.m_print_results == eLazyBoolCalculate) {
+ if (m_command_source_flags.empty()) {
+ // Print output by default
+ flags |= eHandleCommandFlagPrintResult;
+ } else if (m_command_source_flags.back() & eHandleCommandFlagPrintResult) {
+ flags |= eHandleCommandFlagPrintResult;
+ }
+ } else if (options.m_print_results == eLazyBoolYes) {
+ flags |= eHandleCommandFlagPrintResult;
+ }
+
+ if (options.m_print_errors == eLazyBoolCalculate) {
+ if (m_command_source_flags.empty()) {
+ // Print output by default
+ flags |= eHandleCommandFlagPrintErrors;
+ } else if (m_command_source_flags.back() & eHandleCommandFlagPrintErrors) {
+ flags |= eHandleCommandFlagPrintErrors;
+ }
+ } else if (options.m_print_errors == eLazyBoolYes) {
+ flags |= eHandleCommandFlagPrintErrors;
+ }
+
+ if (flags & eHandleCommandFlagPrintResult) {
+ debugger.GetOutputFile().Printf("Executing commands in '%s'.\n",
+ cmd_file_path.c_str());
+ }
+
+ // Used for inheriting the right settings when "command source" might
+ // have nested "command source" commands
+ lldb::StreamFileSP empty_stream_sp;
+ m_command_source_flags.push_back(flags);
+ IOHandlerSP io_handler_sp(new IOHandlerEditline(
+ debugger, IOHandler::Type::CommandInterpreter, input_file_sp,
+ empty_stream_sp, // Pass in an empty stream so we inherit the top
+ // input reader output stream
+ empty_stream_sp, // Pass in an empty stream so we inherit the top
+ // input reader error stream
+ flags,
+ nullptr, // Pass in NULL for "editline_name" so no history is saved,
+ // or written
+ debugger.GetPrompt(), llvm::StringRef(),
+ false, // Not multi-line
+ debugger.GetUseColor(), 0, *this));
+ const bool old_async_execution = debugger.GetAsyncExecution();
+
+ // Set synchronous execution if we are not stopping on continue
+ if ((flags & eHandleCommandFlagStopOnContinue) == 0)
+ debugger.SetAsyncExecution(false);
+
+ m_command_source_depth++;
+ m_command_source_dirs.push_back(cmd_file.CopyByRemovingLastPathComponent());
+
+ debugger.RunIOHandlerSync(io_handler_sp);
+ if (!m_command_source_flags.empty())
+ m_command_source_flags.pop_back();
+
+ m_command_source_dirs.pop_back();
+ m_command_source_depth--;
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ debugger.SetAsyncExecution(old_async_execution);
+}
+
+bool CommandInterpreter::GetSynchronous() { return m_synchronous_execution; }
+
+void CommandInterpreter::SetSynchronous(bool value) {
+ m_synchronous_execution = value;
+}
+
+void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
+ llvm::StringRef prefix,
+ llvm::StringRef help_text) {
+ const uint32_t max_columns = m_debugger.GetTerminalWidth();
+
+ size_t line_width_max = max_columns - prefix.size();
+ if (line_width_max < 16)
+ line_width_max = help_text.size() + prefix.size();
+
+ strm.IndentMore(prefix.size());
+ bool prefixed_yet = false;
+ // Even if we have no help text we still want to emit the command name.
+ if (help_text.empty())
+ help_text = "No help text";
+ while (!help_text.empty()) {
+ // Prefix the first line, indent subsequent lines to line up
+ if (!prefixed_yet) {
+ strm << prefix;
+ prefixed_yet = true;
+ } else
+ strm.Indent();
+
+ // Never print more than the maximum on one line.
+ llvm::StringRef this_line = help_text.substr(0, line_width_max);
+
+ // Always break on an explicit newline.
+ std::size_t first_newline = this_line.find_first_of("\n");
+
+ // Don't break on space/tab unless the text is too long to fit on one line.
+ std::size_t last_space = llvm::StringRef::npos;
+ if (this_line.size() != help_text.size())
+ last_space = this_line.find_last_of(" \t");
+
+ // Break at whichever condition triggered first.
+ this_line = this_line.substr(0, std::min(first_newline, last_space));
+ strm.PutCString(this_line);
+ strm.EOL();
+
+ // Remove whitespace / newlines after breaking.
+ help_text = help_text.drop_front(this_line.size()).ltrim();
+ }
+ strm.IndentLess(prefix.size());
+}
+
+void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
+ llvm::StringRef word_text,
+ llvm::StringRef separator,
+ llvm::StringRef help_text,
+ size_t max_word_len) {
+ StreamString prefix_stream;
+ prefix_stream.Printf(" %-*s %*s ", (int)max_word_len, word_text.data(),
+ (int)separator.size(), separator.data());
+ OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
+}
+
+void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
+ llvm::StringRef separator,
+ llvm::StringRef help_text,
+ uint32_t max_word_len) {
+ int indent_size = max_word_len + separator.size() + 2;
+
+ strm.IndentMore(indent_size);
+
+ StreamString text_strm;
+ text_strm.Printf("%-*s ", (int)max_word_len, word_text.data());
+ text_strm << separator << " " << help_text;
+
+ const uint32_t max_columns = m_debugger.GetTerminalWidth();
+
+ llvm::StringRef text = text_strm.GetString();
+
+ uint32_t chars_left = max_columns;
+
+ auto nextWordLength = [](llvm::StringRef S) {
+ size_t pos = S.find(' ');
+ return pos == llvm::StringRef::npos ? S.size() : pos;
+ };
+
+ while (!text.empty()) {
+ if (text.front() == '\n' ||
+ (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) {
+ strm.EOL();
+ strm.Indent();
+ chars_left = max_columns - indent_size;
+ if (text.front() == '\n')
+ text = text.drop_front();
+ else
+ text = text.ltrim(' ');
+ } else {
+ strm.PutChar(text.front());
+ --chars_left;
+ text = text.drop_front();
+ }
+ }
+
+ strm.EOL();
+ strm.IndentLess(indent_size);
+}
+
+void CommandInterpreter::FindCommandsForApropos(
+ llvm::StringRef search_word, StringList &commands_found,
+ StringList &commands_help, const CommandObject::CommandMap &command_map) {
+ for (const auto &pair : command_map) {
+ llvm::StringRef command_name = pair.first;
+ CommandObject *cmd_obj = pair.second.get();
+
+ const bool search_short_help = true;
+ const bool search_long_help = false;
+ const bool search_syntax = false;
+ const bool search_options = false;
+ if (command_name.contains_insensitive(search_word) ||
+ cmd_obj->HelpTextContainsWord(search_word, search_short_help,
+ search_long_help, search_syntax,
+ search_options)) {
+ commands_found.AppendString(command_name);
+ commands_help.AppendString(cmd_obj->GetHelp());
+ }
+
+ if (auto *multiword_cmd = cmd_obj->GetAsMultiwordCommand()) {
+ StringList subcommands_found;
+ FindCommandsForApropos(search_word, subcommands_found, commands_help,
+ multiword_cmd->GetSubcommandDictionary());
+ for (const auto &subcommand_name : subcommands_found) {
+ std::string qualified_name =
+ (command_name + " " + subcommand_name).str();
+ commands_found.AppendString(qualified_name);
+ }
+ }
+ }
+}
+
+void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word,
+ StringList &commands_found,
+ StringList &commands_help,
+ bool search_builtin_commands,
+ bool search_user_commands,
+ bool search_alias_commands,
+ bool search_user_mw_commands) {
+ CommandObject::CommandMap::const_iterator pos;
+
+ if (search_builtin_commands)
+ FindCommandsForApropos(search_word, commands_found, commands_help,
+ m_command_dict);
+
+ if (search_user_commands)
+ FindCommandsForApropos(search_word, commands_found, commands_help,
+ m_user_dict);
+
+ if (search_user_mw_commands)
+ FindCommandsForApropos(search_word, commands_found, commands_help,
+ m_user_mw_dict);
+
+ if (search_alias_commands)
+ FindCommandsForApropos(search_word, commands_found, commands_help,
+ m_alias_dict);
+}
+
+ExecutionContext CommandInterpreter::GetExecutionContext() const {
+ return !m_overriden_exe_contexts.empty()
+ ? m_overriden_exe_contexts.top()
+ : m_debugger.GetSelectedExecutionContext();
+}
+
+void CommandInterpreter::OverrideExecutionContext(
+ const ExecutionContext &override_context) {
+ m_overriden_exe_contexts.push(override_context);
+}
+
+void CommandInterpreter::RestoreExecutionContext() {
+ if (!m_overriden_exe_contexts.empty())
+ m_overriden_exe_contexts.pop();
+}
+
+void CommandInterpreter::GetProcessOutput() {
+ if (ProcessSP process_sp = GetExecutionContext().GetProcessSP())
+ m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true,
+ /*flush_stderr*/ true);
+}
+
+void CommandInterpreter::StartHandlingCommand() {
+ auto idle_state = CommandHandlingState::eIdle;
+ if (m_command_state.compare_exchange_strong(
+ idle_state, CommandHandlingState::eInProgress))
+ lldbassert(m_iohandler_nesting_level == 0);
+ else
+ lldbassert(m_iohandler_nesting_level > 0);
+ ++m_iohandler_nesting_level;
+}
+
+void CommandInterpreter::FinishHandlingCommand() {
+ lldbassert(m_iohandler_nesting_level > 0);
+ if (--m_iohandler_nesting_level == 0) {
+ auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle);
+ lldbassert(prev_state != CommandHandlingState::eIdle);
+ }
+}
+
+bool CommandInterpreter::InterruptCommand() {
+ auto in_progress = CommandHandlingState::eInProgress;
+ return m_command_state.compare_exchange_strong(
+ in_progress, CommandHandlingState::eInterrupted);
+}
+
+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);
+ return was_interrupted;
+}
+
+void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler,
+ llvm::StringRef str,
+ bool is_stdout) {
+
+ lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP()
+ : io_handler.GetErrorStreamFileSP();
+ // Split the output into lines and poll for interrupt requests
+ bool had_output = !str.empty();
+ while (!str.empty()) {
+ llvm::StringRef line;
+ std::tie(line, str) = str.split('\n');
+ {
+ std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
+ stream->Write(line.data(), line.size());
+ stream->Write("\n", 1);
+ }
+ }
+
+ std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
+ if (had_output &&
+ INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping command output"))
+ stream->Printf("\n... Interrupted.\n");
+ stream->Flush();
+}
+
+bool CommandInterpreter::EchoCommandNonInteractive(
+ llvm::StringRef line, const Flags &io_handler_flags) const {
+ if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand))
+ return false;
+
+ llvm::StringRef command = line.trim();
+ if (command.empty())
+ return true;
+
+ if (command.front() == m_comment_char)
+ return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand);
+
+ return true;
+}
+
+void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
+ std::string &line) {
+ // If we were interrupted, bail out...
+ if (WasInterrupted())
+ return;
+
+ const bool is_interactive = io_handler.GetIsInteractive();
+ const bool allow_repeats =
+ io_handler.GetFlags().Test(eHandleCommandFlagAllowRepeats);
+
+ if (!is_interactive && !allow_repeats) {
+ // When we are not interactive, don't execute blank lines. This will happen
+ // sourcing a commands file. We don't want blank lines to repeat the
+ // previous command and cause any errors to occur (like redefining an
+ // alias, get an error and stop parsing the commands file).
+ // But obey the AllowRepeats flag if the user has set it.
+ if (line.empty())
+ return;
+ }
+ if (!is_interactive) {
+ // When using a non-interactive file handle (like when sourcing commands
+ // 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())) {
+ std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
+ io_handler.GetOutputStreamFileSP()->Printf(
+ "%s%s\n", io_handler.GetPrompt(), line.c_str());
+ }
+ }
+
+ StartHandlingCommand();
+
+ ExecutionContext exe_ctx = m_debugger.GetSelectedExecutionContext();
+ bool pushed_exe_ctx = false;
+ if (exe_ctx.HasTargetScope()) {
+ OverrideExecutionContext(exe_ctx);
+ pushed_exe_ctx = true;
+ }
+ auto finalize = llvm::make_scope_exit([this, pushed_exe_ctx]() {
+ if (pushed_exe_ctx)
+ RestoreExecutionContext();
+ });
+
+ lldb_private::CommandReturnObject result(m_debugger.GetUseColor());
+ HandleCommand(line.c_str(), eLazyBoolCalculate, result);
+
+ // Now emit the command output text from the command we just executed
+ if ((result.Succeeded() &&
+ io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) ||
+ io_handler.GetFlags().Test(eHandleCommandFlagPrintErrors)) {
+ // Display any STDOUT/STDERR _prior_ to emitting the command result text
+ GetProcessOutput();
+
+ if (!result.GetImmediateOutputStream()) {
+ llvm::StringRef output = result.GetOutputData();
+ PrintCommandOutput(io_handler, output, true);
+ }
+
+ // Now emit the command error text from the command we just executed
+ if (!result.GetImmediateErrorStream()) {
+ llvm::StringRef error = result.GetErrorData();
+ PrintCommandOutput(io_handler, error, false);
+ }
+ }
+
+ FinishHandlingCommand();
+
+ switch (result.GetStatus()) {
+ case eReturnStatusInvalid:
+ case eReturnStatusSuccessFinishNoResult:
+ case eReturnStatusSuccessFinishResult:
+ case eReturnStatusStarted:
+ break;
+
+ case eReturnStatusSuccessContinuingNoResult:
+ case eReturnStatusSuccessContinuingResult:
+ if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnContinue))
+ io_handler.SetIsDone(true);
+ break;
+
+ case eReturnStatusFailed:
+ m_result.IncrementNumberOfErrors();
+ if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) {
+ m_result.SetResult(lldb::eCommandInterpreterResultCommandError);
+ io_handler.SetIsDone(true);
+ }
+ break;
+
+ case eReturnStatusQuit:
+ m_result.SetResult(lldb::eCommandInterpreterResultQuitRequested);
+ io_handler.SetIsDone(true);
+ break;
+ }
+
+ // Finally, if we're going to stop on crash, check that here:
+ if (m_result.IsResult(lldb::eCommandInterpreterResultSuccess) &&
+ result.GetDidChangeProcessState() &&
+ io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash) &&
+ DidProcessStopAbnormally()) {
+ io_handler.SetIsDone(true);
+ m_result.SetResult(lldb::eCommandInterpreterResultInferiorCrash);
+ }
+}
+
+bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) {
+ ExecutionContext exe_ctx(GetExecutionContext());
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (InterruptCommand())
+ return true;
+
+ if (process) {
+ StateType state = process->GetState();
+ if (StateIsRunningState(state)) {
+ process->Halt();
+ return true; // Don't do any updating when we are running
+ }
+ }
+
+ ScriptInterpreter *script_interpreter =
+ m_debugger.GetScriptInterpreter(false);
+ if (script_interpreter) {
+ if (script_interpreter->Interrupt())
+ return true;
+ }
+ return false;
+}
+
+bool CommandInterpreter::SaveTranscript(
+ CommandReturnObject &result, std::optional<std::string> output_file) {
+ if (output_file == std::nullopt || output_file->empty()) {
+ std::string now = llvm::to_string(std::chrono::system_clock::now());
+ std::replace(now.begin(), now.end(), ' ', '_');
+ // Can't have file name with colons on Windows
+ std::replace(now.begin(), now.end(), ':', '-');
+ const std::string file_name = "lldb_session_" + now + ".log";
+
+ FileSpec save_location = GetSaveSessionDirectory();
+
+ if (!save_location)
+ save_location = HostInfo::GetGlobalTempDir();
+
+ FileSystem::Instance().Resolve(save_location);
+ save_location.AppendPathComponent(file_name);
+ output_file = save_location.GetPath();
+ }
+
+ auto error_out = [&](llvm::StringRef error_message, std::string description) {
+ LLDB_LOG(GetLog(LLDBLog::Commands), "{0} ({1}:{2})", error_message,
+ output_file, description);
+ result.AppendErrorWithFormatv(
+ "Failed to save session's transcripts to {0}!", *output_file);
+ return false;
+ };
+
+ File::OpenOptions flags = File::eOpenOptionWriteOnly |
+ File::eOpenOptionCanCreate |
+ File::eOpenOptionTruncate;
+
+ auto opened_file = FileSystem::Instance().Open(FileSpec(*output_file), flags);
+
+ if (!opened_file)
+ return error_out("Unable to create file",
+ llvm::toString(opened_file.takeError()));
+
+ FileUP file = std::move(opened_file.get());
+
+ size_t byte_size = m_transcript_stream.GetSize();
+
+ Status error = file->Write(m_transcript_stream.GetData(), byte_size);
+
+ if (error.Fail() || byte_size != m_transcript_stream.GetSize())
+ return error_out("Unable to write to destination file",
+ "Bytes written do not match transcript size.");
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ result.AppendMessageWithFormat("Session's transcripts saved to %s\n",
+ output_file->c_str());
+
+ if (GetOpenTranscriptInEditor() && Host::IsInteractiveGraphicSession()) {
+ const FileSpec file_spec;
+ error = file->GetFileSpec(const_cast<FileSpec &>(file_spec));
+ if (error.Success()) {
+ if (llvm::Error e = Host::OpenFileInExternalEditor(
+ m_debugger.GetExternalEditor(), file_spec, 1))
+ result.AppendError(llvm::toString(std::move(e)));
+ }
+ }
+
+ return true;
+}
+
+bool CommandInterpreter::IsInteractive() {
+ return (GetIOHandler() ? GetIOHandler()->GetIsInteractive() : false);
+}
+
+FileSpec CommandInterpreter::GetCurrentSourceDir() {
+ if (m_command_source_dirs.empty())
+ return {};
+ return m_command_source_dirs.back();
+}
+
+void CommandInterpreter::GetLLDBCommandsFromIOHandler(
+ const char *prompt, IOHandlerDelegate &delegate, void *baton) {
+ Debugger &debugger = GetDebugger();
+ IOHandlerSP io_handler_sp(
+ new IOHandlerEditline(debugger, IOHandler::Type::CommandList,
+ "lldb", // Name of input reader for history
+ llvm::StringRef(prompt), // Prompt
+ llvm::StringRef(), // Continuation prompt
+ true, // Get multiple lines
+ debugger.GetUseColor(),
+ 0, // Don't show line numbers
+ delegate)); // IOHandlerDelegate
+
+ if (io_handler_sp) {
+ io_handler_sp->SetUserData(baton);
+ debugger.RunIOHandlerAsync(io_handler_sp);
+ }
+}
+
+void CommandInterpreter::GetPythonCommandsFromIOHandler(
+ const char *prompt, IOHandlerDelegate &delegate, void *baton) {
+ Debugger &debugger = GetDebugger();
+ IOHandlerSP io_handler_sp(
+ new IOHandlerEditline(debugger, IOHandler::Type::PythonCode,
+ "lldb-python", // Name of input reader for history
+ llvm::StringRef(prompt), // Prompt
+ llvm::StringRef(), // Continuation prompt
+ true, // Get multiple lines
+ debugger.GetUseColor(),
+ 0, // Don't show line numbers
+ delegate)); // IOHandlerDelegate
+
+ if (io_handler_sp) {
+ io_handler_sp->SetUserData(baton);
+ debugger.RunIOHandlerAsync(io_handler_sp);
+ }
+}
+
+bool CommandInterpreter::IsActive() {
+ return m_debugger.IsTopIOHandler(m_command_io_handler_sp);
+}
+
+lldb::IOHandlerSP
+CommandInterpreter::GetIOHandler(bool force_create,
+ CommandInterpreterRunOptions *options) {
+ // Always re-create the IOHandlerEditline in case the input changed. The old
+ // instance might have had a non-interactive input and now it does or vice
+ // versa.
+ if (force_create || !m_command_io_handler_sp) {
+ // Always re-create the IOHandlerEditline in case the input changed. The
+ // old instance might have had a non-interactive input and now it does or
+ // vice versa.
+ uint32_t flags = 0;
+
+ if (options) {
+ if (options->m_stop_on_continue == eLazyBoolYes)
+ flags |= eHandleCommandFlagStopOnContinue;
+ if (options->m_stop_on_error == eLazyBoolYes)
+ flags |= eHandleCommandFlagStopOnError;
+ if (options->m_stop_on_crash == eLazyBoolYes)
+ flags |= eHandleCommandFlagStopOnCrash;
+ if (options->m_echo_commands != eLazyBoolNo)
+ flags |= eHandleCommandFlagEchoCommand;
+ if (options->m_echo_comment_commands != eLazyBoolNo)
+ flags |= eHandleCommandFlagEchoCommentCommand;
+ if (options->m_print_results != eLazyBoolNo)
+ flags |= eHandleCommandFlagPrintResult;
+ if (options->m_print_errors != eLazyBoolNo)
+ flags |= eHandleCommandFlagPrintErrors;
+ if (options->m_allow_repeats == eLazyBoolYes)
+ flags |= eHandleCommandFlagAllowRepeats;
+ } else {
+ flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult |
+ eHandleCommandFlagPrintErrors;
+ }
+
+ m_command_io_handler_sp = std::make_shared<IOHandlerEditline>(
+ m_debugger, IOHandler::Type::CommandInterpreter,
+ 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(),
+ 0, // Don't show line numbers
+ *this); // IOHandlerDelegate
+ }
+ return m_command_io_handler_sp;
+}
+
+CommandInterpreterRunResult CommandInterpreter::RunCommandInterpreter(
+ CommandInterpreterRunOptions &options) {
+ // Always re-create the command interpreter when we run it in case any file
+ // handles have changed.
+ bool force_create = true;
+ m_debugger.RunIOHandlerAsync(GetIOHandler(force_create, &options));
+ m_result = CommandInterpreterRunResult();
+
+ if (options.GetAutoHandleEvents())
+ m_debugger.StartEventHandlerThread();
+
+ 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();
+ }
+
+ return m_result;
+}
+
+CommandObject *
+CommandInterpreter::ResolveCommandImpl(std::string &command_line,
+ CommandReturnObject &result) {
+ std::string scratch_command(command_line); // working copy so we don't modify
+ // command_line unless we succeed
+ CommandObject *cmd_obj = nullptr;
+ StreamString revised_command_line;
+ bool wants_raw_input = false;
+ std::string next_word;
+ StringList matches;
+ bool done = false;
+ while (!done) {
+ char quote_char = '\0';
+ std::string suffix;
+ ExtractCommand(scratch_command, next_word, suffix, quote_char);
+ if (cmd_obj == nullptr) {
+ std::string full_name;
+ bool is_alias = GetAliasFullName(next_word, full_name);
+ cmd_obj = GetCommandObject(next_word, &matches);
+ bool is_real_command =
+ (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias());
+ if (!is_real_command) {
+ matches.Clear();
+ std::string alias_result;
+ cmd_obj =
+ BuildAliasResult(full_name, scratch_command, alias_result, result);
+ revised_command_line.Printf("%s", alias_result.c_str());
+ if (cmd_obj) {
+ wants_raw_input = cmd_obj->WantsRawCommandString();
+ }
+ } else {
+ if (cmd_obj) {
+ llvm::StringRef cmd_name = cmd_obj->GetCommandName();
+ revised_command_line.Printf("%s", cmd_name.str().c_str());
+ wants_raw_input = cmd_obj->WantsRawCommandString();
+ } else {
+ revised_command_line.Printf("%s", next_word.c_str());
+ }
+ }
+ } else {
+ if (cmd_obj->IsMultiwordObject()) {
+ CommandObject *sub_cmd_obj =
+ cmd_obj->GetSubcommandObject(next_word.c_str());
+ if (sub_cmd_obj) {
+ // The subcommand's name includes the parent command's name, so
+ // restart rather than append to the revised_command_line.
+ llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName();
+ revised_command_line.Clear();
+ revised_command_line.Printf("%s", sub_cmd_name.str().c_str());
+ cmd_obj = sub_cmd_obj;
+ wants_raw_input = cmd_obj->WantsRawCommandString();
+ } else {
+ if (quote_char)
+ revised_command_line.Printf(" %c%s%s%c", quote_char,
+ next_word.c_str(), suffix.c_str(),
+ quote_char);
+ else
+ revised_command_line.Printf(" %s%s", next_word.c_str(),
+ suffix.c_str());
+ done = true;
+ }
+ } else {
+ if (quote_char)
+ revised_command_line.Printf(" %c%s%s%c", quote_char,
+ next_word.c_str(), suffix.c_str(),
+ quote_char);
+ else
+ revised_command_line.Printf(" %s%s", next_word.c_str(),
+ suffix.c_str());
+ done = true;
+ }
+ }
+
+ if (cmd_obj == nullptr) {
+ const size_t num_matches = matches.GetSize();
+ if (matches.GetSize() > 1) {
+ StreamString error_msg;
+ error_msg.Printf("Ambiguous command '%s'. Possible matches:\n",
+ next_word.c_str());
+
+ for (uint32_t i = 0; i < num_matches; ++i) {
+ error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
+ }
+ result.AppendRawError(error_msg.GetString());
+ } else {
+ // We didn't have only one match, otherwise we wouldn't get here.
+ lldbassert(num_matches == 0);
+ result.AppendErrorWithFormat("'%s' is not a valid command.\n",
+ next_word.c_str());
+ }
+ return nullptr;
+ }
+
+ if (cmd_obj->IsMultiwordObject()) {
+ if (!suffix.empty()) {
+ result.AppendErrorWithFormat(
+ "command '%s' did not recognize '%s%s%s' as valid (subcommand "
+ "might be invalid).\n",
+ cmd_obj->GetCommandName().str().c_str(),
+ next_word.empty() ? "" : next_word.c_str(),
+ next_word.empty() ? " -- " : " ", suffix.c_str());
+ return nullptr;
+ }
+ } else {
+ // If we found a normal command, we are done
+ done = true;
+ if (!suffix.empty()) {
+ switch (suffix[0]) {
+ case '/':
+ // GDB format suffixes
+ {
+ Options *command_options = cmd_obj->GetOptions();
+ if (command_options &&
+ command_options->SupportsLongOption("gdb-format")) {
+ std::string gdb_format_option("--gdb-format=");
+ gdb_format_option += (suffix.c_str() + 1);
+
+ std::string cmd = std::string(revised_command_line.GetString());
+ size_t arg_terminator_idx = FindArgumentTerminator(cmd);
+ if (arg_terminator_idx != std::string::npos) {
+ // Insert the gdb format option before the "--" that terminates
+ // options
+ gdb_format_option.append(1, ' ');
+ cmd.insert(arg_terminator_idx, gdb_format_option);
+ revised_command_line.Clear();
+ revised_command_line.PutCString(cmd);
+ } else
+ revised_command_line.Printf(" %s", gdb_format_option.c_str());
+
+ if (wants_raw_input &&
+ FindArgumentTerminator(cmd) == std::string::npos)
+ revised_command_line.PutCString(" --");
+ } else {
+ result.AppendErrorWithFormat(
+ "the '%s' command doesn't support the --gdb-format option\n",
+ cmd_obj->GetCommandName().str().c_str());
+ return nullptr;
+ }
+ }
+ break;
+
+ default:
+ result.AppendErrorWithFormat(
+ "unknown command shorthand suffix: '%s'\n", suffix.c_str());
+ return nullptr;
+ }
+ }
+ }
+ if (scratch_command.empty())
+ done = true;
+ }
+
+ if (!scratch_command.empty())
+ revised_command_line.Printf(" %s", scratch_command.c_str());
+
+ if (cmd_obj != nullptr)
+ command_line = std::string(revised_command_line.GetString());
+
+ return cmd_obj;
+}
+
+llvm::json::Value CommandInterpreter::GetStatistics() {
+ llvm::json::Object stats;
+ for (const auto &command_usage : m_command_usages)
+ stats.try_emplace(command_usage.getKey(), command_usage.getValue());
+ return stats;
+}
+
+const StructuredData::Array &CommandInterpreter::GetTranscript() const {
+ return m_transcript;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/CommandObject.cpp b/contrib/llvm-project/lldb/source/Interpreter/CommandObject.cpp
new file mode 100644
index 000000000000..4634b75c6a33
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/CommandObject.cpp
@@ -0,0 +1,854 @@
+//===-- CommandObject.cpp -------------------------------------------------===//
+//
+// 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/CommandObject.h"
+
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <cctype>
+#include <cstdlib>
+
+#include "lldb/Core/Address.h"
+#include "lldb/Interpreter/CommandOptionArgumentTable.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "llvm/ADT/ScopeExit.h"
+
+// These are for the Sourcename completers.
+// FIXME: Make a separate file for the completers.
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/FileSpecList.h"
+
+#include "lldb/Target/Language.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandOptionArgumentTable.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// CommandObject
+
+CommandObject::CommandObject(CommandInterpreter &interpreter,
+ llvm::StringRef name, llvm::StringRef help,
+ llvm::StringRef syntax, uint32_t flags)
+ : m_interpreter(interpreter), m_cmd_name(std::string(name)),
+ m_flags(flags), m_deprecated_command_override_callback(nullptr),
+ m_command_override_callback(nullptr), m_command_override_baton(nullptr) {
+ m_cmd_help_short = std::string(help);
+ m_cmd_syntax = std::string(syntax);
+}
+
+Debugger &CommandObject::GetDebugger() { return m_interpreter.GetDebugger(); }
+
+llvm::StringRef CommandObject::GetHelp() { return m_cmd_help_short; }
+
+llvm::StringRef CommandObject::GetHelpLong() { return m_cmd_help_long; }
+
+llvm::StringRef CommandObject::GetSyntax() {
+ if (!m_cmd_syntax.empty())
+ return m_cmd_syntax;
+
+ StreamString syntax_str;
+ syntax_str.PutCString(GetCommandName());
+
+ if (!IsDashDashCommand() && GetOptions() != nullptr)
+ syntax_str.PutCString(" <cmd-options>");
+
+ if (!m_arguments.empty()) {
+ syntax_str.PutCString(" ");
+
+ if (!IsDashDashCommand() && WantsRawCommandString() && GetOptions() &&
+ GetOptions()->NumCommandOptions())
+ syntax_str.PutCString("-- ");
+ GetFormattedCommandArguments(syntax_str);
+ }
+ m_cmd_syntax = std::string(syntax_str.GetString());
+
+ return m_cmd_syntax;
+}
+
+llvm::StringRef CommandObject::GetCommandName() const { return m_cmd_name; }
+
+void CommandObject::SetCommandName(llvm::StringRef name) {
+ m_cmd_name = std::string(name);
+}
+
+void CommandObject::SetHelp(llvm::StringRef str) {
+ m_cmd_help_short = std::string(str);
+}
+
+void CommandObject::SetHelpLong(llvm::StringRef str) {
+ m_cmd_help_long = std::string(str);
+}
+
+void CommandObject::SetSyntax(llvm::StringRef str) {
+ m_cmd_syntax = std::string(str);
+}
+
+Options *CommandObject::GetOptions() {
+ // By default commands don't have options unless this virtual function is
+ // overridden by base classes.
+ return nullptr;
+}
+
+bool CommandObject::ParseOptions(Args &args, CommandReturnObject &result) {
+ // See if the subclass has options?
+ Options *options = GetOptions();
+ if (options != nullptr) {
+ Status error;
+
+ auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
+ options->NotifyOptionParsingStarting(&exe_ctx);
+
+ const bool require_validation = true;
+ llvm::Expected<Args> args_or = options->Parse(
+ args, &exe_ctx, GetCommandInterpreter().GetPlatform(true),
+ require_validation);
+
+ if (args_or) {
+ args = std::move(*args_or);
+ error = options->NotifyOptionParsingFinished(&exe_ctx);
+ } else
+ error = args_or.takeError();
+
+ if (error.Success()) {
+ if (options->VerifyOptions(result))
+ return true;
+ } else {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr) {
+ // We got an error string, lets use that
+ result.AppendError(error_cstr);
+ } else {
+ // No error string, output the usage information into result
+ options->GenerateOptionUsage(
+ result.GetErrorStream(), *this,
+ GetCommandInterpreter().GetDebugger().GetTerminalWidth());
+ }
+ }
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ return true;
+}
+
+bool CommandObject::CheckRequirements(CommandReturnObject &result) {
+ // Nothing should be stored in m_exe_ctx between running commands as
+ // m_exe_ctx has shared pointers to the target, process, thread and frame and
+ // we don't want any CommandObject instances to keep any of these objects
+ // around longer than for a single command. Every command should call
+ // CommandObject::Cleanup() after it has completed.
+ assert(!m_exe_ctx.GetTargetPtr());
+ assert(!m_exe_ctx.GetProcessPtr());
+ assert(!m_exe_ctx.GetThreadPtr());
+ assert(!m_exe_ctx.GetFramePtr());
+
+ // Lock down the interpreter's execution context prior to running the command
+ // so we guarantee the selected target, process, thread and frame can't go
+ // away during the execution
+ m_exe_ctx = m_interpreter.GetExecutionContext();
+
+ const uint32_t flags = GetFlags().Get();
+ if (flags & (eCommandRequiresTarget | eCommandRequiresProcess |
+ eCommandRequiresThread | eCommandRequiresFrame |
+ eCommandTryTargetAPILock)) {
+
+ if ((flags & eCommandRequiresTarget) && !m_exe_ctx.HasTargetScope()) {
+ result.AppendError(GetInvalidTargetDescription());
+ return false;
+ }
+
+ if ((flags & eCommandRequiresProcess) && !m_exe_ctx.HasProcessScope()) {
+ if (!m_exe_ctx.HasTargetScope())
+ result.AppendError(GetInvalidTargetDescription());
+ else
+ result.AppendError(GetInvalidProcessDescription());
+ return false;
+ }
+
+ if ((flags & eCommandRequiresThread) && !m_exe_ctx.HasThreadScope()) {
+ if (!m_exe_ctx.HasTargetScope())
+ result.AppendError(GetInvalidTargetDescription());
+ else if (!m_exe_ctx.HasProcessScope())
+ result.AppendError(GetInvalidProcessDescription());
+ else
+ result.AppendError(GetInvalidThreadDescription());
+ return false;
+ }
+
+ if ((flags & eCommandRequiresFrame) && !m_exe_ctx.HasFrameScope()) {
+ if (!m_exe_ctx.HasTargetScope())
+ result.AppendError(GetInvalidTargetDescription());
+ else if (!m_exe_ctx.HasProcessScope())
+ result.AppendError(GetInvalidProcessDescription());
+ else if (!m_exe_ctx.HasThreadScope())
+ result.AppendError(GetInvalidThreadDescription());
+ else
+ result.AppendError(GetInvalidFrameDescription());
+ return false;
+ }
+
+ if ((flags & eCommandRequiresRegContext) &&
+ (m_exe_ctx.GetRegisterContext() == nullptr)) {
+ result.AppendError(GetInvalidRegContextDescription());
+ return false;
+ }
+
+ if (flags & eCommandTryTargetAPILock) {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (target)
+ m_api_locker =
+ std::unique_lock<std::recursive_mutex>(target->GetAPIMutex());
+ }
+ }
+
+ if (GetFlags().AnySet(eCommandProcessMustBeLaunched |
+ eCommandProcessMustBePaused)) {
+ Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process == nullptr) {
+ // A process that is not running is considered paused.
+ if (GetFlags().Test(eCommandProcessMustBeLaunched)) {
+ result.AppendError("Process must exist.");
+ return false;
+ }
+ } else {
+ StateType state = process->GetState();
+ switch (state) {
+ case eStateInvalid:
+ case eStateSuspended:
+ case eStateCrashed:
+ case eStateStopped:
+ break;
+
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateDetached:
+ case eStateExited:
+ case eStateUnloaded:
+ if (GetFlags().Test(eCommandProcessMustBeLaunched)) {
+ result.AppendError("Process must be launched.");
+ return false;
+ }
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ if (GetFlags().Test(eCommandProcessMustBePaused)) {
+ result.AppendError("Process is running. Use 'process interrupt' to "
+ "pause execution.");
+ return false;
+ }
+ }
+ }
+ }
+
+ if (GetFlags().Test(eCommandProcessMustBeTraced)) {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (target && !target->GetTrace()) {
+ result.AppendError("Process is not being traced.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void CommandObject::Cleanup() {
+ m_exe_ctx.Clear();
+ if (m_api_locker.owns_lock())
+ m_api_locker.unlock();
+}
+
+void CommandObject::HandleCompletion(CompletionRequest &request) {
+
+ m_exe_ctx = m_interpreter.GetExecutionContext();
+ auto reset_ctx = llvm::make_scope_exit([this]() { Cleanup(); });
+
+ // 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;
+ } else {
+ // Can we do anything generic with the options?
+ Options *cur_options = GetOptions();
+ CommandReturnObject result(m_interpreter.GetDebugger().GetUseColor());
+ OptionElementVector opt_element_vector;
+
+ if (cur_options != nullptr) {
+ opt_element_vector = cur_options->ParseForCompletion(
+ request.GetParsedLine(), request.GetCursorIndex());
+
+ bool handled_by_options = cur_options->HandleOptionCompletion(
+ request, opt_element_vector, GetCommandInterpreter());
+ if (handled_by_options)
+ return;
+ }
+
+ // If we got here, the last word is not an option or an option argument.
+ HandleArgumentCompletion(request, opt_element_vector);
+ }
+}
+
+void CommandObject::HandleArgumentCompletion(
+ CompletionRequest &request, OptionElementVector &opt_element_vector) {
+ size_t num_arg_entries = GetNumArgumentEntries();
+ if (num_arg_entries != 1)
+ return;
+
+ CommandArgumentEntry *entry_ptr = GetArgumentEntryAtIndex(0);
+ if (!entry_ptr) {
+ assert(entry_ptr && "We said there was one entry, but there wasn't.");
+ return; // Not worth crashing if asserts are off...
+ }
+
+ CommandArgumentEntry &entry = *entry_ptr;
+ // For now, we only handle the simple case of one homogenous argument type.
+ if (entry.size() != 1)
+ return;
+
+ // Look up the completion type, and if it has one, invoke it:
+ const CommandObject::ArgumentTableEntry *arg_entry =
+ FindArgumentDataByType(entry[0].arg_type);
+ const ArgumentRepetitionType repeat = entry[0].arg_repetition;
+
+ if (arg_entry == nullptr || arg_entry->completion_type == lldb::eNoCompletion)
+ return;
+
+ // FIXME: This should be handled higher in the Command Parser.
+ // Check the case where this command only takes one argument, and don't do
+ // the completion if we aren't on the first entry:
+ if (repeat == eArgRepeatPlain && request.GetCursorIndex() != 0)
+ return;
+
+ lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(), arg_entry->completion_type, request, nullptr);
+
+}
+
+
+bool CommandObject::HelpTextContainsWord(llvm::StringRef search_word,
+ bool search_short_help,
+ bool search_long_help,
+ bool search_syntax,
+ bool search_options) {
+ std::string options_usage_help;
+
+ bool found_word = false;
+
+ llvm::StringRef short_help = GetHelp();
+ llvm::StringRef long_help = GetHelpLong();
+ llvm::StringRef syntax_help = GetSyntax();
+
+ if (search_short_help && short_help.contains_insensitive(search_word))
+ found_word = true;
+ else if (search_long_help && long_help.contains_insensitive(search_word))
+ found_word = true;
+ else if (search_syntax && syntax_help.contains_insensitive(search_word))
+ found_word = true;
+
+ if (!found_word && search_options && GetOptions() != nullptr) {
+ StreamString usage_help;
+ GetOptions()->GenerateOptionUsage(
+ usage_help, *this,
+ GetCommandInterpreter().GetDebugger().GetTerminalWidth());
+ if (!usage_help.Empty()) {
+ llvm::StringRef usage_text = usage_help.GetString();
+ if (usage_text.contains_insensitive(search_word))
+ found_word = true;
+ }
+ }
+
+ return found_word;
+}
+
+bool CommandObject::ParseOptionsAndNotify(Args &args,
+ CommandReturnObject &result,
+ OptionGroupOptions &group_options,
+ ExecutionContext &exe_ctx) {
+ if (!ParseOptions(args, result))
+ return false;
+
+ Status error(group_options.NotifyOptionParsingFinished(&exe_ctx));
+ if (error.Fail()) {
+ result.AppendError(error.AsCString());
+ return false;
+ }
+ return true;
+}
+
+void CommandObject::AddSimpleArgumentList(
+ CommandArgumentType arg_type, ArgumentRepetitionType repetition_type) {
+
+ CommandArgumentEntry arg_entry;
+ CommandArgumentData simple_arg;
+
+ // Define the first (and only) variant of this arg.
+ simple_arg.arg_type = arg_type;
+ simple_arg.arg_repetition = repetition_type;
+
+ // There is only one variant this argument could be; put it into the argument
+ // entry.
+ arg_entry.push_back(simple_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back(arg_entry);
+}
+
+int CommandObject::GetNumArgumentEntries() { return m_arguments.size(); }
+
+CommandObject::CommandArgumentEntry *
+CommandObject::GetArgumentEntryAtIndex(int idx) {
+ if (static_cast<size_t>(idx) < m_arguments.size())
+ return &(m_arguments[idx]);
+
+ return nullptr;
+}
+
+const CommandObject::ArgumentTableEntry *
+CommandObject::FindArgumentDataByType(CommandArgumentType arg_type) {
+ for (int i = 0; i < eArgTypeLastArg; ++i)
+ if (g_argument_table[i].arg_type == arg_type)
+ return &(g_argument_table[i]);
+
+ return nullptr;
+}
+
+void CommandObject::GetArgumentHelp(Stream &str, CommandArgumentType arg_type,
+ CommandInterpreter &interpreter) {
+ const ArgumentTableEntry *entry = &(g_argument_table[arg_type]);
+
+ // The table is *supposed* to be kept in arg_type order, but someone *could*
+ // have messed it up...
+
+ if (entry->arg_type != arg_type)
+ entry = CommandObject::FindArgumentDataByType(arg_type);
+
+ if (!entry)
+ return;
+
+ StreamString name_str;
+ name_str.Printf("<%s>", entry->arg_name);
+
+ if (entry->help_function) {
+ llvm::StringRef help_text = entry->help_function();
+ if (!entry->help_function.self_formatting) {
+ interpreter.OutputFormattedHelpText(str, name_str.GetString(), "--",
+ help_text, name_str.GetSize());
+ } else {
+ interpreter.OutputHelpText(str, name_str.GetString(), "--", help_text,
+ name_str.GetSize());
+ }
+ } else {
+ interpreter.OutputFormattedHelpText(str, name_str.GetString(), "--",
+ entry->help_text, name_str.GetSize());
+
+ // Print enum values and their description if any.
+ OptionEnumValues enum_values = g_argument_table[arg_type].enum_values;
+ if (!enum_values.empty()) {
+ str.EOL();
+ size_t longest = 0;
+ for (const OptionEnumValueElement &element : enum_values)
+ longest =
+ std::max(longest, llvm::StringRef(element.string_value).size());
+ str.IndentMore(5);
+ for (const OptionEnumValueElement &element : enum_values) {
+ str.Indent();
+ interpreter.OutputHelpText(str, element.string_value, ":",
+ element.usage, longest);
+ }
+ str.IndentLess(5);
+ str.EOL();
+ }
+ }
+}
+
+const char *CommandObject::GetArgumentName(CommandArgumentType arg_type) {
+ const ArgumentTableEntry *entry = &(g_argument_table[arg_type]);
+
+ // The table is *supposed* to be kept in arg_type order, but someone *could*
+ // have messed it up...
+
+ if (entry->arg_type != arg_type)
+ entry = CommandObject::FindArgumentDataByType(arg_type);
+
+ if (entry)
+ return entry->arg_name;
+
+ return nullptr;
+}
+
+bool CommandObject::IsPairType(ArgumentRepetitionType arg_repeat_type) {
+ return (arg_repeat_type == eArgRepeatPairPlain) ||
+ (arg_repeat_type == eArgRepeatPairOptional) ||
+ (arg_repeat_type == eArgRepeatPairPlus) ||
+ (arg_repeat_type == eArgRepeatPairStar) ||
+ (arg_repeat_type == eArgRepeatPairRange) ||
+ (arg_repeat_type == eArgRepeatPairRangeOptional);
+}
+
+std::optional<ArgumentRepetitionType>
+CommandObject::ArgRepetitionFromString(llvm::StringRef string) {
+ return llvm::StringSwitch<ArgumentRepetitionType>(string)
+ .Case("plain", eArgRepeatPlain)
+ .Case("optional", eArgRepeatOptional)
+ .Case("plus", eArgRepeatPlus)
+ .Case("star", eArgRepeatStar)
+ .Case("range", eArgRepeatRange)
+ .Case("pair-plain", eArgRepeatPairPlain)
+ .Case("pair-optional", eArgRepeatPairOptional)
+ .Case("pair-plus", eArgRepeatPairPlus)
+ .Case("pair-star", eArgRepeatPairStar)
+ .Case("pair-range", eArgRepeatPairRange)
+ .Case("pair-range-optional", eArgRepeatPairRangeOptional)
+ .Default({});
+}
+
+static CommandObject::CommandArgumentEntry
+OptSetFiltered(uint32_t opt_set_mask,
+ CommandObject::CommandArgumentEntry &cmd_arg_entry) {
+ CommandObject::CommandArgumentEntry ret_val;
+ for (unsigned i = 0; i < cmd_arg_entry.size(); ++i)
+ if (opt_set_mask & cmd_arg_entry[i].arg_opt_set_association)
+ ret_val.push_back(cmd_arg_entry[i]);
+ return ret_val;
+}
+
+// Default parameter value of opt_set_mask is LLDB_OPT_SET_ALL, which means
+// take all the argument data into account. On rare cases where some argument
+// sticks with certain option sets, this function returns the option set
+// filtered args.
+void CommandObject::GetFormattedCommandArguments(Stream &str,
+ uint32_t opt_set_mask) {
+ int num_args = m_arguments.size();
+ for (int i = 0; i < num_args; ++i) {
+ if (i > 0)
+ str.Printf(" ");
+ CommandArgumentEntry arg_entry =
+ opt_set_mask == LLDB_OPT_SET_ALL
+ ? m_arguments[i]
+ : OptSetFiltered(opt_set_mask, m_arguments[i]);
+ // This argument is not associated with the current option set, so skip it.
+ if (arg_entry.empty())
+ continue;
+ int num_alternatives = arg_entry.size();
+
+ if ((num_alternatives == 2) && IsPairType(arg_entry[0].arg_repetition)) {
+ const char *first_name = GetArgumentName(arg_entry[0].arg_type);
+ const char *second_name = GetArgumentName(arg_entry[1].arg_type);
+ switch (arg_entry[0].arg_repetition) {
+ case eArgRepeatPairPlain:
+ str.Printf("<%s> <%s>", first_name, second_name);
+ break;
+ case eArgRepeatPairOptional:
+ str.Printf("[<%s> <%s>]", first_name, second_name);
+ break;
+ case eArgRepeatPairPlus:
+ str.Printf("<%s> <%s> [<%s> <%s> [...]]", first_name, second_name,
+ first_name, second_name);
+ break;
+ case eArgRepeatPairStar:
+ str.Printf("[<%s> <%s> [<%s> <%s> [...]]]", first_name, second_name,
+ first_name, second_name);
+ break;
+ case eArgRepeatPairRange:
+ str.Printf("<%s_1> <%s_1> ... <%s_n> <%s_n>", first_name, second_name,
+ first_name, second_name);
+ break;
+ case eArgRepeatPairRangeOptional:
+ str.Printf("[<%s_1> <%s_1> ... <%s_n> <%s_n>]", first_name, second_name,
+ first_name, second_name);
+ break;
+ // Explicitly test for all the rest of the cases, so if new types get
+ // added we will notice the missing case statement(s).
+ case eArgRepeatPlain:
+ case eArgRepeatOptional:
+ case eArgRepeatPlus:
+ case eArgRepeatStar:
+ case eArgRepeatRange:
+ // These should not be reached, as they should fail the IsPairType test
+ // above.
+ break;
+ }
+ } else {
+ StreamString names;
+ for (int j = 0; j < num_alternatives; ++j) {
+ if (j > 0)
+ names.Printf(" | ");
+ names.Printf("%s", GetArgumentName(arg_entry[j].arg_type));
+ }
+
+ std::string name_str = std::string(names.GetString());
+ switch (arg_entry[0].arg_repetition) {
+ case eArgRepeatPlain:
+ str.Printf("<%s>", name_str.c_str());
+ break;
+ case eArgRepeatPlus:
+ str.Printf("<%s> [<%s> [...]]", name_str.c_str(), name_str.c_str());
+ break;
+ case eArgRepeatStar:
+ str.Printf("[<%s> [<%s> [...]]]", name_str.c_str(), name_str.c_str());
+ break;
+ case eArgRepeatOptional:
+ str.Printf("[<%s>]", name_str.c_str());
+ break;
+ case eArgRepeatRange:
+ str.Printf("<%s_1> .. <%s_n>", name_str.c_str(), name_str.c_str());
+ break;
+ // Explicitly test for all the rest of the cases, so if new types get
+ // added we will notice the missing case statement(s).
+ case eArgRepeatPairPlain:
+ case eArgRepeatPairOptional:
+ case eArgRepeatPairPlus:
+ case eArgRepeatPairStar:
+ case eArgRepeatPairRange:
+ case eArgRepeatPairRangeOptional:
+ // These should not be hit, as they should pass the IsPairType test
+ // above, and control should have gone into the other branch of the if
+ // statement.
+ break;
+ }
+ }
+ }
+}
+
+CommandArgumentType
+CommandObject::LookupArgumentName(llvm::StringRef arg_name) {
+ CommandArgumentType return_type = eArgTypeLastArg;
+
+ arg_name = arg_name.ltrim('<').rtrim('>');
+
+ for (int i = 0; i < eArgTypeLastArg; ++i)
+ if (arg_name == g_argument_table[i].arg_name)
+ return_type = g_argument_table[i].arg_type;
+
+ return return_type;
+}
+
+void CommandObject::FormatLongHelpText(Stream &output_strm,
+ llvm::StringRef long_help) {
+ CommandInterpreter &interpreter = GetCommandInterpreter();
+ std::stringstream lineStream{std::string(long_help)};
+ std::string line;
+ while (std::getline(lineStream, line)) {
+ if (line.empty()) {
+ output_strm << "\n";
+ continue;
+ }
+ size_t result = line.find_first_not_of(" \t");
+ if (result == std::string::npos) {
+ result = 0;
+ }
+ std::string whitespace_prefix = line.substr(0, result);
+ std::string remainder = line.substr(result);
+ interpreter.OutputFormattedHelpText(output_strm, whitespace_prefix,
+ remainder);
+ }
+}
+
+void CommandObject::GenerateHelpText(CommandReturnObject &result) {
+ GenerateHelpText(result.GetOutputStream());
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+}
+
+void CommandObject::GenerateHelpText(Stream &output_strm) {
+ CommandInterpreter &interpreter = GetCommandInterpreter();
+ std::string help_text(GetHelp());
+ if (WantsRawCommandString()) {
+ help_text.append(" Expects 'raw' input (see 'help raw-input'.)");
+ }
+ interpreter.OutputFormattedHelpText(output_strm, "", help_text);
+ output_strm << "\nSyntax: " << GetSyntax() << "\n";
+ Options *options = GetOptions();
+ if (options != nullptr) {
+ options->GenerateOptionUsage(
+ output_strm, *this,
+ GetCommandInterpreter().GetDebugger().GetTerminalWidth());
+ }
+ llvm::StringRef long_help = GetHelpLong();
+ if (!long_help.empty()) {
+ FormatLongHelpText(output_strm, long_help);
+ }
+ if (!IsDashDashCommand() && options && options->NumCommandOptions() > 0) {
+ if (WantsRawCommandString() && !WantsCompletion()) {
+ // Emit the message about using ' -- ' between the end of the command
+ // options and the raw input conditionally, i.e., only if the command
+ // object does not want completion.
+ interpreter.OutputFormattedHelpText(
+ output_strm, "", "",
+ "\nImportant Note: Because this command takes 'raw' input, if you "
+ "use any command options"
+ " you must use ' -- ' between the end of the command options and the "
+ "beginning of the raw input.",
+ 1);
+ } else if (GetNumArgumentEntries() > 0) {
+ // Also emit a warning about using "--" in case you are using a command
+ // that takes options and arguments.
+ interpreter.OutputFormattedHelpText(
+ output_strm, "", "",
+ "\nThis command takes options and free-form arguments. If your "
+ "arguments resemble"
+ " option specifiers (i.e., they start with a - or --), you must use "
+ "' -- ' between"
+ " the end of the command options and the beginning of the arguments.",
+ 1);
+ }
+ }
+}
+
+void CommandObject::AddIDsArgumentData(CommandObject::IDType type) {
+ CommandArgumentEntry arg;
+ CommandArgumentData id_arg;
+ CommandArgumentData id_range_arg;
+
+ // Create the first variant for the first (and only) argument for this
+ // command.
+ switch (type) {
+ case eBreakpointArgs:
+ id_arg.arg_type = eArgTypeBreakpointID;
+ id_range_arg.arg_type = eArgTypeBreakpointIDRange;
+ break;
+ case eWatchpointArgs:
+ id_arg.arg_type = eArgTypeWatchpointID;
+ id_range_arg.arg_type = eArgTypeWatchpointIDRange;
+ break;
+ }
+ id_arg.arg_repetition = eArgRepeatOptional;
+ id_range_arg.arg_repetition = eArgRepeatOptional;
+
+ // The first (and only) argument for this command could be either an id or an
+ // id_range. Push both variants into the entry for the first argument for
+ // this command.
+ arg.push_back(id_arg);
+ arg.push_back(id_range_arg);
+ m_arguments.push_back(arg);
+}
+
+const char *CommandObject::GetArgumentTypeAsCString(
+ const lldb::CommandArgumentType arg_type) {
+ assert(arg_type < eArgTypeLastArg &&
+ "Invalid argument type passed to GetArgumentTypeAsCString");
+ return g_argument_table[arg_type].arg_name;
+}
+
+const char *CommandObject::GetArgumentDescriptionAsCString(
+ const lldb::CommandArgumentType arg_type) {
+ assert(arg_type < eArgTypeLastArg &&
+ "Invalid argument type passed to GetArgumentDescriptionAsCString");
+ return g_argument_table[arg_type].help_text;
+}
+
+Target &CommandObject::GetDummyTarget() {
+ return m_interpreter.GetDebugger().GetDummyTarget();
+}
+
+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() {
+ Thread *thread_to_use = m_exe_ctx.GetThreadPtr();
+ if (thread_to_use)
+ return thread_to_use;
+
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (!process) {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (!target) {
+ target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ }
+ if (target)
+ process = target->GetProcessSP().get();
+ }
+
+ if (process)
+ return process->GetThreadList().GetSelectedThread().get();
+ else
+ return nullptr;
+}
+
+void CommandObjectParsed::Execute(const char *args_string,
+ CommandReturnObject &result) {
+ bool handled = false;
+ Args cmd_args(args_string);
+ if (HasOverrideCallback()) {
+ Args full_args(GetCommandName());
+ full_args.AppendArguments(cmd_args);
+ handled =
+ InvokeOverrideCallback(full_args.GetConstArgumentVector(), result);
+ }
+ if (!handled) {
+ for (auto entry : llvm::enumerate(cmd_args.entries())) {
+ const Args::ArgEntry &value = entry.value();
+ if (!value.ref().empty() && value.GetQuoteChar() == '`') {
+ // We have to put the backtick back in place for PreprocessCommand.
+ std::string opt_string = value.c_str();
+ Status error;
+ error = m_interpreter.PreprocessToken(opt_string);
+ if (error.Success())
+ cmd_args.ReplaceArgumentAtIndex(entry.index(), opt_string);
+ }
+ }
+
+ if (CheckRequirements(result)) {
+ if (ParseOptions(cmd_args, result)) {
+ // Call the command-specific version of 'Execute', passing it the
+ // already processed arguments.
+ if (cmd_args.GetArgumentCount() != 0 && m_arguments.empty()) {
+ result.AppendErrorWithFormatv("'{0}' doesn't take any arguments.",
+ GetCommandName());
+ Cleanup();
+ return;
+ }
+ m_interpreter.IncreaseCommandUsage(*this);
+ DoExecute(cmd_args, result);
+ }
+ }
+
+ Cleanup();
+ }
+}
+
+void CommandObjectRaw::Execute(const char *args_string,
+ CommandReturnObject &result) {
+ bool handled = false;
+ if (HasOverrideCallback()) {
+ std::string full_command(GetCommandName());
+ full_command += ' ';
+ full_command += args_string;
+ const char *argv[2] = {nullptr, nullptr};
+ argv[0] = full_command.c_str();
+ handled = InvokeOverrideCallback(argv, result);
+ }
+ if (!handled) {
+ if (CheckRequirements(result))
+ DoExecute(args_string, result);
+
+ Cleanup();
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/CommandOptionValidators.cpp b/contrib/llvm-project/lldb/source/Interpreter/CommandOptionValidators.cpp
new file mode 100644
index 000000000000..a4b4b57c54b1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/CommandOptionValidators.cpp
@@ -0,0 +1,36 @@
+//===-- CommandOptionValidators.cpp ---------------------------------------===//
+//
+// 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/CommandOptionValidators.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/Platform.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool PosixPlatformCommandOptionValidator::IsValid(
+ Platform &platform, const ExecutionContext &target) const {
+ llvm::Triple::OSType os =
+ platform.GetSystemArchitecture().GetTriple().getOS();
+ switch (os) {
+ // Are there any other platforms that are not POSIX-compatible?
+ case llvm::Triple::Win32:
+ return false;
+ default:
+ return true;
+ }
+}
+
+const char *PosixPlatformCommandOptionValidator::ShortConditionString() const {
+ return "POSIX";
+}
+
+const char *PosixPlatformCommandOptionValidator::LongConditionString() const {
+ return "Option only valid for POSIX-compliant hosts.";
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/CommandReturnObject.cpp b/contrib/llvm-project/lldb/source/Interpreter/CommandReturnObject.cpp
new file mode 100644
index 000000000000..0bc58124f394
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/CommandReturnObject.cpp
@@ -0,0 +1,175 @@
+//===-- CommandReturnObject.cpp -------------------------------------------===//
+//
+// 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/CommandReturnObject.h"
+
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static llvm::raw_ostream &error(Stream &strm) {
+ return llvm::WithColor(strm.AsRawOstream(), llvm::HighlightColor::Error,
+ llvm::ColorMode::Enable)
+ << "error: ";
+}
+
+static llvm::raw_ostream &warning(Stream &strm) {
+ return llvm::WithColor(strm.AsRawOstream(), llvm::HighlightColor::Warning,
+ llvm::ColorMode::Enable)
+ << "warning: ";
+}
+
+static void DumpStringToStreamWithNewline(Stream &strm, const std::string &s) {
+ bool add_newline = false;
+ if (!s.empty()) {
+ // We already checked for empty above, now make sure there is a newline in
+ // the error, and if there isn't one, add one.
+ strm.Write(s.c_str(), s.size());
+
+ const char last_char = *s.rbegin();
+ add_newline = last_char != '\n' && last_char != '\r';
+ }
+ if (add_newline)
+ strm.EOL();
+}
+
+CommandReturnObject::CommandReturnObject(bool colors)
+ : m_out_stream(colors), m_err_stream(colors) {}
+
+void CommandReturnObject::AppendErrorWithFormat(const char *format, ...) {
+ SetStatus(eReturnStatusFailed);
+
+ if (!format)
+ return;
+ va_list args;
+ va_start(args, format);
+ StreamString sstrm;
+ sstrm.PrintfVarArg(format, args);
+ va_end(args);
+
+ const std::string &s = std::string(sstrm.GetString());
+ if (!s.empty()) {
+ error(GetErrorStream());
+ DumpStringToStreamWithNewline(GetErrorStream(), s);
+ }
+}
+
+void CommandReturnObject::AppendMessageWithFormat(const char *format, ...) {
+ if (!format)
+ return;
+ va_list args;
+ va_start(args, format);
+ StreamString sstrm;
+ sstrm.PrintfVarArg(format, args);
+ va_end(args);
+
+ GetOutputStream() << sstrm.GetString();
+}
+
+void CommandReturnObject::AppendWarningWithFormat(const char *format, ...) {
+ if (!format)
+ return;
+ va_list args;
+ va_start(args, format);
+ StreamString sstrm;
+ sstrm.PrintfVarArg(format, args);
+ va_end(args);
+
+ warning(GetErrorStream()) << sstrm.GetString();
+}
+
+void CommandReturnObject::AppendMessage(llvm::StringRef in_string) {
+ if (in_string.empty())
+ return;
+ GetOutputStream() << in_string.rtrim() << '\n';
+}
+
+void CommandReturnObject::AppendWarning(llvm::StringRef in_string) {
+ if (in_string.empty())
+ return;
+ warning(GetErrorStream()) << in_string.rtrim() << '\n';
+}
+
+void CommandReturnObject::AppendError(llvm::StringRef in_string) {
+ SetStatus(eReturnStatusFailed);
+ if (in_string.empty())
+ return;
+ // Workaround to deal with already fully formatted compiler diagnostics.
+ llvm::StringRef msg(in_string.rtrim());
+ msg.consume_front("error: ");
+ error(GetErrorStream()) << msg << '\n';
+}
+
+void CommandReturnObject::SetError(const Status &error,
+ const char *fallback_error_cstr) {
+ if (error.Fail())
+ AppendError(error.AsCString(fallback_error_cstr));
+}
+
+void CommandReturnObject::SetError(llvm::Error error) {
+ if (error)
+ AppendError(llvm::toString(std::move(error)));
+}
+
+// Similar to AppendError, but do not prepend 'Status: ' to message, and don't
+// append "\n" to the end of it.
+
+void CommandReturnObject::AppendRawError(llvm::StringRef in_string) {
+ SetStatus(eReturnStatusFailed);
+ assert(!in_string.empty() && "Expected a non-empty error message");
+ GetErrorStream() << in_string;
+}
+
+void CommandReturnObject::SetStatus(ReturnStatus status) { m_status = status; }
+
+ReturnStatus CommandReturnObject::GetStatus() const { return m_status; }
+
+bool CommandReturnObject::Succeeded() const {
+ return m_status <= eReturnStatusSuccessContinuingResult;
+}
+
+bool CommandReturnObject::HasResult() const {
+ return (m_status == eReturnStatusSuccessFinishResult ||
+ m_status == eReturnStatusSuccessContinuingResult);
+}
+
+void CommandReturnObject::Clear() {
+ lldb::StreamSP stream_sp;
+ stream_sp = m_out_stream.GetStreamAtIndex(eStreamStringIndex);
+ if (stream_sp)
+ static_cast<StreamString *>(stream_sp.get())->Clear();
+ stream_sp = m_err_stream.GetStreamAtIndex(eStreamStringIndex);
+ if (stream_sp)
+ static_cast<StreamString *>(stream_sp.get())->Clear();
+ m_status = eReturnStatusStarted;
+ m_did_change_process_state = false;
+ m_suppress_immediate_output = false;
+ m_interactive = true;
+}
+
+bool CommandReturnObject::GetDidChangeProcessState() const {
+ return m_did_change_process_state;
+}
+
+void CommandReturnObject::SetDidChangeProcessState(bool b) {
+ m_did_change_process_state = b;
+}
+
+bool CommandReturnObject::GetInteractive() const { return m_interactive; }
+
+void CommandReturnObject::SetInteractive(bool b) { m_interactive = b; }
+
+bool CommandReturnObject::GetSuppressImmediateOutput() const {
+ return m_suppress_immediate_output;
+}
+
+void CommandReturnObject::SetSuppressImmediateOutput(bool b) {
+ m_suppress_immediate_output = b;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/InterpreterProperties.td b/contrib/llvm-project/lldb/source/Interpreter/InterpreterProperties.td
new file mode 100644
index 000000000000..a5fccbbca091
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/InterpreterProperties.td
@@ -0,0 +1,51 @@
+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 SaveTranscript: Property<"save-transcript", "Boolean">,
+ Global,
+ DefaultFalse,
+ Desc<"If true, commands will be saved into a transcript buffer for user access.">;
+ def SaveSessionOnQuit: Property<"save-session-on-quit", "Boolean">,
+ Global,
+ DefaultFalse,
+ Desc<"If true, LLDB will save the session's transcripts before quitting.">;
+ def OpenTranscriptInEditor: Property<"open-transcript-in-editor", "Boolean">,
+ Global,
+ DefaultTrue,
+ Desc<"If true, LLDB will open the saved session's transcripts in the external editor.">;
+ def SaveSessionDirectory: Property<"save-session-directory", "FileSpec">,
+ DefaultStringValue<"">,
+ Desc<"A path where LLDB will save the session's transcripts. This is particularly useful when you can't set the session file, for example when using `save-session-on-quit`.">;
+ 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.">;
+ def RepeatPreviousCommand: Property<"repeat-previous-command", "Boolean">,
+ Global,
+ DefaultTrue,
+ Desc<"If true, LLDB will repeat the previous command if no command was passed to the interpreter. If false, LLDB won't repeat the previous command but only return a new prompt.">;
+ def RequireCommandOverwrite: Property<"require-overwrite", "Boolean">,
+ Global,
+ DefaultTrue,
+ Desc<"If true, require --overwrite in 'command script add' before overwriting existing user commands.">;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionArgParser.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionArgParser.cpp
new file mode 100644
index 000000000000..105d4846da14
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionArgParser.cpp
@@ -0,0 +1,320 @@
+//===-- OptionArgParser.cpp -----------------------------------------------===//
+//
+// 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/OptionArgParser.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value,
+ bool *success_ptr) {
+ if (success_ptr)
+ *success_ptr = true;
+ ref = ref.trim();
+ if (ref.equals_insensitive("false") || ref.equals_insensitive("off") ||
+ ref.equals_insensitive("no") || ref.equals_insensitive("0")) {
+ return false;
+ } else if (ref.equals_insensitive("true") || ref.equals_insensitive("on") ||
+ ref.equals_insensitive("yes") || ref.equals_insensitive("1")) {
+ return true;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+llvm::Expected<bool> OptionArgParser::ToBoolean(llvm::StringRef option_name,
+ llvm::StringRef option_arg) {
+ bool parse_success;
+ const bool option_value =
+ ToBoolean(option_arg, false /* doesn't matter */, &parse_success);
+ if (parse_success)
+ return option_value;
+ else
+ return llvm::createStringError(
+ "Invalid boolean value for option '%s': '%s'",
+ option_name.str().c_str(),
+ option_arg.empty() ? "<null>" : option_arg.str().c_str());
+}
+
+char OptionArgParser::ToChar(llvm::StringRef s, char fail_value,
+ bool *success_ptr) {
+ if (success_ptr)
+ *success_ptr = false;
+ if (s.size() != 1)
+ return fail_value;
+
+ if (success_ptr)
+ *success_ptr = true;
+ return s[0];
+}
+
+int64_t OptionArgParser::ToOptionEnum(llvm::StringRef s,
+ const OptionEnumValues &enum_values,
+ int32_t fail_value, Status &error) {
+ error.Clear();
+ if (enum_values.empty()) {
+ error.SetErrorString("invalid enumeration argument");
+ return fail_value;
+ }
+
+ if (s.empty()) {
+ error.SetErrorString("empty enumeration string");
+ return fail_value;
+ }
+
+ for (const auto &enum_value : enum_values) {
+ llvm::StringRef this_enum(enum_value.string_value);
+ if (this_enum.starts_with(s))
+ return enum_value.value;
+ }
+
+ StreamString strm;
+ strm.PutCString("invalid enumeration value, valid values are: ");
+ bool is_first = true;
+ for (const auto &enum_value : enum_values) {
+ strm.Printf("%s\"%s\"",
+ is_first ? is_first = false,"" : ", ", enum_value.string_value);
+ }
+ error.SetErrorString(strm.GetString());
+ return fail_value;
+}
+
+Status OptionArgParser::ToFormat(const char *s, lldb::Format &format,
+ size_t *byte_size_ptr) {
+ format = eFormatInvalid;
+ Status error;
+
+ if (s && s[0]) {
+ if (byte_size_ptr) {
+ if (isdigit(s[0])) {
+ char *format_char = nullptr;
+ unsigned long byte_size = ::strtoul(s, &format_char, 0);
+ if (byte_size != ULONG_MAX)
+ *byte_size_ptr = byte_size;
+ s = format_char;
+ } else
+ *byte_size_ptr = 0;
+ }
+
+ if (!FormatManager::GetFormatFromCString(s, format)) {
+ StreamString error_strm;
+ error_strm.Printf(
+ "Invalid format character or name '%s'. Valid values are:\n", s);
+ for (Format f = eFormatDefault; f < kNumFormats; f = Format(f + 1)) {
+ char format_char = FormatManager::GetFormatAsFormatChar(f);
+ if (format_char)
+ error_strm.Printf("'%c' or ", format_char);
+
+ error_strm.Printf("\"%s\"", FormatManager::GetFormatAsCString(f));
+ error_strm.EOL();
+ }
+
+ if (byte_size_ptr)
+ error_strm.PutCString(
+ "An optional byte size can precede the format character.\n");
+ error.SetErrorString(error_strm.GetString());
+ }
+
+ if (error.Fail())
+ return error;
+ } else {
+ error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid");
+ }
+ return error;
+}
+
+lldb::ScriptLanguage OptionArgParser::ToScriptLanguage(
+ llvm::StringRef s, lldb::ScriptLanguage fail_value, bool *success_ptr) {
+ if (success_ptr)
+ *success_ptr = true;
+
+ if (s.equals_insensitive("python"))
+ return eScriptLanguagePython;
+ if (s.equals_insensitive("lua"))
+ return eScriptLanguageLua;
+ if (s.equals_insensitive("default"))
+ return eScriptLanguageDefault;
+ if (s.equals_insensitive("none"))
+ return eScriptLanguageNone;
+
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+lldb::addr_t OptionArgParser::ToRawAddress(const ExecutionContext *exe_ctx,
+ llvm::StringRef s,
+ lldb::addr_t fail_value,
+ Status *error_ptr) {
+ std::optional<lldb::addr_t> maybe_addr = DoToAddress(exe_ctx, s, error_ptr);
+ return maybe_addr ? *maybe_addr : fail_value;
+}
+
+lldb::addr_t OptionArgParser::ToAddress(const ExecutionContext *exe_ctx,
+ llvm::StringRef s,
+ lldb::addr_t fail_value,
+ Status *error_ptr) {
+ std::optional<lldb::addr_t> maybe_addr = DoToAddress(exe_ctx, s, error_ptr);
+ if (!maybe_addr)
+ return fail_value;
+
+ lldb::addr_t addr = *maybe_addr;
+
+ if (Process *process = exe_ctx->GetProcessPtr())
+ if (ABISP abi_sp = process->GetABI())
+ addr = abi_sp->FixCodeAddress(addr);
+
+ return addr;
+}
+
+std::optional<lldb::addr_t>
+OptionArgParser::DoToAddress(const ExecutionContext *exe_ctx, llvm::StringRef s,
+ Status *error_ptr) {
+ if (s.empty()) {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"",
+ s.str().c_str());
+ return {};
+ }
+
+ llvm::StringRef sref = s;
+
+ lldb::addr_t addr = LLDB_INVALID_ADDRESS;
+ if (!s.getAsInteger(0, addr)) {
+ if (error_ptr)
+ error_ptr->Clear();
+
+ return addr;
+ }
+
+ // Try base 16 with no prefix...
+ if (!s.getAsInteger(16, addr)) {
+ if (error_ptr)
+ error_ptr->Clear();
+ return addr;
+ }
+
+ Target *target = nullptr;
+ if (!exe_ctx || !(target = exe_ctx->GetTargetPtr())) {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"",
+ s.str().c_str());
+ return {};
+ }
+
+ lldb::ValueObjectSP valobj_sp;
+ EvaluateExpressionOptions options;
+ options.SetCoerceToId(false);
+ options.SetUnwindOnError(true);
+ options.SetKeepInMemory(false);
+ options.SetTryAllThreads(true);
+
+ ExpressionResults expr_result =
+ target->EvaluateExpression(s, exe_ctx->GetFramePtr(), valobj_sp, options);
+
+ bool success = false;
+ if (expr_result == eExpressionCompleted) {
+ if (valobj_sp)
+ valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable(
+ valobj_sp->GetDynamicValueType(), true);
+ // Get the address to watch.
+ if (valobj_sp)
+ addr = valobj_sp->GetValueAsUnsigned(0, &success);
+ if (success) {
+ if (error_ptr)
+ error_ptr->Clear();
+ return addr;
+ }
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat(
+ "address expression \"%s\" resulted in a value whose type "
+ "can't be converted to an address: %s",
+ s.str().c_str(), valobj_sp->GetTypeName().GetCString());
+ return {};
+ }
+
+ // Since the compiler can't handle things like "main + 12" we should try to
+ // do this for now. The compiler doesn't like adding offsets to function
+ // pointer types.
+ // Some languages also don't have a natural representation for register
+ // values (e.g. swift) so handle simple uses of them here as well.
+ // We use a regex to parse these forms, the regex handles:
+ // $reg_name
+ // $reg_name+offset
+ // symbol_name+offset
+ //
+ // The important matching elements in the regex below are:
+ // 1: The reg name if there's no +offset
+ // 3: The symbol/reg name if there is an offset
+ // 4: +/-
+ // 5: The offset value.
+ static RegularExpression g_symbol_plus_offset_regex(
+ "^(\\$[^ +-]+)|(([^ +-]+)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*)$");
+
+ llvm::SmallVector<llvm::StringRef, 4> matches;
+ if (g_symbol_plus_offset_regex.Execute(sref, &matches)) {
+ uint64_t offset = 0;
+ llvm::StringRef name;
+ if (!matches[1].empty())
+ name = matches[1];
+ else
+ name = matches[3];
+
+ llvm::StringRef sign = matches[4];
+ llvm::StringRef str_offset = matches[5];
+
+ // Some languages don't have a natural type for register values, but it
+ // is still useful to look them up here:
+ std::optional<lldb::addr_t> register_value;
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ llvm::StringRef reg_name = name;
+ if (frame && reg_name.consume_front("$")) {
+ RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
+ if (reg_ctx_sp) {
+ const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfoByName(reg_name);
+ if (reg_info) {
+ RegisterValue reg_val;
+ bool success = reg_ctx_sp->ReadRegister(reg_info, reg_val);
+ if (success && reg_val.GetType() != RegisterValue::eTypeInvalid) {
+ register_value = reg_val.GetAsUInt64(0, &success);
+ if (!success)
+ register_value.reset();
+ }
+ }
+ }
+ }
+ if (!str_offset.empty() && !str_offset.getAsInteger(0, offset)) {
+ Status error;
+ if (register_value)
+ addr = register_value.value();
+ else
+ addr = ToAddress(exe_ctx, name, LLDB_INVALID_ADDRESS, &error);
+ if (addr != LLDB_INVALID_ADDRESS) {
+ if (sign[0] == '+')
+ return addr + offset;
+ return addr - offset;
+ }
+ } else if (register_value)
+ // In the case of register values, someone might just want to get the
+ // value in a language whose expression parser doesn't support registers.
+ return register_value.value();
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat(
+ "address expression \"%s\" evaluation failed", s.str().c_str());
+ return {};
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupArchitecture.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupArchitecture.cpp
new file mode 100644
index 000000000000..3925f835885f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupArchitecture.cpp
@@ -0,0 +1,54 @@
+//===-- OptionGroupArchitecture.cpp ---------------------------------------===//
+//
+// 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/OptionGroupArchitecture.h"
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Target/Platform.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static constexpr OptionDefinition g_option_table[] = {
+ {LLDB_OPT_SET_1, false, "arch", 'a', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeArchitecture,
+ "Specify the architecture for the target."},
+};
+
+llvm::ArrayRef<OptionDefinition> OptionGroupArchitecture::GetDefinitions() {
+ return llvm::ArrayRef(g_option_table);
+}
+
+bool OptionGroupArchitecture::GetArchitecture(Platform *platform,
+ ArchSpec &arch) {
+ arch = Platform::GetAugmentedArchSpec(platform, m_arch_str);
+ return arch.IsValid();
+}
+
+Status
+OptionGroupArchitecture::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
+ const int short_option = g_option_table[option_idx].short_option;
+
+ switch (short_option) {
+ case 'a':
+ m_arch_str.assign(std::string(option_arg));
+ break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+}
+
+void OptionGroupArchitecture::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ m_arch_str.clear();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupBoolean.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupBoolean.cpp
new file mode 100644
index 000000000000..3f73893fca96
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupBoolean.cpp
@@ -0,0 +1,54 @@
+//===-- OptionGroupBoolean.cpp --------------------------------------------===//
+//
+// 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/OptionGroupBoolean.h"
+
+#include "lldb/Host/OptionParser.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupBoolean::OptionGroupBoolean(uint32_t usage_mask, bool required,
+ const char *long_option,
+ int short_option, const char *usage_text,
+ bool default_value,
+ bool no_argument_toggle_default)
+ : m_value(default_value, default_value) {
+ m_option_definition.usage_mask = usage_mask;
+ m_option_definition.required = required;
+ m_option_definition.long_option = long_option;
+ m_option_definition.short_option = short_option;
+ m_option_definition.validator = nullptr;
+ m_option_definition.option_has_arg = no_argument_toggle_default
+ ? OptionParser::eNoArgument
+ : OptionParser::eRequiredArgument;
+ m_option_definition.enum_values = {};
+ m_option_definition.completion_type = 0;
+ m_option_definition.argument_type = eArgTypeBoolean;
+ m_option_definition.usage_text = usage_text;
+}
+
+Status OptionGroupBoolean::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_value,
+ ExecutionContext *execution_context) {
+ Status error;
+ if (m_option_definition.option_has_arg == OptionParser::eNoArgument) {
+ // Not argument, toggle the default value and mark the option as having
+ // been set
+ m_value.SetCurrentValue(!m_value.GetDefaultValue());
+ m_value.SetOptionWasSet();
+ } else {
+ error = m_value.SetValueFromString(option_value);
+ }
+ return error;
+}
+
+void OptionGroupBoolean::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ m_value.Clear();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupFile.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupFile.cpp
new file mode 100644
index 000000000000..12ade1855829
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupFile.cpp
@@ -0,0 +1,75 @@
+//===-- OptionGroupFile.cpp -----------------------------------------------===//
+//
+// 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/OptionGroupFile.h"
+
+#include "lldb/Host/OptionParser.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupFile::OptionGroupFile(uint32_t usage_mask, bool required,
+ const char *long_option, int short_option,
+ uint32_t completion_type,
+ lldb::CommandArgumentType argument_type,
+ const char *usage_text) {
+ m_option_definition.usage_mask = usage_mask;
+ m_option_definition.required = required;
+ m_option_definition.long_option = long_option;
+ m_option_definition.short_option = short_option;
+ m_option_definition.validator = nullptr;
+ m_option_definition.option_has_arg = OptionParser::eRequiredArgument;
+ m_option_definition.enum_values = {};
+ m_option_definition.completion_type = completion_type;
+ m_option_definition.argument_type = argument_type;
+ m_option_definition.usage_text = usage_text;
+}
+
+Status OptionGroupFile::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error(m_file.SetValueFromString(option_arg));
+ return error;
+}
+
+void OptionGroupFile::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ m_file.Clear();
+}
+
+OptionGroupFileList::OptionGroupFileList(
+ uint32_t usage_mask, bool required, const char *long_option,
+ int short_option, uint32_t completion_type,
+ lldb::CommandArgumentType argument_type, const char *usage_text)
+ : m_file_list() {
+ m_option_definition.usage_mask = usage_mask;
+ m_option_definition.required = required;
+ m_option_definition.long_option = long_option;
+ m_option_definition.short_option = short_option;
+ m_option_definition.validator = nullptr;
+ m_option_definition.option_has_arg = OptionParser::eRequiredArgument;
+ m_option_definition.enum_values = {};
+ m_option_definition.completion_type = completion_type;
+ m_option_definition.argument_type = argument_type;
+ m_option_definition.usage_text = usage_text;
+}
+
+OptionGroupFileList::~OptionGroupFileList() = default;
+
+Status
+OptionGroupFileList::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_value,
+ ExecutionContext *execution_context) {
+ Status error(m_file_list.SetValueFromString(option_value));
+ return error;
+}
+
+void OptionGroupFileList::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ m_file_list.Clear();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupFormat.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupFormat.cpp
new file mode 100644
index 000000000000..6b56ad2ea819
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupFormat.cpp
@@ -0,0 +1,283 @@
+//===-- OptionGroupFormat.cpp ---------------------------------------------===//
+//
+// 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/OptionGroupFormat.h"
+
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static constexpr OptionDefinition g_default_option_definitions[] = {
+ {LLDB_OPT_SET_1, false, "format", 'f', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeFormat,
+ "Specify a format to be used for display."},
+ {LLDB_OPT_SET_2, false, "gdb-format", 'G', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeGDBFormat,
+ "Specify a format using a GDB format specifier string."},
+ {LLDB_OPT_SET_3, false, "size", 's', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeByteSize,
+ "The size in bytes to use when displaying with the selected format."},
+ {LLDB_OPT_SET_4, false, "count", 'c', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeCount,
+ "The number of total items to display."},
+};
+
+OptionGroupFormat::OptionGroupFormat(
+ lldb::Format default_format, uint64_t default_byte_size,
+ uint64_t default_count, OptionGroupFormatUsageTextVector usage_text_vector)
+ : m_format(default_format, default_format),
+ m_byte_size(default_byte_size, default_byte_size),
+ m_count(default_count, default_count), m_prev_gdb_format('x'),
+ m_prev_gdb_size('w'), m_has_gdb_format(false) {
+ // Copy the default option definitions.
+ std::copy(std::begin(g_default_option_definitions),
+ std::end(g_default_option_definitions),
+ std::begin(m_option_definitions));
+
+ for (auto usage_text_tuple : usage_text_vector) {
+ switch (std::get<0>(usage_text_tuple)) {
+ case eArgTypeFormat:
+ m_option_definitions[0].usage_text = std::get<1>(usage_text_tuple);
+ break;
+ case eArgTypeByteSize:
+ m_option_definitions[2].usage_text = std::get<1>(usage_text_tuple);
+ break;
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+ }
+}
+
+llvm::ArrayRef<OptionDefinition> OptionGroupFormat::GetDefinitions() {
+ auto result = llvm::ArrayRef(m_option_definitions);
+ if (m_byte_size.GetDefaultValue() < UINT64_MAX) {
+ if (m_count.GetDefaultValue() < UINT64_MAX)
+ return result;
+ else
+ return result.take_front(3);
+ }
+ return result.take_front(2);
+}
+
+Status OptionGroupFormat::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
+ const int short_option = m_option_definitions[option_idx].short_option;
+
+ switch (short_option) {
+ case 'f':
+ error = m_format.SetValueFromString(option_arg);
+ break;
+
+ case 'c':
+ if (m_count.GetDefaultValue() == 0) {
+ error.SetErrorString("--count option is disabled");
+ } else {
+ error = m_count.SetValueFromString(option_arg);
+ if (m_count.GetCurrentValue() == 0)
+ error.SetErrorStringWithFormat("invalid --count option value '%s'",
+ option_arg.str().c_str());
+ }
+ break;
+
+ case 's':
+ if (m_byte_size.GetDefaultValue() == 0) {
+ error.SetErrorString("--size option is disabled");
+ } else {
+ error = m_byte_size.SetValueFromString(option_arg);
+ if (m_byte_size.GetCurrentValue() == 0)
+ error.SetErrorStringWithFormat("invalid --size option value '%s'",
+ option_arg.str().c_str());
+ }
+ break;
+
+ case 'G': {
+ uint64_t count = 0;
+ llvm::StringRef gdb_format_str = option_arg;
+ gdb_format_str.consumeInteger(0, count);
+
+ Format format = eFormatDefault;
+ uint32_t byte_size = 0;
+
+ while (!gdb_format_str.empty() &&
+ ParserGDBFormatLetter(execution_context, gdb_format_str[0], format,
+ byte_size)) {
+ gdb_format_str = gdb_format_str.drop_front();
+ }
+
+ // We the first character of the "gdb_format_str" is not the
+ // NULL terminator, we didn't consume the entire string and
+ // something is wrong. Also, if none of the format, size or count was
+ // specified correctly, then abort.
+ if (!gdb_format_str.empty() ||
+ (format == eFormatInvalid && byte_size == 0 && count == 0)) {
+ // Nothing got set correctly
+ error.SetErrorStringWithFormat("invalid gdb format string '%s'",
+ option_arg.str().c_str());
+ return error;
+ }
+
+ // At least one of the format, size or count was set correctly. Anything
+ // that wasn't set correctly should be set to the previous default
+ if (format == eFormatInvalid)
+ ParserGDBFormatLetter(execution_context, m_prev_gdb_format, format,
+ byte_size);
+
+ const bool byte_size_enabled = m_byte_size.GetDefaultValue() < UINT64_MAX;
+ const bool count_enabled = m_count.GetDefaultValue() < UINT64_MAX;
+ if (byte_size_enabled) {
+ // Byte size is enabled
+ if (byte_size == 0)
+ ParserGDBFormatLetter(execution_context, m_prev_gdb_size, format,
+ byte_size);
+ } else {
+ // Byte size is disabled, make sure it wasn't specified but if this is an
+ // address, it's actually necessary to specify one so don't error out
+ if (byte_size > 0 && format != lldb::eFormatAddressInfo) {
+ error.SetErrorString(
+ "this command doesn't support specifying a byte size");
+ return error;
+ }
+ }
+
+ if (count_enabled) {
+ // Count is enabled and was not set, set it to the default for gdb format
+ // statements (which is 1).
+ if (count == 0)
+ count = 1;
+ } else {
+ // Count is disabled, make sure it wasn't specified
+ if (count > 0) {
+ error.SetErrorString("this command doesn't support specifying a count");
+ return error;
+ }
+ }
+
+ m_format.SetCurrentValue(format);
+ m_format.SetOptionWasSet();
+ if (byte_size_enabled) {
+ m_byte_size.SetCurrentValue(byte_size);
+ m_byte_size.SetOptionWasSet();
+ }
+ if (count_enabled) {
+ m_count.SetCurrentValue(count);
+ m_count.SetOptionWasSet();
+ }
+ } break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+}
+
+bool OptionGroupFormat::ParserGDBFormatLetter(
+ ExecutionContext *execution_context, char format_letter, Format &format,
+ uint32_t &byte_size) {
+ m_has_gdb_format = true;
+ switch (format_letter) {
+ case 'o':
+ format = eFormatOctal;
+ m_prev_gdb_format = format_letter;
+ return true;
+ case 'x':
+ format = eFormatHex;
+ m_prev_gdb_format = format_letter;
+ return true;
+ case 'd':
+ format = eFormatDecimal;
+ m_prev_gdb_format = format_letter;
+ return true;
+ case 'u':
+ format = eFormatUnsigned;
+ m_prev_gdb_format = format_letter;
+ return true;
+ case 't':
+ format = eFormatBinary;
+ m_prev_gdb_format = format_letter;
+ return true;
+ case 'f':
+ format = eFormatFloat;
+ m_prev_gdb_format = format_letter;
+ return true;
+ case 'a':
+ format = eFormatAddressInfo;
+ {
+ TargetSP target_sp =
+ execution_context ? execution_context->GetTargetSP() : TargetSP();
+ if (target_sp)
+ byte_size = target_sp->GetArchitecture().GetAddressByteSize();
+ m_prev_gdb_format = format_letter;
+ return true;
+ }
+ case 'i':
+ format = eFormatInstruction;
+ m_prev_gdb_format = format_letter;
+ return true;
+ case 'c':
+ format = eFormatChar;
+ m_prev_gdb_format = format_letter;
+ return true;
+ case 's':
+ format = eFormatCString;
+ m_prev_gdb_format = format_letter;
+ return true;
+ case 'T':
+ format = eFormatOSType;
+ m_prev_gdb_format = format_letter;
+ return true;
+ case 'A':
+ format = eFormatHexFloat;
+ m_prev_gdb_format = format_letter;
+ return true;
+
+ case 'b':
+ case 'h':
+ case 'w':
+ case 'g':
+ {
+ // Size isn't used for printing instructions, so if a size is specified,
+ // and the previous format was 'i', then we should reset it to the
+ // default ('x'). Otherwise we'll continue to print as instructions,
+ // which isn't expected.
+ if (format_letter == 'b')
+ byte_size = 1;
+ else if (format_letter == 'h')
+ byte_size = 2;
+ else if (format_letter == 'w')
+ byte_size = 4;
+ else if (format_letter == 'g')
+ byte_size = 8;
+
+ m_prev_gdb_size = format_letter;
+ if (m_prev_gdb_format == 'i')
+ m_prev_gdb_format = 'x';
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+
+
+ return false;
+}
+
+void OptionGroupFormat::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ m_format.Clear();
+ m_byte_size.Clear();
+ m_count.Clear();
+ m_has_gdb_format = false;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupMemoryTag.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupMemoryTag.cpp
new file mode 100644
index 000000000000..c6efab7c3871
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupMemoryTag.cpp
@@ -0,0 +1,60 @@
+//===-- OptionGroupMemoryTag.cpp -----------------------------------------===//
+//
+// 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/OptionGroupMemoryTag.h"
+
+#include "lldb/Host/OptionParser.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const uint32_t SHORT_OPTION_SHOW_TAGS = 0x54414753; // 'tags'
+
+OptionGroupMemoryTag::OptionGroupMemoryTag(bool note_binary /*=false*/)
+ : m_show_tags(false, false), m_option_definition{
+ LLDB_OPT_SET_1,
+ false,
+ "show-tags",
+ SHORT_OPTION_SHOW_TAGS,
+ OptionParser::eNoArgument,
+ nullptr,
+ {},
+ 0,
+ eArgTypeNone,
+ note_binary
+ ? "Include memory tags in output "
+ "(does not apply to binary output)."
+ : "Include memory tags in output."} {}
+
+llvm::ArrayRef<OptionDefinition> OptionGroupMemoryTag::GetDefinitions() {
+ return llvm::ArrayRef(m_option_definition);
+}
+
+Status
+OptionGroupMemoryTag::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ assert(option_idx == 0 && "Only one option in memory tag group!");
+
+ switch (m_option_definition.short_option) {
+ case SHORT_OPTION_SHOW_TAGS:
+ m_show_tags.SetCurrentValue(true);
+ m_show_tags.SetOptionWasSet();
+ break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return {};
+}
+
+void OptionGroupMemoryTag::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ m_show_tags.Clear();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupOutputFile.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupOutputFile.cpp
new file mode 100644
index 000000000000..f0044606e1de
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupOutputFile.cpp
@@ -0,0 +1,60 @@
+//===-- OptionGroupOutputFile.cpp -----------------------------------------===//
+//
+// 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/OptionGroupOutputFile.h"
+
+#include "lldb/Host/OptionParser.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupOutputFile::OptionGroupOutputFile() : m_append(false, false) {}
+
+static const uint32_t SHORT_OPTION_APND = 0x61706e64; // 'apnd'
+
+static constexpr OptionDefinition g_option_table[] = {
+ {LLDB_OPT_SET_1, false, "outfile", 'o', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeFilename,
+ "Specify a path for capturing command output."},
+ {LLDB_OPT_SET_1, false, "append-outfile", SHORT_OPTION_APND,
+ OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
+ "Append to the file specified with '--outfile <path>'."},
+};
+
+llvm::ArrayRef<OptionDefinition> OptionGroupOutputFile::GetDefinitions() {
+ return llvm::ArrayRef(g_option_table);
+}
+
+Status
+OptionGroupOutputFile::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
+ const int short_option = g_option_table[option_idx].short_option;
+
+ switch (short_option) {
+ case 'o':
+ error = m_file.SetValueFromString(option_arg);
+ break;
+
+ case SHORT_OPTION_APND:
+ m_append.SetCurrentValue(true);
+ break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+}
+
+void OptionGroupOutputFile::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ m_file.Clear();
+ m_append.Clear();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupPlatform.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupPlatform.cpp
new file mode 100644
index 000000000000..9928a5cda03e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupPlatform.cpp
@@ -0,0 +1,148 @@
+//===-- OptionGroupPlatform.cpp -------------------------------------------===//
+//
+// 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/OptionGroupPlatform.h"
+
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/Platform.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+PlatformSP OptionGroupPlatform::CreatePlatformWithOptions(
+ CommandInterpreter &interpreter, const ArchSpec &arch, bool make_selected,
+ Status &error, ArchSpec &platform_arch) const {
+ PlatformList &platforms = interpreter.GetDebugger().GetPlatformList();
+
+ PlatformSP platform_sp;
+
+ if (!m_platform_name.empty()) {
+ platform_sp = platforms.Create(m_platform_name);
+ if (!platform_sp) {
+ error.SetErrorStringWithFormatv(
+ "unable to find a plug-in for the platform named \"{0}\"",
+ m_platform_name);
+ }
+ if (platform_sp) {
+ if (platform_arch.IsValid() &&
+ !platform_sp->IsCompatibleArchitecture(
+ arch, {}, ArchSpec::CompatibleMatch, &platform_arch)) {
+ error.SetErrorStringWithFormatv("platform '{0}' doesn't support '{1}'",
+ platform_sp->GetPluginName(),
+ arch.GetTriple().getTriple());
+ platform_sp.reset();
+ return platform_sp;
+ }
+ }
+ } else if (arch.IsValid()) {
+ platform_sp = platforms.GetOrCreate(arch, {}, &platform_arch, error);
+ }
+
+ if (platform_sp) {
+ if (make_selected)
+ platforms.SetSelectedPlatform(platform_sp);
+ if (!m_os_version.empty())
+ platform_sp->SetOSVersion(m_os_version);
+
+ if (!m_sdk_sysroot.empty())
+ platform_sp->SetSDKRootDirectory(m_sdk_sysroot);
+
+ if (!m_sdk_build.empty())
+ platform_sp->SetSDKBuild(m_sdk_build);
+ }
+
+ return platform_sp;
+}
+
+void OptionGroupPlatform::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ m_platform_name.clear();
+ m_sdk_sysroot.clear();
+ m_sdk_build.clear();
+ m_os_version = llvm::VersionTuple();
+}
+
+static constexpr OptionDefinition g_option_table[] = {
+ {LLDB_OPT_SET_ALL, false, "platform", 'p', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypePlatform, "Specify name of the platform to "
+ "use for this target, creating the "
+ "platform if necessary."},
+ {LLDB_OPT_SET_ALL, false, "version", 'v', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeNone,
+ "Specify the initial SDK version to use prior to connecting."},
+ {LLDB_OPT_SET_ALL, false, "build", 'b', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeNone,
+ "Specify the initial SDK build number."},
+ {LLDB_OPT_SET_ALL, false, "sysroot", 'S', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeFilename, "Specify the SDK root directory "
+ "that contains a root of all "
+ "remote system files."}};
+
+llvm::ArrayRef<OptionDefinition> OptionGroupPlatform::GetDefinitions() {
+ llvm::ArrayRef<OptionDefinition> result(g_option_table);
+ if (m_include_platform_option)
+ return result;
+ return result.drop_front();
+}
+
+Status
+OptionGroupPlatform::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
+ if (!m_include_platform_option)
+ ++option_idx;
+
+ const int short_option = g_option_table[option_idx].short_option;
+
+ switch (short_option) {
+ case 'p':
+ m_platform_name.assign(option_arg.str());
+ break;
+
+ case 'v':
+ if (m_os_version.tryParse(option_arg))
+ error.SetErrorStringWithFormatv("invalid version string '{0}'",
+ option_arg);
+ break;
+
+ case 'b':
+ m_sdk_build.assign(option_arg.str());
+ break;
+
+ case 'S':
+ m_sdk_sysroot.assign(option_arg.str());
+ break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+ return error;
+}
+
+bool OptionGroupPlatform::PlatformMatches(
+ const lldb::PlatformSP &platform_sp) const {
+ if (!platform_sp)
+ return false;
+
+ if (!m_platform_name.empty() && platform_sp->GetName() != m_platform_name)
+ return false;
+
+ if (!m_sdk_build.empty() && platform_sp->GetSDKBuild() != m_sdk_build)
+ return false;
+
+ if (!m_sdk_sysroot.empty() &&
+ platform_sp->GetSDKRootDirectory() != m_sdk_sysroot)
+ return false;
+
+ if (!m_os_version.empty() && platform_sp->GetOSVersion() != m_os_version)
+ return false;
+
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp
new file mode 100644
index 000000000000..8f507828518b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp
@@ -0,0 +1,156 @@
+//===-- OptionGroupPythonClassWithDict.cpp --------------------------------===//
+//
+// 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, bool is_class, int class_option, int key_option,
+ int value_option, uint16_t required_options)
+ : m_is_class(is_class), m_required_options(required_options) {
+ m_key_usage_text.assign("The key for a key/value pair passed to the "
+ "implementation of 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 the previous key in the pair passed "
+ "to the implementation of 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 ");
+ m_class_usage_text.append(m_is_class ? "class" : "function");
+ m_class_usage_text.append(" 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 = m_required_options.Test(eScriptClass);
+ m_option_definition[0].long_option = "script-class";
+ 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_2;
+ m_option_definition[1].required = m_required_options.Test(eDictKey);
+ m_option_definition[1].long_option = "structured-data-key";
+ 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_2;
+ m_option_definition[2].required = m_required_options.Test(eDictValue);
+ m_option_definition[2].long_option = "structured-data-value";
+ 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();
+
+ m_option_definition[3].usage_mask = LLDB_OPT_SET_3;
+ m_option_definition[3].required = m_required_options.Test(ePythonFunction);
+ m_option_definition[3].long_option = "python-function";
+ m_option_definition[3].short_option = class_option;
+ m_option_definition[3].validator = nullptr;
+ m_option_definition[3].option_has_arg = OptionParser::eRequiredArgument;
+ m_option_definition[3].enum_values = {};
+ m_option_definition[3].completion_type = 0;
+ m_option_definition[3].argument_type = eArgTypePythonFunction;
+ m_option_definition[3].usage_text = m_class_usage_text.data();
+}
+
+Status OptionGroupPythonClassWithDict::SetOptionValue(
+ uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
+ switch (option_idx) {
+ case 0:
+ case 3: {
+ m_name.assign(std::string(option_arg));
+ } break;
+ case 1: {
+ if (!m_dict_sp)
+ m_dict_sp = std::make_shared<StructuredData::Dictionary>();
+ if (m_current_key.empty())
+ m_current_key.assign(std::string(option_arg));
+ else
+ error.SetErrorStringWithFormat("Key: \"%s\" missing value.",
+ m_current_key.c_str());
+
+ } break;
+ case 2: {
+ if (!m_dict_sp)
+ m_dict_sp = std::make_shared<StructuredData::Dictionary>();
+ if (!m_current_key.empty()) {
+ if (!option_arg.empty()) {
+ double d = 0;
+ std::string opt = option_arg.lower();
+
+ if (llvm::to_integer(option_arg, d)) {
+ if (opt[0] == '-')
+ m_dict_sp->AddIntegerItem(m_current_key, static_cast<int64_t>(d));
+ else
+ m_dict_sp->AddIntegerItem(m_current_key,
+ static_cast<uint64_t>(d));
+ } else if (llvm::to_float(option_arg, d)) {
+ m_dict_sp->AddFloatItem(m_current_key, d);
+ } else if (opt == "true" || opt == "false") {
+ m_dict_sp->AddBooleanItem(m_current_key, opt == "true");
+ } else {
+ 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();
+ // Leave the dictionary shared pointer unset. That way you can tell that
+ // the user didn't pass any -k -v pairs. We want to be able to warn if these
+ // were passed when the function they passed won't use them.
+ m_dict_sp.reset();
+ m_name.clear();
+}
+
+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/contrib/llvm-project/lldb/source/Interpreter/OptionGroupString.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupString.cpp
new file mode 100644
index 000000000000..75faaac9f6dd
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupString.cpp
@@ -0,0 +1,45 @@
+//===-- OptionGroupString.cpp ---------------------------------------------===//
+//
+// 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/OptionGroupString.h"
+
+#include "lldb/Host/OptionParser.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupString::OptionGroupString(uint32_t usage_mask, bool required,
+ const char *long_option, int short_option,
+ uint32_t completion_type,
+ lldb::CommandArgumentType argument_type,
+ const char *usage_text,
+ const char *default_value)
+ : m_value(default_value, default_value) {
+ m_option_definition.usage_mask = usage_mask;
+ m_option_definition.required = required;
+ m_option_definition.long_option = long_option;
+ m_option_definition.short_option = short_option;
+ m_option_definition.validator = nullptr;
+ m_option_definition.option_has_arg = OptionParser::eRequiredArgument;
+ m_option_definition.enum_values = {};
+ m_option_definition.completion_type = completion_type;
+ m_option_definition.argument_type = argument_type;
+ m_option_definition.usage_text = usage_text;
+}
+
+Status OptionGroupString::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error(m_value.SetValueFromString(option_arg));
+ return error;
+}
+
+void OptionGroupString::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ m_value.Clear();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupUInt64.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupUInt64.cpp
new file mode 100644
index 000000000000..486941a7555a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupUInt64.cpp
@@ -0,0 +1,45 @@
+//===-- OptionGroupUInt64.cpp ---------------------------------------------===//
+//
+// 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/OptionGroupUInt64.h"
+
+#include "lldb/Host/OptionParser.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupUInt64::OptionGroupUInt64(uint32_t usage_mask, bool required,
+ const char *long_option, int short_option,
+ uint32_t completion_type,
+ lldb::CommandArgumentType argument_type,
+ const char *usage_text,
+ uint64_t default_value)
+ : m_value(default_value, default_value) {
+ m_option_definition.usage_mask = usage_mask;
+ m_option_definition.required = required;
+ m_option_definition.long_option = long_option;
+ m_option_definition.short_option = short_option;
+ m_option_definition.validator = nullptr;
+ m_option_definition.option_has_arg = OptionParser::eRequiredArgument;
+ m_option_definition.enum_values = {};
+ m_option_definition.completion_type = completion_type;
+ m_option_definition.argument_type = argument_type;
+ m_option_definition.usage_text = usage_text;
+}
+
+Status OptionGroupUInt64::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error(m_value.SetValueFromString(option_arg));
+ return error;
+}
+
+void OptionGroupUInt64::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ m_value.Clear();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupUUID.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupUUID.cpp
new file mode 100644
index 000000000000..7a0efbab0398
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupUUID.cpp
@@ -0,0 +1,48 @@
+//===-- OptionGroupUUID.cpp -----------------------------------------------===//
+//
+// 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/OptionGroupUUID.h"
+
+#include "lldb/Host/OptionParser.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static constexpr OptionDefinition g_option_table[] = {
+ {LLDB_OPT_SET_1, false, "uuid", 'u', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeModuleUUID, "A module UUID value."},
+};
+
+llvm::ArrayRef<OptionDefinition> OptionGroupUUID::GetDefinitions() {
+ return llvm::ArrayRef(g_option_table);
+}
+
+Status OptionGroupUUID::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
+ const int short_option = g_option_table[option_idx].short_option;
+
+ switch (short_option) {
+ case 'u':
+ error = m_uuid.SetValueFromString(option_arg);
+ if (error.Success())
+ m_uuid.SetOptionWasSet();
+ break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+}
+
+void OptionGroupUUID::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ m_uuid.Clear();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp
new file mode 100644
index 000000000000..294665fa6b45
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp
@@ -0,0 +1,223 @@
+//===-- OptionGroupValueObjectDisplay.cpp ---------------------------------===//
+//
+// 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/OptionGroupValueObjectDisplay.h"
+
+#include "lldb/DataFormatters/ValueObjectPrinter.h"
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Target/Target.h"
+
+#include "llvm/ADT/ArrayRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const OptionDefinition g_option_table[] = {
+ {LLDB_OPT_SET_1, false, "dynamic-type", 'd',
+ OptionParser::eRequiredArgument, nullptr, GetDynamicValueTypes(), 0,
+ eArgTypeNone, "Show the object as its full dynamic type, not its static "
+ "type, if available."},
+ {LLDB_OPT_SET_1, false, "synthetic-type", 'S',
+ OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean,
+ "Show the object obeying its synthetic provider, if available."},
+ {LLDB_OPT_SET_1, false, "depth", 'D', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeCount, "Set the max recurse depth when dumping "
+ "aggregate types (default is infinity)."},
+ {LLDB_OPT_SET_1, false, "flat", 'F', OptionParser::eNoArgument, nullptr,
+ {}, 0, eArgTypeNone, "Display results in a flat format that uses "
+ "expression paths for each variable or member."},
+ {LLDB_OPT_SET_1, false, "location", 'L', OptionParser::eNoArgument, nullptr,
+ {}, 0, eArgTypeNone, "Show variable location information."},
+ {LLDB_OPT_SET_1, false, "object-description", 'O',
+ OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
+ "Display using a language-specific description API, if possible."},
+ {LLDB_OPT_SET_1, false, "ptr-depth", 'P', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeCount, "The number of pointers to be traversed "
+ "when dumping values (default is zero)."},
+ {LLDB_OPT_SET_1, false, "show-types", 'T', OptionParser::eNoArgument,
+ nullptr, {}, 0, eArgTypeNone,
+ "Show variable types when dumping values."},
+ {LLDB_OPT_SET_1, false, "no-summary-depth", 'Y',
+ OptionParser::eOptionalArgument, nullptr, {}, 0, eArgTypeCount,
+ "Set the depth at which omitting summary information stops (default is "
+ "1)."},
+ {LLDB_OPT_SET_1, false, "raw-output", 'R', OptionParser::eNoArgument,
+ nullptr, {}, 0, eArgTypeNone, "Don't use formatting options."},
+ {LLDB_OPT_SET_1, false, "show-all-children", 'A', OptionParser::eNoArgument,
+ nullptr, {}, 0, eArgTypeNone,
+ "Ignore the upper bound on the number of children to show."},
+ {LLDB_OPT_SET_1, false, "validate", 'V', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeBoolean, "Show results of type validators."},
+ {LLDB_OPT_SET_1, false, "element-count", 'Z',
+ OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCount,
+ "Treat the result of the expression as if its type is an array of this "
+ "many values."}};
+
+llvm::ArrayRef<OptionDefinition>
+OptionGroupValueObjectDisplay::GetDefinitions() {
+ return llvm::ArrayRef(g_option_table);
+}
+
+Status OptionGroupValueObjectDisplay::SetOptionValue(
+ uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
+ const int short_option = g_option_table[option_idx].short_option;
+ bool success = false;
+
+ switch (short_option) {
+ case 'd': {
+ int32_t result;
+ result = OptionArgParser::ToOptionEnum(option_arg, GetDynamicValueTypes(),
+ 2, error);
+ if (error.Success())
+ use_dynamic = (lldb::DynamicValueType)result;
+ } break;
+ case 'T':
+ show_types = true;
+ break;
+ case 'L':
+ show_location = true;
+ break;
+ case 'F':
+ flat_output = true;
+ break;
+ case 'O':
+ use_objc = true;
+ break;
+ case 'R':
+ be_raw = true;
+ break;
+ case 'A':
+ ignore_cap = true;
+ break;
+
+ case 'D':
+ if (option_arg.getAsInteger(0, max_depth)) {
+ max_depth = UINT32_MAX;
+ error.SetErrorStringWithFormat("invalid max depth '%s'",
+ option_arg.str().c_str());
+ } else {
+ max_depth_is_default = false;
+ }
+ break;
+
+ case 'Z':
+ if (option_arg.getAsInteger(0, elem_count)) {
+ elem_count = UINT32_MAX;
+ error.SetErrorStringWithFormat("invalid element count '%s'",
+ option_arg.str().c_str());
+ }
+ break;
+
+ case 'P':
+ if (option_arg.getAsInteger(0, ptr_depth)) {
+ ptr_depth = 0;
+ error.SetErrorStringWithFormat("invalid pointer depth '%s'",
+ option_arg.str().c_str());
+ }
+ break;
+
+ case 'Y':
+ if (option_arg.empty())
+ no_summary_depth = 1;
+ else if (option_arg.getAsInteger(0, no_summary_depth)) {
+ no_summary_depth = 0;
+ error.SetErrorStringWithFormat("invalid pointer depth '%s'",
+ option_arg.str().c_str());
+ }
+ break;
+
+ case 'S':
+ use_synth = OptionArgParser::ToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid synthetic-type '%s'",
+ option_arg.str().c_str());
+ break;
+
+ case 'V':
+ run_validator = OptionArgParser::ToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid validate '%s'",
+ option_arg.str().c_str());
+ break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+}
+
+void OptionGroupValueObjectDisplay::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ // If these defaults change, be sure to modify AnyOptionWasSet().
+ show_types = false;
+ no_summary_depth = 0;
+ show_location = false;
+ flat_output = false;
+ use_objc = false;
+ max_depth = UINT32_MAX;
+ max_depth_is_default = true;
+ ptr_depth = 0;
+ elem_count = 0;
+ use_synth = true;
+ be_raw = false;
+ ignore_cap = false;
+ run_validator = false;
+
+ TargetSP target_sp =
+ execution_context ? execution_context->GetTargetSP() : TargetSP();
+ if (target_sp) {
+ use_dynamic = target_sp->GetPreferDynamicValue();
+ auto max_depth_config = target_sp->GetMaximumDepthOfChildrenToDisplay();
+ max_depth = std::get<uint32_t>(max_depth_config);
+ max_depth_is_default = std::get<bool>(max_depth_config);
+ } else {
+ // If we don't have any targets, then dynamic values won't do us much good.
+ use_dynamic = lldb::eNoDynamicValues;
+ }
+}
+
+DumpValueObjectOptions OptionGroupValueObjectDisplay::GetAsDumpOptions(
+ LanguageRuntimeDescriptionDisplayVerbosity lang_descr_verbosity,
+ lldb::Format format, lldb::TypeSummaryImplSP summary_sp) {
+ DumpValueObjectOptions options;
+ options.SetMaximumPointerDepth(
+ {DumpValueObjectOptions::PointerDepth::Mode::Always, ptr_depth});
+ if (use_objc)
+ options.SetShowSummary(false);
+ else
+ options.SetOmitSummaryDepth(no_summary_depth);
+ options.SetMaximumDepth(max_depth, max_depth_is_default)
+ .SetShowTypes(show_types)
+ .SetShowLocation(show_location)
+ .SetUseObjectiveC(use_objc)
+ .SetUseDynamicType(use_dynamic)
+ .SetUseSyntheticValue(use_synth)
+ .SetFlatOutput(flat_output)
+ .SetIgnoreCap(ignore_cap)
+ .SetFormat(format)
+ .SetSummary(summary_sp);
+
+ if (lang_descr_verbosity ==
+ eLanguageRuntimeDescriptionDisplayVerbosityCompact)
+ options.SetHideRootType(use_objc).SetHideName(use_objc).SetHideValue(
+ use_objc);
+
+ if (be_raw)
+ options.SetRawDisplay();
+
+ options.SetRunValidator(run_validator);
+
+ options.SetElementCount(elem_count);
+
+ return options;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupVariable.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupVariable.cpp
new file mode 100644
index 000000000000..99644b3f423c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupVariable.cpp
@@ -0,0 +1,141 @@
+//===-- OptionGroupVariable.cpp -------------------------------------------===//
+//
+// 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/OptionGroupVariable.h"
+
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Status.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// if you add any options here, remember to update the counters in
+// OptionGroupVariable::GetNumDefinitions()
+static constexpr OptionDefinition g_variable_options[] = {
+ {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-args", 'a',
+ OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
+ "Omit function arguments."},
+ {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-recognized-args", 't',
+ OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
+ "Omit recognized function arguments."},
+ {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-locals", 'l',
+ OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
+ "Omit local variables."},
+ {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "show-globals", 'g',
+ OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
+ "Show the current frame source file global and static variables."},
+ {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "show-declaration", 'c',
+ OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
+ "Show variable declaration information (source file and line where the "
+ "variable was declared)."},
+ {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "regex", 'r',
+ OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeRegularExpression,
+ "The <variable-name> argument for name lookups are regular expressions."},
+ {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "scope", 's',
+ OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone,
+ "Show variable scope (argument, local, global, static)."},
+ {LLDB_OPT_SET_1, false, "summary", 'y', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeName,
+ "Specify the summary that the variable output should use."},
+ {LLDB_OPT_SET_2, false, "summary-string", 'z',
+ OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeName,
+ "Specify a summary string to use to format the variable output."},
+};
+
+static constexpr auto g_num_frame_options = 4;
+static const auto g_variable_options_noframe =
+ llvm::ArrayRef<OptionDefinition>(g_variable_options)
+ .drop_front(g_num_frame_options);
+
+static Status ValidateNamedSummary(const char *str, void *) {
+ if (!str || !str[0])
+ return Status("must specify a valid named summary");
+ TypeSummaryImplSP summary_sp;
+ if (!DataVisualization::NamedSummaryFormats::GetSummaryFormat(
+ ConstString(str), summary_sp))
+ return Status("must specify a valid named summary");
+ return Status();
+}
+
+static Status ValidateSummaryString(const char *str, void *) {
+ if (!str || !str[0])
+ return Status("must specify a non-empty summary string");
+ return Status();
+}
+
+OptionGroupVariable::OptionGroupVariable(bool show_frame_options)
+ : include_frame_options(show_frame_options), show_args(false),
+ show_recognized_args(false), show_locals(false), show_globals(false),
+ use_regex(false), show_scope(false), show_decl(false),
+ summary(ValidateNamedSummary), summary_string(ValidateSummaryString) {}
+
+Status
+OptionGroupVariable::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
+ llvm::ArrayRef<OptionDefinition> variable_options =
+ include_frame_options ? g_variable_options : g_variable_options_noframe;
+ const int short_option = variable_options[option_idx].short_option;
+ switch (short_option) {
+ case 'r':
+ use_regex = true;
+ break;
+ case 'a':
+ show_args = false;
+ break;
+ case 'l':
+ show_locals = false;
+ break;
+ case 'g':
+ show_globals = true;
+ break;
+ case 'c':
+ show_decl = true;
+ break;
+ case 's':
+ show_scope = true;
+ break;
+ case 't':
+ show_recognized_args = false;
+ break;
+ case 'y':
+ error = summary.SetCurrentValue(option_arg);
+ break;
+ case 'z':
+ error = summary_string.SetCurrentValue(option_arg);
+ break;
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+}
+
+void OptionGroupVariable::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ show_args = true; // Frame option only
+ show_recognized_args = true; // Frame option only
+ show_locals = true; // Frame option only
+ show_globals = false; // Frame option only
+ show_decl = false;
+ use_regex = false;
+ show_scope = false;
+ summary.Clear();
+ summary_string.Clear();
+}
+
+llvm::ArrayRef<OptionDefinition> OptionGroupVariable::GetDefinitions() {
+ // Show the "--no-args", "--no-recognized-args", "--no-locals" and
+ // "--show-globals" options if we are showing frame specific options
+ return include_frame_options ? g_variable_options
+ : g_variable_options_noframe;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupWatchpoint.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
new file mode 100644
index 000000000000..d1ae916cd74b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
@@ -0,0 +1,113 @@
+//===-- OptionGroupWatchpoint.cpp -----------------------------------------===//
+//
+// 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/OptionGroupWatchpoint.h"
+
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Target/Language.h"
+#include "lldb/lldb-enumerations.h"
+
+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::eWatchModify,
+ "modify",
+ "Watch for modifications",
+ },
+ {
+ OptionGroupWatchpoint::eWatchReadWrite,
+ "read_write",
+ "Watch for read/write",
+ },
+};
+
+static constexpr OptionDefinition g_option_table[] = {
+ {LLDB_OPT_SET_1, false, "watch", 'w', OptionParser::eRequiredArgument,
+ nullptr, OptionEnumValues(g_watch_type), 0, eArgTypeWatchType,
+ "Specify the type of watching to perform."},
+ {LLDB_OPT_SET_1, false, "size", 's', OptionParser::eRequiredArgument,
+ nullptr, {}, 0, eArgTypeByteSize,
+ "Number of bytes to use to watch a region."},
+ {LLDB_OPT_SET_2,
+ false,
+ "language",
+ 'l',
+ OptionParser::eRequiredArgument,
+ nullptr,
+ {},
+ 0,
+ eArgTypeLanguage,
+ "Language of expression to run"}};
+
+Status
+OptionGroupWatchpoint::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
+ const int short_option = g_option_table[option_idx].short_option;
+ switch (short_option) {
+ case 'l': {
+ language_type = Language::GetLanguageTypeFromString(option_arg);
+ if (language_type == eLanguageTypeUnknown) {
+ StreamString sstr;
+ sstr.Printf("Unknown language type: '%s' for expression. List of "
+ "supported languages:\n",
+ option_arg.str().c_str());
+ Language::PrintSupportedLanguagesForExpressions(sstr, " ", "\n");
+ error.SetErrorString(sstr.GetString());
+ }
+ break;
+ }
+ case 'w': {
+ WatchType tmp_watch_type;
+ tmp_watch_type = (WatchType)OptionArgParser::ToOptionEnum(
+ option_arg, g_option_table[option_idx].enum_values, 0, error);
+ if (error.Success()) {
+ watch_type = tmp_watch_type;
+ watch_type_specified = true;
+ }
+ break;
+ }
+ case 's':
+ error = watch_size.SetValueFromString(option_arg);
+ if (watch_size.GetCurrentValue() == 0)
+ error.SetErrorStringWithFormat("invalid --size option value '%s'",
+ option_arg.str().c_str());
+ break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+}
+
+void OptionGroupWatchpoint::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ watch_type_specified = false;
+ watch_type = eWatchInvalid;
+ watch_size.Clear();
+ language_type = eLanguageTypeUnknown;
+}
+
+llvm::ArrayRef<OptionDefinition> OptionGroupWatchpoint::GetDefinitions() {
+ return llvm::ArrayRef(g_option_table);
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValue.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValue.cpp
new file mode 100644
index 000000000000..fe1d8829c5ad
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValue.cpp
@@ -0,0 +1,643 @@
+//===-- OptionValue.cpp ---------------------------------------------------===//
+//
+// 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/OptionValue.h"
+#include "lldb/Interpreter/OptionValues.h"
+#include "lldb/Utility/StringList.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionValue::OptionValue(const OptionValue &other) {
+ std::lock_guard<std::mutex> lock(other.m_mutex);
+
+ m_parent_wp = other.m_parent_wp;
+ m_callback = other.m_callback;
+ m_value_was_set = other.m_value_was_set;
+
+}
+
+OptionValue& OptionValue::operator=(const OptionValue &other) {
+ std::scoped_lock<std::mutex, std::mutex> lock(m_mutex, other.m_mutex);
+
+ m_parent_wp = other.m_parent_wp;
+ m_callback = other.m_callback;
+ m_value_was_set = other.m_value_was_set;
+
+ return *this;
+}
+
+Status OptionValue::SetSubValue(const ExecutionContext *exe_ctx,
+ VarSetOperationType op, llvm::StringRef name,
+ llvm::StringRef value) {
+ Status error;
+ error.SetErrorString("SetSubValue is not supported");
+ return error;
+}
+
+OptionValueBoolean *OptionValue::GetAsBoolean() {
+ if (GetType() == OptionValue::eTypeBoolean)
+ return static_cast<OptionValueBoolean *>(this);
+ return nullptr;
+}
+
+const OptionValueBoolean *OptionValue::GetAsBoolean() const {
+ if (GetType() == OptionValue::eTypeBoolean)
+ return static_cast<const OptionValueBoolean *>(this);
+ return nullptr;
+}
+
+const OptionValueChar *OptionValue::GetAsChar() const {
+ if (GetType() == OptionValue::eTypeChar)
+ return static_cast<const OptionValueChar *>(this);
+ return nullptr;
+}
+
+OptionValueChar *OptionValue::GetAsChar() {
+ if (GetType() == OptionValue::eTypeChar)
+ return static_cast<OptionValueChar *>(this);
+ return nullptr;
+}
+
+OptionValueFileSpec *OptionValue::GetAsFileSpec() {
+ if (GetType() == OptionValue::eTypeFileSpec)
+ return static_cast<OptionValueFileSpec *>(this);
+ return nullptr;
+}
+
+const OptionValueFileSpec *OptionValue::GetAsFileSpec() const {
+ if (GetType() == OptionValue::eTypeFileSpec)
+ return static_cast<const OptionValueFileSpec *>(this);
+ return nullptr;
+}
+
+OptionValueFileSpecList *OptionValue::GetAsFileSpecList() {
+ if (GetType() == OptionValue::eTypeFileSpecList)
+ return static_cast<OptionValueFileSpecList *>(this);
+ return nullptr;
+}
+
+const OptionValueFileSpecList *OptionValue::GetAsFileSpecList() const {
+ if (GetType() == OptionValue::eTypeFileSpecList)
+ return static_cast<const OptionValueFileSpecList *>(this);
+ return nullptr;
+}
+
+OptionValueArch *OptionValue::GetAsArch() {
+ if (GetType() == OptionValue::eTypeArch)
+ return static_cast<OptionValueArch *>(this);
+ return nullptr;
+}
+
+const OptionValueArch *OptionValue::GetAsArch() const {
+ if (GetType() == OptionValue::eTypeArch)
+ return static_cast<const OptionValueArch *>(this);
+ return nullptr;
+}
+
+OptionValueArray *OptionValue::GetAsArray() {
+ if (GetType() == OptionValue::eTypeArray)
+ return static_cast<OptionValueArray *>(this);
+ return nullptr;
+}
+
+const OptionValueArray *OptionValue::GetAsArray() const {
+ if (GetType() == OptionValue::eTypeArray)
+ return static_cast<const OptionValueArray *>(this);
+ return nullptr;
+}
+
+OptionValueArgs *OptionValue::GetAsArgs() {
+ if (GetType() == OptionValue::eTypeArgs)
+ return static_cast<OptionValueArgs *>(this);
+ return nullptr;
+}
+
+const OptionValueArgs *OptionValue::GetAsArgs() const {
+ if (GetType() == OptionValue::eTypeArgs)
+ return static_cast<const OptionValueArgs *>(this);
+ return nullptr;
+}
+
+OptionValueDictionary *OptionValue::GetAsDictionary() {
+ if (GetType() == OptionValue::eTypeDictionary)
+ return static_cast<OptionValueDictionary *>(this);
+ return nullptr;
+}
+
+const OptionValueDictionary *OptionValue::GetAsDictionary() const {
+ if (GetType() == OptionValue::eTypeDictionary)
+ return static_cast<const OptionValueDictionary *>(this);
+ return nullptr;
+}
+
+OptionValueEnumeration *OptionValue::GetAsEnumeration() {
+ if (GetType() == OptionValue::eTypeEnum)
+ return static_cast<OptionValueEnumeration *>(this);
+ return nullptr;
+}
+
+const OptionValueEnumeration *OptionValue::GetAsEnumeration() const {
+ if (GetType() == OptionValue::eTypeEnum)
+ return static_cast<const OptionValueEnumeration *>(this);
+ return nullptr;
+}
+
+OptionValueFormat *OptionValue::GetAsFormat() {
+ if (GetType() == OptionValue::eTypeFormat)
+ return static_cast<OptionValueFormat *>(this);
+ return nullptr;
+}
+
+const OptionValueFormat *OptionValue::GetAsFormat() const {
+ if (GetType() == OptionValue::eTypeFormat)
+ return static_cast<const OptionValueFormat *>(this);
+ return nullptr;
+}
+
+OptionValueLanguage *OptionValue::GetAsLanguage() {
+ if (GetType() == OptionValue::eTypeLanguage)
+ return static_cast<OptionValueLanguage *>(this);
+ return nullptr;
+}
+
+const OptionValueLanguage *OptionValue::GetAsLanguage() const {
+ if (GetType() == OptionValue::eTypeLanguage)
+ return static_cast<const OptionValueLanguage *>(this);
+ return nullptr;
+}
+
+OptionValueFormatEntity *OptionValue::GetAsFormatEntity() {
+ if (GetType() == OptionValue::eTypeFormatEntity)
+ return static_cast<OptionValueFormatEntity *>(this);
+ return nullptr;
+}
+
+const OptionValueFormatEntity *OptionValue::GetAsFormatEntity() const {
+ if (GetType() == OptionValue::eTypeFormatEntity)
+ return static_cast<const OptionValueFormatEntity *>(this);
+ return nullptr;
+}
+
+OptionValuePathMappings *OptionValue::GetAsPathMappings() {
+ if (GetType() == OptionValue::eTypePathMap)
+ return static_cast<OptionValuePathMappings *>(this);
+ return nullptr;
+}
+
+const OptionValuePathMappings *OptionValue::GetAsPathMappings() const {
+ if (GetType() == OptionValue::eTypePathMap)
+ return static_cast<const OptionValuePathMappings *>(this);
+ return nullptr;
+}
+
+OptionValueProperties *OptionValue::GetAsProperties() {
+ if (GetType() == OptionValue::eTypeProperties)
+ return static_cast<OptionValueProperties *>(this);
+ return nullptr;
+}
+
+const OptionValueProperties *OptionValue::GetAsProperties() const {
+ if (GetType() == OptionValue::eTypeProperties)
+ return static_cast<const OptionValueProperties *>(this);
+ return nullptr;
+}
+
+OptionValueRegex *OptionValue::GetAsRegex() {
+ if (GetType() == OptionValue::eTypeRegex)
+ return static_cast<OptionValueRegex *>(this);
+ return nullptr;
+}
+
+const OptionValueRegex *OptionValue::GetAsRegex() const {
+ if (GetType() == OptionValue::eTypeRegex)
+ return static_cast<const OptionValueRegex *>(this);
+ return nullptr;
+}
+
+OptionValueSInt64 *OptionValue::GetAsSInt64() {
+ if (GetType() == OptionValue::eTypeSInt64)
+ return static_cast<OptionValueSInt64 *>(this);
+ return nullptr;
+}
+
+const OptionValueSInt64 *OptionValue::GetAsSInt64() const {
+ if (GetType() == OptionValue::eTypeSInt64)
+ return static_cast<const OptionValueSInt64 *>(this);
+ return nullptr;
+}
+
+OptionValueString *OptionValue::GetAsString() {
+ if (GetType() == OptionValue::eTypeString)
+ return static_cast<OptionValueString *>(this);
+ return nullptr;
+}
+
+const OptionValueString *OptionValue::GetAsString() const {
+ if (GetType() == OptionValue::eTypeString)
+ return static_cast<const OptionValueString *>(this);
+ return nullptr;
+}
+
+OptionValueUInt64 *OptionValue::GetAsUInt64() {
+ if (GetType() == OptionValue::eTypeUInt64)
+ return static_cast<OptionValueUInt64 *>(this);
+ return nullptr;
+}
+
+const OptionValueUInt64 *OptionValue::GetAsUInt64() const {
+ if (GetType() == OptionValue::eTypeUInt64)
+ return static_cast<const OptionValueUInt64 *>(this);
+ return nullptr;
+}
+
+OptionValueUUID *OptionValue::GetAsUUID() {
+ if (GetType() == OptionValue::eTypeUUID)
+ return static_cast<OptionValueUUID *>(this);
+ return nullptr;
+}
+
+const OptionValueUUID *OptionValue::GetAsUUID() const {
+ if (GetType() == OptionValue::eTypeUUID)
+ return static_cast<const OptionValueUUID *>(this);
+ return nullptr;
+}
+
+std::optional<bool> OptionValue::GetBooleanValue() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueBoolean *option_value = GetAsBoolean())
+ return option_value->GetCurrentValue();
+ return {};
+}
+
+bool OptionValue::SetBooleanValue(bool new_value) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueBoolean *option_value = GetAsBoolean()) {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
+std::optional<char> OptionValue::GetCharValue() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueChar *option_value = GetAsChar())
+ return option_value->GetCurrentValue();
+ return {};
+}
+
+bool OptionValue::SetCharValue(char new_value) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueChar *option_value = GetAsChar()) {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
+std::optional<int64_t> OptionValue::GetEnumerationValue() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueEnumeration *option_value = GetAsEnumeration())
+ return option_value->GetCurrentValue();
+ return {};
+}
+
+bool OptionValue::SetEnumerationValue(int64_t value) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueEnumeration *option_value = GetAsEnumeration()) {
+ option_value->SetCurrentValue(value);
+ return true;
+ }
+ return false;
+}
+
+std::optional<FileSpec> OptionValue::GetFileSpecValue() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueFileSpec *option_value = GetAsFileSpec())
+ return option_value->GetCurrentValue();
+ return {};
+}
+
+bool OptionValue::SetFileSpecValue(FileSpec file_spec) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueFileSpec *option_value = GetAsFileSpec()) {
+ option_value->SetCurrentValue(file_spec, false);
+ return true;
+ }
+ return false;
+}
+
+bool OptionValue::AppendFileSpecValue(FileSpec file_spec) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueFileSpecList *option_value = GetAsFileSpecList()) {
+ option_value->AppendCurrentValue(file_spec);
+ return true;
+ }
+ return false;
+}
+
+std::optional<FileSpecList> OptionValue::GetFileSpecListValue() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueFileSpecList *option_value = GetAsFileSpecList())
+ return option_value->GetCurrentValue();
+ return {};
+}
+
+std::optional<lldb::Format> OptionValue::GetFormatValue() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueFormat *option_value = GetAsFormat())
+ return option_value->GetCurrentValue();
+ return {};
+}
+
+bool OptionValue::SetFormatValue(lldb::Format new_value) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueFormat *option_value = GetAsFormat()) {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
+std::optional<lldb::LanguageType> OptionValue::GetLanguageValue() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueLanguage *option_value = GetAsLanguage())
+ return option_value->GetCurrentValue();
+ return {};
+}
+
+bool OptionValue::SetLanguageValue(lldb::LanguageType new_language) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueLanguage *option_value = GetAsLanguage()) {
+ option_value->SetCurrentValue(new_language);
+ return true;
+ }
+ return false;
+}
+
+const FormatEntity::Entry *OptionValue::GetFormatEntity() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueFormatEntity *option_value = GetAsFormatEntity())
+ return &option_value->GetCurrentValue();
+ return nullptr;
+}
+
+const RegularExpression *OptionValue::GetRegexValue() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueRegex *option_value = GetAsRegex())
+ return option_value->GetCurrentValue();
+ return nullptr;
+}
+
+std::optional<int64_t> OptionValue::GetSInt64Value() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueSInt64 *option_value = GetAsSInt64())
+ return option_value->GetCurrentValue();
+ return {};
+}
+
+bool OptionValue::SetSInt64Value(int64_t new_value) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueSInt64 *option_value = GetAsSInt64()) {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
+std::optional<llvm::StringRef> OptionValue::GetStringValue() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueString *option_value = GetAsString())
+ return option_value->GetCurrentValueAsRef();
+ return {};
+}
+
+bool OptionValue::SetStringValue(llvm::StringRef new_value) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueString *option_value = GetAsString()) {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
+std::optional<uint64_t> OptionValue::GetUInt64Value() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueUInt64 *option_value = GetAsUInt64())
+ return option_value->GetCurrentValue();
+ return {};
+}
+
+bool OptionValue::SetUInt64Value(uint64_t new_value) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueUInt64 *option_value = GetAsUInt64()) {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
+std::optional<UUID> OptionValue::GetUUIDValue() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueUUID *option_value = GetAsUUID())
+ return option_value->GetCurrentValue();
+ return {};
+}
+
+bool OptionValue::SetUUIDValue(const UUID &uuid) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueUUID *option_value = GetAsUUID()) {
+ option_value->SetCurrentValue(uuid);
+ return true;
+ }
+ return false;
+}
+
+std::optional<ArchSpec> OptionValue::GetArchSpecValue() const {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (const OptionValueArch *option_value = GetAsArch())
+ return option_value->GetCurrentValue();
+ return {};
+}
+
+bool OptionValue::SetArchSpecValue(ArchSpec arch_spec) {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (OptionValueArch *option_value = GetAsArch()) {
+ option_value->SetCurrentValue(arch_spec, false);
+ return true;
+ }
+ return false;
+}
+
+const char *OptionValue::GetBuiltinTypeAsCString(Type t) {
+ switch (t) {
+ case eTypeInvalid:
+ return "invalid";
+ case eTypeArch:
+ return "arch";
+ case eTypeArgs:
+ return "arguments";
+ case eTypeArray:
+ return "array";
+ case eTypeBoolean:
+ return "boolean";
+ case eTypeChar:
+ return "char";
+ case eTypeDictionary:
+ return "dictionary";
+ case eTypeEnum:
+ return "enum";
+ case eTypeFileLineColumn:
+ return "file:line:column specifier";
+ case eTypeFileSpec:
+ return "file";
+ case eTypeFileSpecList:
+ return "file-list";
+ case eTypeFormat:
+ return "format";
+ case eTypeFormatEntity:
+ return "format-string";
+ case eTypeLanguage:
+ return "language";
+ case eTypePathMap:
+ return "path-map";
+ case eTypeProperties:
+ return "properties";
+ case eTypeRegex:
+ return "regex";
+ case eTypeSInt64:
+ return "int";
+ case eTypeString:
+ return "string";
+ case eTypeUInt64:
+ return "unsigned";
+ case eTypeUUID:
+ return "uuid";
+ }
+ return nullptr;
+}
+
+lldb::OptionValueSP OptionValue::CreateValueFromCStringForTypeMask(
+ const char *value_cstr, uint32_t type_mask, Status &error) {
+ // If only 1 bit is set in the type mask for a dictionary or array then we
+ // know how to decode a value from a cstring
+ lldb::OptionValueSP value_sp;
+ switch (type_mask) {
+ case 1u << eTypeArch:
+ value_sp = std::make_shared<OptionValueArch>();
+ break;
+ case 1u << eTypeBoolean:
+ value_sp = std::make_shared<OptionValueBoolean>(false);
+ break;
+ case 1u << eTypeChar:
+ value_sp = std::make_shared<OptionValueChar>('\0');
+ break;
+ case 1u << eTypeFileSpec:
+ value_sp = std::make_shared<OptionValueFileSpec>();
+ break;
+ case 1u << eTypeFormat:
+ value_sp = std::make_shared<OptionValueFormat>(eFormatInvalid);
+ break;
+ case 1u << eTypeFormatEntity:
+ value_sp = std::make_shared<OptionValueFormatEntity>(nullptr);
+ break;
+ case 1u << eTypeLanguage:
+ value_sp = std::make_shared<OptionValueLanguage>(eLanguageTypeUnknown);
+ break;
+ case 1u << eTypeSInt64:
+ value_sp = std::make_shared<OptionValueSInt64>();
+ break;
+ case 1u << eTypeString:
+ value_sp = std::make_shared<OptionValueString>();
+ break;
+ case 1u << eTypeUInt64:
+ value_sp = std::make_shared<OptionValueUInt64>();
+ break;
+ case 1u << eTypeUUID:
+ value_sp = std::make_shared<OptionValueUUID>();
+ break;
+ }
+
+ if (value_sp)
+ error = value_sp->SetValueFromString(value_cstr, eVarSetOperationAssign);
+ else
+ error.SetErrorString("unsupported type mask");
+ return value_sp;
+}
+
+bool OptionValue::DumpQualifiedName(Stream &strm) const {
+ bool dumped_something = false;
+ lldb::OptionValueSP m_parent_sp(m_parent_wp.lock());
+ if (m_parent_sp) {
+ if (m_parent_sp->DumpQualifiedName(strm))
+ dumped_something = true;
+ }
+ llvm::StringRef name(GetName());
+ if (!name.empty()) {
+ if (dumped_something)
+ strm.PutChar('.');
+ else
+ dumped_something = true;
+ strm << name;
+ }
+ return dumped_something;
+}
+
+OptionValueSP OptionValue::DeepCopy(const OptionValueSP &new_parent) const {
+ auto clone = Clone();
+ clone->SetParent(new_parent);
+ return clone;
+}
+
+void OptionValue::AutoComplete(CommandInterpreter &interpreter,
+ CompletionRequest &request) {}
+
+Status OptionValue::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationReplace:
+ error.SetErrorStringWithFormat(
+ "%s objects do not support the 'replace' operation",
+ GetTypeAsCString());
+ break;
+ case eVarSetOperationInsertBefore:
+ error.SetErrorStringWithFormat(
+ "%s objects do not support the 'insert-before' operation",
+ GetTypeAsCString());
+ break;
+ case eVarSetOperationInsertAfter:
+ error.SetErrorStringWithFormat(
+ "%s objects do not support the 'insert-after' operation",
+ GetTypeAsCString());
+ break;
+ case eVarSetOperationRemove:
+ error.SetErrorStringWithFormat(
+ "%s objects do not support the 'remove' operation", GetTypeAsCString());
+ break;
+ case eVarSetOperationAppend:
+ error.SetErrorStringWithFormat(
+ "%s objects do not support the 'append' operation", GetTypeAsCString());
+ break;
+ case eVarSetOperationClear:
+ error.SetErrorStringWithFormat(
+ "%s objects do not support the 'clear' operation", GetTypeAsCString());
+ break;
+ case eVarSetOperationAssign:
+ error.SetErrorStringWithFormat(
+ "%s objects do not support the 'assign' operation", GetTypeAsCString());
+ break;
+ case eVarSetOperationInvalid:
+ error.SetErrorStringWithFormat("invalid operation performed on a %s object",
+ GetTypeAsCString());
+ break;
+ }
+ return error;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueArch.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueArch.cpp
new file mode 100644
index 000000000000..71a3627fbe5e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueArch.cpp
@@ -0,0 +1,71 @@
+//===-- OptionValueArch.cpp -----------------------------------------------===//
+//
+// 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/OptionValueArch.h"
+
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/State.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueArch::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
+ uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+
+ if (m_current_value.IsValid()) {
+ const char *arch_name = m_current_value.GetArchitectureName();
+ if (arch_name)
+ strm.PutCString(arch_name);
+ }
+ }
+}
+
+Status OptionValueArch::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign: {
+ std::string value_str = value.trim().str();
+ if (m_current_value.SetTriple(value_str.c_str())) {
+ m_value_was_set = true;
+ NotifyValueChanged();
+ } else
+ error.SetErrorStringWithFormat("unsupported architecture '%s'",
+ value_str.c_str());
+ break;
+ }
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+ return error;
+}
+
+void OptionValueArch::AutoComplete(CommandInterpreter &interpreter,
+ CompletionRequest &request) {
+ lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
+ interpreter, lldb::eArchitectureCompletion, request, nullptr);
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueArgs.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueArgs.cpp
new file mode 100644
index 000000000000..963651640539
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueArgs.cpp
@@ -0,0 +1,21 @@
+//===-- OptionValueArgs.cpp -----------------------------------------------===//
+//
+// 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/OptionValueArgs.h"
+
+#include "lldb/Utility/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+size_t OptionValueArgs::GetArgs(Args &args) const {
+ args.Clear();
+ for (const auto &value : m_values)
+ args.AppendArgument(value->GetValueAs<llvm::StringRef>().value_or(""));
+ return args.GetArgumentCount();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueArray.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueArray.cpp
new file mode 100644
index 000000000000..08b5f86202d3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueArray.cpp
@@ -0,0 +1,320 @@
+//===-- OptionValueArray.cpp ----------------------------------------------===//
+//
+// 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/OptionValueArray.h"
+
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
+ uint32_t dump_mask) {
+ const Type array_element_type = ConvertTypeMaskToType(m_type_mask);
+ if (dump_mask & eDumpOptionType) {
+ if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid))
+ strm.Printf("(%s of %ss)", GetTypeAsCString(),
+ GetBuiltinTypeAsCString(array_element_type));
+ else
+ strm.Printf("(%s)", GetTypeAsCString());
+ }
+ if (dump_mask & eDumpOptionValue) {
+ const bool one_line = dump_mask & eDumpOptionCommand;
+ const uint32_t size = m_values.size();
+ if (dump_mask & eDumpOptionType)
+ strm.Printf(" =%s", (m_values.size() > 0 && !one_line) ? "\n" : "");
+ if (!one_line)
+ strm.IndentMore();
+ for (uint32_t i = 0; i < size; ++i) {
+ if (!one_line) {
+ strm.Indent();
+ strm.Printf("[%u]: ", i);
+ }
+ const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
+ switch (array_element_type) {
+ default:
+ case eTypeArray:
+ case eTypeDictionary:
+ case eTypeProperties:
+ case eTypeFileSpecList:
+ case eTypePathMap:
+ m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
+ break;
+
+ case eTypeBoolean:
+ case eTypeChar:
+ case eTypeEnum:
+ case eTypeFileSpec:
+ case eTypeFileLineColumn:
+ case eTypeFormat:
+ case eTypeSInt64:
+ case eTypeString:
+ case eTypeUInt64:
+ case eTypeUUID:
+ // No need to show the type for dictionaries of simple items
+ m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) |
+ extra_dump_options);
+ break;
+ }
+
+ if (!one_line) {
+ if (i < (size - 1))
+ strm.EOL();
+ } else {
+ strm << ' ';
+ }
+ }
+ if (!one_line)
+ strm.IndentLess();
+ }
+}
+
+llvm::json::Value OptionValueArray::ToJSON(const ExecutionContext *exe_ctx) {
+ llvm::json::Array json_array;
+ const uint32_t size = m_values.size();
+ for (uint32_t i = 0; i < size; ++i)
+ json_array.emplace_back(m_values[i]->ToJSON(exe_ctx));
+ return json_array;
+}
+
+Status OptionValueArray::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Args args(value.str());
+ Status error = SetArgs(args, op);
+ if (error.Success())
+ NotifyValueChanged();
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueArray::GetSubValue(const ExecutionContext *exe_ctx,
+ llvm::StringRef name, Status &error) const {
+ if (name.empty() || name.front() != '[') {
+ error.SetErrorStringWithFormat(
+ "invalid value path '%s', %s values only support '[<index>]' subvalues "
+ "where <index> is a positive or negative array index",
+ name.str().c_str(), GetTypeAsCString());
+ return nullptr;
+ }
+
+ name = name.drop_front();
+ llvm::StringRef index, sub_value;
+ std::tie(index, sub_value) = name.split(']');
+ if (index.size() == name.size()) {
+ // Couldn't find a closing bracket
+ return nullptr;
+ }
+
+ const size_t array_count = m_values.size();
+ int32_t idx = 0;
+ if (index.getAsInteger(0, idx))
+ return nullptr;
+
+ uint32_t new_idx = UINT32_MAX;
+ if (idx < 0) {
+ // Access from the end of the array if the index is negative
+ new_idx = array_count - idx;
+ } else {
+ // Just a standard index
+ new_idx = idx;
+ }
+
+ if (new_idx < array_count) {
+ if (m_values[new_idx]) {
+ if (!sub_value.empty())
+ return m_values[new_idx]->GetSubValue(exe_ctx, sub_value, error);
+ else
+ return m_values[new_idx];
+ }
+ } else {
+ if (array_count == 0)
+ error.SetErrorStringWithFormat(
+ "index %i is not valid for an empty array", idx);
+ else if (idx > 0)
+ error.SetErrorStringWithFormat(
+ "index %i out of range, valid values are 0 through %" PRIu64,
+ idx, (uint64_t)(array_count - 1));
+ else
+ error.SetErrorStringWithFormat("negative index %i out of range, "
+ "valid values are -1 through "
+ "-%" PRIu64,
+ idx, (uint64_t)array_count);
+ }
+ return OptionValueSP();
+}
+
+size_t OptionValueArray::GetArgs(Args &args) const {
+ args.Clear();
+ const uint32_t size = m_values.size();
+ for (uint32_t i = 0; i < size; ++i) {
+ auto string_value = m_values[i]->GetValueAs<llvm::StringRef>();
+ if (string_value)
+ args.AppendArgument(*string_value);
+ }
+
+ return args.GetArgumentCount();
+}
+
+Status OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) {
+ Status error;
+ const size_t argc = args.GetArgumentCount();
+ switch (op) {
+ case eVarSetOperationInvalid:
+ error.SetErrorString("unsupported operation");
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ if (argc > 1) {
+ uint32_t idx;
+ const uint32_t count = GetSize();
+ if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
+ error.SetErrorStringWithFormat(
+ "invalid insert array index %s, index must be 0 through %u",
+ args.GetArgumentAtIndex(0), count);
+ } else {
+ if (op == eVarSetOperationInsertAfter)
+ ++idx;
+ for (size_t i = 1; i < argc; ++i, ++idx) {
+ lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
+ args.GetArgumentAtIndex(i), m_type_mask, error));
+ if (value_sp) {
+ if (error.Fail())
+ return error;
+ if (idx >= m_values.size())
+ m_values.push_back(value_sp);
+ else
+ m_values.insert(m_values.begin() + idx, value_sp);
+ } else {
+ error.SetErrorString(
+ "array of complex types must subclass OptionValueArray");
+ return error;
+ }
+ }
+ }
+ } else {
+ error.SetErrorString("insert operation takes an array index followed by "
+ "one or more values");
+ }
+ break;
+
+ case eVarSetOperationRemove:
+ if (argc > 0) {
+ const uint32_t size = m_values.size();
+ std::vector<int> remove_indexes;
+ bool all_indexes_valid = true;
+ size_t i;
+ for (i = 0; i < argc; ++i) {
+ size_t idx;
+ if (!llvm::to_integer(args.GetArgumentAtIndex(i), idx) || idx >= size) {
+ all_indexes_valid = false;
+ break;
+ } else
+ remove_indexes.push_back(idx);
+ }
+
+ if (all_indexes_valid) {
+ size_t num_remove_indexes = remove_indexes.size();
+ if (num_remove_indexes) {
+ // Sort and then erase in reverse so indexes are always valid
+ if (num_remove_indexes > 1) {
+ llvm::sort(remove_indexes);
+ for (std::vector<int>::const_reverse_iterator
+ pos = remove_indexes.rbegin(),
+ end = remove_indexes.rend();
+ pos != end; ++pos) {
+ m_values.erase(m_values.begin() + *pos);
+ }
+ } else {
+ // Only one index
+ m_values.erase(m_values.begin() + remove_indexes.front());
+ }
+ }
+ } else {
+ error.SetErrorStringWithFormat(
+ "invalid array index '%s', aborting remove operation",
+ args.GetArgumentAtIndex(i));
+ }
+ } else {
+ error.SetErrorString("remove operation takes one or more array indices");
+ }
+ break;
+
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ if (argc > 1) {
+ uint32_t idx;
+ const uint32_t count = GetSize();
+ if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
+ error.SetErrorStringWithFormat(
+ "invalid replace array index %s, index must be 0 through %u",
+ args.GetArgumentAtIndex(0), count);
+ } else {
+ for (size_t i = 1; i < argc; ++i, ++idx) {
+ lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
+ args.GetArgumentAtIndex(i), m_type_mask, error));
+ if (value_sp) {
+ if (error.Fail())
+ return error;
+ if (idx < count)
+ m_values[idx] = value_sp;
+ else
+ m_values.push_back(value_sp);
+ } else {
+ error.SetErrorString(
+ "array of complex types must subclass OptionValueArray");
+ return error;
+ }
+ }
+ }
+ } else {
+ error.SetErrorString("replace operation takes an array index followed by "
+ "one or more values");
+ }
+ break;
+
+ case eVarSetOperationAssign:
+ m_values.clear();
+ // Fall through to append case
+ [[fallthrough]];
+ case eVarSetOperationAppend:
+ for (size_t i = 0; i < argc; ++i) {
+ lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
+ args.GetArgumentAtIndex(i), m_type_mask, error));
+ if (value_sp) {
+ if (error.Fail())
+ return error;
+ m_value_was_set = true;
+ AppendValue(value_sp);
+ } else {
+ error.SetErrorString(
+ "array of complex types must subclass OptionValueArray");
+ }
+ }
+ break;
+ }
+ return error;
+}
+
+OptionValueSP
+OptionValueArray::DeepCopy(const OptionValueSP &new_parent) const {
+ auto copy_sp = OptionValue::DeepCopy(new_parent);
+ // copy_sp->GetAsArray cannot be used here as it doesn't work for derived
+ // types that override GetType returning a different value.
+ auto *array_value_ptr = static_cast<OptionValueArray *>(copy_sp.get());
+ lldbassert(array_value_ptr);
+
+ for (auto &value : array_value_ptr->m_values)
+ value = value->DeepCopy(copy_sp);
+
+ return copy_sp;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueBoolean.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueBoolean.cpp
new file mode 100644
index 000000000000..4ac2ed5efe75
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueBoolean.cpp
@@ -0,0 +1,83 @@
+//===-- OptionValueBoolean.cpp --------------------------------------------===//
+//
+// 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/OptionValueBoolean.h"
+
+#include "lldb/Host/PosixApi.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueBoolean::DumpValue(const ExecutionContext *exe_ctx,
+ Stream &strm, uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ // if (dump_mask & eDumpOptionName)
+ // DumpQualifiedName (strm);
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+ strm.PutCString(m_current_value ? "true" : "false");
+ }
+}
+
+Status OptionValueBoolean::SetValueFromString(llvm::StringRef value_str,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign: {
+ bool success = false;
+ bool value = OptionArgParser::ToBoolean(value_str, false, &success);
+ if (success) {
+ m_value_was_set = true;
+ m_current_value = value;
+ NotifyValueChanged();
+ } else {
+ if (value_str.size() == 0)
+ error.SetErrorString("invalid boolean string value <empty>");
+ else
+ error.SetErrorStringWithFormat("invalid boolean string value: '%s'",
+ value_str.str().c_str());
+ }
+ } break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value_str, op);
+ break;
+ }
+ return error;
+}
+
+void OptionValueBoolean::AutoComplete(CommandInterpreter &interpreter,
+ CompletionRequest &request) {
+ llvm::StringRef autocomplete_entries[] = {"true", "false", "on", "off",
+ "yes", "no", "1", "0"};
+
+ auto entries = llvm::ArrayRef(autocomplete_entries);
+
+ // only suggest "true" or "false" by default
+ if (request.GetCursorArgumentPrefix().empty())
+ entries = entries.take_front(2);
+
+ for (auto entry : entries)
+ request.TryCompleteCurrentArg(entry);
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueChar.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueChar.cpp
new file mode 100644
index 000000000000..7fe72c9aa221
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueChar.cpp
@@ -0,0 +1,59 @@
+//===-- OptionValueChar.cpp -----------------------------------------------===//
+//
+// 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/OptionValueChar.h"
+
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueChar::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
+ uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+ if (m_current_value != '\0')
+ strm.PutChar(m_current_value);
+ else
+ strm.PutCString("(null)");
+ }
+}
+
+Status OptionValueChar::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign: {
+ bool success = false;
+ char char_value = OptionArgParser::ToChar(value, '\0', &success);
+ if (success) {
+ m_current_value = char_value;
+ m_value_was_set = true;
+ } else
+ error.SetErrorStringWithFormat("'%s' cannot be longer than 1 character",
+ value.str().c_str());
+ } break;
+
+ default:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+ return error;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueDictionary.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueDictionary.cpp
new file mode 100644
index 000000000000..c7d501fd4521
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueDictionary.cpp
@@ -0,0 +1,347 @@
+//===-- OptionValueDictionary.cpp -----------------------------------------===//
+//
+// 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/OptionValueDictionary.h"
+
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Interpreter/OptionValueEnumeration.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/State.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx,
+ Stream &strm, uint32_t dump_mask) {
+ const Type dict_type = ConvertTypeMaskToType(m_type_mask);
+ if (dump_mask & eDumpOptionType) {
+ if (m_type_mask != eTypeInvalid)
+ strm.Printf("(%s of %ss)", GetTypeAsCString(),
+ GetBuiltinTypeAsCString(dict_type));
+ else
+ strm.Printf("(%s)", GetTypeAsCString());
+ }
+ if (dump_mask & eDumpOptionValue) {
+ const bool one_line = dump_mask & eDumpOptionCommand;
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" =");
+
+ if (!one_line)
+ strm.IndentMore();
+
+ // m_values is not guaranteed to be sorted alphabetically, so for
+ // consistentcy we will sort them here before dumping
+ std::map<llvm::StringRef, OptionValue *> sorted_values;
+ for (const auto &value : m_values) {
+ sorted_values[value.first()] = value.second.get();
+ }
+ for (const auto &value : sorted_values) {
+ OptionValue *option_value = value.second;
+
+ if (one_line)
+ strm << ' ';
+ else
+ strm.EOL();
+
+ strm.Indent(value.first);
+
+ const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
+ switch (dict_type) {
+ default:
+ case eTypeArray:
+ case eTypeDictionary:
+ case eTypeProperties:
+ case eTypeFileSpecList:
+ case eTypePathMap:
+ strm.PutChar(' ');
+ option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
+ break;
+
+ case eTypeBoolean:
+ case eTypeChar:
+ case eTypeEnum:
+ case eTypeFileLineColumn:
+ case eTypeFileSpec:
+ case eTypeFormat:
+ case eTypeSInt64:
+ case eTypeString:
+ case eTypeUInt64:
+ case eTypeUUID:
+ // No need to show the type for dictionaries of simple items
+ strm.PutCString("=");
+ option_value->DumpValue(exe_ctx, strm,
+ (dump_mask & (~eDumpOptionType)) |
+ extra_dump_options);
+ break;
+ }
+ }
+ if (!one_line)
+ strm.IndentLess();
+ }
+}
+
+llvm::json::Value
+OptionValueDictionary::ToJSON(const ExecutionContext *exe_ctx) {
+ llvm::json::Object dict;
+ for (const auto &value : m_values) {
+ dict.try_emplace(value.first(), value.second->ToJSON(exe_ctx));
+ }
+ return dict;
+}
+
+size_t OptionValueDictionary::GetArgs(Args &args) const {
+ args.Clear();
+ for (const auto &value : m_values) {
+ StreamString strm;
+ strm.Printf("%s=", value.first().data());
+ value.second->DumpValue(nullptr, strm, eDumpOptionValue | eDumpOptionRaw);
+ args.AppendArgument(strm.GetString());
+ }
+ return args.GetArgumentCount();
+}
+
+Status OptionValueDictionary::SetArgs(const Args &args,
+ VarSetOperationType op) {
+ Status error;
+ const size_t argc = args.GetArgumentCount();
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationAppend:
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ if (argc == 0) {
+ error.SetErrorString(
+ "assign operation takes one or more key=value arguments");
+ return error;
+ }
+ for (const auto &entry : args) {
+ if (entry.ref().empty()) {
+ error.SetErrorString("empty argument");
+ return error;
+ }
+ 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('=');
+ bool key_valid = false;
+ if (key.empty()) {
+ error.SetErrorString("empty dictionary key");
+ return error;
+ }
+
+ if (key.front() == '[') {
+ // Key name starts with '[', so the key value must be in single or
+ // double quotes like: ['<key>'] ["<key>"]
+ if ((key.size() > 2) && (key.back() == ']')) {
+ // Strip leading '[' and trailing ']'
+ key = key.substr(1, key.size() - 2);
+ const char quote_char = key.front();
+ if ((quote_char == '\'') || (quote_char == '"')) {
+ if ((key.size() > 2) && (key.back() == quote_char)) {
+ // Strip the quotes
+ key = key.substr(1, key.size() - 2);
+ key_valid = true;
+ }
+ } else {
+ // square brackets, no quotes
+ key_valid = true;
+ }
+ }
+ } else {
+ // No square brackets or quotes
+ key_valid = true;
+ }
+ if (!key_valid) {
+ error.SetErrorStringWithFormat(
+ "invalid key \"%s\", the key must be a bare string or "
+ "surrounded by brackets with optional quotes: [<key>] or "
+ "['<key>'] or [\"<key>\"]",
+ key.str().c_str());
+ return error;
+ }
+
+ if (m_type_mask == 1u << eTypeEnum) {
+ auto enum_value =
+ std::make_shared<OptionValueEnumeration>(m_enum_values, 0);
+ error = enum_value->SetValueFromString(value);
+ if (error.Fail())
+ return error;
+ m_value_was_set = true;
+ SetValueForKey(key, enum_value, true);
+ } else {
+ lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
+ value.str().c_str(), m_type_mask, error));
+ if (value_sp) {
+ if (error.Fail())
+ return error;
+ m_value_was_set = true;
+ SetValueForKey(key, value_sp, true);
+ } else {
+ error.SetErrorString("dictionaries that can contain multiple types "
+ "must subclass OptionValueArray");
+ }
+ }
+ }
+ break;
+
+ case eVarSetOperationRemove:
+ if (argc > 0) {
+ for (size_t i = 0; i < argc; ++i) {
+ llvm::StringRef key(args.GetArgumentAtIndex(i));
+ if (!DeleteValueForKey(key)) {
+ error.SetErrorStringWithFormat(
+ "no value found named '%s', aborting remove operation",
+ key.data());
+ break;
+ }
+ }
+ } else {
+ error.SetErrorString("remove operation takes one or more key arguments");
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(llvm::StringRef(), op);
+ break;
+ }
+ return error;
+}
+
+Status OptionValueDictionary::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Args args(value.str());
+ Status error = SetArgs(args, op);
+ if (error.Success())
+ NotifyValueChanged();
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueDictionary::GetSubValue(const ExecutionContext *exe_ctx,
+ llvm::StringRef name, Status &error) const {
+ lldb::OptionValueSP value_sp;
+ if (name.empty())
+ return nullptr;
+
+ llvm::StringRef left, temp;
+ std::tie(left, temp) = name.split('[');
+ if (left.size() == name.size()) {
+ error.SetErrorStringWithFormat("invalid value path '%s', %s values only "
+ "support '[<key>]' subvalues where <key> "
+ "a string value optionally delimited by "
+ "single or double quotes",
+ name.str().c_str(), GetTypeAsCString());
+ return nullptr;
+ }
+ assert(!temp.empty());
+
+ llvm::StringRef key, quote_char;
+
+ if (temp[0] == '\"' || temp[0] == '\'') {
+ quote_char = temp.take_front();
+ temp = temp.drop_front();
+ }
+
+ llvm::StringRef sub_name;
+ std::tie(key, sub_name) = temp.split(']');
+
+ if (!key.consume_back(quote_char) || key.empty()) {
+ error.SetErrorStringWithFormat("invalid value path '%s', "
+ "key names must be formatted as ['<key>'] where <key> "
+ "is a string that doesn't contain quotes and the quote"
+ " char is optional", name.str().c_str());
+ return nullptr;
+ }
+
+ value_sp = GetValueForKey(key);
+ if (!value_sp) {
+ error.SetErrorStringWithFormat(
+ "dictionary does not contain a value for the key name '%s'",
+ key.str().c_str());
+ return nullptr;
+ }
+
+ if (sub_name.empty())
+ return value_sp;
+ return value_sp->GetSubValue(exe_ctx, sub_name, error);
+}
+
+Status OptionValueDictionary::SetSubValue(const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ llvm::StringRef name,
+ llvm::StringRef value) {
+ Status error;
+ lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, error));
+ if (value_sp)
+ error = value_sp->SetValueFromString(value, op);
+ else {
+ if (error.AsCString() == nullptr)
+ error.SetErrorStringWithFormat("invalid value path '%s'", name.str().c_str());
+ }
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueDictionary::GetValueForKey(llvm::StringRef key) const {
+ lldb::OptionValueSP value_sp;
+ auto pos = m_values.find(key);
+ if (pos != m_values.end())
+ value_sp = pos->second;
+ return value_sp;
+}
+
+bool OptionValueDictionary::SetValueForKey(llvm::StringRef key,
+ const lldb::OptionValueSP &value_sp,
+ bool can_replace) {
+ // Make sure the value_sp object is allowed to contain values of the type
+ // passed in...
+ if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) {
+ if (!can_replace) {
+ auto pos = m_values.find(key);
+ if (pos != m_values.end())
+ return false;
+ }
+ m_values[key] = value_sp;
+ return true;
+ }
+ return false;
+}
+
+bool OptionValueDictionary::DeleteValueForKey(llvm::StringRef key) {
+ auto pos = m_values.find(key);
+ if (pos != m_values.end()) {
+ m_values.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+OptionValueSP
+OptionValueDictionary::DeepCopy(const OptionValueSP &new_parent) const {
+ auto copy_sp = OptionValue::DeepCopy(new_parent);
+ // copy_sp->GetAsDictionary cannot be used here as it doesn't work for derived
+ // types that override GetType returning a different value.
+ auto *dict_value_ptr = static_cast<OptionValueDictionary *>(copy_sp.get());
+ lldbassert(dict_value_ptr);
+
+ for (auto &value : dict_value_ptr->m_values)
+ value.second = value.second->DeepCopy(copy_sp);
+
+ return copy_sp;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueEnumeration.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueEnumeration.cpp
new file mode 100644
index 000000000000..f75519c577c5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueEnumeration.cpp
@@ -0,0 +1,110 @@
+//===-- OptionValueEnumeration.cpp ----------------------------------------===//
+//
+// 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/OptionValueEnumeration.h"
+
+#include "lldb/Utility/StringList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionValueEnumeration::OptionValueEnumeration(
+ const OptionEnumValues &enumerators, enum_type value)
+ : m_current_value(value), m_default_value(value) {
+ SetEnumerations(enumerators);
+}
+
+void OptionValueEnumeration::DumpValue(const ExecutionContext *exe_ctx,
+ Stream &strm, uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+ const size_t count = m_enumerations.GetSize();
+ for (size_t i = 0; i < count; ++i) {
+ if (m_enumerations.GetValueAtIndexUnchecked(i).value == m_current_value) {
+ strm.PutCString(m_enumerations.GetCStringAtIndex(i).GetStringRef());
+ return;
+ }
+ }
+ strm.Printf("%" PRIu64, (uint64_t)m_current_value);
+ }
+}
+
+Status OptionValueEnumeration::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign: {
+ ConstString const_enumerator_name(value.trim());
+ const EnumerationMapEntry *enumerator_entry =
+ m_enumerations.FindFirstValueForName(const_enumerator_name);
+ if (enumerator_entry) {
+ m_current_value = enumerator_entry->value.value;
+ NotifyValueChanged();
+ } else {
+ StreamString error_strm;
+ error_strm.Printf("invalid enumeration value '%s'", value.str().c_str());
+ const size_t count = m_enumerations.GetSize();
+ if (count) {
+ error_strm.Printf(", valid values are: %s",
+ m_enumerations.GetCStringAtIndex(0).GetCString());
+ for (size_t i = 1; i < count; ++i) {
+ error_strm.Printf(", %s",
+ m_enumerations.GetCStringAtIndex(i).GetCString());
+ }
+ }
+ error.SetErrorString(error_strm.GetString());
+ }
+ break;
+ }
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+ return error;
+}
+
+void OptionValueEnumeration::SetEnumerations(
+ const OptionEnumValues &enumerators) {
+ m_enumerations.Clear();
+
+ for (const auto &enumerator : enumerators) {
+ ConstString const_enumerator_name(enumerator.string_value);
+ EnumeratorInfo enumerator_info = {enumerator.value, enumerator.usage};
+ m_enumerations.Append(const_enumerator_name, enumerator_info);
+ }
+
+ m_enumerations.Sort();
+}
+
+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();
+ request.TryCompleteCurrentArg(name);
+ }
+ return;
+ }
+ for (size_t i = 0; i < num_enumerators; ++i)
+ request.AddCompletion(m_enumerations.GetCStringAtIndex(i).GetStringRef());
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueFileColonLine.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueFileColonLine.cpp
new file mode 100644
index 000000000000..a68967b81797
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueFileColonLine.cpp
@@ -0,0 +1,137 @@
+//===-- OptionValueFileColonLine.cpp---------------------------------------===//
+//
+// 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/OptionValueFileColonLine.h"
+
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/State.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// This is an OptionValue for parsing file:line:column specifications.
+// I set the completer to "source file" which isn't quite right, but we can
+// only usefully complete in the file name part of it so it should be good
+// enough.
+OptionValueFileColonLine::OptionValueFileColonLine() = default;
+
+OptionValueFileColonLine::OptionValueFileColonLine(llvm::StringRef input)
+
+{
+ SetValueFromString(input, eVarSetOperationAssign);
+}
+
+void OptionValueFileColonLine::DumpValue(const ExecutionContext *exe_ctx,
+ Stream &strm, uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+
+ if (m_file_spec)
+ strm << '"' << m_file_spec.GetPath().c_str() << '"';
+ if (m_line_number != LLDB_INVALID_LINE_NUMBER)
+ strm.Printf(":%d", m_line_number);
+ if (m_column_number != LLDB_INVALID_COLUMN_NUMBER)
+ strm.Printf(":%d", m_column_number);
+ }
+}
+
+Status OptionValueFileColonLine::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ if (value.size() > 0) {
+ // This is in the form filename:linenumber:column.
+ // I wish we could use filename:linenumber.column, that would make the
+ // parsing unambiguous and so much easier...
+ // But clang & gcc both print the output with two : so we're stuck with
+ // the two colons. Practically, the only actual ambiguity this introduces
+ // is with files like "foo:10", which doesn't seem terribly likely.
+
+ // Providing the column is optional, so the input value might have one or
+ // two colons. First pick off the last colon separated piece.
+ // It has to be there, since the line number is required:
+ llvm::StringRef last_piece;
+ llvm::StringRef left_of_last_piece;
+
+ std::tie(left_of_last_piece, last_piece) = value.rsplit(':');
+ if (last_piece.empty()) {
+ error.SetErrorStringWithFormat("Line specifier must include file and "
+ "line: '%s'",
+ value.str().c_str());
+ return error;
+ }
+
+ // Now see if there's another colon and if so pull out the middle piece:
+ // Then check whether the middle piece is an integer. If it is, then it
+ // was the line number, and if it isn't we're going to assume that there
+ // was a colon in the filename (see note at the beginning of the function)
+ // and ignore it.
+ llvm::StringRef file_name;
+ llvm::StringRef middle_piece;
+
+ std::tie(file_name, middle_piece) = left_of_last_piece.rsplit(':');
+ if (middle_piece.empty() ||
+ !llvm::to_integer(middle_piece, m_line_number)) {
+ // The middle piece was empty or not an integer, so there were only two
+ // legit pieces; our original division was right. Reassign the file
+ // name and pull out the line number:
+ file_name = left_of_last_piece;
+ if (!llvm::to_integer(last_piece, m_line_number)) {
+ error.SetErrorStringWithFormat("Bad line number value '%s' in: '%s'",
+ last_piece.str().c_str(),
+ value.str().c_str());
+ return error;
+ }
+ } else {
+ // There were three pieces, and we've got the line number. So now
+ // we just need to check the column number which was the last peice.
+ if (!llvm::to_integer(last_piece, m_column_number)) {
+ error.SetErrorStringWithFormat("Bad column value '%s' in: '%s'",
+ last_piece.str().c_str(),
+ value.str().c_str());
+ return error;
+ }
+ }
+
+ m_value_was_set = true;
+ m_file_spec.SetFile(file_name, FileSpec::Style::native);
+ NotifyValueChanged();
+ } else {
+ error.SetErrorString("invalid value string");
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+ return error;
+}
+
+void OptionValueFileColonLine::AutoComplete(CommandInterpreter &interpreter,
+ CompletionRequest &request) {
+ lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
+ interpreter, m_completion_mask, request, nullptr);
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueFileSpec.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueFileSpec.cpp
new file mode 100644
index 000000000000..35a1081dba1e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueFileSpec.cpp
@@ -0,0 +1,101 @@
+//===-- OptionValueFileSpec.cpp -------------------------------------------===//
+//
+// 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/OptionValueFileSpec.h"
+
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/State.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionValueFileSpec::OptionValueFileSpec(bool resolve) : m_resolve(resolve) {}
+
+OptionValueFileSpec::OptionValueFileSpec(const FileSpec &value, bool resolve)
+ : m_current_value(value), m_default_value(value),
+
+ m_resolve(resolve) {}
+
+OptionValueFileSpec::OptionValueFileSpec(const FileSpec &current_value,
+ const FileSpec &default_value,
+ bool resolve)
+ : m_current_value(current_value), m_default_value(default_value),
+
+ m_resolve(resolve) {}
+
+void OptionValueFileSpec::DumpValue(const ExecutionContext *exe_ctx,
+ Stream &strm, uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+
+ if (m_current_value) {
+ strm << '"' << m_current_value.GetPath().c_str() << '"';
+ }
+ }
+}
+
+Status OptionValueFileSpec::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ if (value.size() > 0) {
+ value = value.trim("\"' \t");
+ m_value_was_set = true;
+ m_current_value.SetFile(value.str(), FileSpec::Style::native);
+ if (m_resolve)
+ FileSystem::Instance().Resolve(m_current_value);
+ m_data_sp.reset();
+ m_data_mod_time = llvm::sys::TimePoint<>();
+ NotifyValueChanged();
+ } else {
+ error.SetErrorString("invalid value string");
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+ return error;
+}
+
+void OptionValueFileSpec::AutoComplete(CommandInterpreter &interpreter,
+ CompletionRequest &request) {
+ lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
+ interpreter, m_completion_mask, request, nullptr);
+}
+
+const lldb::DataBufferSP &OptionValueFileSpec::GetFileContents() {
+ if (m_current_value) {
+ const auto file_mod_time = FileSystem::Instance().GetModificationTime(m_current_value);
+ if (m_data_sp && m_data_mod_time == file_mod_time)
+ return m_data_sp;
+ m_data_sp =
+ FileSystem::Instance().CreateDataBuffer(m_current_value.GetPath());
+ m_data_mod_time = file_mod_time;
+ }
+ return m_data_sp;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueFileSpecList.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueFileSpecList.cpp
new file mode 100644
index 000000000000..b47feb9989dd
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueFileSpecList.cpp
@@ -0,0 +1,166 @@
+//===-- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Interpreter/OptionValueFileSpecList.h"
+
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueFileSpecList::DumpValue(const ExecutionContext *exe_ctx,
+ Stream &strm, uint32_t dump_mask) {
+ std::lock_guard<std::recursive_mutex> lock(m_mutex);
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ const bool one_line = dump_mask & eDumpOptionCommand;
+ const uint32_t size = m_current_value.GetSize();
+ if (dump_mask & eDumpOptionType)
+ strm.Printf(" =%s",
+ (m_current_value.GetSize() > 0 && !one_line) ? "\n" : "");
+ if (!one_line)
+ strm.IndentMore();
+ for (uint32_t i = 0; i < size; ++i) {
+ if (!one_line) {
+ strm.Indent();
+ strm.Printf("[%u]: ", i);
+ }
+ m_current_value.GetFileSpecAtIndex(i).Dump(strm.AsRawOstream());
+ if (one_line)
+ strm << ' ';
+ }
+ if (!one_line)
+ strm.IndentLess();
+ }
+}
+
+Status OptionValueFileSpecList::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ std::lock_guard<std::recursive_mutex> lock(m_mutex);
+ Status error;
+ Args args(value.str());
+ const size_t argc = args.GetArgumentCount();
+
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ if (argc > 1) {
+ uint32_t idx;
+ const uint32_t count = m_current_value.GetSize();
+ if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
+ error.SetErrorStringWithFormat(
+ "invalid file list index %s, index must be 0 through %u",
+ args.GetArgumentAtIndex(0), count);
+ } else {
+ for (size_t i = 1; i < argc; ++i, ++idx) {
+ FileSpec file(args.GetArgumentAtIndex(i));
+ if (idx < count)
+ m_current_value.Replace(idx, file);
+ else
+ m_current_value.Append(file);
+ }
+ NotifyValueChanged();
+ }
+ } else {
+ error.SetErrorString("replace operation takes an array index followed by "
+ "one or more values");
+ }
+ break;
+
+ case eVarSetOperationAssign:
+ m_current_value.Clear();
+ // Fall through to append case
+ [[fallthrough]];
+ case eVarSetOperationAppend:
+ if (argc > 0) {
+ m_value_was_set = true;
+ for (size_t i = 0; i < argc; ++i) {
+ FileSpec file(args.GetArgumentAtIndex(i));
+ m_current_value.Append(file);
+ }
+ NotifyValueChanged();
+ } else {
+ error.SetErrorString(
+ "assign operation takes at least one file path argument");
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ if (argc > 1) {
+ uint32_t idx;
+ const uint32_t count = m_current_value.GetSize();
+ if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
+ error.SetErrorStringWithFormat(
+ "invalid insert file list index %s, index must be 0 through %u",
+ args.GetArgumentAtIndex(0), count);
+ } else {
+ if (op == eVarSetOperationInsertAfter)
+ ++idx;
+ for (size_t i = 1; i < argc; ++i, ++idx) {
+ FileSpec file(args.GetArgumentAtIndex(i));
+ m_current_value.Insert(idx, file);
+ }
+ NotifyValueChanged();
+ }
+ } else {
+ error.SetErrorString("insert operation takes an array index followed by "
+ "one or more values");
+ }
+ break;
+
+ case eVarSetOperationRemove:
+ if (argc > 0) {
+ std::vector<int> remove_indexes;
+ bool all_indexes_valid = true;
+ size_t i;
+ for (i = 0; all_indexes_valid && i < argc; ++i) {
+ int idx;
+ if (!llvm::to_integer(args.GetArgumentAtIndex(i), idx))
+ all_indexes_valid = false;
+ else
+ remove_indexes.push_back(idx);
+ }
+
+ if (all_indexes_valid) {
+ size_t num_remove_indexes = remove_indexes.size();
+ if (num_remove_indexes) {
+ // Sort and then erase in reverse so indexes are always valid
+ llvm::sort(remove_indexes);
+ for (size_t j = num_remove_indexes - 1; j < num_remove_indexes; ++j) {
+ m_current_value.Remove(j);
+ }
+ }
+ NotifyValueChanged();
+ } else {
+ error.SetErrorStringWithFormat(
+ "invalid array index '%s', aborting remove operation",
+ args.GetArgumentAtIndex(i));
+ }
+ } else {
+ error.SetErrorString("remove operation takes one or more array index");
+ }
+ break;
+
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+ return error;
+}
+
+OptionValueSP OptionValueFileSpecList::Clone() const {
+ std::lock_guard<std::recursive_mutex> lock(m_mutex);
+ return Cloneable::Clone();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueFormat.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueFormat.cpp
new file mode 100644
index 000000000000..ab89f673e96f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueFormat.cpp
@@ -0,0 +1,62 @@
+//===-- OptionValueFormat.cpp ---------------------------------------------===//
+//
+// 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/OptionValueFormat.h"
+
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueFormat::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
+ uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+ strm.PutCString(FormatManager::GetFormatAsCString(m_current_value));
+ }
+}
+
+llvm::json::Value OptionValueFormat::ToJSON(const ExecutionContext *exe_ctx) {
+ return FormatManager::GetFormatAsCString(m_current_value);
+}
+
+Status OptionValueFormat::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign: {
+ Format new_format;
+ error = OptionArgParser::ToFormat(value.str().c_str(), new_format, nullptr);
+ if (error.Success()) {
+ m_value_was_set = true;
+ m_current_value = new_format;
+ NotifyValueChanged();
+ }
+ } break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+ return error;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueFormatEntity.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueFormatEntity.cpp
new file mode 100644
index 000000000000..98216e13ad83
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueFormatEntity.cpp
@@ -0,0 +1,122 @@
+//===-- OptionValueFormatEntity.cpp ---------------------------------------===//
+//
+// 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/OptionValueFormatEntity.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+using namespace lldb;
+using namespace lldb_private;
+
+OptionValueFormatEntity::OptionValueFormatEntity(const char *default_format) {
+ if (default_format && default_format[0]) {
+ llvm::StringRef default_format_str(default_format);
+ Status error = FormatEntity::Parse(default_format_str, m_default_entry);
+ if (error.Success()) {
+ m_default_format = default_format;
+ m_current_format = default_format;
+ m_current_entry = m_default_entry;
+ }
+ }
+}
+
+void OptionValueFormatEntity::Clear() {
+ m_current_entry = m_default_entry;
+ m_current_format = m_default_format;
+ m_value_was_set = false;
+}
+
+static void EscapeBackticks(llvm::StringRef str, std::string &dst) {
+ dst.clear();
+ dst.reserve(str.size());
+
+ for (size_t i = 0, e = str.size(); i != e; ++i) {
+ char c = str[i];
+ if (c == '`') {
+ if (i == 0 || str[i - 1] != '\\')
+ dst += '\\';
+ }
+ dst += c;
+ }
+}
+
+void OptionValueFormatEntity::DumpValue(const ExecutionContext *exe_ctx,
+ Stream &strm, uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+ std::string escaped;
+ EscapeBackticks(m_current_format, escaped);
+ strm << '"' << escaped << '"';
+ }
+}
+
+llvm::json::Value
+OptionValueFormatEntity::ToJSON(const ExecutionContext *exe_ctx) {
+ std::string escaped;
+ EscapeBackticks(m_current_format, escaped);
+ return escaped;
+}
+
+Status OptionValueFormatEntity::SetValueFromString(llvm::StringRef value_str,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign: {
+ // Check if the string starts with a quote character after removing leading
+ // and trailing spaces. If it does start with a quote character, make sure
+ // it ends with the same quote character and remove the quotes before we
+ // parse the format string. If the string doesn't start with a quote, leave
+ // the string alone and parse as is.
+ llvm::StringRef trimmed_value_str = value_str.trim();
+ if (!trimmed_value_str.empty()) {
+ const char first_char = trimmed_value_str[0];
+ if (first_char == '"' || first_char == '\'') {
+ const size_t trimmed_len = trimmed_value_str.size();
+ if (trimmed_len == 1 || value_str[trimmed_len - 1] != first_char) {
+ error.SetErrorString("mismatched quotes");
+ return error;
+ }
+ value_str = trimmed_value_str.substr(1, trimmed_len - 2);
+ }
+ }
+ FormatEntity::Entry entry;
+ error = FormatEntity::Parse(value_str, entry);
+ if (error.Success()) {
+ m_current_entry = std::move(entry);
+ m_current_format = std::string(value_str);
+ m_value_was_set = true;
+ NotifyValueChanged();
+ }
+ } break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value_str, op);
+ break;
+ }
+ return error;
+}
+
+void OptionValueFormatEntity::AutoComplete(CommandInterpreter &interpreter,
+ CompletionRequest &request) {
+ FormatEntity::AutoComplete(request);
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueLanguage.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueLanguage.cpp
new file mode 100644
index 000000000000..409fcf882bcb
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueLanguage.cpp
@@ -0,0 +1,73 @@
+//===-- OptionValueLanguage.cpp -------------------------------------------===//
+//
+// 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/OptionValueLanguage.h"
+
+#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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueLanguage::DumpValue(const ExecutionContext *exe_ctx,
+ Stream &strm, uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+ if (m_current_value != eLanguageTypeUnknown)
+ strm.PutCString(Language::GetNameForLanguageType(m_current_value));
+ }
+}
+
+llvm::json::Value OptionValueLanguage::ToJSON(const ExecutionContext *exe_ctx) {
+ return Language::GetNameForLanguageType(m_current_value);
+}
+
+Status OptionValueLanguage::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign: {
+ LanguageSet languages_for_types = Language::GetLanguagesSupportingTypeSystems();
+ LanguageType new_type = Language::GetLanguageTypeFromString(value.trim());
+ 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 (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());
+ }
+ } break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+ return error;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValuePathMappings.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValuePathMappings.cpp
new file mode 100644
index 000000000000..7cfc445f5580
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValuePathMappings.cpp
@@ -0,0 +1,196 @@
+//===-- OptionValuePathMappings.cpp ---------------------------------------===//
+//
+// 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/OptionValuePathMappings.h"
+
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool VerifyPathExists(const char *path) {
+ if (path && path[0])
+ return FileSystem::Instance().Exists(path);
+ else
+ return false;
+}
+
+void OptionValuePathMappings::DumpValue(const ExecutionContext *exe_ctx,
+ Stream &strm, uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf(" =%s", (m_path_mappings.GetSize() > 0) ? "\n" : "");
+ m_path_mappings.Dump(&strm);
+ }
+}
+
+llvm::json::Value
+OptionValuePathMappings::ToJSON(const ExecutionContext *exe_ctx) {
+ return m_path_mappings.ToJSON();
+}
+
+Status OptionValuePathMappings::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+ Args args(value.str());
+ const size_t argc = args.GetArgumentCount();
+
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ // Must be at least one index + 1 pair of paths, and the pair count must be
+ // even
+ if (argc >= 3 && (((argc - 1) & 1) == 0)) {
+ uint32_t idx;
+ const uint32_t count = m_path_mappings.GetSize();
+ if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
+ error.SetErrorStringWithFormat(
+ "invalid file list index %s, index must be 0 through %u",
+ args.GetArgumentAtIndex(0), count);
+ } else {
+ bool changed = false;
+ for (size_t i = 1; i < argc; idx++, i += 2) {
+ const char *orginal_path = args.GetArgumentAtIndex(i);
+ const char *replace_path = args.GetArgumentAtIndex(i + 1);
+ if (VerifyPathExists(replace_path)) {
+ if (!m_path_mappings.Replace(orginal_path, replace_path, idx,
+ m_notify_changes))
+ m_path_mappings.Append(orginal_path, replace_path,
+ m_notify_changes);
+ changed = true;
+ } else {
+ std::string previousError =
+ error.Fail() ? std::string(error.AsCString()) + "\n" : "";
+ error.SetErrorStringWithFormat(
+ "%sthe replacement path doesn't exist: \"%s\"",
+ previousError.c_str(), replace_path);
+ }
+ }
+ if (changed)
+ NotifyValueChanged();
+ }
+ } else {
+ error.SetErrorString("replace operation takes an array index followed by "
+ "one or more path pairs");
+ }
+ break;
+
+ case eVarSetOperationAssign:
+ if (argc < 2 || (argc & 1)) {
+ error.SetErrorString("assign operation takes one or more path pairs");
+ break;
+ }
+ m_path_mappings.Clear(m_notify_changes);
+ // Fall through to append case
+ [[fallthrough]];
+ case eVarSetOperationAppend:
+ if (argc < 2 || (argc & 1)) {
+ error.SetErrorString("append operation takes one or more path pairs");
+ break;
+ } else {
+ bool changed = false;
+ for (size_t i = 0; i < argc; i += 2) {
+ const char *orginal_path = args.GetArgumentAtIndex(i);
+ const char *replace_path = args.GetArgumentAtIndex(i + 1);
+ if (VerifyPathExists(replace_path)) {
+ m_path_mappings.Append(orginal_path, replace_path, m_notify_changes);
+ m_value_was_set = true;
+ changed = true;
+ } else {
+ std::string previousError =
+ error.Fail() ? std::string(error.AsCString()) + "\n" : "";
+ error.SetErrorStringWithFormat(
+ "%sthe replacement path doesn't exist: \"%s\"",
+ previousError.c_str(), replace_path);
+ }
+ }
+ if (changed)
+ NotifyValueChanged();
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ // Must be at least one index + 1 pair of paths, and the pair count must be
+ // even
+ if (argc >= 3 && (((argc - 1) & 1) == 0)) {
+ uint32_t idx;
+ const uint32_t count = m_path_mappings.GetSize();
+ if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
+ error.SetErrorStringWithFormat(
+ "invalid file list index %s, index must be 0 through %u",
+ args.GetArgumentAtIndex(0), count);
+ } else {
+ bool changed = false;
+ if (op == eVarSetOperationInsertAfter)
+ ++idx;
+ for (size_t i = 1; i < argc; i += 2) {
+ const char *orginal_path = args.GetArgumentAtIndex(i);
+ const char *replace_path = args.GetArgumentAtIndex(i + 1);
+ if (VerifyPathExists(replace_path)) {
+ m_path_mappings.Insert(orginal_path, replace_path, idx,
+ m_notify_changes);
+ changed = true;
+ idx++;
+ } else {
+ std::string previousError =
+ error.Fail() ? std::string(error.AsCString()) + "\n" : "";
+ error.SetErrorStringWithFormat(
+ "%sthe replacement path doesn't exist: \"%s\"",
+ previousError.c_str(), replace_path);
+ }
+ }
+ if (changed)
+ NotifyValueChanged();
+ }
+ } else {
+ error.SetErrorString("insert operation takes an array index followed by "
+ "one or more path pairs");
+ }
+ break;
+
+ case eVarSetOperationRemove:
+ if (argc > 0) {
+ std::vector<int> remove_indexes;
+ for (size_t i = 0; i < argc; ++i) {
+ int idx;
+ if (!llvm::to_integer(args.GetArgumentAtIndex(i), idx) || idx < 0 ||
+ idx >= (int)m_path_mappings.GetSize()) {
+ error.SetErrorStringWithFormat(
+ "invalid array index '%s', aborting remove operation",
+ args.GetArgumentAtIndex(i));
+ break;
+ } else
+ remove_indexes.push_back(idx);
+ }
+
+ // Sort and then erase in reverse so indexes are always valid
+ llvm::sort(remove_indexes);
+ for (auto index : llvm::reverse(remove_indexes))
+ m_path_mappings.Remove(index, m_notify_changes);
+ NotifyValueChanged();
+ } else {
+ error.SetErrorString("remove operation takes one or more array index");
+ }
+ break;
+
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+ return error;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueProperties.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueProperties.cpp
new file mode 100644
index 000000000000..8719a2b63656
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueProperties.cpp
@@ -0,0 +1,491 @@
+//===-- OptionValueProperties.cpp -----------------------------------------===//
+//
+// 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/OptionValueProperties.h"
+
+#include "lldb/Utility/Flags.h"
+
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Interpreter/OptionValues.h"
+#include "lldb/Interpreter/Property.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionValueProperties::OptionValueProperties(llvm::StringRef name)
+ : m_name(name.str()) {}
+
+void OptionValueProperties::Initialize(const PropertyDefinitions &defs) {
+ for (const auto &definition : defs) {
+ Property property(definition);
+ assert(property.IsValid());
+ m_name_to_index.insert({property.GetName(), m_properties.size()});
+ property.GetValue()->SetParent(shared_from_this());
+ m_properties.push_back(property);
+ }
+}
+
+void OptionValueProperties::SetValueChangedCallback(
+ size_t property_idx, std::function<void()> callback) {
+ Property *property = ProtectedGetPropertyAtIndex(property_idx);
+ if (property)
+ property->SetValueChangedCallback(std::move(callback));
+}
+
+void OptionValueProperties::AppendProperty(llvm::StringRef name,
+ llvm::StringRef desc, bool is_global,
+ const OptionValueSP &value_sp) {
+ Property property(name, desc, is_global, value_sp);
+ m_name_to_index.insert({name, m_properties.size()});
+ m_properties.push_back(property);
+ value_sp->SetParent(shared_from_this());
+}
+
+lldb::OptionValueSP
+OptionValueProperties::GetValueForKey(const ExecutionContext *exe_ctx,
+ llvm::StringRef key) const {
+ auto iter = m_name_to_index.find(key);
+ if (iter == m_name_to_index.end())
+ return OptionValueSP();
+ const size_t idx = iter->second;
+ if (idx >= m_properties.size())
+ return OptionValueSP();
+ return GetPropertyAtIndex(idx, exe_ctx)->GetValue();
+}
+
+lldb::OptionValueSP
+OptionValueProperties::GetSubValue(const ExecutionContext *exe_ctx,
+ llvm::StringRef name, Status &error) const {
+ lldb::OptionValueSP value_sp;
+ if (name.empty())
+ return OptionValueSP();
+
+ llvm::StringRef sub_name;
+ llvm::StringRef key;
+ size_t key_len = name.find_first_of(".[{");
+ if (key_len != llvm::StringRef::npos) {
+ key = name.take_front(key_len);
+ sub_name = name.drop_front(key_len);
+ } else
+ key = name;
+
+ value_sp = GetValueForKey(exe_ctx, key);
+ if (sub_name.empty() || !value_sp)
+ return value_sp;
+
+ switch (sub_name[0]) {
+ case '.': {
+ lldb::OptionValueSP return_val_sp;
+ return_val_sp =
+ value_sp->GetSubValue(exe_ctx, sub_name.drop_front(), error);
+ if (!return_val_sp) {
+ if (Properties::IsSettingExperimental(sub_name.drop_front())) {
+ const size_t experimental_len =
+ Properties::GetExperimentalSettingsName().size();
+ if (sub_name[experimental_len + 1] == '.')
+ return_val_sp = value_sp->GetSubValue(
+ exe_ctx, sub_name.drop_front(experimental_len + 2), error);
+ // It isn't an error if an experimental setting is not present.
+ if (!return_val_sp)
+ error.Clear();
+ }
+ }
+ return return_val_sp;
+ }
+ case '[':
+ // Array or dictionary access for subvalues like: "[12]" -- access
+ // 12th array element "['hello']" -- dictionary access of key named hello
+ return value_sp->GetSubValue(exe_ctx, sub_name, error);
+
+ default:
+ value_sp.reset();
+ break;
+ }
+ return value_sp;
+}
+
+Status OptionValueProperties::SetSubValue(const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ llvm::StringRef name,
+ llvm::StringRef value) {
+ Status error;
+ llvm::SmallVector<llvm::StringRef, 8> components;
+ name.split(components, '.');
+ bool name_contains_experimental = false;
+ for (const auto &part : components)
+ if (Properties::IsSettingExperimental(part))
+ name_contains_experimental = true;
+
+ lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, error));
+ if (value_sp)
+ error = value_sp->SetValueFromString(value, op);
+ else {
+ // Don't set an error if the path contained .experimental. - those are
+ // allowed to be missing and should silently fail.
+ if (!name_contains_experimental && error.AsCString() == nullptr) {
+ error.SetErrorStringWithFormat("invalid value path '%s'",
+ name.str().c_str());
+ }
+ }
+ return error;
+}
+
+size_t OptionValueProperties::GetPropertyIndex(llvm::StringRef name) const {
+ auto iter = m_name_to_index.find(name);
+ if (iter == m_name_to_index.end())
+ return SIZE_MAX;
+ return iter->second;
+}
+
+const Property *
+OptionValueProperties::GetProperty(llvm::StringRef name,
+ const ExecutionContext *exe_ctx) const {
+ auto iter = m_name_to_index.find(name);
+ if (iter == m_name_to_index.end())
+ return nullptr;
+ return GetPropertyAtIndex(iter->second, exe_ctx);
+}
+
+lldb::OptionValueSP OptionValueProperties::GetPropertyValueAtIndex(
+ size_t idx, const ExecutionContext *exe_ctx) const {
+ const Property *setting = GetPropertyAtIndex(idx, exe_ctx);
+ if (setting)
+ return setting->GetValue();
+ return OptionValueSP();
+}
+
+OptionValuePathMappings *
+OptionValueProperties::GetPropertyAtIndexAsOptionValuePathMappings(
+ size_t idx, const ExecutionContext *exe_ctx) const {
+ OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx));
+ if (value_sp)
+ return value_sp->GetAsPathMappings();
+ return nullptr;
+}
+
+OptionValueFileSpecList *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList(
+ size_t idx, const ExecutionContext *exe_ctx) const {
+ OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx));
+ if (value_sp)
+ return value_sp->GetAsFileSpecList();
+ return nullptr;
+}
+
+bool OptionValueProperties::GetPropertyAtIndexAsArgs(
+ size_t idx, Args &args, const ExecutionContext *exe_ctx) const {
+ const Property *property = GetPropertyAtIndex(idx, exe_ctx);
+ if (!property)
+ return false;
+
+ OptionValue *value = property->GetValue().get();
+ if (!value)
+ return false;
+
+ const OptionValueArgs *arguments = value->GetAsArgs();
+ if (arguments) {
+ arguments->GetArgs(args);
+ return true;
+ }
+
+ const OptionValueArray *array = value->GetAsArray();
+ if (array) {
+ array->GetArgs(args);
+ return true;
+ }
+
+ const OptionValueDictionary *dict = value->GetAsDictionary();
+ if (dict) {
+ dict->GetArgs(args);
+ return true;
+ }
+
+ return false;
+}
+
+bool OptionValueProperties::SetPropertyAtIndexFromArgs(
+ size_t idx, const Args &args, const ExecutionContext *exe_ctx) {
+ const Property *property = GetPropertyAtIndex(idx, exe_ctx);
+ if (!property)
+ return false;
+
+ OptionValue *value = property->GetValue().get();
+ if (!value)
+ return false;
+
+ OptionValueArgs *arguments = value->GetAsArgs();
+ if (arguments)
+ return arguments->SetArgs(args, eVarSetOperationAssign).Success();
+
+ OptionValueArray *array = value->GetAsArray();
+ if (array)
+ return array->SetArgs(args, eVarSetOperationAssign).Success();
+
+ OptionValueDictionary *dict = value->GetAsDictionary();
+ if (dict)
+ return dict->SetArgs(args, eVarSetOperationAssign).Success();
+
+ return false;
+}
+
+OptionValueDictionary *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary(
+ size_t idx, const ExecutionContext *exe_ctx) const {
+ const Property *property = GetPropertyAtIndex(idx, exe_ctx);
+ if (property)
+ return property->GetValue()->GetAsDictionary();
+ return nullptr;
+}
+
+OptionValueFileSpec *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec(
+ size_t idx, const ExecutionContext *exe_ctx) const {
+ const Property *property = GetPropertyAtIndex(idx, exe_ctx);
+ if (property) {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetAsFileSpec();
+ }
+ return nullptr;
+}
+
+OptionValueSInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64(
+ size_t idx, const ExecutionContext *exe_ctx) const {
+ const Property *property = GetPropertyAtIndex(idx, exe_ctx);
+ if (property) {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetAsSInt64();
+ }
+ return nullptr;
+}
+
+OptionValueUInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueUInt64(
+ size_t idx, const ExecutionContext *exe_ctx) const {
+ const Property *property = GetPropertyAtIndex(idx, exe_ctx);
+ if (property) {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetAsUInt64();
+ }
+ return nullptr;
+}
+
+OptionValueString *OptionValueProperties::GetPropertyAtIndexAsOptionValueString(
+ size_t idx, const ExecutionContext *exe_ctx) const {
+ OptionValueSP value_sp(GetPropertyValueAtIndex(idx, exe_ctx));
+ if (value_sp)
+ return value_sp->GetAsString();
+ return nullptr;
+}
+
+void OptionValueProperties::Clear() {
+ const size_t num_properties = m_properties.size();
+ for (size_t i = 0; i < num_properties; ++i)
+ m_properties[i].GetValue()->Clear();
+}
+
+Status OptionValueProperties::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+
+ // Args args(value_cstr);
+ // const size_t argc = args.GetArgumentCount();
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ case eVarSetOperationRemove:
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+
+ return error;
+}
+
+void OptionValueProperties::DumpValue(const ExecutionContext *exe_ctx,
+ Stream &strm, uint32_t dump_mask) {
+ const size_t num_properties = m_properties.size();
+ for (size_t i = 0; i < num_properties; ++i) {
+ const Property *property = GetPropertyAtIndex(i, exe_ctx);
+ if (property) {
+ OptionValue *option_value = property->GetValue().get();
+ assert(option_value);
+ const bool transparent_value = option_value->ValueIsTransparent();
+ property->Dump(exe_ctx, strm, dump_mask);
+ if (!transparent_value)
+ strm.EOL();
+ }
+ }
+}
+
+llvm::json::Value
+OptionValueProperties::ToJSON(const ExecutionContext *exe_ctx) {
+ llvm::json::Object json_properties;
+ const size_t num_properties = m_properties.size();
+ for (size_t i = 0; i < num_properties; ++i) {
+ const Property *property = GetPropertyAtIndex(i, exe_ctx);
+ if (property) {
+ OptionValue *option_value = property->GetValue().get();
+ assert(option_value);
+ json_properties.try_emplace(property->GetName(),
+ option_value->ToJSON(exe_ctx));
+ }
+ }
+ return json_properties;
+}
+
+Status OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx,
+ Stream &strm,
+ llvm::StringRef property_path,
+ uint32_t dump_mask,
+ bool is_json) {
+ Status error;
+ lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, property_path, error));
+ if (value_sp) {
+ if (!value_sp->ValueIsTransparent()) {
+ if (dump_mask & eDumpOptionName)
+ strm.PutCString(property_path);
+ if (dump_mask & ~eDumpOptionName)
+ strm.PutChar(' ');
+ }
+ if (is_json) {
+ strm.Printf(
+ "%s",
+ llvm::formatv("{0:2}", value_sp->ToJSON(exe_ctx)).str().c_str());
+ } else
+ value_sp->DumpValue(exe_ctx, strm, dump_mask);
+ }
+ return error;
+}
+
+OptionValuePropertiesSP
+OptionValueProperties::CreateLocalCopy(const Properties &global_properties) {
+ auto global_props_sp = global_properties.GetValueProperties();
+ lldbassert(global_props_sp);
+
+ auto copy_sp = global_props_sp->DeepCopy(global_props_sp->GetParent());
+ return std::static_pointer_cast<OptionValueProperties>(copy_sp);
+}
+
+OptionValueSP
+OptionValueProperties::DeepCopy(const OptionValueSP &new_parent) const {
+ auto copy_sp = OptionValue::DeepCopy(new_parent);
+ // copy_sp->GetAsProperties cannot be used here as it doesn't work for derived
+ // types that override GetType returning a different value.
+ auto *props_value_ptr = static_cast<OptionValueProperties *>(copy_sp.get());
+ lldbassert(props_value_ptr);
+
+ for (auto &property : props_value_ptr->m_properties) {
+ // Duplicate any values that are not global when constructing properties
+ // from a global copy.
+ if (!property.IsGlobal()) {
+ auto value_sp = property.GetValue()->DeepCopy(copy_sp);
+ property.SetOptionValue(value_sp);
+ }
+ }
+ return copy_sp;
+}
+
+const Property *
+OptionValueProperties::GetPropertyAtPath(const ExecutionContext *exe_ctx,
+ llvm::StringRef name) const {
+ if (name.empty())
+ return nullptr;
+
+ const Property *property = nullptr;
+ llvm::StringRef sub_name;
+ llvm::StringRef key;
+ size_t key_len = name.find_first_of(".[{");
+
+ if (key_len != llvm::StringRef::npos) {
+ key = name.take_front(key_len);
+ sub_name = name.drop_front(key_len);
+ } else
+ key = name;
+
+ property = GetProperty(key, exe_ctx);
+ if (sub_name.empty() || !property)
+ return property;
+
+ if (sub_name[0] == '.') {
+ OptionValueProperties *sub_properties =
+ property->GetValue()->GetAsProperties();
+ if (sub_properties)
+ return sub_properties->GetPropertyAtPath(exe_ctx, sub_name.drop_front());
+ }
+ return nullptr;
+}
+
+void OptionValueProperties::DumpAllDescriptions(CommandInterpreter &interpreter,
+ Stream &strm) const {
+ size_t max_name_len = 0;
+ const size_t num_properties = m_properties.size();
+ for (size_t i = 0; i < num_properties; ++i) {
+ const Property *property = ProtectedGetPropertyAtIndex(i);
+ if (property)
+ max_name_len = std::max<size_t>(property->GetName().size(), max_name_len);
+ }
+ for (size_t i = 0; i < num_properties; ++i) {
+ const Property *property = ProtectedGetPropertyAtIndex(i);
+ if (property)
+ property->DumpDescription(interpreter, strm, max_name_len, false);
+ }
+}
+
+void OptionValueProperties::Apropos(
+ llvm::StringRef keyword,
+ std::vector<const Property *> &matching_properties) const {
+ const size_t num_properties = m_properties.size();
+ StreamString strm;
+ for (size_t i = 0; i < num_properties; ++i) {
+ const Property *property = ProtectedGetPropertyAtIndex(i);
+ if (property) {
+ const OptionValueProperties *properties =
+ property->GetValue()->GetAsProperties();
+ if (properties) {
+ properties->Apropos(keyword, matching_properties);
+ } else {
+ bool match = false;
+ llvm::StringRef name = property->GetName();
+ if (name.contains_insensitive(keyword))
+ match = true;
+ else {
+ llvm::StringRef desc = property->GetDescription();
+ if (desc.contains_insensitive(keyword))
+ match = true;
+ }
+ if (match) {
+ matching_properties.push_back(property);
+ }
+ }
+ }
+ }
+}
+
+lldb::OptionValuePropertiesSP
+OptionValueProperties::GetSubProperty(const ExecutionContext *exe_ctx,
+ llvm::StringRef name) {
+ lldb::OptionValueSP option_value_sp(GetValueForKey(exe_ctx, name));
+ if (option_value_sp) {
+ OptionValueProperties *ov_properties = option_value_sp->GetAsProperties();
+ if (ov_properties)
+ return ov_properties->shared_from_this();
+ }
+ return lldb::OptionValuePropertiesSP();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueRegex.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueRegex.cpp
new file mode 100644
index 000000000000..bbeca8da7714
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueRegex.cpp
@@ -0,0 +1,61 @@
+//===-- OptionValueRegex.cpp ----------------------------------------------===//
+//
+// 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/OptionValueRegex.h"
+
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueRegex::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
+ uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+ if (m_regex.IsValid()) {
+ llvm::StringRef regex_text = m_regex.GetText();
+ strm.Printf("%s", regex_text.str().c_str());
+ }
+ }
+}
+
+Status OptionValueRegex::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationInvalid:
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ 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 {
+ error.SetErrorString("regex error");
+ }
+ break;
+ }
+ return error;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueSInt64.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueSInt64.cpp
new file mode 100644
index 000000000000..c1db5056cd94
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueSInt64.cpp
@@ -0,0 +1,70 @@
+//===-- OptionValueSInt64.cpp ---------------------------------------------===//
+//
+// 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/OptionValueSInt64.h"
+
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueSInt64::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
+ uint32_t dump_mask) {
+ // printf ("%p: DumpValue (exe_ctx=%p, strm, mask) m_current_value = %"
+ // PRIi64
+ // "\n", this, exe_ctx, m_current_value);
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ // if (dump_mask & eDumpOptionName)
+ // DumpQualifiedName (strm);
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+ strm.Printf("%" PRIi64, m_current_value);
+ }
+}
+
+Status OptionValueSInt64::SetValueFromString(llvm::StringRef value_ref,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign: {
+ llvm::StringRef value_trimmed = value_ref.trim();
+ int64_t value;
+ if (llvm::to_integer(value_trimmed, value)) {
+ if (value >= m_min_value && value <= m_max_value) {
+ m_value_was_set = true;
+ m_current_value = value;
+ NotifyValueChanged();
+ } else
+ error.SetErrorStringWithFormat(
+ "%" PRIi64 " is out of range, valid values must be between %" PRIi64
+ " and %" PRIi64 ".",
+ value, m_min_value, m_max_value);
+ } else {
+ error.SetErrorStringWithFormat("invalid int64_t string value: '%s'",
+ value_ref.str().c_str());
+ }
+ } break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value_ref, op);
+ break;
+ }
+ return error;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueString.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueString.cpp
new file mode 100644
index 000000000000..b4fec91bc33f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueString.cpp
@@ -0,0 +1,143 @@
+//===-- OptionValueString.cpp ---------------------------------------------===//
+//
+// 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/OptionValueString.h"
+
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueString::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
+ uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+ if (!m_current_value.empty() || m_value_was_set) {
+ if (m_options.Test(eOptionEncodeCharacterEscapeSequences)) {
+ std::string expanded_escape_value;
+ Args::ExpandEscapedCharacters(m_current_value.c_str(),
+ expanded_escape_value);
+ if (dump_mask & eDumpOptionRaw)
+ strm.Printf("%s", expanded_escape_value.c_str());
+ else
+ strm.Printf("\"%s\"", expanded_escape_value.c_str());
+ } else {
+ if (dump_mask & eDumpOptionRaw)
+ strm.Printf("%s", m_current_value.c_str());
+ else
+ strm.Printf("\"%s\"", m_current_value.c_str());
+ }
+ }
+ }
+}
+
+Status OptionValueString::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+
+ std::string value_str = value.str();
+ value = value.trim();
+ if (value.size() > 0) {
+ switch (value.front()) {
+ case '"':
+ case '\'': {
+ if (value.size() <= 1 || value.back() != value.front()) {
+ error.SetErrorString("mismatched quotes");
+ return error;
+ }
+ value = value.drop_front().drop_back();
+ } break;
+ }
+ value_str = value.str();
+ }
+
+ switch (op) {
+ case eVarSetOperationInvalid:
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ if (m_validator) {
+ error = m_validator(value_str.c_str(), m_validator_baton);
+ if (error.Fail())
+ return error;
+ }
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+
+ case eVarSetOperationAppend: {
+ std::string new_value(m_current_value);
+ if (value.size() > 0) {
+ if (m_options.Test(eOptionEncodeCharacterEscapeSequences)) {
+ std::string str;
+ Args::EncodeEscapeSequences(value_str.c_str(), str);
+ new_value.append(str);
+ } else
+ new_value.append(std::string(value));
+ }
+ if (m_validator) {
+ error = m_validator(new_value.c_str(), m_validator_baton);
+ if (error.Fail())
+ return error;
+ }
+ m_current_value.assign(new_value);
+ NotifyValueChanged();
+ } break;
+
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ if (m_validator) {
+ error = m_validator(value_str.c_str(), m_validator_baton);
+ if (error.Fail())
+ return error;
+ }
+ m_value_was_set = true;
+ if (m_options.Test(eOptionEncodeCharacterEscapeSequences)) {
+ Args::EncodeEscapeSequences(value_str.c_str(), m_current_value);
+ } else {
+ SetCurrentValue(value_str);
+ }
+ NotifyValueChanged();
+ break;
+ }
+ return error;
+}
+
+Status OptionValueString::SetCurrentValue(llvm::StringRef value) {
+ if (m_validator) {
+ Status error(m_validator(value.str().c_str(), m_validator_baton));
+ if (error.Fail())
+ return error;
+ }
+ m_current_value.assign(std::string(value));
+ return Status();
+}
+
+Status OptionValueString::AppendToCurrentValue(const char *value) {
+ if (value && value[0]) {
+ if (m_validator) {
+ std::string new_value(m_current_value);
+ new_value.append(value);
+ Status error(m_validator(value, m_validator_baton));
+ if (error.Fail())
+ return error;
+ m_current_value.assign(new_value);
+ } else
+ m_current_value.append(value);
+ }
+ return Status();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueUInt64.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueUInt64.cpp
new file mode 100644
index 000000000000..2e69c164e32a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueUInt64.cpp
@@ -0,0 +1,75 @@
+//===-- OptionValueUInt64.cpp ---------------------------------------------===//
+//
+// 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/OptionValueUInt64.h"
+
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+lldb::OptionValueSP OptionValueUInt64::Create(llvm::StringRef value_str,
+ Status &error) {
+ lldb::OptionValueSP value_sp(new OptionValueUInt64());
+ error = value_sp->SetValueFromString(value_str);
+ if (error.Fail())
+ value_sp.reset();
+ return value_sp;
+}
+
+void OptionValueUInt64::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
+ uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+ strm.Printf("%" PRIu64, m_current_value);
+ }
+}
+
+Status OptionValueUInt64::SetValueFromString(llvm::StringRef value_ref,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign: {
+ llvm::StringRef value_trimmed = value_ref.trim();
+ uint64_t value;
+ if (llvm::to_integer(value_trimmed, value)) {
+ if (value >= m_min_value && value <= m_max_value) {
+ m_value_was_set = true;
+ m_current_value = value;
+ NotifyValueChanged();
+ } else {
+ error.SetErrorStringWithFormat(
+ "%" PRIu64 " is out of range, valid values must be between %" PRIu64
+ " and %" PRIu64 ".",
+ value, m_min_value, m_max_value);
+ }
+ } else {
+ error.SetErrorStringWithFormat("invalid uint64_t string value: '%s'",
+ value_ref.str().c_str());
+ }
+ } break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value_ref, op);
+ break;
+ }
+ return error;
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueUUID.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueUUID.cpp
new file mode 100644
index 000000000000..ff35870a76e8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueUUID.cpp
@@ -0,0 +1,81 @@
+//===-- OptionValueUUID.cpp -----------------------------------------------===//
+//
+// 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/OptionValueUUID.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void OptionValueUUID::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
+ uint32_t dump_mask) {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf("(%s)", GetTypeAsCString());
+ if (dump_mask & eDumpOptionValue) {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString(" = ");
+ m_uuid.Dump(strm);
+ }
+}
+
+Status OptionValueUUID::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
+ switch (op) {
+ case eVarSetOperationClear:
+ Clear();
+ NotifyValueChanged();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign: {
+ if (!m_uuid.SetFromStringRef(value))
+ error.SetErrorStringWithFormat("invalid uuid string value '%s'",
+ value.str().c_str());
+ else {
+ m_value_was_set = true;
+ NotifyValueChanged();
+ }
+ } break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromString(value, op);
+ break;
+ }
+ return error;
+}
+
+void OptionValueUUID::AutoComplete(CommandInterpreter &interpreter,
+ CompletionRequest &request) {
+ ExecutionContext exe_ctx(interpreter.GetExecutionContext());
+ Target *target = exe_ctx.GetTargetPtr();
+ 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());
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/Options.cpp b/contrib/llvm-project/lldb/source/Interpreter/Options.cpp
new file mode 100644
index 000000000000..c5e75e0b9dce
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/Options.cpp
@@ -0,0 +1,1364 @@
+//===-- Options.cpp -------------------------------------------------------===//
+//
+// 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/Options.h"
+
+#include <algorithm>
+#include <bitset>
+#include <map>
+#include <set>
+
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Options
+Options::Options() { BuildValidOptionSets(); }
+
+Options::~Options() = default;
+
+void Options::NotifyOptionParsingStarting(ExecutionContext *execution_context) {
+ m_seen_options.clear();
+ // Let the subclass reset its option values
+ OptionParsingStarting(execution_context);
+}
+
+Status
+Options::NotifyOptionParsingFinished(ExecutionContext *execution_context) {
+ return OptionParsingFinished(execution_context);
+}
+
+void Options::OptionSeen(int option_idx) { m_seen_options.insert(option_idx); }
+
+// Returns true is set_a is a subset of set_b; Otherwise returns false.
+
+bool Options::IsASubset(const OptionSet &set_a, const OptionSet &set_b) {
+ bool is_a_subset = true;
+ OptionSet::const_iterator pos_a;
+ OptionSet::const_iterator pos_b;
+
+ // set_a is a subset of set_b if every member of set_a is also a member of
+ // set_b
+
+ for (pos_a = set_a.begin(); pos_a != set_a.end() && is_a_subset; ++pos_a) {
+ pos_b = set_b.find(*pos_a);
+ if (pos_b == set_b.end())
+ is_a_subset = false;
+ }
+
+ return is_a_subset;
+}
+
+// Returns the set difference set_a - set_b, i.e. { x | ElementOf (x, set_a) &&
+// !ElementOf (x, set_b) }
+
+size_t Options::OptionsSetDiff(const OptionSet &set_a, const OptionSet &set_b,
+ OptionSet &diffs) {
+ size_t num_diffs = 0;
+ OptionSet::const_iterator pos_a;
+ OptionSet::const_iterator pos_b;
+
+ for (pos_a = set_a.begin(); pos_a != set_a.end(); ++pos_a) {
+ pos_b = set_b.find(*pos_a);
+ if (pos_b == set_b.end()) {
+ ++num_diffs;
+ diffs.insert(*pos_a);
+ }
+ }
+
+ return num_diffs;
+}
+
+// Returns the union of set_a and set_b. Does not put duplicate members into
+// the union.
+
+void Options::OptionsSetUnion(const OptionSet &set_a, const OptionSet &set_b,
+ OptionSet &union_set) {
+ OptionSet::const_iterator pos;
+ OptionSet::iterator pos_union;
+
+ // Put all the elements of set_a into the union.
+
+ for (pos = set_a.begin(); pos != set_a.end(); ++pos)
+ union_set.insert(*pos);
+
+ // Put all the elements of set_b that are not already there into the union.
+ for (pos = set_b.begin(); pos != set_b.end(); ++pos) {
+ pos_union = union_set.find(*pos);
+ if (pos_union == union_set.end())
+ union_set.insert(*pos);
+ }
+}
+
+bool Options::VerifyOptions(CommandReturnObject &result) {
+ bool options_are_valid = false;
+
+ int num_levels = GetRequiredOptions().size();
+ if (num_levels) {
+ for (int i = 0; i < num_levels && !options_are_valid; ++i) {
+ // This is the correct set of options if: 1). m_seen_options contains
+ // all of m_required_options[i] (i.e. all the required options at this
+ // level are a subset of m_seen_options); AND 2). { m_seen_options -
+ // m_required_options[i] is a subset of m_options_options[i] (i.e. all
+ // the rest of m_seen_options are in the set of optional options at this
+ // level.
+
+ // Check to see if all of m_required_options[i] are a subset of
+ // m_seen_options
+ if (IsASubset(GetRequiredOptions()[i], m_seen_options)) {
+ // Construct the set difference: remaining_options = {m_seen_options} -
+ // {m_required_options[i]}
+ OptionSet remaining_options;
+ OptionsSetDiff(m_seen_options, GetRequiredOptions()[i],
+ remaining_options);
+ // Check to see if remaining_options is a subset of
+ // m_optional_options[i]
+ if (IsASubset(remaining_options, GetOptionalOptions()[i]))
+ options_are_valid = true;
+ }
+ }
+ } else {
+ options_are_valid = true;
+ }
+
+ if (options_are_valid) {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ } else {
+ result.AppendError("invalid combination of options for the given command");
+ }
+
+ return options_are_valid;
+}
+
+// This is called in the Options constructor, though we could call it lazily if
+// that ends up being a performance problem.
+
+void Options::BuildValidOptionSets() {
+ // Check to see if we already did this.
+ if (m_required_options.size() != 0)
+ return;
+
+ // Check to see if there are any options.
+ int num_options = NumCommandOptions();
+ if (num_options == 0)
+ return;
+
+ auto opt_defs = GetDefinitions();
+ m_required_options.resize(1);
+ m_optional_options.resize(1);
+
+ // First count the number of option sets we've got. Ignore
+ // LLDB_ALL_OPTION_SETS...
+
+ uint32_t num_option_sets = 0;
+
+ for (const auto &def : opt_defs) {
+ uint32_t this_usage_mask = def.usage_mask;
+ if (this_usage_mask == LLDB_OPT_SET_ALL) {
+ if (num_option_sets == 0)
+ num_option_sets = 1;
+ } else {
+ for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) {
+ if (this_usage_mask & (1 << j)) {
+ if (num_option_sets <= j)
+ num_option_sets = j + 1;
+ }
+ }
+ }
+ }
+
+ if (num_option_sets > 0) {
+ m_required_options.resize(num_option_sets);
+ m_optional_options.resize(num_option_sets);
+
+ for (const auto &def : opt_defs) {
+ for (uint32_t j = 0; j < num_option_sets; j++) {
+ if (def.usage_mask & 1 << j) {
+ if (def.required)
+ m_required_options[j].insert(def.short_option);
+ else
+ m_optional_options[j].insert(def.short_option);
+ }
+ }
+ }
+ }
+}
+
+uint32_t Options::NumCommandOptions() { return GetDefinitions().size(); }
+
+Option *Options::GetLongOptions() {
+ // Check to see if this has already been done.
+ if (m_getopt_table.empty()) {
+ auto defs = GetDefinitions();
+ if (defs.empty())
+ return nullptr;
+
+ std::map<int, uint32_t> option_seen;
+
+ m_getopt_table.resize(defs.size() + 1);
+ for (size_t i = 0; i < defs.size(); ++i) {
+ const int short_opt = defs[i].short_option;
+
+ m_getopt_table[i].definition = &defs[i];
+ m_getopt_table[i].flag = nullptr;
+ m_getopt_table[i].val = short_opt;
+
+ if (option_seen.find(short_opt) == option_seen.end()) {
+ option_seen[short_opt] = i;
+ } else if (short_opt) {
+ m_getopt_table[i].val = 0;
+ std::map<int, uint32_t>::const_iterator pos =
+ option_seen.find(short_opt);
+ StreamString strm;
+ if (defs[i].HasShortOption())
+ Debugger::ReportError(
+ llvm::formatv(
+ "option[{0}] --{1} has a short option -{2} that "
+ "conflicts with option[{3}] --{4}, short option won't "
+ "be used for --{5}",
+ i, defs[i].long_option, short_opt, pos->second,
+ m_getopt_table[pos->second].definition->long_option,
+ defs[i].long_option)
+ .str());
+ else
+ Debugger::ReportError(
+ llvm::formatv(
+ "option[{0}] --{1} has a short option {2:x} that "
+ "conflicts with option[{3}] --{4}, short option won't "
+ "be used for --{5}",
+ (int)i, defs[i].long_option, short_opt, pos->second,
+ m_getopt_table[pos->second].definition->long_option,
+ defs[i].long_option)
+ .str());
+ }
+ }
+
+ // getopt_long_only requires a NULL final entry in the table:
+
+ m_getopt_table.back().definition = nullptr;
+ m_getopt_table.back().flag = nullptr;
+ m_getopt_table.back().val = 0;
+ }
+
+ if (m_getopt_table.empty())
+ return nullptr;
+
+ return &m_getopt_table.front();
+}
+
+// This function takes INDENT, which tells how many spaces to output at the
+// front of each line; SPACES, which is a string containing 80 spaces; and
+// TEXT, which is the text that is to be output. It outputs the text, on
+// multiple lines if necessary, to RESULT, with INDENT spaces at the front of
+// each line. It breaks lines on spaces, tabs or newlines, shortening the line
+// if necessary to not break in the middle of a word. It assumes that each
+// output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
+
+void Options::OutputFormattedUsageText(Stream &strm,
+ const OptionDefinition &option_def,
+ uint32_t output_max_columns) {
+ std::string actual_text;
+ if (option_def.validator) {
+ const char *condition = option_def.validator->ShortConditionString();
+ if (condition) {
+ actual_text = "[";
+ actual_text.append(condition);
+ actual_text.append("] ");
+ }
+ }
+ actual_text.append(option_def.usage_text);
+
+ // Will it all fit on one line?
+
+ if (static_cast<uint32_t>(actual_text.length() + strm.GetIndentLevel()) <
+ output_max_columns) {
+ // Output it as a single line.
+ strm.Indent(actual_text);
+ strm.EOL();
+ } else {
+ // We need to break it up into multiple lines.
+
+ int text_width = output_max_columns - strm.GetIndentLevel() - 1;
+ int start = 0;
+ int end = start;
+ int final_end = actual_text.length();
+ int sub_len;
+
+ while (end < final_end) {
+ // Don't start the 'text' on a space, since we're already outputting the
+ // indentation.
+ while ((start < final_end) && (actual_text[start] == ' '))
+ start++;
+
+ end = start + text_width;
+ if (end > final_end)
+ end = final_end;
+ else {
+ // If we're not at the end of the text, make sure we break the line on
+ // white space.
+ while (end > start && actual_text[end] != ' ' &&
+ actual_text[end] != '\t' && actual_text[end] != '\n')
+ end--;
+ }
+
+ sub_len = end - start;
+ if (start != 0)
+ strm.EOL();
+ strm.Indent();
+ assert(start < final_end);
+ assert(start + sub_len <= final_end);
+ strm.Write(actual_text.c_str() + start, sub_len);
+ start = end + 1;
+ }
+ strm.EOL();
+ }
+}
+
+bool Options::SupportsLongOption(const char *long_option) {
+ if (!long_option || !long_option[0])
+ return false;
+
+ auto opt_defs = GetDefinitions();
+ if (opt_defs.empty())
+ return false;
+
+ const char *long_option_name = long_option;
+ if (long_option[0] == '-' && long_option[1] == '-')
+ long_option_name += 2;
+
+ for (auto &def : opt_defs) {
+ if (!def.long_option)
+ continue;
+
+ if (strcmp(def.long_option, long_option_name) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+enum OptionDisplayType {
+ eDisplayBestOption,
+ eDisplayShortOption,
+ eDisplayLongOption
+};
+
+static bool PrintOption(const OptionDefinition &opt_def,
+ OptionDisplayType display_type, const char *header,
+ const char *footer, bool show_optional, Stream &strm) {
+ if (display_type == eDisplayShortOption && !opt_def.HasShortOption())
+ return false;
+
+ if (header && header[0])
+ strm.PutCString(header);
+
+ if (show_optional && !opt_def.required)
+ strm.PutChar('[');
+ const bool show_short_option =
+ opt_def.HasShortOption() && display_type != eDisplayLongOption;
+ if (show_short_option)
+ strm.Printf("-%c", opt_def.short_option);
+ else
+ strm.Printf("--%s", opt_def.long_option);
+ switch (opt_def.option_has_arg) {
+ case OptionParser::eNoArgument:
+ break;
+ case OptionParser::eRequiredArgument:
+ strm.Printf(" <%s>", CommandObject::GetArgumentName(opt_def.argument_type));
+ break;
+
+ case OptionParser::eOptionalArgument:
+ strm.Printf("%s[<%s>]", show_short_option ? "" : "=",
+ CommandObject::GetArgumentName(opt_def.argument_type));
+ break;
+ }
+ if (show_optional && !opt_def.required)
+ strm.PutChar(']');
+ if (footer && footer[0])
+ strm.PutCString(footer);
+ return true;
+}
+
+void Options::GenerateOptionUsage(Stream &strm, CommandObject &cmd,
+ uint32_t screen_width) {
+ auto opt_defs = GetDefinitions();
+ const uint32_t save_indent_level = strm.GetIndentLevel();
+ llvm::StringRef name = cmd.GetCommandName();
+ StreamString arguments_str;
+ cmd.GetFormattedCommandArguments(arguments_str);
+
+ const uint32_t num_options = NumCommandOptions();
+ if (num_options == 0)
+ return;
+
+ const bool only_print_args = cmd.IsDashDashCommand();
+ if (!only_print_args)
+ strm.PutCString("\nCommand Options Usage:\n");
+
+ strm.IndentMore(2);
+
+ // First, show each usage level set of options, e.g. <cmd> [options-for-
+ // level-0]
+ // <cmd>
+ // [options-for-level-1]
+ // etc.
+
+ if (!only_print_args) {
+ uint32_t num_option_sets = GetRequiredOptions().size();
+ for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set) {
+ if (opt_set > 0)
+ strm.Printf("\n");
+ strm.Indent(name);
+
+ // Different option sets may require different args.
+ StreamString args_str;
+ uint32_t opt_set_mask = 1 << opt_set;
+ cmd.GetFormattedCommandArguments(args_str, opt_set_mask);
+
+ // First go through and print all options that take no arguments as a
+ // single string. If a command has "-a" "-b" and "-c", this will show up
+ // as [-abc]
+
+ // We use a set here so that they will be sorted.
+ std::set<int> required_options;
+ std::set<int> optional_options;
+
+ for (auto &def : opt_defs) {
+ if (def.usage_mask & opt_set_mask && def.HasShortOption() &&
+ def.option_has_arg == OptionParser::eNoArgument) {
+ if (def.required) {
+ required_options.insert(def.short_option);
+ } else {
+ optional_options.insert(def.short_option);
+ }
+ }
+ }
+
+ if (!required_options.empty()) {
+ strm.PutCString(" -");
+ for (int short_option : required_options)
+ strm.PutChar(short_option);
+ }
+
+ if (!optional_options.empty()) {
+ strm.PutCString(" [-");
+ for (int short_option : optional_options)
+ strm.PutChar(short_option);
+ strm.PutChar(']');
+ }
+
+ // First go through and print the required options (list them up front).
+ for (auto &def : opt_defs) {
+ if (def.usage_mask & opt_set_mask && def.HasShortOption() &&
+ def.required && def.option_has_arg != OptionParser::eNoArgument)
+ PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm);
+ }
+
+ // Now go through again, and this time only print the optional options.
+ for (auto &def : opt_defs) {
+ if (def.usage_mask & opt_set_mask && !def.required &&
+ def.option_has_arg != OptionParser::eNoArgument)
+ PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm);
+ }
+
+ if (args_str.GetSize() > 0) {
+ if (cmd.WantsRawCommandString())
+ strm.Printf(" --");
+ strm << " " << args_str.GetString();
+ }
+ }
+ }
+
+ if ((only_print_args || cmd.WantsRawCommandString()) &&
+ arguments_str.GetSize() > 0) {
+ if (!only_print_args)
+ strm.PutChar('\n');
+ strm.Indent(name);
+ strm << " " << arguments_str.GetString();
+ }
+
+ if (!only_print_args) {
+ strm.Printf("\n\n");
+
+ // Now print out all the detailed information about the various options:
+ // long form, short form and help text:
+ // -short <argument> ( --long_name <argument> )
+ // help text
+
+ strm.IndentMore(5);
+
+ // Put the command options in a sorted container, so we can output
+ // them alphabetically by short_option.
+ std::multimap<int, uint32_t> options_ordered;
+ for (auto def : llvm::enumerate(opt_defs))
+ options_ordered.insert(
+ std::make_pair(def.value().short_option, def.index()));
+
+ // Go through each option, find the table entry and write out the detailed
+ // help information for that option.
+
+ bool first_option_printed = false;
+
+ for (auto pos : options_ordered) {
+ // Put a newline separation between arguments
+ if (first_option_printed)
+ strm.EOL();
+ else
+ first_option_printed = true;
+
+ OptionDefinition opt_def = opt_defs[pos.second];
+
+ strm.Indent();
+ if (opt_def.short_option && opt_def.HasShortOption()) {
+ PrintOption(opt_def, eDisplayShortOption, nullptr, nullptr, false,
+ strm);
+ PrintOption(opt_def, eDisplayLongOption, " ( ", " )", false, strm);
+ } else {
+ // Short option is not printable, just print long option
+ PrintOption(opt_def, eDisplayLongOption, nullptr, nullptr, false, strm);
+ }
+ strm.EOL();
+
+ strm.IndentMore(5);
+
+ if (opt_def.usage_text)
+ OutputFormattedUsageText(strm, opt_def, screen_width);
+ if (!opt_def.enum_values.empty()) {
+ strm.Indent();
+ strm.Printf("Values: ");
+ bool is_first = true;
+ for (const auto &enum_value : opt_def.enum_values) {
+ if (is_first) {
+ strm.Printf("%s", enum_value.string_value);
+ is_first = false;
+ }
+ else
+ strm.Printf(" | %s", enum_value.string_value);
+ }
+ strm.EOL();
+ }
+ strm.IndentLess(5);
+ }
+ }
+
+ // Restore the indent level
+ strm.SetIndentLevel(save_indent_level);
+}
+
+// This function is called when we have been given a potentially incomplete set
+// of options, such as when an alias has been defined (more options might be
+// added at at the time the alias is invoked). We need to verify that the
+// options in the set m_seen_options are all part of a set that may be used
+// together, but m_seen_options may be missing some of the "required" options.
+
+bool Options::VerifyPartialOptions(CommandReturnObject &result) {
+ bool options_are_valid = false;
+
+ int num_levels = GetRequiredOptions().size();
+ if (num_levels) {
+ for (int i = 0; i < num_levels && !options_are_valid; ++i) {
+ // In this case we are treating all options as optional rather than
+ // required. Therefore a set of options is correct if m_seen_options is a
+ // subset of the union of m_required_options and m_optional_options.
+ OptionSet union_set;
+ OptionsSetUnion(GetRequiredOptions()[i], GetOptionalOptions()[i],
+ union_set);
+ if (IsASubset(m_seen_options, union_set))
+ options_are_valid = true;
+ }
+ }
+
+ return options_are_valid;
+}
+
+bool Options::HandleOptionCompletion(CompletionRequest &request,
+ OptionElementVector &opt_element_vector,
+ CommandInterpreter &interpreter) {
+ // 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
+ // want.
+
+ auto opt_defs = GetDefinitions();
+
+ llvm::StringRef cur_opt_str = request.GetCursorArgumentPrefix();
+
+ for (size_t i = 0; i < opt_element_vector.size(); i++) {
+ 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.
+
+ if (opt_defs_index == OptionArgElement::eBareDash) {
+ // We're completing a bare dash. That means all options are open.
+ // FIXME: We should scan the other options provided and only complete
+ // options
+ // within the option group they belong to.
+ 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, def.usage_text);
+ }
+
+ return true;
+ } else if (opt_defs_index == OptionArgElement::eBareDoubleDash) {
+ std::string full_name("--");
+ for (auto &def : opt_defs) {
+ if (!def.short_option)
+ continue;
+
+ full_name.erase(full_name.begin() + 2, full_name.end());
+ full_name.append(def.long_option);
+ request.AddCompletion(full_name, def.usage_text);
+ }
+ return true;
+ } else if (opt_defs_index != OptionArgElement::eUnrecognizedArg) {
+ // We recognized it, if it an incomplete long option, complete it
+ // 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 " ".
+ const OptionDefinition &opt = opt_defs[opt_defs_index];
+ llvm::StringRef long_option = opt.long_option;
+ if (cur_opt_str.starts_with("--") && 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.
+ // I think we will only get in here if the long option table has two
+ // elements
+ // that are not unique up to this point. getopt_long_only does
+ // shortest unique match for long options already.
+ if (cur_opt_str.consume_front("--")) {
+ for (auto &def : opt_defs) {
+ llvm::StringRef long_option(def.long_option);
+ if (long_option.starts_with(cur_opt_str))
+ request.AddCompletion("--" + long_option.str(), def.usage_text);
+ }
+ }
+ return true;
+ }
+
+ } 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.
+ if (opt_defs_index != -1) {
+ HandleOptionArgumentCompletion(request, opt_element_vector, i,
+ interpreter);
+ return true;
+ } else {
+ // No completion callback means no completions...
+ return true;
+ }
+
+ } else {
+ // Not the last element, keep going.
+ continue;
+ }
+ }
+ return false;
+}
+
+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_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())
+ 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
+ // that shared library.
+ // FIXME: Do we want to also have an "OptionType" so we don't have to match
+ // string names?
+
+ uint32_t completion_mask = opt_defs[opt_defs_index].completion_type;
+
+ if (completion_mask == 0) {
+ lldb::CommandArgumentType option_arg_type =
+ opt_defs[opt_defs_index].argument_type;
+ if (option_arg_type != eArgTypeNone) {
+ const CommandObject::ArgumentTableEntry *arg_entry =
+ CommandObject::FindArgumentDataByType(
+ opt_defs[opt_defs_index].argument_type);
+ if (arg_entry)
+ completion_mask = arg_entry->completion_type;
+ }
+ }
+
+ if (completion_mask & lldb::eSourceFileCompletion ||
+ completion_mask & lldb::eSymbolCompletion) {
+ for (size_t i = 0; i < opt_element_vector.size(); i++) {
+ int cur_defs_index = opt_element_vector[i].opt_defs_index;
+
+ // trying to use <0 indices will definitely cause problems
+ if (cur_defs_index == OptionArgElement::eUnrecognizedArg ||
+ cur_defs_index == OptionArgElement::eBareDash ||
+ cur_defs_index == OptionArgElement::eBareDoubleDash)
+ continue;
+
+ int cur_arg_pos = opt_element_vector[i].opt_arg_pos;
+ const char *cur_opt_name = opt_defs[cur_defs_index].long_option;
+
+ // If this is the "shlib" option and there was an argument provided,
+ // restrict it to that shared library.
+ if (cur_opt_name && strcmp(cur_opt_name, "shlib") == 0 &&
+ cur_arg_pos != -1) {
+ const char *module_name =
+ request.GetParsedLine().GetArgumentAtIndex(cur_arg_pos);
+ if (module_name) {
+ FileSpec module_spec(module_name);
+ lldb::TargetSP target_sp =
+ interpreter.GetDebugger().GetSelectedTarget();
+ // Search filters require a target...
+ if (target_sp)
+ filter_up =
+ std::make_unique<SearchFilterByModule>(target_sp, module_spec);
+ }
+ break;
+ }
+ }
+ }
+
+ lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
+ interpreter, completion_mask, request, filter_up.get());
+}
+
+void OptionGroupOptions::Append(OptionGroup *group) {
+ auto group_option_defs = group->GetDefinitions();
+ for (uint32_t i = 0; i < group_option_defs.size(); ++i) {
+ m_option_infos.push_back(OptionInfo(group, i));
+ m_option_defs.push_back(group_option_defs[i]);
+ }
+}
+
+const OptionGroup *OptionGroupOptions::GetGroupWithOption(char short_opt) {
+ for (uint32_t i = 0; i < m_option_defs.size(); i++) {
+ OptionDefinition opt_def = m_option_defs[i];
+ if (opt_def.short_option == short_opt)
+ return m_option_infos[i].option_group;
+ }
+ return nullptr;
+}
+
+void OptionGroupOptions::Append(OptionGroup *group, uint32_t src_mask,
+ uint32_t dst_mask) {
+ auto group_option_defs = group->GetDefinitions();
+ for (uint32_t i = 0; i < group_option_defs.size(); ++i) {
+ if (group_option_defs[i].usage_mask & src_mask) {
+ m_option_infos.push_back(OptionInfo(group, i));
+ m_option_defs.push_back(group_option_defs[i]);
+ m_option_defs.back().usage_mask = dst_mask;
+ }
+ }
+}
+
+void OptionGroupOptions::Append(
+ OptionGroup *group, llvm::ArrayRef<llvm::StringRef> exclude_long_options) {
+ auto group_option_defs = group->GetDefinitions();
+ for (uint32_t i = 0; i < group_option_defs.size(); ++i) {
+ const auto &definition = group_option_defs[i];
+ if (llvm::is_contained(exclude_long_options, definition.long_option))
+ continue;
+
+ m_option_infos.push_back(OptionInfo(group, i));
+ m_option_defs.push_back(definition);
+ }
+}
+
+void OptionGroupOptions::Finalize() {
+ m_did_finalize = true;
+}
+
+Status OptionGroupOptions::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_value,
+ ExecutionContext *execution_context) {
+ // After calling OptionGroupOptions::Append(...), you must finalize the
+ // groups by calling OptionGroupOptions::Finlize()
+ assert(m_did_finalize);
+ Status error;
+ if (option_idx < m_option_infos.size()) {
+ error = m_option_infos[option_idx].option_group->SetOptionValue(
+ m_option_infos[option_idx].option_index, option_value,
+ execution_context);
+
+ } else {
+ error.SetErrorString("invalid option index"); // Shouldn't happen...
+ }
+ return error;
+}
+
+void OptionGroupOptions::OptionParsingStarting(
+ ExecutionContext *execution_context) {
+ std::set<OptionGroup *> group_set;
+ OptionInfos::iterator pos, end = m_option_infos.end();
+ for (pos = m_option_infos.begin(); pos != end; ++pos) {
+ OptionGroup *group = pos->option_group;
+ if (group_set.find(group) == group_set.end()) {
+ group->OptionParsingStarting(execution_context);
+ group_set.insert(group);
+ }
+ }
+}
+Status
+OptionGroupOptions::OptionParsingFinished(ExecutionContext *execution_context) {
+ std::set<OptionGroup *> group_set;
+ Status error;
+ OptionInfos::iterator pos, end = m_option_infos.end();
+ for (pos = m_option_infos.begin(); pos != end; ++pos) {
+ OptionGroup *group = pos->option_group;
+ if (group_set.find(group) == group_set.end()) {
+ error = group->OptionParsingFinished(execution_context);
+ group_set.insert(group);
+ if (error.Fail())
+ return error;
+ }
+ }
+ return error;
+}
+
+// OptionParser permutes the arguments while processing them, so we create a
+// temporary array holding to avoid modification of the input arguments. The
+// options themselves are never modified, but the API expects a char * anyway,
+// hence the const_cast.
+static std::vector<char *> GetArgvForParsing(const Args &args) {
+ std::vector<char *> result;
+ // OptionParser always skips the first argument as it is based on getopt().
+ result.push_back(const_cast<char *>("<FAKE-ARG0>"));
+ for (const Args::ArgEntry &entry : args)
+ result.push_back(const_cast<char *>(entry.c_str()));
+ result.push_back(nullptr);
+ return result;
+}
+
+// Given a permuted argument, find it's position in the original Args vector.
+static Args::const_iterator FindOriginalIter(const char *arg,
+ const Args &original) {
+ return llvm::find_if(
+ original, [arg](const Args::ArgEntry &D) { return D.c_str() == arg; });
+}
+
+// Given a permuted argument, find it's index in the original Args vector.
+static size_t FindOriginalIndex(const char *arg, const Args &original) {
+ return std::distance(original.begin(), FindOriginalIter(arg, original));
+}
+
+// Construct a new Args object, consisting of the entries from the original
+// arguments, but in the permuted order.
+static Args ReconstituteArgsAfterParsing(llvm::ArrayRef<char *> parsed,
+ const Args &original) {
+ Args result;
+ for (const char *arg : parsed) {
+ auto pos = FindOriginalIter(arg, original);
+ assert(pos != original.end());
+ result.AppendArgument(pos->ref(), pos->GetQuoteChar());
+ }
+ return result;
+}
+
+static size_t FindArgumentIndexForOption(const Args &args,
+ const Option &long_option) {
+ std::string short_opt = llvm::formatv("-{0}", char(long_option.val)).str();
+ std::string long_opt =
+ std::string(llvm::formatv("--{0}", long_option.definition->long_option));
+ for (const auto &entry : llvm::enumerate(args)) {
+ if (entry.value().ref().starts_with(short_opt) ||
+ entry.value().ref().starts_with(long_opt))
+ return entry.index();
+ }
+
+ return size_t(-1);
+}
+
+static std::string BuildShortOptions(const Option *long_options) {
+ std::string storage;
+ llvm::raw_string_ostream sstr(storage);
+
+ // Leading : tells getopt to return a : for a missing option argument AND to
+ // suppress error messages.
+ sstr << ":";
+
+ for (size_t i = 0; long_options[i].definition != nullptr; ++i) {
+ if (long_options[i].flag == nullptr) {
+ sstr << (char)long_options[i].val;
+ switch (long_options[i].definition->option_has_arg) {
+ default:
+ case OptionParser::eNoArgument:
+ break;
+ case OptionParser::eRequiredArgument:
+ sstr << ":";
+ break;
+ case OptionParser::eOptionalArgument:
+ sstr << "::";
+ break;
+ }
+ }
+ }
+ return std::move(sstr.str());
+}
+
+llvm::Expected<Args> Options::ParseAlias(const Args &args,
+ OptionArgVector *option_arg_vector,
+ std::string &input_line) {
+ Option *long_options = GetLongOptions();
+
+ if (long_options == nullptr) {
+ return llvm::createStringError("Invalid long options");
+ }
+
+ std::string short_options = BuildShortOptions(long_options);
+
+ Args args_copy = args;
+ std::vector<char *> argv = GetArgvForParsing(args);
+
+ std::unique_lock<std::mutex> lock;
+ OptionParser::Prepare(lock);
+ int val;
+ while (true) {
+ int long_options_index = -1;
+ val = OptionParser::Parse(argv, short_options, long_options,
+ &long_options_index);
+
+ if (val == ':') {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "last option requires an argument");
+ }
+
+ if (val == -1)
+ break;
+
+ if (val == '?') {
+ return llvm::createStringError("Unknown or ambiguous option");
+ }
+
+ if (val == 0)
+ continue;
+
+ OptionSeen(val);
+
+ // Look up the long option index
+ if (long_options_index == -1) {
+ for (int j = 0; long_options[j].definition || long_options[j].flag ||
+ long_options[j].val;
+ ++j) {
+ if (long_options[j].val == val) {
+ long_options_index = j;
+ break;
+ }
+ }
+ }
+
+ // See if the option takes an argument, and see if one was supplied.
+ if (long_options_index == -1) {
+ return llvm::createStringError(
+ llvm::formatv("Invalid option with value '{0}'.", char(val)).str());
+ }
+
+ StreamString option_str;
+ option_str.Printf("-%c", val);
+ const OptionDefinition *def = long_options[long_options_index].definition;
+ int has_arg =
+ (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
+
+ const char *option_arg = nullptr;
+ switch (has_arg) {
+ case OptionParser::eRequiredArgument:
+ if (OptionParser::GetOptionArgument() == nullptr) {
+ return llvm::createStringError(
+ llvm::formatv("Option '{0}' is missing argument specifier.",
+ option_str.GetString())
+ .str());
+ }
+ [[fallthrough]];
+ case OptionParser::eOptionalArgument:
+ option_arg = OptionParser::GetOptionArgument();
+ [[fallthrough]];
+ case OptionParser::eNoArgument:
+ break;
+ default:
+ return llvm::createStringError(
+ llvm::formatv("error with options table; invalid value in has_arg "
+ "field for option '{0}'.",
+ char(val))
+ .str());
+ }
+ // Find option in the argument list; also see if it was supposed to take an
+ // argument and if one was supplied. Remove option (and argument, if
+ // given) from the argument list. Also remove them from the
+ // raw_input_string, if one was passed in.
+ // Note: We also need to preserve any option argument values that were
+ // surrounded by backticks, as we lose track of them in the
+ // option_args_vector.
+ size_t idx =
+ FindArgumentIndexForOption(args_copy, long_options[long_options_index]);
+ std::string option_to_insert;
+ if (option_arg) {
+ if (idx != size_t(-1) && has_arg) {
+ bool arg_has_backtick = args_copy[idx + 1].GetQuoteChar() == '`';
+ if (arg_has_backtick)
+ option_to_insert = "`";
+ option_to_insert += option_arg;
+ if (arg_has_backtick)
+ option_to_insert += "`";
+ } else
+ option_to_insert = option_arg;
+ } else
+ option_to_insert = CommandInterpreter::g_no_argument;
+
+ option_arg_vector->emplace_back(std::string(option_str.GetString()),
+ has_arg, option_to_insert);
+
+ if (idx == size_t(-1))
+ continue;
+
+ if (!input_line.empty()) {
+ llvm::StringRef tmp_arg = args_copy[idx].ref();
+ size_t pos = input_line.find(std::string(tmp_arg));
+ if (pos != std::string::npos)
+ input_line.erase(pos, tmp_arg.size());
+ }
+ args_copy.DeleteArgumentAtIndex(idx);
+ if ((option_to_insert != CommandInterpreter::g_no_argument) &&
+ (OptionParser::GetOptionArgument() != nullptr) &&
+ (idx < args_copy.GetArgumentCount()) &&
+ (args_copy[idx].ref() == OptionParser::GetOptionArgument())) {
+ if (input_line.size() > 0) {
+ size_t pos = input_line.find(option_to_insert);
+ if (pos != std::string::npos)
+ input_line.erase(pos, option_to_insert.size());
+ }
+ args_copy.DeleteArgumentAtIndex(idx);
+ }
+ }
+
+ return std::move(args_copy);
+}
+
+OptionElementVector Options::ParseForCompletion(const Args &args,
+ uint32_t cursor_index) {
+ OptionElementVector option_element_vector;
+ Option *long_options = GetLongOptions();
+ option_element_vector.clear();
+
+ if (long_options == nullptr)
+ return option_element_vector;
+
+ std::string short_options = BuildShortOptions(long_options);
+
+ std::unique_lock<std::mutex> lock;
+ OptionParser::Prepare(lock);
+ OptionParser::EnableError(false);
+
+ int val;
+ auto opt_defs = GetDefinitions();
+
+ std::vector<char *> dummy_vec = GetArgvForParsing(args);
+
+ bool failed_once = false;
+ uint32_t dash_dash_pos = -1;
+
+ while (true) {
+ bool missing_argument = false;
+ int long_options_index = -1;
+
+ val = OptionParser::Parse(dummy_vec, short_options, long_options,
+ &long_options_index);
+
+ if (val == -1) {
+ // When we're completing a "--" which is the last option on line,
+ if (failed_once)
+ break;
+
+ failed_once = true;
+
+ // If this is a bare "--" we mark it as such so we can complete it
+ // successfully later. Handling the "--" is a little tricky, since that
+ // may mean end of options or arguments, or the user might want to
+ // complete options by long name. I make this work by checking whether
+ // the cursor is in the "--" argument, and if so I assume we're
+ // completing the long option, otherwise I let it pass to
+ // OptionParser::Parse which will terminate the option parsing. Note, in
+ // either case we continue parsing the line so we can figure out what
+ // other options were passed. This will be useful when we come to
+ // restricting completions based on what other options we've seen on the
+ // line.
+
+ if (static_cast<size_t>(OptionParser::GetOptionIndex()) <
+ dummy_vec.size() &&
+ (strcmp(dummy_vec[OptionParser::GetOptionIndex() - 1], "--") == 0)) {
+ dash_dash_pos = FindOriginalIndex(
+ dummy_vec[OptionParser::GetOptionIndex() - 1], args);
+ if (dash_dash_pos == cursor_index) {
+ option_element_vector.push_back(
+ OptionArgElement(OptionArgElement::eBareDoubleDash, dash_dash_pos,
+ OptionArgElement::eBareDoubleDash));
+ continue;
+ } else
+ break;
+ } else
+ break;
+ } else if (val == '?') {
+ option_element_vector.push_back(OptionArgElement(
+ OptionArgElement::eUnrecognizedArg,
+ FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
+ args),
+ OptionArgElement::eUnrecognizedArg));
+ continue;
+ } else if (val == 0) {
+ continue;
+ } else if (val == ':') {
+ // This is a missing argument.
+ val = OptionParser::GetOptionErrorCause();
+ missing_argument = true;
+ }
+
+ OptionSeen(val);
+
+ // Look up the long option index
+ if (long_options_index == -1) {
+ for (int j = 0; long_options[j].definition || long_options[j].flag ||
+ long_options[j].val;
+ ++j) {
+ if (long_options[j].val == val) {
+ long_options_index = j;
+ break;
+ }
+ }
+ }
+
+ // See if the option takes an argument, and see if one was supplied.
+ if (long_options_index >= 0) {
+ int opt_defs_index = -1;
+ for (size_t i = 0; i < opt_defs.size(); i++) {
+ if (opt_defs[i].short_option != val)
+ continue;
+ opt_defs_index = i;
+ break;
+ }
+
+ const OptionDefinition *def = long_options[long_options_index].definition;
+ int has_arg =
+ (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
+ switch (has_arg) {
+ case OptionParser::eNoArgument:
+ option_element_vector.push_back(OptionArgElement(
+ opt_defs_index,
+ FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
+ args),
+ 0));
+ break;
+ case OptionParser::eRequiredArgument:
+ if (OptionParser::GetOptionArgument() != nullptr) {
+ int arg_index;
+ if (missing_argument)
+ arg_index = -1;
+ else
+ arg_index = OptionParser::GetOptionIndex() - 2;
+
+ option_element_vector.push_back(OptionArgElement(
+ opt_defs_index,
+ FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],
+ args),
+ arg_index));
+ } else {
+ option_element_vector.push_back(OptionArgElement(
+ opt_defs_index,
+ FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
+ args),
+ -1));
+ }
+ break;
+ case OptionParser::eOptionalArgument:
+ option_element_vector.push_back(OptionArgElement(
+ opt_defs_index,
+ FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],
+ args),
+ FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
+ args)));
+ break;
+ default:
+ // The options table is messed up. Here we'll just continue
+ option_element_vector.push_back(OptionArgElement(
+ OptionArgElement::eUnrecognizedArg,
+ FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
+ args),
+ OptionArgElement::eUnrecognizedArg));
+ break;
+ }
+ } else {
+ option_element_vector.push_back(OptionArgElement(
+ OptionArgElement::eUnrecognizedArg,
+ FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
+ args),
+ OptionArgElement::eUnrecognizedArg));
+ }
+ }
+
+ // Finally we have to handle the case where the cursor index points at a
+ // single "-". We want to mark that in the option_element_vector, but only
+ // if it is not after the "--". But it turns out that OptionParser::Parse
+ // just ignores an isolated "-". So we have to look it up by hand here. We
+ // only care if it is AT the cursor position. Note, a single quoted dash is
+ // not the same as a single dash...
+
+ 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() == "-") {
+ option_element_vector.push_back(
+ OptionArgElement(OptionArgElement::eBareDash, cursor_index,
+ OptionArgElement::eBareDash));
+ }
+ return option_element_vector;
+}
+
+llvm::Expected<Args> Options::Parse(const Args &args,
+ ExecutionContext *execution_context,
+ lldb::PlatformSP platform_sp,
+ bool require_validation) {
+ Status error;
+ Option *long_options = GetLongOptions();
+ if (long_options == nullptr) {
+ return llvm::createStringError("Invalid long options.");
+ }
+
+ std::string short_options = BuildShortOptions(long_options);
+ std::vector<char *> argv = GetArgvForParsing(args);
+ std::unique_lock<std::mutex> lock;
+ OptionParser::Prepare(lock);
+ int val;
+ while (true) {
+ int long_options_index = -1;
+ val = OptionParser::Parse(argv, short_options, long_options,
+ &long_options_index);
+
+ if (val == ':') {
+ error.SetErrorString("last option requires an argument");
+ break;
+ }
+
+ if (val == -1)
+ break;
+
+ // Did we get an error?
+ if (val == '?') {
+ error.SetErrorString("unknown or ambiguous option");
+ break;
+ }
+ // The option auto-set itself
+ if (val == 0)
+ continue;
+
+ OptionSeen(val);
+
+ // Lookup the long option index
+ if (long_options_index == -1) {
+ for (int i = 0; long_options[i].definition || long_options[i].flag ||
+ long_options[i].val;
+ ++i) {
+ if (long_options[i].val == val) {
+ long_options_index = i;
+ break;
+ }
+ }
+ }
+ // Call the callback with the option
+ if (long_options_index >= 0 &&
+ long_options[long_options_index].definition) {
+ const OptionDefinition *def = long_options[long_options_index].definition;
+
+ if (!platform_sp) {
+ // User did not pass in an explicit platform. Try to grab from the
+ // execution context.
+ TargetSP target_sp =
+ execution_context ? execution_context->GetTargetSP() : TargetSP();
+ platform_sp = target_sp ? target_sp->GetPlatform() : PlatformSP();
+ }
+ OptionValidator *validator = def->validator;
+
+ if (!platform_sp && require_validation) {
+ // Caller requires validation but we cannot validate as we don't have
+ // the mandatory platform against which to validate.
+ return llvm::createStringError(
+ "cannot validate options: no platform available");
+ }
+
+ bool validation_failed = false;
+ if (platform_sp) {
+ // Ensure we have an execution context, empty or not.
+ ExecutionContext dummy_context;
+ ExecutionContext *exe_ctx_p =
+ execution_context ? execution_context : &dummy_context;
+ if (validator && !validator->IsValid(*platform_sp, *exe_ctx_p)) {
+ validation_failed = true;
+ error.SetErrorStringWithFormat("Option \"%s\" invalid. %s",
+ def->long_option,
+ def->validator->LongConditionString());
+ }
+ }
+
+ // As long as validation didn't fail, we set the option value.
+ if (!validation_failed)
+ error =
+ SetOptionValue(long_options_index,
+ (def->option_has_arg == OptionParser::eNoArgument)
+ ? 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);
+ }
+ }
+
+ if (error.Fail())
+ return error.ToError();
+
+ argv.pop_back();
+ argv.erase(argv.begin(), argv.begin() + OptionParser::GetOptionIndex());
+ return ReconstituteArgsAfterParsing(argv, args);
+}
+
+llvm::Error lldb_private::CreateOptionParsingError(
+ llvm::StringRef option_arg, const char short_option,
+ llvm::StringRef long_option, llvm::StringRef additional_context) {
+ std::string buffer;
+ llvm::raw_string_ostream stream(buffer);
+ stream << "Invalid value ('" << option_arg << "') for -" << short_option;
+ if (!long_option.empty())
+ stream << " (" << long_option << ")";
+ if (!additional_context.empty())
+ stream << ": " << additional_context;
+ return llvm::createStringError(llvm::inconvertibleErrorCode(), buffer);
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/Property.cpp b/contrib/llvm-project/lldb/source/Interpreter/Property.cpp
new file mode 100644
index 000000000000..56e45363be89
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/Property.cpp
@@ -0,0 +1,309 @@
+//===-- Property.cpp ------------------------------------------------------===//
+//
+// 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/Property.h"
+
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionValues.h"
+#include "lldb/Target/Language.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+Property::Property(const PropertyDefinition &definition)
+ : m_name(definition.name), m_description(definition.description),
+ m_is_global(definition.global) {
+ switch (definition.type) {
+ case OptionValue::eTypeInvalid:
+ case OptionValue::eTypeProperties:
+ break;
+ case OptionValue::eTypeArch:
+ // "definition.default_uint_value" is not used
+ // "definition.default_cstr_value" as a string value that represents the
+ // default string value for the architecture/triple
+ m_value_sp =
+ std::make_shared<OptionValueArch>(definition.default_cstr_value);
+ break;
+
+ case OptionValue::eTypeArgs:
+ // "definition.default_uint_value" is always a OptionValue::Type
+ m_value_sp = std::make_shared<OptionValueArgs>();
+ break;
+
+ case OptionValue::eTypeArray:
+ // "definition.default_uint_value" is always a OptionValue::Type
+ m_value_sp =
+ std::make_shared<OptionValueArray>(OptionValue::ConvertTypeToMask(
+ (OptionValue::Type)definition.default_uint_value));
+ break;
+
+ case OptionValue::eTypeBoolean:
+ // "definition.default_uint_value" is the default boolean value if
+ // "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the
+ // default value.
+ if (definition.default_cstr_value)
+ m_value_sp =
+ std::make_shared<OptionValueBoolean>(OptionArgParser::ToBoolean(
+ llvm::StringRef(definition.default_cstr_value), false, nullptr));
+ else
+ m_value_sp = std::make_shared<OptionValueBoolean>(
+ definition.default_uint_value != 0);
+ break;
+
+ case OptionValue::eTypeChar: {
+ llvm::StringRef s(definition.default_cstr_value ? definition.default_cstr_value : "");
+ m_value_sp = std::make_shared<OptionValueChar>(
+ OptionArgParser::ToChar(s, '\0', nullptr));
+ break;
+ }
+ case OptionValue::eTypeDictionary:
+ // "definition.default_uint_value" is always a OptionValue::Type
+ m_value_sp = std::make_shared<OptionValueDictionary>(
+ OptionValue::ConvertTypeToMask(
+ (OptionValue::Type)definition.default_uint_value),
+ definition.enum_values);
+ break;
+
+ case OptionValue::eTypeEnum:
+ // "definition.default_uint_value" is the default enumeration value if
+ // "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the
+ // default value.
+ {
+ OptionValueEnumeration *enum_value = new OptionValueEnumeration(
+ definition.enum_values, definition.default_uint_value);
+ m_value_sp.reset(enum_value);
+ if (definition.default_cstr_value) {
+ if (enum_value
+ ->SetValueFromString(
+ llvm::StringRef(definition.default_cstr_value))
+ .Success()) {
+ enum_value->SetDefaultValue(enum_value->GetCurrentValue());
+ // Call Clear() since we don't want the value to appear as having
+ // been set since we called SetValueFromString() above. Clear will
+ // set the current value to the default and clear the boolean that
+ // says that the value has been set.
+ enum_value->Clear();
+ }
+ }
+ }
+ break;
+
+ case OptionValue::eTypeFileLineColumn:
+ // "definition.default_uint_value" is not used for a
+ // OptionValue::eTypeFileSpecList
+ m_value_sp = std::make_shared<OptionValueFileColonLine>();
+ break;
+
+ case OptionValue::eTypeFileSpec: {
+ // "definition.default_uint_value" represents if the
+ // "definition.default_cstr_value" should be resolved or not
+ const bool resolve = definition.default_uint_value != 0;
+ FileSpec file_spec = FileSpec(definition.default_cstr_value);
+ if (resolve)
+ FileSystem::Instance().Resolve(file_spec);
+ m_value_sp = std::make_shared<OptionValueFileSpec>(file_spec, resolve);
+ break;
+ }
+
+ case OptionValue::eTypeFileSpecList:
+ // "definition.default_uint_value" is not used for a
+ // OptionValue::eTypeFileSpecList
+ m_value_sp = std::make_shared<OptionValueFileSpecList>();
+ break;
+
+ case OptionValue::eTypeFormat:
+ // "definition.default_uint_value" is the default format enumeration value
+ // if "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the
+ // default value.
+ {
+ Format new_format = eFormatInvalid;
+ if (definition.default_cstr_value)
+ OptionArgParser::ToFormat(definition.default_cstr_value, new_format,
+ nullptr);
+ else
+ new_format = (Format)definition.default_uint_value;
+ m_value_sp = std::make_shared<OptionValueFormat>(new_format);
+ }
+ break;
+
+ case OptionValue::eTypeLanguage:
+ // "definition.default_uint_value" is the default language enumeration
+ // value if "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the
+ // default value.
+ {
+ LanguageType new_lang = eLanguageTypeUnknown;
+ if (definition.default_cstr_value)
+ Language::GetLanguageTypeFromString(
+ llvm::StringRef(definition.default_cstr_value));
+ else
+ new_lang = (LanguageType)definition.default_uint_value;
+ m_value_sp = std::make_shared<OptionValueLanguage>(new_lang);
+ }
+ break;
+
+ case OptionValue::eTypeFormatEntity:
+ // "definition.default_cstr_value" as a string value that represents the
+ // default
+ m_value_sp = std::make_shared<OptionValueFormatEntity>(
+ definition.default_cstr_value);
+ break;
+
+ case OptionValue::eTypePathMap:
+ // "definition.default_uint_value" tells us if notifications should occur
+ // for path mappings
+ m_value_sp = std::make_shared<OptionValuePathMappings>(
+ definition.default_uint_value != 0);
+ break;
+
+ case OptionValue::eTypeRegex:
+ // "definition.default_uint_value" is used to the regular expression flags
+ // "definition.default_cstr_value" the default regular expression value
+ // value.
+ m_value_sp =
+ std::make_shared<OptionValueRegex>(definition.default_cstr_value);
+ break;
+
+ case OptionValue::eTypeSInt64: {
+ // "definition.default_uint_value" is the default integer value if
+ // "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the
+ // default value.
+ int64_t value = 0;
+ // FIXME: improve error handling for llvm::to_integer()
+ if (definition.default_cstr_value)
+ llvm::to_integer(definition.default_cstr_value, value);
+ m_value_sp = std::make_shared<OptionValueSInt64>(
+ definition.default_cstr_value ? value : definition.default_uint_value);
+ break;
+ }
+ case OptionValue::eTypeUInt64: {
+ uint64_t value = 0;
+ // FIXME: improve error handling for llvm::to_integer()
+ if (definition.default_cstr_value)
+ llvm::to_integer(definition.default_cstr_value, value);
+ // "definition.default_uint_value" is the default unsigned integer value if
+ // "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the
+ // default value.
+ m_value_sp = std::make_shared<OptionValueUInt64>(
+ definition.default_cstr_value ? value : definition.default_uint_value);
+ break;
+ }
+ case OptionValue::eTypeUUID:
+ // "definition.default_uint_value" is not used for a OptionValue::eTypeUUID
+ // "definition.default_cstr_value" can contain a default UUID value
+ {
+ UUID uuid;
+ if (definition.default_cstr_value)
+ uuid.SetFromStringRef(definition.default_cstr_value);
+ m_value_sp = std::make_shared<OptionValueUUID>(uuid);
+ }
+ break;
+
+ case OptionValue::eTypeString:
+ // "definition.default_uint_value" can contain the string option flags
+ // OR'ed together "definition.default_cstr_value" can contain a default
+ // string value
+ {
+ OptionValueString *string_value =
+ new OptionValueString(definition.default_cstr_value);
+ if (definition.default_uint_value != 0)
+ string_value->GetOptions().Reset(definition.default_uint_value);
+ m_value_sp.reset(string_value);
+ }
+ break;
+ }
+ assert(m_value_sp && "invalid property definition");
+}
+
+Property::Property(llvm::StringRef name, llvm::StringRef desc, bool is_global,
+ const lldb::OptionValueSP &value_sp)
+ : m_name(name), m_description(desc), m_value_sp(value_sp),
+ m_is_global(is_global) {}
+
+bool Property::DumpQualifiedName(Stream &strm) const {
+ if (!m_name.empty()) {
+ if (m_value_sp->DumpQualifiedName(strm))
+ strm.PutChar('.');
+ strm << m_name;
+ return true;
+ }
+ return false;
+}
+
+void Property::Dump(const ExecutionContext *exe_ctx, Stream &strm,
+ uint32_t dump_mask) const {
+ if (m_value_sp) {
+ const bool dump_desc = dump_mask & OptionValue::eDumpOptionDescription;
+ const bool dump_cmd = dump_mask & OptionValue::eDumpOptionCommand;
+ const bool transparent = m_value_sp->ValueIsTransparent();
+ if (dump_cmd && !transparent)
+ strm << "settings set -f ";
+ if (dump_desc || !transparent) {
+ if ((dump_mask & OptionValue::eDumpOptionName) && !m_name.empty()) {
+ DumpQualifiedName(strm);
+ if (dump_mask & ~OptionValue::eDumpOptionName)
+ strm.PutChar(' ');
+ }
+ }
+ if (dump_desc) {
+ llvm::StringRef desc = GetDescription();
+ if (!desc.empty())
+ strm << "-- " << desc;
+
+ if (transparent && (dump_mask == (OptionValue::eDumpOptionName |
+ OptionValue::eDumpOptionDescription)))
+ strm.EOL();
+ }
+ m_value_sp->DumpValue(exe_ctx, strm, dump_mask);
+ }
+}
+
+void Property::DumpDescription(CommandInterpreter &interpreter, Stream &strm,
+ uint32_t output_width,
+ bool display_qualified_name) const {
+ if (!m_value_sp)
+ return;
+ llvm::StringRef desc = GetDescription();
+
+ if (desc.empty())
+ return;
+
+ StreamString qualified_name;
+ const OptionValueProperties *sub_properties = m_value_sp->GetAsProperties();
+ if (sub_properties) {
+ strm.EOL();
+
+ if (m_value_sp->DumpQualifiedName(qualified_name))
+ strm.Printf("'%s' variables:\n\n", qualified_name.GetData());
+ sub_properties->DumpAllDescriptions(interpreter, strm);
+ } else {
+ if (display_qualified_name) {
+ StreamString qualified_name;
+ DumpQualifiedName(qualified_name);
+ interpreter.OutputFormattedHelpText(strm, qualified_name.GetString(),
+ "--", desc, output_width);
+ } else {
+ interpreter.OutputFormattedHelpText(strm, m_name, "--", desc,
+ output_width);
+ }
+ }
+}
+
+void Property::SetValueChangedCallback(std::function<void()> callback) {
+ if (m_value_sp)
+ m_value_sp->SetValueChangedCallback(std::move(callback));
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/ScriptInterpreter.cpp b/contrib/llvm-project/lldb/source/Interpreter/ScriptInterpreter.cpp
new file mode 100644
index 000000000000..fa23964a52ff
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -0,0 +1,276 @@
+//===-- ScriptInterpreter.cpp ---------------------------------------------===//
+//
+// 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/ScriptInterpreter.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Pipe.h"
+#include "lldb/Host/PseudoTerminal.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+#if defined(_WIN32)
+#include "lldb/Host/windows/ConnectionGenericFileWindows.h"
+#endif
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+#include <optional>
+#include <string>
+
+using namespace lldb;
+using namespace lldb_private;
+
+ScriptInterpreter::ScriptInterpreter(Debugger &debugger,
+ lldb::ScriptLanguage script_lang)
+ : m_debugger(debugger), m_script_lang(script_lang) {}
+
+void ScriptInterpreter::CollectDataForBreakpointCommandCallback(
+ std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
+ CommandReturnObject &result) {
+ result.AppendError(
+ "This script interpreter does not support breakpoint callbacks.");
+}
+
+void ScriptInterpreter::CollectDataForWatchpointCommandCallback(
+ WatchpointOptions *bp_options, CommandReturnObject &result) {
+ result.AppendError(
+ "This script interpreter does not support watchpoint callbacks.");
+}
+
+StructuredData::DictionarySP ScriptInterpreter::GetInterpreterInfo() {
+ return nullptr;
+}
+
+bool ScriptInterpreter::LoadScriptingModule(const char *filename,
+ const LoadScriptOptions &options,
+ lldb_private::Status &error,
+ StructuredData::ObjectSP *module_sp,
+ FileSpec extra_search_dir) {
+ error.SetErrorString(
+ "This script interpreter does not support importing modules.");
+ return false;
+}
+
+std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) {
+ switch (language) {
+ case eScriptLanguageNone:
+ return "None";
+ case eScriptLanguagePython:
+ return "Python";
+ case eScriptLanguageLua:
+ return "Lua";
+ case eScriptLanguageUnknown:
+ return "Unknown";
+ }
+ llvm_unreachable("Unhandled ScriptInterpreter!");
+}
+
+lldb::DataExtractorSP
+ScriptInterpreter::GetDataExtractorFromSBData(const lldb::SBData &data) const {
+ return data.m_opaque_sp;
+}
+
+lldb::BreakpointSP ScriptInterpreter::GetOpaqueTypeFromSBBreakpoint(
+ const lldb::SBBreakpoint &breakpoint) const {
+ return breakpoint.m_opaque_wp.lock();
+}
+
+lldb::ProcessAttachInfoSP ScriptInterpreter::GetOpaqueTypeFromSBAttachInfo(
+ const lldb::SBAttachInfo &attach_info) const {
+ return attach_info.m_opaque_sp;
+}
+
+lldb::ProcessLaunchInfoSP ScriptInterpreter::GetOpaqueTypeFromSBLaunchInfo(
+ const lldb::SBLaunchInfo &launch_info) const {
+ return std::make_shared<ProcessLaunchInfo>(
+ *reinterpret_cast<ProcessLaunchInfo *>(launch_info.m_opaque_sp.get()));
+}
+
+Status
+ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const {
+ if (error.m_opaque_up)
+ return *error.m_opaque_up;
+
+ return Status();
+}
+
+Event *
+ScriptInterpreter::GetOpaqueTypeFromSBEvent(const lldb::SBEvent &event) const {
+ return event.m_opaque_ptr;
+}
+
+lldb::StreamSP ScriptInterpreter::GetOpaqueTypeFromSBStream(
+ const lldb::SBStream &stream) const {
+ if (stream.m_opaque_up) {
+ lldb::StreamSP s = std::make_shared<lldb_private::StreamString>();
+ *s << reinterpret_cast<StreamString *>(stream.m_opaque_up.get())->m_packet;
+ return s;
+ }
+
+ return nullptr;
+}
+
+std::optional<MemoryRegionInfo>
+ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
+ const lldb::SBMemoryRegionInfo &mem_region) const {
+ if (!mem_region.m_opaque_up)
+ return std::nullopt;
+ return *mem_region.m_opaque_up.get();
+}
+
+lldb::ScriptLanguage
+ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
+ if (language.equals_insensitive(LanguageToString(eScriptLanguageNone)))
+ return eScriptLanguageNone;
+ if (language.equals_insensitive(LanguageToString(eScriptLanguagePython)))
+ return eScriptLanguagePython;
+ if (language.equals_insensitive(LanguageToString(eScriptLanguageLua)))
+ return eScriptLanguageLua;
+ return eScriptLanguageUnknown;
+}
+
+Status ScriptInterpreter::SetBreakpointCommandCallback(
+ std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
+ const char *callback_text) {
+ Status error;
+ for (BreakpointOptions &bp_options : bp_options_vec) {
+ error = SetBreakpointCommandCallback(bp_options, callback_text,
+ /*is_callback=*/false);
+ if (!error.Success())
+ break;
+ }
+ return error;
+}
+
+Status ScriptInterpreter::SetBreakpointCommandCallbackFunction(
+ std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
+ const char *function_name, StructuredData::ObjectSP extra_args_sp) {
+ Status error;
+ for (BreakpointOptions &bp_options : bp_options_vec) {
+ error = SetBreakpointCommandCallbackFunction(bp_options, function_name,
+ extra_args_sp);
+ if (!error.Success())
+ return error;
+ }
+ return error;
+}
+
+std::unique_ptr<ScriptInterpreterLocker>
+ScriptInterpreter::AcquireInterpreterLock() {
+ return std::make_unique<ScriptInterpreterLocker>();
+}
+
+static void ReadThreadBytesReceived(void *baton, const void *src,
+ size_t src_len) {
+ if (src && src_len) {
+ Stream *strm = (Stream *)baton;
+ strm->Write(src, src_len);
+ strm->Flush();
+ }
+}
+
+llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
+ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger,
+ CommandReturnObject *result) {
+ if (enable_io)
+ return std::unique_ptr<ScriptInterpreterIORedirect>(
+ new ScriptInterpreterIORedirect(debugger, result));
+
+ auto nullin = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
+ File::eOpenOptionReadOnly);
+ if (!nullin)
+ return nullin.takeError();
+
+ auto nullout = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
+ File::eOpenOptionWriteOnly);
+ if (!nullout)
+ return nullin.takeError();
+
+ return std::unique_ptr<ScriptInterpreterIORedirect>(
+ new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout)));
+}
+
+ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
+ std::unique_ptr<File> input, std::unique_ptr<File> output)
+ : m_input_file_sp(std::move(input)),
+ m_output_file_sp(std::make_shared<StreamFile>(std::move(output))),
+ m_error_file_sp(m_output_file_sp),
+ m_communication("lldb.ScriptInterpreterIORedirect.comm"),
+ m_disconnect(false) {}
+
+ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
+ Debugger &debugger, CommandReturnObject *result)
+ : m_communication("lldb.ScriptInterpreterIORedirect.comm"),
+ m_disconnect(false) {
+
+ if (result) {
+ m_input_file_sp = debugger.GetInputFileSP();
+
+ Pipe pipe;
+ Status pipe_result = pipe.CreateNew(false);
+#if defined(_WIN32)
+ lldb::file_t read_file = pipe.GetReadNativeHandle();
+ pipe.ReleaseReadFileDescriptor();
+ std::unique_ptr<ConnectionGenericFile> conn_up =
+ std::make_unique<ConnectionGenericFile>(read_file, true);
+#else
+ std::unique_ptr<ConnectionFileDescriptor> conn_up =
+ std::make_unique<ConnectionFileDescriptor>(
+ pipe.ReleaseReadFileDescriptor(), true);
+#endif
+
+ if (conn_up->IsConnected()) {
+ m_communication.SetConnection(std::move(conn_up));
+ m_communication.SetReadThreadBytesReceivedCallback(
+ ReadThreadBytesReceived, &result->GetOutputStream());
+ m_communication.StartReadThread();
+ m_disconnect = true;
+
+ FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w");
+ m_output_file_sp = std::make_shared<StreamFile>(outfile_handle, true);
+ m_error_file_sp = m_output_file_sp;
+ if (outfile_handle)
+ ::setbuf(outfile_handle, nullptr);
+
+ result->SetImmediateOutputFile(debugger.GetOutputStream().GetFileSP());
+ result->SetImmediateErrorFile(debugger.GetErrorStream().GetFileSP());
+ }
+ }
+
+ if (!m_input_file_sp || !m_output_file_sp || !m_error_file_sp)
+ debugger.AdoptTopIOHandlerFilesIfInvalid(m_input_file_sp, m_output_file_sp,
+ m_error_file_sp);
+}
+
+void ScriptInterpreterIORedirect::Flush() {
+ if (m_output_file_sp)
+ m_output_file_sp->Flush();
+ if (m_error_file_sp)
+ m_error_file_sp->Flush();
+}
+
+ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() {
+ if (!m_disconnect)
+ return;
+
+ assert(m_output_file_sp);
+ assert(m_error_file_sp);
+ assert(m_output_file_sp == m_error_file_sp);
+
+ // Close the write end of the pipe since we are done with our one line
+ // script. This should cause the read thread that output_comm is using to
+ // exit.
+ m_output_file_sp->GetFile().Close();
+ // The close above should cause this thread to exit when it gets to the end
+ // of file, so let it get all its data.
+ m_communication.JoinReadThread();
+ // Now we can close the read end of the pipe.
+ m_communication.Disconnect();
+}
diff --git a/contrib/llvm-project/lldb/source/Interpreter/embedded_interpreter.py b/contrib/llvm-project/lldb/source/Interpreter/embedded_interpreter.py
new file mode 100644
index 000000000000..a487592ef1ae
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Interpreter/embedded_interpreter.py
@@ -0,0 +1,136 @@
+import sys
+
+if sys.version_info[0] < 3:
+ import __builtin__ as builtins
+else:
+ import builtins
+import code
+import lldb
+import traceback
+
+try:
+ import readline
+ import rlcompleter
+except ImportError:
+ have_readline = False
+except AttributeError:
+ # This exception gets hit by the rlcompleter when Linux is using
+ # the readline suppression import.
+ have_readline = False
+else:
+ have_readline = True
+ if "libedit" in readline.__doc__:
+ readline.parse_and_bind("bind ^I rl_complete")
+ else:
+ readline.parse_and_bind("tab: complete")
+
+# When running one line, we might place the string to run in this string
+# in case it would be hard to correctly escape a string's contents
+
+g_run_one_line_str = None
+
+
+def get_terminal_size(fd):
+ try:
+ import fcntl
+ import termios
+ import struct
+
+ hw = struct.unpack("hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, "1234"))
+ except:
+ hw = (0, 0)
+ return hw
+
+
+class LLDBExit(SystemExit):
+ pass
+
+
+def strip_and_check_exit(line):
+ line = line.rstrip()
+ if line in ("exit", "quit"):
+ raise LLDBExit
+ return line
+
+
+def readfunc(prompt):
+ line = input(prompt)
+ return strip_and_check_exit(line)
+
+
+def readfunc_stdio(prompt):
+ sys.stdout.write(prompt)
+ sys.stdout.flush()
+ line = sys.stdin.readline()
+ # Readline always includes a trailing newline character unless the file
+ # ends with an incomplete line. An empty line indicates EOF.
+ if not line:
+ raise EOFError
+ return strip_and_check_exit(line)
+
+
+def run_python_interpreter(local_dict):
+ # Pass in the dictionary, for continuity from one session to the next.
+ try:
+ fd = sys.stdin.fileno()
+ interacted = False
+ if get_terminal_size(fd)[1] == 0:
+ try:
+ import termios
+
+ old = termios.tcgetattr(fd)
+ if old[3] & termios.ECHO:
+ # Need to turn off echoing and restore
+ new = termios.tcgetattr(fd)
+ new[3] = new[3] & ~termios.ECHO
+ try:
+ termios.tcsetattr(fd, termios.TCSADRAIN, new)
+ interacted = True
+ code.interact(
+ banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()'.",
+ readfunc=readfunc_stdio,
+ local=local_dict,
+ )
+ finally:
+ termios.tcsetattr(fd, termios.TCSADRAIN, old)
+ except:
+ pass
+ # Don't need to turn off echoing
+ if not interacted:
+ code.interact(
+ banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.",
+ readfunc=readfunc_stdio,
+ local=local_dict,
+ )
+ else:
+ # We have a real interactive terminal
+ code.interact(
+ banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.",
+ readfunc=readfunc,
+ local=local_dict,
+ )
+ except LLDBExit:
+ pass
+ except SystemExit as e:
+ if e.code:
+ print("Script exited with code %s" % e.code)
+
+
+def run_one_line(local_dict, input_string):
+ global g_run_one_line_str
+ try:
+ input_string = strip_and_check_exit(input_string)
+ repl = code.InteractiveConsole(local_dict)
+ if input_string:
+ # A newline is appended to support one-line statements containing
+ # control flow. For example "if True: print(1)" silently does
+ # nothing, but works with a newline: "if True: print(1)\n".
+ input_string += "\n"
+ repl.runsource(input_string)
+ elif g_run_one_line_str:
+ repl.runsource(g_run_one_line_str)
+ except LLDBExit:
+ pass
+ except SystemExit as e:
+ if e.code:
+ print("Script exited with code %s" % e.code)