856 lines · cpp
1//===-- CommandObject.cpp -------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Interpreter/CommandObject.h"10 11#include <map>12#include <sstream>13#include <string>14 15#include <cctype>16#include <cstdlib>17 18#include "lldb/Core/Address.h"19#include "lldb/Interpreter/CommandOptionArgumentTable.h"20#include "lldb/Interpreter/Options.h"21#include "lldb/Utility/ArchSpec.h"22#include "llvm/ADT/ScopeExit.h"23 24// These are for the Sourcename completers.25// FIXME: Make a separate file for the completers.26#include "lldb/DataFormatters/FormatManager.h"27#include "lldb/Target/Process.h"28#include "lldb/Target/Target.h"29#include "lldb/Utility/FileSpec.h"30#include "lldb/Utility/FileSpecList.h"31 32#include "lldb/Target/Language.h"33 34#include "lldb/Interpreter/CommandInterpreter.h"35#include "lldb/Interpreter/CommandReturnObject.h"36 37using namespace lldb;38using namespace lldb_private;39 40// CommandObject41 42CommandObject::CommandObject(CommandInterpreter &interpreter,43 llvm::StringRef name, llvm::StringRef help,44 llvm::StringRef syntax, uint32_t flags)45 : m_interpreter(interpreter), m_cmd_name(std::string(name)),46 m_flags(flags), m_deprecated_command_override_callback(nullptr),47 m_command_override_callback(nullptr), m_command_override_baton(nullptr) {48 m_cmd_help_short = std::string(help);49 m_cmd_syntax = std::string(syntax);50}51 52Debugger &CommandObject::GetDebugger() { return m_interpreter.GetDebugger(); }53 54llvm::StringRef CommandObject::GetHelp() { return m_cmd_help_short; }55 56llvm::StringRef CommandObject::GetHelpLong() { return m_cmd_help_long; }57 58llvm::StringRef CommandObject::GetSyntax() {59 if (!m_cmd_syntax.empty())60 return m_cmd_syntax;61 62 StreamString syntax_str;63 syntax_str.PutCString(GetCommandName());64 65 if (!IsDashDashCommand() && GetOptions() != nullptr)66 syntax_str.PutCString(" <cmd-options>");67 68 if (!m_arguments.empty()) {69 syntax_str.PutCString(" ");70 71 if (!IsDashDashCommand() && WantsRawCommandString() && GetOptions() &&72 GetOptions()->NumCommandOptions())73 syntax_str.PutCString("-- ");74 GetFormattedCommandArguments(syntax_str);75 }76 m_cmd_syntax = std::string(syntax_str.GetString());77 78 return m_cmd_syntax;79}80 81llvm::StringRef CommandObject::GetCommandName() const { return m_cmd_name; }82 83void CommandObject::SetCommandName(llvm::StringRef name) {84 m_cmd_name = std::string(name);85}86 87void CommandObject::SetHelp(llvm::StringRef str) {88 m_cmd_help_short = std::string(str);89}90 91void CommandObject::SetHelpLong(llvm::StringRef str) {92 m_cmd_help_long = std::string(str);93}94 95void CommandObject::SetSyntax(llvm::StringRef str) {96 m_cmd_syntax = std::string(str);97}98 99Options *CommandObject::GetOptions() {100 // By default commands don't have options unless this virtual function is101 // overridden by base classes.102 return nullptr;103}104 105bool CommandObject::ParseOptions(Args &args, CommandReturnObject &result) {106 // See if the subclass has options?107 Options *options = GetOptions();108 if (options != nullptr) {109 Status error;110 111 auto exe_ctx = GetCommandInterpreter().GetExecutionContext();112 options->NotifyOptionParsingStarting(&exe_ctx);113 114 const bool require_validation = true;115 llvm::Expected<Args> args_or = options->Parse(116 args, &exe_ctx, GetCommandInterpreter().GetPlatform(true),117 require_validation);118 119 if (args_or) {120 args = std::move(*args_or);121 error = options->NotifyOptionParsingFinished(&exe_ctx);122 } else {123 error = Status::FromError(args_or.takeError());124 }125 126 if (error.Fail()) {127 result.SetError(error.takeError());128 result.SetStatus(eReturnStatusFailed);129 return false;130 }131 132 if (llvm::Error error = options->VerifyOptions()) {133 result.SetError(std::move(error));134 result.SetStatus(eReturnStatusFailed);135 return false;136 }137 138 result.SetStatus(eReturnStatusSuccessFinishNoResult);139 return true;140 }141 return true;142}143 144bool CommandObject::CheckRequirements(CommandReturnObject &result) {145 // Nothing should be stored in m_exe_ctx between running commands as146 // m_exe_ctx has shared pointers to the target, process, thread and frame and147 // we don't want any CommandObject instances to keep any of these objects148 // around longer than for a single command. Every command should call149 // CommandObject::Cleanup() after it has completed.150 assert(!m_exe_ctx.GetTargetPtr());151 assert(!m_exe_ctx.GetProcessPtr());152 assert(!m_exe_ctx.GetThreadPtr());153 assert(!m_exe_ctx.GetFramePtr());154 155 // Lock down the interpreter's execution context prior to running the command156 // so we guarantee the selected target, process, thread and frame can't go157 // away during the execution158 m_exe_ctx = m_interpreter.GetExecutionContext();159 160 const uint32_t flags = GetFlags().Get();161 if (flags & (eCommandRequiresTarget | eCommandRequiresProcess |162 eCommandRequiresThread | eCommandRequiresFrame |163 eCommandTryTargetAPILock)) {164 165 if ((flags & eCommandRequiresTarget) && !m_exe_ctx.HasTargetScope()) {166 result.AppendError(GetInvalidTargetDescription());167 return false;168 }169 170 if ((flags & eCommandRequiresProcess) && !m_exe_ctx.HasProcessScope()) {171 if (!m_exe_ctx.HasTargetScope())172 result.AppendError(GetInvalidTargetDescription());173 else174 result.AppendError(GetInvalidProcessDescription());175 return false;176 }177 178 if ((flags & eCommandRequiresThread) && !m_exe_ctx.HasThreadScope()) {179 if (!m_exe_ctx.HasTargetScope())180 result.AppendError(GetInvalidTargetDescription());181 else if (!m_exe_ctx.HasProcessScope())182 result.AppendError(GetInvalidProcessDescription());183 else184 result.AppendError(GetInvalidThreadDescription());185 return false;186 }187 188 if ((flags & eCommandRequiresFrame) && !m_exe_ctx.HasFrameScope()) {189 if (!m_exe_ctx.HasTargetScope())190 result.AppendError(GetInvalidTargetDescription());191 else if (!m_exe_ctx.HasProcessScope())192 result.AppendError(GetInvalidProcessDescription());193 else if (!m_exe_ctx.HasThreadScope())194 result.AppendError(GetInvalidThreadDescription());195 else196 result.AppendError(GetInvalidFrameDescription());197 return false;198 }199 200 if ((flags & eCommandRequiresRegContext) &&201 (m_exe_ctx.GetRegisterContext() == nullptr)) {202 result.AppendError(GetInvalidRegContextDescription());203 return false;204 }205 206 if (flags & eCommandTryTargetAPILock) {207 Target *target = m_exe_ctx.GetTargetPtr();208 if (target)209 m_api_locker =210 std::unique_lock<std::recursive_mutex>(target->GetAPIMutex());211 }212 }213 214 if (GetFlags().AnySet(eCommandProcessMustBeLaunched |215 eCommandProcessMustBePaused)) {216 Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();217 if (process == nullptr) {218 // A process that is not running is considered paused.219 if (GetFlags().Test(eCommandProcessMustBeLaunched)) {220 result.AppendError("process must exist");221 return false;222 }223 } else {224 StateType state = process->GetState();225 switch (state) {226 case eStateInvalid:227 case eStateSuspended:228 case eStateCrashed:229 case eStateStopped:230 break;231 232 case eStateConnected:233 case eStateAttaching:234 case eStateLaunching:235 case eStateDetached:236 case eStateExited:237 case eStateUnloaded:238 if (GetFlags().Test(eCommandProcessMustBeLaunched)) {239 result.AppendError("process must be launched");240 return false;241 }242 break;243 244 case eStateRunning:245 case eStateStepping:246 if (GetFlags().Test(eCommandProcessMustBePaused)) {247 result.AppendError("Process is running. Use 'process interrupt' to "248 "pause execution.");249 return false;250 }251 }252 }253 }254 255 if (GetFlags().Test(eCommandProcessMustBeTraced)) {256 Target *target = m_exe_ctx.GetTargetPtr();257 if (target && !target->GetTrace()) {258 result.AppendError("process is not being traced");259 return false;260 }261 }262 263 return true;264}265 266void CommandObject::Cleanup() {267 m_exe_ctx.Clear();268 if (m_api_locker.owns_lock())269 m_api_locker.unlock();270}271 272void CommandObject::HandleCompletion(CompletionRequest &request) {273 274 m_exe_ctx = m_interpreter.GetExecutionContext();275 auto reset_ctx = llvm::make_scope_exit([this]() { Cleanup(); });276 277 // Default implementation of WantsCompletion() is !WantsRawCommandString().278 // Subclasses who want raw command string but desire, for example, argument279 // completion should override WantsCompletion() to return true, instead.280 if (WantsRawCommandString() && !WantsCompletion()) {281 // FIXME: Abstract telling the completion to insert the completion282 // character.283 return;284 } else {285 // Can we do anything generic with the options?286 Options *cur_options = GetOptions();287 OptionElementVector opt_element_vector;288 289 if (cur_options != nullptr) {290 opt_element_vector = cur_options->ParseForCompletion(291 request.GetParsedLine(), request.GetCursorIndex());292 293 bool handled_by_options = cur_options->HandleOptionCompletion(294 request, opt_element_vector, GetCommandInterpreter());295 if (handled_by_options)296 return;297 }298 299 // If we got here, the last word is not an option or an option argument.300 HandleArgumentCompletion(request, opt_element_vector);301 }302}303 304void CommandObject::HandleArgumentCompletion(305 CompletionRequest &request, OptionElementVector &opt_element_vector) {306 size_t num_arg_entries = GetNumArgumentEntries();307 if (num_arg_entries != 1)308 return;309 310 CommandArgumentEntry *entry_ptr = GetArgumentEntryAtIndex(0);311 if (!entry_ptr) {312 assert(entry_ptr && "We said there was one entry, but there wasn't.");313 return; // Not worth crashing if asserts are off...314 }315 316 CommandArgumentEntry &entry = *entry_ptr;317 // For now, we only handle the simple case of one homogenous argument type.318 if (entry.size() != 1)319 return;320 321 // Look up the completion type, and if it has one, invoke it:322 const CommandObject::ArgumentTableEntry *arg_entry =323 FindArgumentDataByType(entry[0].arg_type);324 const ArgumentRepetitionType repeat = entry[0].arg_repetition;325 326 if (arg_entry == nullptr || arg_entry->completion_type == lldb::eNoCompletion)327 return;328 329 // FIXME: This should be handled higher in the Command Parser.330 // Check the case where this command only takes one argument, and don't do331 // the completion if we aren't on the first entry:332 if (repeat == eArgRepeatPlain && request.GetCursorIndex() != 0)333 return;334 335 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(336 GetCommandInterpreter(), arg_entry->completion_type, request, nullptr);337 338}339 340bool CommandObject::HelpTextContainsWord(llvm::StringRef search_word,341 bool search_short_help,342 bool search_long_help,343 bool search_syntax,344 bool search_options) {345 bool found_word = false;346 347 llvm::StringRef short_help = GetHelp();348 llvm::StringRef long_help = GetHelpLong();349 llvm::StringRef syntax_help = GetSyntax();350 351 if (search_short_help && short_help.contains_insensitive(search_word))352 found_word = true;353 else if (search_long_help && long_help.contains_insensitive(search_word))354 found_word = true;355 else if (search_syntax && syntax_help.contains_insensitive(search_word))356 found_word = true;357 358 if (!found_word && search_options && GetOptions() != nullptr) {359 StreamString usage_help;360 GetOptions()->GenerateOptionUsage(361 usage_help, *this,362 GetCommandInterpreter().GetDebugger().GetTerminalWidth(),363 GetCommandInterpreter().GetDebugger().GetUseColor());364 if (!usage_help.Empty()) {365 llvm::StringRef usage_text = usage_help.GetString();366 if (usage_text.contains_insensitive(search_word))367 found_word = true;368 }369 }370 371 return found_word;372}373 374bool CommandObject::ParseOptionsAndNotify(Args &args,375 CommandReturnObject &result,376 OptionGroupOptions &group_options,377 ExecutionContext &exe_ctx) {378 if (!ParseOptions(args, result))379 return false;380 381 Status error(group_options.NotifyOptionParsingFinished(&exe_ctx));382 if (error.Fail()) {383 result.AppendError(error.AsCString());384 return false;385 }386 return true;387}388 389void CommandObject::AddSimpleArgumentList(390 CommandArgumentType arg_type, ArgumentRepetitionType repetition_type) {391 392 CommandArgumentEntry arg_entry;393 CommandArgumentData simple_arg;394 395 // Define the first (and only) variant of this arg.396 simple_arg.arg_type = arg_type;397 simple_arg.arg_repetition = repetition_type;398 399 // There is only one variant this argument could be; put it into the argument400 // entry.401 arg_entry.push_back(simple_arg);402 403 // Push the data for the first argument into the m_arguments vector.404 m_arguments.push_back(arg_entry);405}406 407int CommandObject::GetNumArgumentEntries() { return m_arguments.size(); }408 409CommandObject::CommandArgumentEntry *410CommandObject::GetArgumentEntryAtIndex(int idx) {411 if (static_cast<size_t>(idx) < m_arguments.size())412 return &(m_arguments[idx]);413 414 return nullptr;415}416 417const CommandObject::ArgumentTableEntry *418CommandObject::FindArgumentDataByType(CommandArgumentType arg_type) {419 for (int i = 0; i < eArgTypeLastArg; ++i)420 if (g_argument_table[i].arg_type == arg_type)421 return &(g_argument_table[i]);422 423 return nullptr;424}425 426void CommandObject::GetArgumentHelp(Stream &str, CommandArgumentType arg_type,427 CommandInterpreter &interpreter) {428 const ArgumentTableEntry *entry = &(g_argument_table[arg_type]);429 430 // The table is *supposed* to be kept in arg_type order, but someone *could*431 // have messed it up...432 433 if (entry->arg_type != arg_type)434 entry = CommandObject::FindArgumentDataByType(arg_type);435 436 if (!entry)437 return;438 439 StreamString name_str;440 name_str.Printf("<%s>", entry->arg_name);441 442 if (entry->help_function) {443 llvm::StringRef help_text = entry->help_function();444 if (!entry->help_function.self_formatting) {445 interpreter.OutputFormattedHelpText(str, name_str.GetString(), "--",446 help_text, name_str.GetSize());447 } else {448 interpreter.OutputHelpText(str, name_str.GetString(), "--", help_text,449 name_str.GetSize());450 }451 } else {452 interpreter.OutputFormattedHelpText(str, name_str.GetString(), "--",453 entry->help_text, name_str.GetSize());454 455 // Print enum values and their description if any.456 OptionEnumValues enum_values = g_argument_table[arg_type].enum_values;457 if (!enum_values.empty()) {458 str.EOL();459 size_t longest = 0;460 for (const OptionEnumValueElement &element : enum_values)461 longest =462 std::max(longest, llvm::StringRef(element.string_value).size());463 str.IndentMore(5);464 for (const OptionEnumValueElement &element : enum_values) {465 str.Indent();466 interpreter.OutputHelpText(str, element.string_value, ":",467 element.usage, longest);468 }469 str.IndentLess(5);470 str.EOL();471 }472 }473}474 475const char *CommandObject::GetArgumentName(CommandArgumentType arg_type) {476 const ArgumentTableEntry *entry = &(g_argument_table[arg_type]);477 478 // The table is *supposed* to be kept in arg_type order, but someone *could*479 // have messed it up...480 481 if (entry->arg_type != arg_type)482 entry = CommandObject::FindArgumentDataByType(arg_type);483 484 if (entry)485 return entry->arg_name;486 487 return nullptr;488}489 490bool CommandObject::IsPairType(ArgumentRepetitionType arg_repeat_type) {491 return (arg_repeat_type == eArgRepeatPairPlain) ||492 (arg_repeat_type == eArgRepeatPairOptional) ||493 (arg_repeat_type == eArgRepeatPairPlus) ||494 (arg_repeat_type == eArgRepeatPairStar) ||495 (arg_repeat_type == eArgRepeatPairRange) ||496 (arg_repeat_type == eArgRepeatPairRangeOptional);497}498 499std::optional<ArgumentRepetitionType> 500CommandObject::ArgRepetitionFromString(llvm::StringRef string) {501 return llvm::StringSwitch<ArgumentRepetitionType>(string)502 .Case("plain", eArgRepeatPlain) 503 .Case("optional", eArgRepeatOptional)504 .Case("plus", eArgRepeatPlus)505 .Case("star", eArgRepeatStar) 506 .Case("range", eArgRepeatRange)507 .Case("pair-plain", eArgRepeatPairPlain)508 .Case("pair-optional", eArgRepeatPairOptional)509 .Case("pair-plus", eArgRepeatPairPlus)510 .Case("pair-star", eArgRepeatPairStar)511 .Case("pair-range", eArgRepeatPairRange)512 .Case("pair-range-optional", eArgRepeatPairRangeOptional)513 .Default({});514}515 516static CommandObject::CommandArgumentEntry517OptSetFiltered(uint32_t opt_set_mask,518 CommandObject::CommandArgumentEntry &cmd_arg_entry) {519 CommandObject::CommandArgumentEntry ret_val;520 for (unsigned i = 0; i < cmd_arg_entry.size(); ++i)521 if (opt_set_mask & cmd_arg_entry[i].arg_opt_set_association)522 ret_val.push_back(cmd_arg_entry[i]);523 return ret_val;524}525 526// Default parameter value of opt_set_mask is LLDB_OPT_SET_ALL, which means527// take all the argument data into account. On rare cases where some argument528// sticks with certain option sets, this function returns the option set529// filtered args.530void CommandObject::GetFormattedCommandArguments(Stream &str,531 uint32_t opt_set_mask) {532 int num_args = m_arguments.size();533 for (int i = 0; i < num_args; ++i) {534 if (i > 0)535 str.Printf(" ");536 CommandArgumentEntry arg_entry =537 opt_set_mask == LLDB_OPT_SET_ALL538 ? m_arguments[i]539 : OptSetFiltered(opt_set_mask, m_arguments[i]);540 // This argument is not associated with the current option set, so skip it.541 if (arg_entry.empty())542 continue;543 int num_alternatives = arg_entry.size();544 545 if ((num_alternatives == 2) && IsPairType(arg_entry[0].arg_repetition)) {546 const char *first_name = GetArgumentName(arg_entry[0].arg_type);547 const char *second_name = GetArgumentName(arg_entry[1].arg_type);548 switch (arg_entry[0].arg_repetition) {549 case eArgRepeatPairPlain:550 str.Printf("<%s> <%s>", first_name, second_name);551 break;552 case eArgRepeatPairOptional:553 str.Printf("[<%s> <%s>]", first_name, second_name);554 break;555 case eArgRepeatPairPlus:556 str.Printf("<%s> <%s> [<%s> <%s> [...]]", first_name, second_name,557 first_name, second_name);558 break;559 case eArgRepeatPairStar:560 str.Printf("[<%s> <%s> [<%s> <%s> [...]]]", first_name, second_name,561 first_name, second_name);562 break;563 case eArgRepeatPairRange:564 str.Printf("<%s_1> <%s_1> ... <%s_n> <%s_n>", first_name, second_name,565 first_name, second_name);566 break;567 case eArgRepeatPairRangeOptional:568 str.Printf("[<%s_1> <%s_1> ... <%s_n> <%s_n>]", first_name, second_name,569 first_name, second_name);570 break;571 // Explicitly test for all the rest of the cases, so if new types get572 // added we will notice the missing case statement(s).573 case eArgRepeatPlain:574 case eArgRepeatOptional:575 case eArgRepeatPlus:576 case eArgRepeatStar:577 case eArgRepeatRange:578 // These should not be reached, as they should fail the IsPairType test579 // above.580 break;581 }582 } else {583 StreamString names;584 for (int j = 0; j < num_alternatives; ++j) {585 if (j > 0)586 names.Printf(" | ");587 names.Printf("%s", GetArgumentName(arg_entry[j].arg_type));588 }589 590 std::string name_str = std::string(names.GetString());591 switch (arg_entry[0].arg_repetition) {592 case eArgRepeatPlain:593 str.Printf("<%s>", name_str.c_str());594 break;595 case eArgRepeatPlus:596 str.Printf("<%s> [<%s> [...]]", name_str.c_str(), name_str.c_str());597 break;598 case eArgRepeatStar:599 str.Printf("[<%s> [<%s> [...]]]", name_str.c_str(), name_str.c_str());600 break;601 case eArgRepeatOptional:602 str.Printf("[<%s>]", name_str.c_str());603 break;604 case eArgRepeatRange:605 str.Printf("<%s_1> .. <%s_n>", name_str.c_str(), name_str.c_str());606 break;607 // Explicitly test for all the rest of the cases, so if new types get608 // added we will notice the missing case statement(s).609 case eArgRepeatPairPlain:610 case eArgRepeatPairOptional:611 case eArgRepeatPairPlus:612 case eArgRepeatPairStar:613 case eArgRepeatPairRange:614 case eArgRepeatPairRangeOptional:615 // These should not be hit, as they should pass the IsPairType test616 // above, and control should have gone into the other branch of the if617 // statement.618 break;619 }620 }621 }622}623 624CommandArgumentType625CommandObject::LookupArgumentName(llvm::StringRef arg_name) {626 CommandArgumentType return_type = eArgTypeLastArg;627 628 arg_name = arg_name.ltrim('<').rtrim('>');629 630 for (int i = 0; i < eArgTypeLastArg; ++i)631 if (arg_name == g_argument_table[i].arg_name)632 return_type = g_argument_table[i].arg_type;633 634 return return_type;635}636 637void CommandObject::FormatLongHelpText(Stream &output_strm,638 llvm::StringRef long_help) {639 CommandInterpreter &interpreter = GetCommandInterpreter();640 std::stringstream lineStream{std::string(long_help)};641 std::string line;642 while (std::getline(lineStream, line)) {643 if (line.empty()) {644 output_strm << "\n";645 continue;646 }647 size_t result = line.find_first_not_of(" \t");648 if (result == std::string::npos) {649 result = 0;650 }651 std::string whitespace_prefix = line.substr(0, result);652 std::string remainder = line.substr(result);653 interpreter.OutputFormattedHelpText(output_strm, whitespace_prefix,654 remainder);655 }656}657 658void CommandObject::GenerateHelpText(CommandReturnObject &result) {659 GenerateHelpText(result.GetOutputStream());660 661 result.SetStatus(eReturnStatusSuccessFinishNoResult);662}663 664void CommandObject::GenerateHelpText(Stream &output_strm) {665 CommandInterpreter &interpreter = GetCommandInterpreter();666 std::string help_text(GetHelp());667 if (WantsRawCommandString()) {668 help_text.append(" Expects 'raw' input (see 'help raw-input'.)");669 }670 interpreter.OutputFormattedHelpText(output_strm, "", help_text);671 output_strm << "\nSyntax: " << GetSyntax() << "\n";672 Options *options = GetOptions();673 if (options != nullptr) {674 options->GenerateOptionUsage(675 output_strm, *this,676 GetCommandInterpreter().GetDebugger().GetTerminalWidth(),677 GetCommandInterpreter().GetDebugger().GetUseColor());678 }679 llvm::StringRef long_help = GetHelpLong();680 if (!long_help.empty()) {681 FormatLongHelpText(output_strm, long_help);682 }683 if (!IsDashDashCommand() && options && options->NumCommandOptions() > 0) {684 if (WantsRawCommandString() && !WantsCompletion()) {685 // Emit the message about using ' -- ' between the end of the command686 // options and the raw input conditionally, i.e., only if the command687 // object does not want completion.688 interpreter.OutputFormattedHelpText(689 output_strm, "", "",690 "\nImportant Note: Because this command takes 'raw' input, if you "691 "use any command options"692 " you must use ' -- ' between the end of the command options and the "693 "beginning of the raw input.",694 1);695 } else if (GetNumArgumentEntries() > 0) {696 // Also emit a warning about using "--" in case you are using a command697 // that takes options and arguments.698 interpreter.OutputFormattedHelpText(699 output_strm, "", "",700 "\nThis command takes options and free-form arguments. If your "701 "arguments resemble"702 " option specifiers (i.e., they start with a - or --), you must use "703 "' -- ' between"704 " the end of the command options and the beginning of the arguments.",705 1);706 }707 }708}709 710void CommandObject::AddIDsArgumentData(CommandObject::IDType type) {711 CommandArgumentEntry arg;712 CommandArgumentData id_arg;713 CommandArgumentData id_range_arg;714 715 // Create the first variant for the first (and only) argument for this716 // command.717 switch (type) {718 case eBreakpointArgs:719 id_arg.arg_type = eArgTypeBreakpointID;720 id_range_arg.arg_type = eArgTypeBreakpointIDRange;721 break;722 case eWatchpointArgs:723 id_arg.arg_type = eArgTypeWatchpointID;724 id_range_arg.arg_type = eArgTypeWatchpointIDRange;725 break;726 }727 id_arg.arg_repetition = eArgRepeatOptional;728 id_range_arg.arg_repetition = eArgRepeatOptional;729 730 // The first (and only) argument for this command could be either an id or an731 // id_range. Push both variants into the entry for the first argument for732 // this command.733 arg.push_back(id_arg);734 arg.push_back(id_range_arg);735 m_arguments.push_back(arg);736}737 738const char *CommandObject::GetArgumentTypeAsCString(739 const lldb::CommandArgumentType arg_type) {740 assert(arg_type < eArgTypeLastArg &&741 "Invalid argument type passed to GetArgumentTypeAsCString");742 return g_argument_table[arg_type].arg_name;743}744 745const char *CommandObject::GetArgumentDescriptionAsCString(746 const lldb::CommandArgumentType arg_type) {747 assert(arg_type < eArgTypeLastArg &&748 "Invalid argument type passed to GetArgumentDescriptionAsCString");749 return g_argument_table[arg_type].help_text;750}751 752Target &CommandObject::GetDummyTarget() {753 return m_interpreter.GetDebugger().GetDummyTarget();754}755 756Target &CommandObject::GetTarget() {757 // Prefer the frozen execution context in the command object.758 if (Target *target = m_exe_ctx.GetTargetPtr())759 return *target;760 761 // Fallback to the command interpreter's execution context in case we get762 // called after DoExecute has finished. For example, when doing multi-line763 // expression that uses an input reader or breakpoint callbacks.764 if (Target *target = m_interpreter.GetExecutionContext().GetTargetPtr())765 return *target;766 767 // Finally, if we have no other target, get the selected target.768 if (TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget())769 return *target_sp;770 771 // We only have the dummy target.772 return GetDummyTarget();773}774 775Thread *CommandObject::GetDefaultThread() {776 Thread *thread_to_use = m_exe_ctx.GetThreadPtr();777 if (thread_to_use)778 return thread_to_use;779 780 Process *process = m_exe_ctx.GetProcessPtr();781 if (!process) {782 Target *target = m_exe_ctx.GetTargetPtr();783 if (!target) {784 target = m_interpreter.GetDebugger().GetSelectedTarget().get();785 }786 if (target)787 process = target->GetProcessSP().get();788 }789 790 if (process)791 return process->GetThreadList().GetSelectedThread().get();792 else793 return nullptr;794}795 796void CommandObjectParsed::Execute(const char *args_string,797 CommandReturnObject &result) {798 bool handled = false;799 Args cmd_args(args_string);800 if (HasOverrideCallback()) {801 Args full_args(GetCommandName());802 full_args.AppendArguments(cmd_args);803 handled =804 InvokeOverrideCallback(full_args.GetConstArgumentVector(), result);805 }806 if (!handled) {807 for (auto entry : llvm::enumerate(cmd_args.entries())) {808 const Args::ArgEntry &value = entry.value();809 if (!value.ref().empty() && value.GetQuoteChar() == '`') {810 // We have to put the backtick back in place for PreprocessCommand.811 std::string opt_string = value.c_str();812 Status error;813 error = m_interpreter.PreprocessToken(opt_string);814 if (error.Success())815 cmd_args.ReplaceArgumentAtIndex(entry.index(), opt_string);816 }817 }818 819 if (CheckRequirements(result)) {820 if (ParseOptions(cmd_args, result)) {821 // Call the command-specific version of 'Execute', passing it the822 // already processed arguments.823 if (cmd_args.GetArgumentCount() != 0 && m_arguments.empty()) {824 result.AppendErrorWithFormatv("'{0}' doesn't take any arguments.",825 GetCommandName());826 Cleanup();827 return;828 }829 m_interpreter.IncreaseCommandUsage(*this);830 DoExecute(cmd_args, result);831 }832 }833 834 Cleanup();835 }836}837 838void CommandObjectRaw::Execute(const char *args_string,839 CommandReturnObject &result) {840 bool handled = false;841 if (HasOverrideCallback()) {842 std::string full_command(GetCommandName());843 full_command += ' ';844 full_command += args_string;845 const char *argv[2] = {nullptr, nullptr};846 argv[0] = full_command.c_str();847 handled = InvokeOverrideCallback(argv, result);848 }849 if (!handled) {850 if (CheckRequirements(result))851 DoExecute(args_string, result);852 853 Cleanup();854 }855}856