Path: blob/main/contrib/llvm-project/lldb/source/Interpreter/CommandObject.cpp
39587 views
//===-- CommandObject.cpp -------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Interpreter/CommandObject.h"910#include <map>11#include <sstream>12#include <string>1314#include <cctype>15#include <cstdlib>1617#include "lldb/Core/Address.h"18#include "lldb/Interpreter/CommandOptionArgumentTable.h"19#include "lldb/Interpreter/Options.h"20#include "lldb/Utility/ArchSpec.h"21#include "llvm/ADT/ScopeExit.h"2223// These are for the Sourcename completers.24// FIXME: Make a separate file for the completers.25#include "lldb/DataFormatters/FormatManager.h"26#include "lldb/Target/Process.h"27#include "lldb/Target/Target.h"28#include "lldb/Utility/FileSpec.h"29#include "lldb/Utility/FileSpecList.h"3031#include "lldb/Target/Language.h"3233#include "lldb/Interpreter/CommandInterpreter.h"34#include "lldb/Interpreter/CommandOptionArgumentTable.h"35#include "lldb/Interpreter/CommandReturnObject.h"3637using namespace lldb;38using namespace lldb_private;3940// CommandObject4142CommandObject::CommandObject(CommandInterpreter &interpreter,43llvm::StringRef name, llvm::StringRef help,44llvm::StringRef syntax, uint32_t flags)45: m_interpreter(interpreter), m_cmd_name(std::string(name)),46m_flags(flags), m_deprecated_command_override_callback(nullptr),47m_command_override_callback(nullptr), m_command_override_baton(nullptr) {48m_cmd_help_short = std::string(help);49m_cmd_syntax = std::string(syntax);50}5152Debugger &CommandObject::GetDebugger() { return m_interpreter.GetDebugger(); }5354llvm::StringRef CommandObject::GetHelp() { return m_cmd_help_short; }5556llvm::StringRef CommandObject::GetHelpLong() { return m_cmd_help_long; }5758llvm::StringRef CommandObject::GetSyntax() {59if (!m_cmd_syntax.empty())60return m_cmd_syntax;6162StreamString syntax_str;63syntax_str.PutCString(GetCommandName());6465if (!IsDashDashCommand() && GetOptions() != nullptr)66syntax_str.PutCString(" <cmd-options>");6768if (!m_arguments.empty()) {69syntax_str.PutCString(" ");7071if (!IsDashDashCommand() && WantsRawCommandString() && GetOptions() &&72GetOptions()->NumCommandOptions())73syntax_str.PutCString("-- ");74GetFormattedCommandArguments(syntax_str);75}76m_cmd_syntax = std::string(syntax_str.GetString());7778return m_cmd_syntax;79}8081llvm::StringRef CommandObject::GetCommandName() const { return m_cmd_name; }8283void CommandObject::SetCommandName(llvm::StringRef name) {84m_cmd_name = std::string(name);85}8687void CommandObject::SetHelp(llvm::StringRef str) {88m_cmd_help_short = std::string(str);89}9091void CommandObject::SetHelpLong(llvm::StringRef str) {92m_cmd_help_long = std::string(str);93}9495void CommandObject::SetSyntax(llvm::StringRef str) {96m_cmd_syntax = std::string(str);97}9899Options *CommandObject::GetOptions() {100// By default commands don't have options unless this virtual function is101// overridden by base classes.102return nullptr;103}104105bool CommandObject::ParseOptions(Args &args, CommandReturnObject &result) {106// See if the subclass has options?107Options *options = GetOptions();108if (options != nullptr) {109Status error;110111auto exe_ctx = GetCommandInterpreter().GetExecutionContext();112options->NotifyOptionParsingStarting(&exe_ctx);113114const bool require_validation = true;115llvm::Expected<Args> args_or = options->Parse(116args, &exe_ctx, GetCommandInterpreter().GetPlatform(true),117require_validation);118119if (args_or) {120args = std::move(*args_or);121error = options->NotifyOptionParsingFinished(&exe_ctx);122} else123error = args_or.takeError();124125if (error.Success()) {126if (options->VerifyOptions(result))127return true;128} else {129const char *error_cstr = error.AsCString();130if (error_cstr) {131// We got an error string, lets use that132result.AppendError(error_cstr);133} else {134// No error string, output the usage information into result135options->GenerateOptionUsage(136result.GetErrorStream(), *this,137GetCommandInterpreter().GetDebugger().GetTerminalWidth());138}139}140result.SetStatus(eReturnStatusFailed);141return false;142}143return true;144}145146bool CommandObject::CheckRequirements(CommandReturnObject &result) {147// Nothing should be stored in m_exe_ctx between running commands as148// m_exe_ctx has shared pointers to the target, process, thread and frame and149// we don't want any CommandObject instances to keep any of these objects150// around longer than for a single command. Every command should call151// CommandObject::Cleanup() after it has completed.152assert(!m_exe_ctx.GetTargetPtr());153assert(!m_exe_ctx.GetProcessPtr());154assert(!m_exe_ctx.GetThreadPtr());155assert(!m_exe_ctx.GetFramePtr());156157// Lock down the interpreter's execution context prior to running the command158// so we guarantee the selected target, process, thread and frame can't go159// away during the execution160m_exe_ctx = m_interpreter.GetExecutionContext();161162const uint32_t flags = GetFlags().Get();163if (flags & (eCommandRequiresTarget | eCommandRequiresProcess |164eCommandRequiresThread | eCommandRequiresFrame |165eCommandTryTargetAPILock)) {166167if ((flags & eCommandRequiresTarget) && !m_exe_ctx.HasTargetScope()) {168result.AppendError(GetInvalidTargetDescription());169return false;170}171172if ((flags & eCommandRequiresProcess) && !m_exe_ctx.HasProcessScope()) {173if (!m_exe_ctx.HasTargetScope())174result.AppendError(GetInvalidTargetDescription());175else176result.AppendError(GetInvalidProcessDescription());177return false;178}179180if ((flags & eCommandRequiresThread) && !m_exe_ctx.HasThreadScope()) {181if (!m_exe_ctx.HasTargetScope())182result.AppendError(GetInvalidTargetDescription());183else if (!m_exe_ctx.HasProcessScope())184result.AppendError(GetInvalidProcessDescription());185else186result.AppendError(GetInvalidThreadDescription());187return false;188}189190if ((flags & eCommandRequiresFrame) && !m_exe_ctx.HasFrameScope()) {191if (!m_exe_ctx.HasTargetScope())192result.AppendError(GetInvalidTargetDescription());193else if (!m_exe_ctx.HasProcessScope())194result.AppendError(GetInvalidProcessDescription());195else if (!m_exe_ctx.HasThreadScope())196result.AppendError(GetInvalidThreadDescription());197else198result.AppendError(GetInvalidFrameDescription());199return false;200}201202if ((flags & eCommandRequiresRegContext) &&203(m_exe_ctx.GetRegisterContext() == nullptr)) {204result.AppendError(GetInvalidRegContextDescription());205return false;206}207208if (flags & eCommandTryTargetAPILock) {209Target *target = m_exe_ctx.GetTargetPtr();210if (target)211m_api_locker =212std::unique_lock<std::recursive_mutex>(target->GetAPIMutex());213}214}215216if (GetFlags().AnySet(eCommandProcessMustBeLaunched |217eCommandProcessMustBePaused)) {218Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();219if (process == nullptr) {220// A process that is not running is considered paused.221if (GetFlags().Test(eCommandProcessMustBeLaunched)) {222result.AppendError("Process must exist.");223return false;224}225} else {226StateType state = process->GetState();227switch (state) {228case eStateInvalid:229case eStateSuspended:230case eStateCrashed:231case eStateStopped:232break;233234case eStateConnected:235case eStateAttaching:236case eStateLaunching:237case eStateDetached:238case eStateExited:239case eStateUnloaded:240if (GetFlags().Test(eCommandProcessMustBeLaunched)) {241result.AppendError("Process must be launched.");242return false;243}244break;245246case eStateRunning:247case eStateStepping:248if (GetFlags().Test(eCommandProcessMustBePaused)) {249result.AppendError("Process is running. Use 'process interrupt' to "250"pause execution.");251return false;252}253}254}255}256257if (GetFlags().Test(eCommandProcessMustBeTraced)) {258Target *target = m_exe_ctx.GetTargetPtr();259if (target && !target->GetTrace()) {260result.AppendError("Process is not being traced.");261return false;262}263}264265return true;266}267268void CommandObject::Cleanup() {269m_exe_ctx.Clear();270if (m_api_locker.owns_lock())271m_api_locker.unlock();272}273274void CommandObject::HandleCompletion(CompletionRequest &request) {275276m_exe_ctx = m_interpreter.GetExecutionContext();277auto reset_ctx = llvm::make_scope_exit([this]() { Cleanup(); });278279// Default implementation of WantsCompletion() is !WantsRawCommandString().280// Subclasses who want raw command string but desire, for example, argument281// completion should override WantsCompletion() to return true, instead.282if (WantsRawCommandString() && !WantsCompletion()) {283// FIXME: Abstract telling the completion to insert the completion284// character.285return;286} else {287// Can we do anything generic with the options?288Options *cur_options = GetOptions();289CommandReturnObject result(m_interpreter.GetDebugger().GetUseColor());290OptionElementVector opt_element_vector;291292if (cur_options != nullptr) {293opt_element_vector = cur_options->ParseForCompletion(294request.GetParsedLine(), request.GetCursorIndex());295296bool handled_by_options = cur_options->HandleOptionCompletion(297request, opt_element_vector, GetCommandInterpreter());298if (handled_by_options)299return;300}301302// If we got here, the last word is not an option or an option argument.303HandleArgumentCompletion(request, opt_element_vector);304}305}306307void CommandObject::HandleArgumentCompletion(308CompletionRequest &request, OptionElementVector &opt_element_vector) {309size_t num_arg_entries = GetNumArgumentEntries();310if (num_arg_entries != 1)311return;312313CommandArgumentEntry *entry_ptr = GetArgumentEntryAtIndex(0);314if (!entry_ptr) {315assert(entry_ptr && "We said there was one entry, but there wasn't.");316return; // Not worth crashing if asserts are off...317}318319CommandArgumentEntry &entry = *entry_ptr;320// For now, we only handle the simple case of one homogenous argument type.321if (entry.size() != 1)322return;323324// Look up the completion type, and if it has one, invoke it:325const CommandObject::ArgumentTableEntry *arg_entry =326FindArgumentDataByType(entry[0].arg_type);327const ArgumentRepetitionType repeat = entry[0].arg_repetition;328329if (arg_entry == nullptr || arg_entry->completion_type == lldb::eNoCompletion)330return;331332// FIXME: This should be handled higher in the Command Parser.333// Check the case where this command only takes one argument, and don't do334// the completion if we aren't on the first entry:335if (repeat == eArgRepeatPlain && request.GetCursorIndex() != 0)336return;337338lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(339GetCommandInterpreter(), arg_entry->completion_type, request, nullptr);340341}342343344bool CommandObject::HelpTextContainsWord(llvm::StringRef search_word,345bool search_short_help,346bool search_long_help,347bool search_syntax,348bool search_options) {349std::string options_usage_help;350351bool found_word = false;352353llvm::StringRef short_help = GetHelp();354llvm::StringRef long_help = GetHelpLong();355llvm::StringRef syntax_help = GetSyntax();356357if (search_short_help && short_help.contains_insensitive(search_word))358found_word = true;359else if (search_long_help && long_help.contains_insensitive(search_word))360found_word = true;361else if (search_syntax && syntax_help.contains_insensitive(search_word))362found_word = true;363364if (!found_word && search_options && GetOptions() != nullptr) {365StreamString usage_help;366GetOptions()->GenerateOptionUsage(367usage_help, *this,368GetCommandInterpreter().GetDebugger().GetTerminalWidth());369if (!usage_help.Empty()) {370llvm::StringRef usage_text = usage_help.GetString();371if (usage_text.contains_insensitive(search_word))372found_word = true;373}374}375376return found_word;377}378379bool CommandObject::ParseOptionsAndNotify(Args &args,380CommandReturnObject &result,381OptionGroupOptions &group_options,382ExecutionContext &exe_ctx) {383if (!ParseOptions(args, result))384return false;385386Status error(group_options.NotifyOptionParsingFinished(&exe_ctx));387if (error.Fail()) {388result.AppendError(error.AsCString());389return false;390}391return true;392}393394void CommandObject::AddSimpleArgumentList(395CommandArgumentType arg_type, ArgumentRepetitionType repetition_type) {396397CommandArgumentEntry arg_entry;398CommandArgumentData simple_arg;399400// Define the first (and only) variant of this arg.401simple_arg.arg_type = arg_type;402simple_arg.arg_repetition = repetition_type;403404// There is only one variant this argument could be; put it into the argument405// entry.406arg_entry.push_back(simple_arg);407408// Push the data for the first argument into the m_arguments vector.409m_arguments.push_back(arg_entry);410}411412int CommandObject::GetNumArgumentEntries() { return m_arguments.size(); }413414CommandObject::CommandArgumentEntry *415CommandObject::GetArgumentEntryAtIndex(int idx) {416if (static_cast<size_t>(idx) < m_arguments.size())417return &(m_arguments[idx]);418419return nullptr;420}421422const CommandObject::ArgumentTableEntry *423CommandObject::FindArgumentDataByType(CommandArgumentType arg_type) {424for (int i = 0; i < eArgTypeLastArg; ++i)425if (g_argument_table[i].arg_type == arg_type)426return &(g_argument_table[i]);427428return nullptr;429}430431void CommandObject::GetArgumentHelp(Stream &str, CommandArgumentType arg_type,432CommandInterpreter &interpreter) {433const ArgumentTableEntry *entry = &(g_argument_table[arg_type]);434435// The table is *supposed* to be kept in arg_type order, but someone *could*436// have messed it up...437438if (entry->arg_type != arg_type)439entry = CommandObject::FindArgumentDataByType(arg_type);440441if (!entry)442return;443444StreamString name_str;445name_str.Printf("<%s>", entry->arg_name);446447if (entry->help_function) {448llvm::StringRef help_text = entry->help_function();449if (!entry->help_function.self_formatting) {450interpreter.OutputFormattedHelpText(str, name_str.GetString(), "--",451help_text, name_str.GetSize());452} else {453interpreter.OutputHelpText(str, name_str.GetString(), "--", help_text,454name_str.GetSize());455}456} else {457interpreter.OutputFormattedHelpText(str, name_str.GetString(), "--",458entry->help_text, name_str.GetSize());459460// Print enum values and their description if any.461OptionEnumValues enum_values = g_argument_table[arg_type].enum_values;462if (!enum_values.empty()) {463str.EOL();464size_t longest = 0;465for (const OptionEnumValueElement &element : enum_values)466longest =467std::max(longest, llvm::StringRef(element.string_value).size());468str.IndentMore(5);469for (const OptionEnumValueElement &element : enum_values) {470str.Indent();471interpreter.OutputHelpText(str, element.string_value, ":",472element.usage, longest);473}474str.IndentLess(5);475str.EOL();476}477}478}479480const char *CommandObject::GetArgumentName(CommandArgumentType arg_type) {481const ArgumentTableEntry *entry = &(g_argument_table[arg_type]);482483// The table is *supposed* to be kept in arg_type order, but someone *could*484// have messed it up...485486if (entry->arg_type != arg_type)487entry = CommandObject::FindArgumentDataByType(arg_type);488489if (entry)490return entry->arg_name;491492return nullptr;493}494495bool CommandObject::IsPairType(ArgumentRepetitionType arg_repeat_type) {496return (arg_repeat_type == eArgRepeatPairPlain) ||497(arg_repeat_type == eArgRepeatPairOptional) ||498(arg_repeat_type == eArgRepeatPairPlus) ||499(arg_repeat_type == eArgRepeatPairStar) ||500(arg_repeat_type == eArgRepeatPairRange) ||501(arg_repeat_type == eArgRepeatPairRangeOptional);502}503504std::optional<ArgumentRepetitionType>505CommandObject::ArgRepetitionFromString(llvm::StringRef string) {506return llvm::StringSwitch<ArgumentRepetitionType>(string)507.Case("plain", eArgRepeatPlain)508.Case("optional", eArgRepeatOptional)509.Case("plus", eArgRepeatPlus)510.Case("star", eArgRepeatStar)511.Case("range", eArgRepeatRange)512.Case("pair-plain", eArgRepeatPairPlain)513.Case("pair-optional", eArgRepeatPairOptional)514.Case("pair-plus", eArgRepeatPairPlus)515.Case("pair-star", eArgRepeatPairStar)516.Case("pair-range", eArgRepeatPairRange)517.Case("pair-range-optional", eArgRepeatPairRangeOptional)518.Default({});519}520521static CommandObject::CommandArgumentEntry522OptSetFiltered(uint32_t opt_set_mask,523CommandObject::CommandArgumentEntry &cmd_arg_entry) {524CommandObject::CommandArgumentEntry ret_val;525for (unsigned i = 0; i < cmd_arg_entry.size(); ++i)526if (opt_set_mask & cmd_arg_entry[i].arg_opt_set_association)527ret_val.push_back(cmd_arg_entry[i]);528return ret_val;529}530531// Default parameter value of opt_set_mask is LLDB_OPT_SET_ALL, which means532// take all the argument data into account. On rare cases where some argument533// sticks with certain option sets, this function returns the option set534// filtered args.535void CommandObject::GetFormattedCommandArguments(Stream &str,536uint32_t opt_set_mask) {537int num_args = m_arguments.size();538for (int i = 0; i < num_args; ++i) {539if (i > 0)540str.Printf(" ");541CommandArgumentEntry arg_entry =542opt_set_mask == LLDB_OPT_SET_ALL543? m_arguments[i]544: OptSetFiltered(opt_set_mask, m_arguments[i]);545// This argument is not associated with the current option set, so skip it.546if (arg_entry.empty())547continue;548int num_alternatives = arg_entry.size();549550if ((num_alternatives == 2) && IsPairType(arg_entry[0].arg_repetition)) {551const char *first_name = GetArgumentName(arg_entry[0].arg_type);552const char *second_name = GetArgumentName(arg_entry[1].arg_type);553switch (arg_entry[0].arg_repetition) {554case eArgRepeatPairPlain:555str.Printf("<%s> <%s>", first_name, second_name);556break;557case eArgRepeatPairOptional:558str.Printf("[<%s> <%s>]", first_name, second_name);559break;560case eArgRepeatPairPlus:561str.Printf("<%s> <%s> [<%s> <%s> [...]]", first_name, second_name,562first_name, second_name);563break;564case eArgRepeatPairStar:565str.Printf("[<%s> <%s> [<%s> <%s> [...]]]", first_name, second_name,566first_name, second_name);567break;568case eArgRepeatPairRange:569str.Printf("<%s_1> <%s_1> ... <%s_n> <%s_n>", first_name, second_name,570first_name, second_name);571break;572case eArgRepeatPairRangeOptional:573str.Printf("[<%s_1> <%s_1> ... <%s_n> <%s_n>]", first_name, second_name,574first_name, second_name);575break;576// Explicitly test for all the rest of the cases, so if new types get577// added we will notice the missing case statement(s).578case eArgRepeatPlain:579case eArgRepeatOptional:580case eArgRepeatPlus:581case eArgRepeatStar:582case eArgRepeatRange:583// These should not be reached, as they should fail the IsPairType test584// above.585break;586}587} else {588StreamString names;589for (int j = 0; j < num_alternatives; ++j) {590if (j > 0)591names.Printf(" | ");592names.Printf("%s", GetArgumentName(arg_entry[j].arg_type));593}594595std::string name_str = std::string(names.GetString());596switch (arg_entry[0].arg_repetition) {597case eArgRepeatPlain:598str.Printf("<%s>", name_str.c_str());599break;600case eArgRepeatPlus:601str.Printf("<%s> [<%s> [...]]", name_str.c_str(), name_str.c_str());602break;603case eArgRepeatStar:604str.Printf("[<%s> [<%s> [...]]]", name_str.c_str(), name_str.c_str());605break;606case eArgRepeatOptional:607str.Printf("[<%s>]", name_str.c_str());608break;609case eArgRepeatRange:610str.Printf("<%s_1> .. <%s_n>", name_str.c_str(), name_str.c_str());611break;612// Explicitly test for all the rest of the cases, so if new types get613// added we will notice the missing case statement(s).614case eArgRepeatPairPlain:615case eArgRepeatPairOptional:616case eArgRepeatPairPlus:617case eArgRepeatPairStar:618case eArgRepeatPairRange:619case eArgRepeatPairRangeOptional:620// These should not be hit, as they should pass the IsPairType test621// above, and control should have gone into the other branch of the if622// statement.623break;624}625}626}627}628629CommandArgumentType630CommandObject::LookupArgumentName(llvm::StringRef arg_name) {631CommandArgumentType return_type = eArgTypeLastArg;632633arg_name = arg_name.ltrim('<').rtrim('>');634635for (int i = 0; i < eArgTypeLastArg; ++i)636if (arg_name == g_argument_table[i].arg_name)637return_type = g_argument_table[i].arg_type;638639return return_type;640}641642void CommandObject::FormatLongHelpText(Stream &output_strm,643llvm::StringRef long_help) {644CommandInterpreter &interpreter = GetCommandInterpreter();645std::stringstream lineStream{std::string(long_help)};646std::string line;647while (std::getline(lineStream, line)) {648if (line.empty()) {649output_strm << "\n";650continue;651}652size_t result = line.find_first_not_of(" \t");653if (result == std::string::npos) {654result = 0;655}656std::string whitespace_prefix = line.substr(0, result);657std::string remainder = line.substr(result);658interpreter.OutputFormattedHelpText(output_strm, whitespace_prefix,659remainder);660}661}662663void CommandObject::GenerateHelpText(CommandReturnObject &result) {664GenerateHelpText(result.GetOutputStream());665666result.SetStatus(eReturnStatusSuccessFinishNoResult);667}668669void CommandObject::GenerateHelpText(Stream &output_strm) {670CommandInterpreter &interpreter = GetCommandInterpreter();671std::string help_text(GetHelp());672if (WantsRawCommandString()) {673help_text.append(" Expects 'raw' input (see 'help raw-input'.)");674}675interpreter.OutputFormattedHelpText(output_strm, "", help_text);676output_strm << "\nSyntax: " << GetSyntax() << "\n";677Options *options = GetOptions();678if (options != nullptr) {679options->GenerateOptionUsage(680output_strm, *this,681GetCommandInterpreter().GetDebugger().GetTerminalWidth());682}683llvm::StringRef long_help = GetHelpLong();684if (!long_help.empty()) {685FormatLongHelpText(output_strm, long_help);686}687if (!IsDashDashCommand() && options && options->NumCommandOptions() > 0) {688if (WantsRawCommandString() && !WantsCompletion()) {689// Emit the message about using ' -- ' between the end of the command690// options and the raw input conditionally, i.e., only if the command691// object does not want completion.692interpreter.OutputFormattedHelpText(693output_strm, "", "",694"\nImportant Note: Because this command takes 'raw' input, if you "695"use any command options"696" you must use ' -- ' between the end of the command options and the "697"beginning of the raw input.",6981);699} else if (GetNumArgumentEntries() > 0) {700// Also emit a warning about using "--" in case you are using a command701// that takes options and arguments.702interpreter.OutputFormattedHelpText(703output_strm, "", "",704"\nThis command takes options and free-form arguments. If your "705"arguments resemble"706" option specifiers (i.e., they start with a - or --), you must use "707"' -- ' between"708" the end of the command options and the beginning of the arguments.",7091);710}711}712}713714void CommandObject::AddIDsArgumentData(CommandObject::IDType type) {715CommandArgumentEntry arg;716CommandArgumentData id_arg;717CommandArgumentData id_range_arg;718719// Create the first variant for the first (and only) argument for this720// command.721switch (type) {722case eBreakpointArgs:723id_arg.arg_type = eArgTypeBreakpointID;724id_range_arg.arg_type = eArgTypeBreakpointIDRange;725break;726case eWatchpointArgs:727id_arg.arg_type = eArgTypeWatchpointID;728id_range_arg.arg_type = eArgTypeWatchpointIDRange;729break;730}731id_arg.arg_repetition = eArgRepeatOptional;732id_range_arg.arg_repetition = eArgRepeatOptional;733734// The first (and only) argument for this command could be either an id or an735// id_range. Push both variants into the entry for the first argument for736// this command.737arg.push_back(id_arg);738arg.push_back(id_range_arg);739m_arguments.push_back(arg);740}741742const char *CommandObject::GetArgumentTypeAsCString(743const lldb::CommandArgumentType arg_type) {744assert(arg_type < eArgTypeLastArg &&745"Invalid argument type passed to GetArgumentTypeAsCString");746return g_argument_table[arg_type].arg_name;747}748749const char *CommandObject::GetArgumentDescriptionAsCString(750const lldb::CommandArgumentType arg_type) {751assert(arg_type < eArgTypeLastArg &&752"Invalid argument type passed to GetArgumentDescriptionAsCString");753return g_argument_table[arg_type].help_text;754}755756Target &CommandObject::GetDummyTarget() {757return m_interpreter.GetDebugger().GetDummyTarget();758}759760Target &CommandObject::GetSelectedOrDummyTarget(bool prefer_dummy) {761return m_interpreter.GetDebugger().GetSelectedOrDummyTarget(prefer_dummy);762}763764Target &CommandObject::GetSelectedTarget() {765assert(m_flags.AnySet(eCommandRequiresTarget | eCommandProcessMustBePaused |766eCommandProcessMustBeLaunched | eCommandRequiresFrame |767eCommandRequiresThread | eCommandRequiresProcess |768eCommandRequiresRegContext) &&769"GetSelectedTarget called from object that may have no target");770return *m_interpreter.GetDebugger().GetSelectedTarget();771}772773Thread *CommandObject::GetDefaultThread() {774Thread *thread_to_use = m_exe_ctx.GetThreadPtr();775if (thread_to_use)776return thread_to_use;777778Process *process = m_exe_ctx.GetProcessPtr();779if (!process) {780Target *target = m_exe_ctx.GetTargetPtr();781if (!target) {782target = m_interpreter.GetDebugger().GetSelectedTarget().get();783}784if (target)785process = target->GetProcessSP().get();786}787788if (process)789return process->GetThreadList().GetSelectedThread().get();790else791return nullptr;792}793794void CommandObjectParsed::Execute(const char *args_string,795CommandReturnObject &result) {796bool handled = false;797Args cmd_args(args_string);798if (HasOverrideCallback()) {799Args full_args(GetCommandName());800full_args.AppendArguments(cmd_args);801handled =802InvokeOverrideCallback(full_args.GetConstArgumentVector(), result);803}804if (!handled) {805for (auto entry : llvm::enumerate(cmd_args.entries())) {806const Args::ArgEntry &value = entry.value();807if (!value.ref().empty() && value.GetQuoteChar() == '`') {808// We have to put the backtick back in place for PreprocessCommand.809std::string opt_string = value.c_str();810Status error;811error = m_interpreter.PreprocessToken(opt_string);812if (error.Success())813cmd_args.ReplaceArgumentAtIndex(entry.index(), opt_string);814}815}816817if (CheckRequirements(result)) {818if (ParseOptions(cmd_args, result)) {819// Call the command-specific version of 'Execute', passing it the820// already processed arguments.821if (cmd_args.GetArgumentCount() != 0 && m_arguments.empty()) {822result.AppendErrorWithFormatv("'{0}' doesn't take any arguments.",823GetCommandName());824Cleanup();825return;826}827m_interpreter.IncreaseCommandUsage(*this);828DoExecute(cmd_args, result);829}830}831832Cleanup();833}834}835836void CommandObjectRaw::Execute(const char *args_string,837CommandReturnObject &result) {838bool handled = false;839if (HasOverrideCallback()) {840std::string full_command(GetCommandName());841full_command += ' ';842full_command += args_string;843const char *argv[2] = {nullptr, nullptr};844argv[0] = full_command.c_str();845handled = InvokeOverrideCallback(argv, result);846}847if (!handled) {848if (CheckRequirements(result))849DoExecute(args_string, result);850851Cleanup();852}853}854855856