Have CommandObjectParsed check for "commands that take no arguments".

This is currently being done in an ad hoc way, and so for some
commands it isn't being checked.  We have the info to make this check,
since commands are supposed to add their arguments to the m_arguments
field of the CommandObject.  This change uses that info to check whether
the command received arguments in error.

A handful of commands weren't defining their argument types, I also had
to fix them.  And a bunch of commands were checking for arguments by
hand, so I removed those checks in favor of the CommandObject one.  That
also meant I had to change some tests that were checking for the ad hoc
error outputs.

Differential Revision: https://reviews.llvm.org/D128453
This commit is contained in:
Jim Ingham 2022-06-23 09:33:40 -07:00
parent 6824eee942
commit c1b07d6177
27 changed files with 333 additions and 321 deletions

View File

@ -603,6 +603,11 @@ enum CommandArgumentType {
eArgTypeModuleUUID,
eArgTypeSaveCoreStyle,
eArgTypeLogHandler,
eArgTypeSEDStylePair,
eArgTypeRecognizerID,
eArgTypeConnectURL,
eArgTypeTargetID,
eArgTypeStopHookID,
eArgTypeLastArg // Always keep this entry as the last entry in this
// enumeration!!
};

View File

@ -47,6 +47,10 @@ public:
auto_repeat_command == nullptr
? llvm::None
: llvm::Optional<std::string>(auto_repeat_command);
// We don't know whether any given command coming from this interface takes
// arguments or not so here we're just disabling the basic args check.
CommandArgumentData none_arg{eArgTypeNone, eArgRepeatStar};
m_arguments.push_back({none_arg});
}
bool IsRemovable() const override { return true; }

View File

@ -824,6 +824,8 @@ a number follows 'f':"
R"(
(lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
CommandArgumentData thread_arg{eArgTypeSEDStylePair, eArgRepeatOptional};
m_arguments.push_back({thread_arg});
}
~CommandObjectCommandsAddRegex() override = default;
@ -1664,11 +1666,6 @@ public:
~CommandObjectCommandsScriptList() override = default;
bool DoExecute(Args &command, CommandReturnObject &result) override {
if (command.GetArgumentCount() != 0) {
result.AppendError("'command script list' doesn't take any arguments");
return false;
}
m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
result.SetStatus(eReturnStatusSuccessFinishResult);
@ -1689,11 +1686,6 @@ public:
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
if (command.GetArgumentCount() != 0) {
result.AppendError("'command script clear' doesn't take any arguments");
return false;
}
m_interpreter.RemoveAllUser();
result.SetStatus(eReturnStatusSuccessFinishResult);

View File

@ -924,7 +924,11 @@ class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
public:
CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "frame recognizer delete",
"Delete an existing frame recognizer.", nullptr) {}
"Delete an existing frame recognizer by id.",
nullptr) {
CommandArgumentData thread_arg{eArgTypeRecognizerID, eArgRepeatPlain};
m_arguments.push_back({thread_arg});
}
~CommandObjectFrameRecognizerDelete() override = default;

View File

@ -26,22 +26,18 @@ CommandObjectGUI::~CommandObjectGUI() = default;
bool CommandObjectGUI::DoExecute(Args &args, CommandReturnObject &result) {
#if LLDB_ENABLE_CURSES
if (args.GetArgumentCount() == 0) {
Debugger &debugger = GetDebugger();
Debugger &debugger = GetDebugger();
File &input = debugger.GetInputFile();
File &output = debugger.GetOutputFile();
if (input.GetStream() && output.GetStream() && input.GetIsRealTerminal() &&
input.GetIsInteractive()) {
IOHandlerSP io_handler_sp(new IOHandlerCursesGUI(debugger));
if (io_handler_sp)
debugger.RunIOHandlerAsync(io_handler_sp);
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
result.AppendError("the gui command requires an interactive terminal.");
}
File &input = debugger.GetInputFile();
File &output = debugger.GetOutputFile();
if (input.GetStream() && output.GetStream() && input.GetIsRealTerminal() &&
input.GetIsInteractive()) {
IOHandlerSP io_handler_sp(new IOHandlerCursesGUI(debugger));
if (io_handler_sp)
debugger.RunIOHandlerAsync(io_handler_sp);
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
result.AppendError("the gui command takes no arguments.");
result.AppendError("the gui command requires an interactive terminal.");
}
return true;
#else

View File

@ -150,6 +150,8 @@ public:
{
m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1);
m_option_group.Finalize();
CommandArgumentData platform_arg{eArgTypePlatform, eArgRepeatPlain};
m_arguments.push_back({platform_arg});
}
~CommandObjectPlatformSelect() override = default;
@ -271,7 +273,10 @@ public:
: CommandObjectParsed(
interpreter, "platform connect",
"Select the current platform by providing a connection URL.",
"platform connect <connect-url>", 0) {}
"platform connect <connect-url>", 0) {
CommandArgumentData platform_arg{eArgTypeConnectURL, eArgRepeatPlain};
m_arguments.push_back({platform_arg});
}
~CommandObjectPlatformConnect() override = default;
@ -415,7 +420,10 @@ public:
CommandObjectPlatformMkDir(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "platform mkdir",
"Make a new directory on the remote end.", nullptr,
0) {}
0) {
CommandArgumentData thread_arg{eArgTypePath, eArgRepeatPlain};
m_arguments.push_back({thread_arg});
}
~CommandObjectPlatformMkDir() override = default;
@ -461,7 +469,10 @@ class CommandObjectPlatformFOpen : public CommandObjectParsed {
public:
CommandObjectPlatformFOpen(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "platform file open",
"Open a file on the remote end.", nullptr, 0) {}
"Open a file on the remote end.", nullptr, 0) {
CommandArgumentData path_arg{eArgTypePath, eArgRepeatPlain};
m_arguments.push_back({path_arg});
}
~CommandObjectPlatformFOpen() override = default;
@ -521,7 +532,10 @@ class CommandObjectPlatformFClose : public CommandObjectParsed {
public:
CommandObjectPlatformFClose(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "platform file close",
"Close a file on the remote end.", nullptr, 0) {}
"Close a file on the remote end.", nullptr, 0) {
CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
m_arguments.push_back({path_arg});
}
~CommandObjectPlatformFClose() override = default;
@ -562,7 +576,10 @@ public:
CommandObjectPlatformFRead(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "platform file read",
"Read data from a file on the remote end.", nullptr,
0) {}
0) {
CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
m_arguments.push_back({path_arg});
}
~CommandObjectPlatformFRead() override = default;
@ -655,7 +672,10 @@ public:
CommandObjectPlatformFWrite(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "platform file write",
"Write data to a file on the remote end.", nullptr,
0) {}
0) {
CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
m_arguments.push_back({path_arg});
}
~CommandObjectPlatformFWrite() override = default;
@ -1070,6 +1090,10 @@ public:
Relative source file paths are resolved against lldb's local working directory.
Omitting the destination places the file in the platform working directory.)");
CommandArgumentData source_arg{eArgTypePath, eArgRepeatPlain};
CommandArgumentData path_arg{eArgTypePath, eArgRepeatOptional};
m_arguments.push_back({source_arg});
m_arguments.push_back({path_arg});
}
~CommandObjectPlatformPutFile() override = default;
@ -1121,6 +1145,8 @@ public:
eCommandRequiresTarget | eCommandTryTargetAPILock) {
m_all_options.Append(&m_options);
m_all_options.Finalize();
CommandArgumentData run_arg_arg{eArgTypeRunArgs, eArgRepeatStar};
m_arguments.push_back({run_arg_arg});
}
~CommandObjectPlatformProcessLaunch() override = default;
@ -1229,83 +1255,78 @@ protected:
if (platform_sp) {
Status error;
if (args.GetArgumentCount() == 0) {
if (platform_sp) {
Stream &ostrm = result.GetOutputStream();
if (platform_sp) {
Stream &ostrm = result.GetOutputStream();
lldb::pid_t pid =
m_options.match_info.GetProcessInfo().GetProcessID();
if (pid != LLDB_INVALID_PROCESS_ID) {
ProcessInstanceInfo proc_info;
if (platform_sp->GetProcessInfo(pid, proc_info)) {
ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
m_options.verbose);
proc_info.DumpAsTableRow(ostrm, platform_sp->GetUserIDResolver(),
m_options.show_args, m_options.verbose);
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
result.AppendErrorWithFormat(
"no process found with pid = %" PRIu64 "\n", pid);
}
lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();
if (pid != LLDB_INVALID_PROCESS_ID) {
ProcessInstanceInfo proc_info;
if (platform_sp->GetProcessInfo(pid, proc_info)) {
ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
m_options.verbose);
proc_info.DumpAsTableRow(ostrm, platform_sp->GetUserIDResolver(),
m_options.show_args, m_options.verbose);
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
ProcessInstanceInfoList proc_infos;
const uint32_t matches =
platform_sp->FindProcesses(m_options.match_info, proc_infos);
const char *match_desc = nullptr;
const char *match_name =
m_options.match_info.GetProcessInfo().GetName();
if (match_name && match_name[0]) {
switch (m_options.match_info.GetNameMatchType()) {
case NameMatch::Ignore:
break;
case NameMatch::Equals:
match_desc = "matched";
break;
case NameMatch::Contains:
match_desc = "contained";
break;
case NameMatch::StartsWith:
match_desc = "started with";
break;
case NameMatch::EndsWith:
match_desc = "ended with";
break;
case NameMatch::RegularExpression:
match_desc = "matched the regular expression";
break;
}
result.AppendErrorWithFormat(
"no process found with pid = %" PRIu64 "\n", pid);
}
} else {
ProcessInstanceInfoList proc_infos;
const uint32_t matches =
platform_sp->FindProcesses(m_options.match_info, proc_infos);
const char *match_desc = nullptr;
const char *match_name =
m_options.match_info.GetProcessInfo().GetName();
if (match_name && match_name[0]) {
switch (m_options.match_info.GetNameMatchType()) {
case NameMatch::Ignore:
break;
case NameMatch::Equals:
match_desc = "matched";
break;
case NameMatch::Contains:
match_desc = "contained";
break;
case NameMatch::StartsWith:
match_desc = "started with";
break;
case NameMatch::EndsWith:
match_desc = "ended with";
break;
case NameMatch::RegularExpression:
match_desc = "matched the regular expression";
break;
}
}
if (matches == 0) {
if (match_desc)
result.AppendErrorWithFormatv(
"no processes were found that {0} \"{1}\" on the \"{2}\" "
"platform\n",
match_desc, match_name, platform_sp->GetName());
else
result.AppendErrorWithFormatv(
"no processes were found on the \"{0}\" platform\n",
platform_sp->GetName());
} else {
result.AppendMessageWithFormatv(
"{0} matching process{1} found on \"{2}\"", matches,
matches > 1 ? "es were" : " was", platform_sp->GetName());
if (match_desc)
result.AppendMessageWithFormat(" whose name %s \"%s\"",
match_desc, match_name);
result.AppendMessageWithFormat("\n");
ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
m_options.verbose);
for (uint32_t i = 0; i < matches; ++i) {
proc_infos[i].DumpAsTableRow(
ostrm, platform_sp->GetUserIDResolver(),
m_options.show_args, m_options.verbose);
}
if (matches == 0) {
if (match_desc)
result.AppendErrorWithFormatv(
"no processes were found that {0} \"{1}\" on the \"{2}\" "
"platform\n",
match_desc, match_name, platform_sp->GetName());
else
result.AppendErrorWithFormatv(
"no processes were found on the \"{0}\" platform\n",
platform_sp->GetName());
} else {
result.AppendMessageWithFormatv(
"{0} matching process{1} found on \"{2}\"", matches,
matches > 1 ? "es were" : " was", platform_sp->GetName());
if (match_desc)
result.AppendMessageWithFormat(" whose name %s \"%s\"",
match_desc, match_name);
result.AppendMessageWithFormat("\n");
ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
m_options.verbose);
for (uint32_t i = 0; i < matches; ++i) {
proc_infos[i].DumpAsTableRow(
ostrm, platform_sp->GetUserIDResolver(), m_options.show_args,
m_options.verbose);
}
}
}
} else {
result.AppendError("invalid args: process list takes only options\n");
}
} else {
result.AppendError("no platform is selected\n");
@ -1737,7 +1758,10 @@ public:
CommandObjectPlatformShell(CommandInterpreter &interpreter)
: CommandObjectRaw(interpreter, "platform shell",
"Run a shell command on the current platform.",
"platform shell <shell-command>", 0) {}
"platform shell <shell-command>", 0) {
CommandArgumentData thread_arg{eArgTypeNone, eArgRepeatStar};
m_arguments.push_back({thread_arg});
}
~CommandObjectPlatformShell() override = default;
@ -1824,7 +1848,12 @@ public:
: CommandObjectParsed(
interpreter, "platform target-install",
"Install a target (bundle or executable file) to the remote end.",
"platform target-install <local-thing> <remote-sandbox>", 0) {}
"platform target-install <local-thing> <remote-sandbox>", 0) {
CommandArgumentData local_arg{eArgTypePath, eArgRepeatPlain};
CommandArgumentData remote_arg{eArgTypePath, eArgRepeatPlain};
m_arguments.push_back({local_arg});
m_arguments.push_back({remote_arg});
}
~CommandObjectPlatformInstall() override = default;

View File

@ -414,12 +414,6 @@ protected:
ModuleSP old_exec_module_sp = target->GetExecutableModule();
ArchSpec old_arch_spec = target->GetArchitecture();
if (command.GetArgumentCount()) {
result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n",
m_cmd_name.c_str(), m_cmd_syntax.c_str());
return false;
}
StreamString stream;
ProcessSP process_sp;
const auto error = target->Attach(m_options.attach_info, &stream);
@ -562,13 +556,6 @@ protected:
bool synchronous_execution = m_interpreter.GetSynchronous();
StateType state = process->GetState();
if (state == eStateStopped) {
if (command.GetArgumentCount() != 0) {
result.AppendErrorWithFormat(
"The '%s' command does not take any arguments.\n",
m_cmd_name.c_str());
return false;
}
if (m_options.m_ignore > 0) {
ThreadSP sel_thread_sp(GetDefaultThread()->shared_from_this());
if (sel_thread_sp) {
@ -943,7 +930,10 @@ public:
CommandObjectProcessConnect(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "process connect",
"Connect to a remote debug service.",
"process connect <remote-url>", 0) {}
"process connect <remote-url>", 0) {
CommandArgumentData connect_arg{eArgTypeConnectURL, eArgRepeatPlain};
m_arguments.push_back({connect_arg});
}
~CommandObjectProcessConnect() override = default;
@ -1068,7 +1058,10 @@ public:
"process load <filename> [<filename> ...]",
eCommandRequiresProcess | eCommandTryTargetAPILock |
eCommandProcessMustBeLaunched |
eCommandProcessMustBePaused) {}
eCommandProcessMustBePaused) {
CommandArgumentData file_arg{eArgTypePath, eArgRepeatPlus};
m_arguments.push_back({file_arg});
}
~CommandObjectProcessLoad() override = default;
@ -1143,7 +1136,10 @@ public:
"returned by a previous call to \"process load\".",
"process unload <index>",
eCommandRequiresProcess | eCommandTryTargetAPILock |
eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
CommandArgumentData load_idx_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
m_arguments.push_back({load_idx_arg});
}
~CommandObjectProcessUnload() override = default;
@ -1291,18 +1287,13 @@ protected:
return false;
}
if (command.GetArgumentCount() == 0) {
bool clear_thread_plans = true;
Status error(process->Halt(clear_thread_plans));
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
result.AppendErrorWithFormat("Failed to halt process: %s\n",
error.AsCString());
}
bool clear_thread_plans = true;
Status error(process->Halt(clear_thread_plans));
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
m_cmd_name.c_str(), m_cmd_syntax.c_str());
result.AppendErrorWithFormat("Failed to halt process: %s\n",
error.AsCString());
}
return result.Succeeded();
}
@ -1330,17 +1321,12 @@ protected:
return false;
}
if (command.GetArgumentCount() == 0) {
Status error(process->Destroy(true));
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
result.AppendErrorWithFormat("Failed to kill process: %s\n",
error.AsCString());
}
Status error(process->Destroy(true));
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
m_cmd_name.c_str(), m_cmd_syntax.c_str());
result.AppendErrorWithFormat("Failed to kill process: %s\n",
error.AsCString());
}
return result.Succeeded();
}
@ -1372,7 +1358,10 @@ public:
"appropriate file type.",
"process save-core [-s corefile-style -p plugin-name] FILE",
eCommandRequiresProcess | eCommandTryTargetAPILock |
eCommandProcessMustBeLaunched) {}
eCommandProcessMustBeLaunched) {
CommandArgumentData file_arg{eArgTypePath, eArgRepeatPlain};
m_arguments.push_back({file_arg});
}
~CommandObjectProcessSaveCore() override = default;
@ -1519,11 +1508,6 @@ protected:
Stream &strm = result.GetOutputStream();
result.SetStatus(eReturnStatusSuccessFinishNoResult);
if (command.GetArgumentCount()) {
result.AppendError("'process status' takes no arguments");
return result.Succeeded();
}
// No need to check "process" for validity as eCommandRequiresProcess
// ensures it is valid
Process *process = m_exe_ctx.GetProcessPtr();

View File

@ -20,7 +20,10 @@ using namespace lldb_private;
CommandObjectQuit::CommandObjectQuit(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "quit", "Quit the LLDB debugger.",
"quit [exit-code]") {}
"quit [exit-code]") {
CommandArgumentData exit_code_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
m_arguments.push_back({exit_code_arg});
}
CommandObjectQuit::~CommandObjectQuit() = default;

View File

@ -182,12 +182,6 @@ public:
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
if (!command.empty()) {
result.AppendErrorWithFormat("'%s' takes no arguments",
m_cmd_name.c_str());
return false;
}
auto &r = Reproducer::Instance();
if (auto generator = r.GetGenerator()) {
generator->Keep();
@ -260,12 +254,6 @@ public:
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
if (!command.empty()) {
result.AppendErrorWithFormat("'%s' takes no arguments",
m_cmd_name.c_str());
return false;
}
auto &r = Reproducer::Instance();
if (!r.IsCapturing()) {
@ -309,12 +297,6 @@ public:
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
if (!command.empty()) {
result.AppendErrorWithFormat("'%s' takes no arguments",
m_cmd_name.c_str());
return false;
}
auto &r = Reproducer::Instance();
if (r.IsCapturing()) {
result.GetOutputStream() << "Reproducer is in capture mode.\n";
@ -394,12 +376,6 @@ public:
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
if (!command.empty()) {
result.AppendErrorWithFormat("'%s' takes no arguments",
m_cmd_name.c_str());
return false;
}
llvm::Optional<Loader> loader_storage;
Loader *loader =
GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file);

View File

@ -538,14 +538,6 @@ protected:
}
bool DoExecute(Args &command, CommandReturnObject &result) override {
const size_t argc = command.GetArgumentCount();
if (argc != 0) {
result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
GetCommandName().str().c_str());
return false;
}
Target *target = m_exe_ctx.GetTargetPtr();
if (target == nullptr) {
target = GetDebugger().GetSelectedTarget().get();
@ -924,14 +916,6 @@ protected:
}
bool DoExecute(Args &command, CommandReturnObject &result) override {
const size_t argc = command.GetArgumentCount();
if (argc != 0) {
result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n",
GetCommandName().str().c_str());
return false;
}
Target *target = m_exe_ctx.GetTargetPtr();
if (!m_options.symbol_name.empty()) {

View File

@ -487,18 +487,14 @@ public:
protected:
bool DoExecute(Args &args, CommandReturnObject &result) override {
if (args.GetArgumentCount() == 0) {
Stream &strm = result.GetOutputStream();
Stream &strm = result.GetOutputStream();
bool show_stopped_process_status = false;
if (DumpTargetList(GetDebugger().GetTargetList(),
show_stopped_process_status, strm) == 0) {
strm.PutCString("No targets.\n");
}
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
result.AppendError("the 'target list' command takes no arguments\n");
bool show_stopped_process_status = false;
if (DumpTargetList(GetDebugger().GetTargetList(),
show_stopped_process_status, strm) == 0) {
strm.PutCString("No targets.\n");
}
result.SetStatus(eReturnStatusSuccessFinishResult);
return result.Succeeded();
}
};
@ -511,6 +507,8 @@ public:
: CommandObjectParsed(
interpreter, "target select",
"Select a target as the current target by target index.", nullptr) {
CommandArgumentData target_arg{eArgTypeTargetID, eArgRepeatPlain};
m_arguments.push_back({target_arg});
}
~CommandObjectTargetSelect() override = default;
@ -575,6 +573,8 @@ public:
m_option_group.Append(&m_all_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Append(&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Finalize();
CommandArgumentData target_arg{eArgTypeTargetID, eArgRepeatStar};
m_arguments.push_back({target_arg});
}
~CommandObjectTargetDelete() override = default;
@ -1230,10 +1230,6 @@ public:
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
Target *target = &GetSelectedTarget();
if (command.GetArgumentCount() != 0) {
result.AppendError("list takes no arguments\n");
return result.Succeeded();
}
target->GetImageSearchPathList().Dump(&result.GetOutputStream());
result.SetStatus(eReturnStatusSuccessFinishResult);
@ -2454,6 +2450,8 @@ public:
LLDB_OPT_SET_1);
m_option_group.Append(&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Finalize();
CommandArgumentData module_arg{eArgTypePath, eArgRepeatStar};
m_arguments.push_back({module_arg});
}
~CommandObjectTargetModulesAdd() override = default;
@ -4019,6 +4017,8 @@ public:
m_option_group.Append(&m_current_stack_option, LLDB_OPT_SET_2,
LLDB_OPT_SET_2);
m_option_group.Finalize();
CommandArgumentData module_arg{eArgTypeShlibName, eArgRepeatPlain};
m_arguments.push_back({module_arg});
}
~CommandObjectTargetSymbolsAdd() override = default;
@ -4867,7 +4867,10 @@ public:
CommandObjectTargetStopHookDelete(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "target stop-hook delete",
"Delete a stop-hook.",
"target stop-hook delete [<idx>]") {}
"target stop-hook delete [<idx>]") {
CommandArgumentData hook_arg{eArgTypeStopHookID, eArgRepeatStar};
m_arguments.push_back({hook_arg});
}
~CommandObjectTargetStopHookDelete() override = default;
@ -4921,6 +4924,8 @@ public:
bool enable, const char *name,
const char *help, const char *syntax)
: CommandObjectParsed(interpreter, name, help, syntax), m_enable(enable) {
CommandArgumentData hook_arg{eArgTypeStopHookID, eArgRepeatStar};
m_arguments.push_back({hook_arg});
}
~CommandObjectTargetStopHookEnableDisable() override = default;
@ -4976,8 +4981,7 @@ class CommandObjectTargetStopHookList : public CommandObjectParsed {
public:
CommandObjectTargetStopHookList(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "target stop-hook list",
"List all stop-hooks.",
"target stop-hook list [<type>]") {}
"List all stop-hooks.", "target stop-hook list") {}
~CommandObjectTargetStopHookList() override = default;
@ -5049,11 +5053,6 @@ public:
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
if (!command.empty()) {
result.AppendError("target dump typesystem doesn't take arguments.");
return result.Succeeded();
}
// Go over every scratch TypeSystem and dump to the command output.
for (TypeSystem *ts : GetSelectedTarget().GetScratchTypeSystems())
ts->Dump(result.GetOutputStream().AsRawOstream());

View File

@ -19,7 +19,11 @@ using namespace llvm;
CommandObjectIterateOverThreads::CommandObjectIterateOverThreads(
CommandInterpreter &interpreter, const char *name, const char *help,
const char *syntax, uint32_t flags)
: CommandObjectParsed(interpreter, name, help, syntax, flags) {}
: CommandObjectParsed(interpreter, name, help, syntax, flags) {
// These commands all take thread ID's as arguments.
CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatStar};
m_arguments.push_back({thread_arg});
}
bool CommandObjectIterateOverThreads::DoExecute(Args &command,
CommandReturnObject &result) {

View File

@ -75,7 +75,10 @@ public:
: CommandObjectParsed(
interpreter, "trace load",
"Load a post-mortem processor trace session from a trace bundle.",
"trace load") {}
"trace load") {
CommandArgumentData session_file_arg{eArgTypePath, eArgRepeatPlain};
m_arguments.push_back({session_file_arg});
}
~CommandObjectTraceLoad() override = default;
@ -223,7 +226,10 @@ public:
: CommandObjectParsed(interpreter, "trace schema",
"Show the schema of the given trace plugin.",
"trace schema <plug-in>. Use the plug-in name "
"\"all\" to see all schemas.\n") {}
"\"all\" to see all schemas.\n") {
CommandArgumentData plugin_arg{eArgTypeNone, eArgRepeatPlain};
m_arguments.push_back({plugin_arg});
}
~CommandObjectTraceSchema() override = default;

View File

@ -914,7 +914,10 @@ public:
uint32_t formatter_kind_mask,
const char *name, const char *help)
: CommandObjectParsed(interpreter, name, help, nullptr),
m_formatter_kind_mask(formatter_kind_mask) {}
m_formatter_kind_mask(formatter_kind_mask) {
CommandArgumentData category_arg{eArgTypeName, eArgRepeatOptional};
m_arguments.push_back({category_arg});
}
~CommandObjectTypeFormatterClear() override = default;

View File

@ -23,11 +23,7 @@ CommandObjectVersion::CommandObjectVersion(CommandInterpreter &interpreter)
CommandObjectVersion::~CommandObjectVersion() = default;
bool CommandObjectVersion::DoExecute(Args &args, CommandReturnObject &result) {
if (args.GetArgumentCount() == 0) {
result.AppendMessageWithFormat("%s\n", lldb_private::GetVersion());
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
result.AppendError("the version command takes no arguments.");
}
result.AppendMessageWithFormat("%s\n", lldb_private::GetVersion());
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}

View File

@ -995,6 +995,11 @@ bool CommandObjectParsed::Execute(const char *args_string,
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());
return false;
}
handled = DoExecute(cmd_args, result);
}
}
@ -1128,6 +1133,10 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = {
{ eArgTypeModuleUUID, "module-uuid", CommandCompletions::eModuleUUIDCompletion, { nullptr, false }, "A module UUID value." },
{ eArgTypeSaveCoreStyle, "corefile-style", CommandCompletions::eNoCompletion, { nullptr, false }, "The type of corefile that lldb will try to create, dependant on this target's capabilities." },
{ eArgTypeLogHandler, "log-handler", CommandCompletions::eNoCompletion, { nullptr, false }, "The log handle that will be used to write out log messages." },
{ eArgTypeSEDStylePair, "substitution-pair", CommandCompletions::eNoCompletion, { nullptr, false }, "A sed-style pattern and target pair." },
{ eArgTypeConnectURL, "process-connect-url", CommandCompletions::eNoCompletion, { nullptr, false }, "A URL-style specification for a remote connection." },
{ eArgTypeTargetID, "target-id", CommandCompletions::eNoCompletion, { nullptr, false }, "The index ID for an lldb Target." },
{ eArgTypeStopHookID, "stop-hook-id", CommandCompletions::eNoCompletion, { nullptr, false }, "The ID you receive when you create a stop-hook." }
// clang-format on
};

View File

@ -4067,7 +4067,10 @@ public:
"<reduction_kernel_type,...>]",
eCommandRequiresProcess | eCommandProcessMustBeLaunched |
eCommandProcessMustBePaused),
m_options(){};
m_options() {
CommandArgumentData name_arg{eArgTypeName, eArgRepeatPlain};
m_arguments.push_back({name_arg});
};
class CommandOptions : public Options {
public:
@ -4216,7 +4219,10 @@ public:
"renderscript kernel breakpoint set <kernel_name> [-c x,y,z]",
eCommandRequiresProcess | eCommandProcessMustBeLaunched |
eCommandProcessMustBePaused),
m_options() {}
m_options() {
CommandArgumentData name_arg{eArgTypeName, eArgRepeatPlain};
m_arguments.push_back({name_arg});
}
~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default;
@ -4311,7 +4317,10 @@ public:
"but does not remove currently set breakpoints.",
"renderscript kernel breakpoint all <enable/disable>",
eCommandRequiresProcess | eCommandProcessMustBeLaunched |
eCommandProcessMustBePaused) {}
eCommandProcessMustBePaused) {
CommandArgumentData enable_arg{eArgTypeNone, eArgRepeatPlain};
m_arguments.push_back({enable_arg});
}
~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default;
@ -4493,7 +4502,10 @@ public:
"renderscript allocation dump <ID>",
eCommandRequiresProcess |
eCommandProcessMustBeLaunched),
m_options() {}
m_options() {
CommandArgumentData id_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
m_arguments.push_back({id_arg});
}
~CommandObjectRenderScriptRuntimeAllocationDump() override = default;
@ -4679,7 +4691,12 @@ public:
interpreter, "renderscript allocation load",
"Loads renderscript allocation contents from a file.",
"renderscript allocation load <ID> <filename>",
eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
eCommandRequiresProcess | eCommandProcessMustBeLaunched) {
CommandArgumentData id_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
CommandArgumentData name_arg{eArgTypeFilename, eArgRepeatPlain};
m_arguments.push_back({id_arg});
m_arguments.push_back({name_arg});
}
~CommandObjectRenderScriptRuntimeAllocationLoad() override = default;
@ -4726,7 +4743,12 @@ public:
"Write renderscript allocation contents to a file.",
"renderscript allocation save <ID> <filename>",
eCommandRequiresProcess |
eCommandProcessMustBeLaunched) {}
eCommandProcessMustBeLaunched) {
CommandArgumentData id_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
CommandArgumentData name_arg{eArgTypeFilename, eArgRepeatPlain};
m_arguments.push_back({id_arg});
m_arguments.push_back({name_arg});
}
~CommandObjectRenderScriptRuntimeAllocationSave() override = default;

View File

@ -39,7 +39,10 @@ public:
interpreter, "renderscript scriptgroup breakpoint set",
"Place a breakpoint on all kernels forming a script group.",
"renderscript scriptgroup breakpoint set <group_name>",
eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
eCommandRequiresProcess | eCommandProcessMustBeLaunched) {
CommandArgumentData name_arg{eArgTypeName, eArgRepeatPlus};
m_arguments.push_back({name_arg});
}
~CommandObjectRenderScriptScriptGroupBreakpointSet() override = default;

View File

@ -883,87 +883,81 @@ public:
~CommandObjectProcessKDPPacketSend() override = default;
bool DoExecute(Args &command, CommandReturnObject &result) override {
const size_t argc = command.GetArgumentCount();
if (argc == 0) {
if (!m_command_byte.GetOptionValue().OptionWasSet()) {
result.AppendError(
"the --command option must be set to a valid command byte");
} else {
const uint64_t command_byte =
m_command_byte.GetOptionValue().GetUInt64Value(0);
if (command_byte > 0 && command_byte <= UINT8_MAX) {
ProcessKDP *process =
(ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr();
if (process) {
const StateType state = process->GetState();
if (!m_command_byte.GetOptionValue().OptionWasSet()) {
result.AppendError(
"the --command option must be set to a valid command byte");
} else {
const uint64_t command_byte =
m_command_byte.GetOptionValue().GetUInt64Value(0);
if (command_byte > 0 && command_byte <= UINT8_MAX) {
ProcessKDP *process =
(ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr();
if (process) {
const StateType state = process->GetState();
if (StateIsStoppedState(state, true)) {
std::vector<uint8_t> payload_bytes;
const char *ascii_hex_bytes_cstr =
m_packet_data.GetOptionValue().GetCurrentValue();
if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0]) {
StringExtractor extractor(ascii_hex_bytes_cstr);
const size_t ascii_hex_bytes_cstr_len =
extractor.GetStringRef().size();
if (ascii_hex_bytes_cstr_len & 1) {
result.AppendErrorWithFormat("payload data must contain an "
"even number of ASCII hex "
"characters: '%s'",
ascii_hex_bytes_cstr);
return false;
}
payload_bytes.resize(ascii_hex_bytes_cstr_len / 2);
if (extractor.GetHexBytes(payload_bytes, '\xdd') !=
payload_bytes.size()) {
result.AppendErrorWithFormat("payload data must only contain "
"ASCII hex characters (no "
"spaces or hex prefixes): '%s'",
ascii_hex_bytes_cstr);
return false;
}
}
Status error;
DataExtractor reply;
process->GetCommunication().SendRawRequest(
command_byte,
payload_bytes.empty() ? NULL : payload_bytes.data(),
payload_bytes.size(), reply, error);
if (error.Success()) {
// Copy the binary bytes into a hex ASCII string for the result
StreamString packet;
packet.PutBytesAsRawHex8(
reply.GetDataStart(), reply.GetByteSize(),
endian::InlHostByteOrder(), endian::InlHostByteOrder());
result.AppendMessage(packet.GetString());
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
} else {
const char *error_cstr = error.AsCString();
if (error_cstr && error_cstr[0])
result.AppendError(error_cstr);
else
result.AppendErrorWithFormat("unknown error 0x%8.8x",
error.GetError());
if (StateIsStoppedState(state, true)) {
std::vector<uint8_t> payload_bytes;
const char *ascii_hex_bytes_cstr =
m_packet_data.GetOptionValue().GetCurrentValue();
if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0]) {
StringExtractor extractor(ascii_hex_bytes_cstr);
const size_t ascii_hex_bytes_cstr_len =
extractor.GetStringRef().size();
if (ascii_hex_bytes_cstr_len & 1) {
result.AppendErrorWithFormat("payload data must contain an "
"even number of ASCII hex "
"characters: '%s'",
ascii_hex_bytes_cstr);
return false;
}
payload_bytes.resize(ascii_hex_bytes_cstr_len / 2);
if (extractor.GetHexBytes(payload_bytes, '\xdd') !=
payload_bytes.size()) {
result.AppendErrorWithFormat("payload data must only contain "
"ASCII hex characters (no "
"spaces or hex prefixes): '%s'",
ascii_hex_bytes_cstr);
return false;
}
}
Status error;
DataExtractor reply;
process->GetCommunication().SendRawRequest(
command_byte,
payload_bytes.empty() ? NULL : payload_bytes.data(),
payload_bytes.size(), reply, error);
if (error.Success()) {
// Copy the binary bytes into a hex ASCII string for the result
StreamString packet;
packet.PutBytesAsRawHex8(
reply.GetDataStart(), reply.GetByteSize(),
endian::InlHostByteOrder(), endian::InlHostByteOrder());
result.AppendMessage(packet.GetString());
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
} else {
result.AppendErrorWithFormat("process must be stopped in order "
"to send KDP packets, state is %s",
StateAsCString(state));
const char *error_cstr = error.AsCString();
if (error_cstr && error_cstr[0])
result.AppendError(error_cstr);
else
result.AppendErrorWithFormat("unknown error 0x%8.8x",
error.GetError());
return false;
}
} else {
result.AppendError("invalid process");
result.AppendErrorWithFormat("process must be stopped in order "
"to send KDP packets, state is %s",
StateAsCString(state));
}
} else {
result.AppendErrorWithFormat("invalid command byte 0x%" PRIx64
", valid values are 1 - 255",
command_byte);
result.AppendError("invalid process");
}
} else {
result.AppendErrorWithFormat("invalid command byte 0x%" PRIx64
", valid values are 1 - 255",
command_byte);
}
} else {
result.AppendErrorWithFormat("'%s' takes no arguments, only options.",
m_cmd_name.c_str());
}
return false;
}

View File

@ -5008,19 +5008,12 @@ public:
~CommandObjectProcessGDBRemotePacketHistory() override = default;
bool DoExecute(Args &command, CommandReturnObject &result) override {
const size_t argc = command.GetArgumentCount();
if (argc == 0) {
ProcessGDBRemote *process =
(ProcessGDBRemote *)m_interpreter.GetExecutionContext()
.GetProcessPtr();
if (process) {
process->GetGDBRemote().DumpHistory(result.GetOutputStream());
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
} else {
result.AppendErrorWithFormat("'%s' takes no arguments",
m_cmd_name.c_str());
ProcessGDBRemote *process =
(ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
if (process) {
process->GetGDBRemote().DumpHistory(result.GetOutputStream());
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
result.SetStatus(eReturnStatusFailed);
return false;
@ -5034,7 +5027,10 @@ public:
: CommandObjectParsed(
interpreter, "process plugin packet xfer-size",
"Maximum size that lldb will try to read/write one one chunk.",
nullptr) {}
nullptr) {
CommandArgumentData max_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
m_arguments.push_back({max_arg});
}
~CommandObjectProcessGDBRemotePacketXferSize() override = default;
@ -5075,7 +5071,10 @@ public:
"The packet header and footer will automatically "
"be added to the packet prior to sending and "
"stripped from the result.",
nullptr) {}
nullptr) {
CommandArgumentData packet_arg{eArgTypeNone, eArgRepeatStar};
m_arguments.push_back({packet_arg});
}
~CommandObjectProcessGDBRemotePacketSend() override = default;

View File

@ -8,4 +8,4 @@ class GuiTestCase(TestBase):
@skipIfCursesSupportMissing
def test_reproducer_generate_invalid_invocation(self):
self.expect("gui blub", error=True,
substrs=["the gui command takes no arguments."])
substrs=["'gui' doesn't take any arguments."])

View File

@ -7,9 +7,9 @@ class ReproducerTestCase(TestBase):
@no_debug_info_test
def test_reproducer_generate_invalid_invocation(self):
self.expect("reproducer generate f", error=True,
substrs=["'reproducer generate' takes no arguments"])
substrs=["'reproducer generate' doesn't take any arguments"])
@no_debug_info_test
def test_reproducer_status_invalid_invocation(self):
self.expect("reproducer status f", error=True,
substrs=["'reproducer status' takes no arguments"])
substrs=["'reproducer status' doesn't take any arguments"])

View File

@ -325,7 +325,7 @@ class targetCommandTestCase(TestBase):
@no_debug_info_test
def test_target_list_args(self):
self.expect("target list blub", error=True,
substrs=["the 'target list' command takes no arguments"])
substrs=["'target list' doesn't take any arguments"])
@no_debug_info_test
def test_target_select_no_index(self):

View File

@ -28,4 +28,4 @@ class TestCase(TestBase):
self.build()
self.createTestTarget()
self.expect("target dump typesystem arg", error=True,
substrs=["error: target dump typesystem doesn't take arguments."])
substrs=["'target dump typesystem' doesn't take any arguments."])

View File

@ -14,4 +14,4 @@ class VersionTestCase(TestBase):
@no_debug_info_test
def test_version_invalid_invocation(self):
self.expect("version a", error=True,
substrs=['the version command takes no arguments.'])
substrs=["'version' doesn't take any arguments."])

View File

@ -88,10 +88,10 @@ class WatchpointSlotsTestCase(TestBase):
# The stop reason of the thread should be watchpoint.
if self.platformIsDarwin():
# On darwin we'll hit byteArray[3] which is watchpoint 2
self.expect("thread list -v", STOPPED_DUE_TO_WATCHPOINT,
self.expect("thread list", STOPPED_DUE_TO_WATCHPOINT,
substrs=['stopped', 'stop reason = watchpoint 2'])
else:
self.expect("thread list -v", STOPPED_DUE_TO_WATCHPOINT,
self.expect("thread list", STOPPED_DUE_TO_WATCHPOINT,
substrs=['stopped', 'stop reason = watchpoint 3'])
# Resume inferior.

View File

@ -675,7 +675,7 @@ class CommandLineCompletionTestCase(TestBase):
self.build()
self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
self.runCmd('target stop-hook add test DONE')
self.runCmd('target stop-hook add -o test')
for subcommand in subcommands:
self.complete_from_to('target stop-hook ' + subcommand + ' ',