xref: /freebsd/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===-- CommandObjectCommands.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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CommandObjectCommands.h"
10 #include "CommandObjectHelp.h"
11 #include "CommandObjectRegexCommand.h"
12 #include "lldb/Core/Debugger.h"
13 #include "lldb/Core/IOHandler.h"
14 #include "lldb/Interpreter/CommandHistory.h"
15 #include "lldb/Interpreter/CommandInterpreter.h"
16 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17 #include "lldb/Interpreter/CommandReturnObject.h"
18 #include "lldb/Interpreter/OptionArgParser.h"
19 #include "lldb/Interpreter/OptionValueBoolean.h"
20 #include "lldb/Interpreter/OptionValueString.h"
21 #include "lldb/Interpreter/OptionValueUInt64.h"
22 #include "lldb/Interpreter/Options.h"
23 #include "lldb/Interpreter/ScriptInterpreter.h"
24 #include "lldb/Utility/Args.h"
25 #include "lldb/Utility/StringList.h"
26 #include "llvm/ADT/StringRef.h"
27 #include <optional>
28 
29 using namespace lldb;
30 using namespace lldb_private;
31 
32 // CommandObjectCommandsSource
33 
34 #define LLDB_OPTIONS_source
35 #include "CommandOptions.inc"
36 
37 class CommandObjectCommandsSource : public CommandObjectParsed {
38 public:
CommandObjectCommandsSource(CommandInterpreter & interpreter)39   CommandObjectCommandsSource(CommandInterpreter &interpreter)
40       : CommandObjectParsed(
41             interpreter, "command source",
42             "Read and execute LLDB commands from the file <filename>.",
43             nullptr) {
44     AddSimpleArgumentList(eArgTypeFilename);
45   }
46 
47   ~CommandObjectCommandsSource() override = default;
48 
GetRepeatCommand(Args & current_command_args,uint32_t index)49   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
50                                               uint32_t index) override {
51     return std::string("");
52   }
53 
GetOptions()54   Options *GetOptions() override { return &m_options; }
55 
56 protected:
57   class CommandOptions : public Options {
58   public:
CommandOptions()59     CommandOptions()
60         : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true),
61           m_cmd_relative_to_command_file(false) {}
62 
63     ~CommandOptions() override = default;
64 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)65     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
66                           ExecutionContext *execution_context) override {
67       Status error;
68       const int short_option = m_getopt_table[option_idx].val;
69 
70       switch (short_option) {
71       case 'e':
72         error = m_stop_on_error.SetValueFromString(option_arg);
73         break;
74 
75       case 'c':
76         error = m_stop_on_continue.SetValueFromString(option_arg);
77         break;
78 
79       case 'C':
80         m_cmd_relative_to_command_file = true;
81         break;
82 
83       case 's':
84         error = m_silent_run.SetValueFromString(option_arg);
85         break;
86 
87       default:
88         llvm_unreachable("Unimplemented option");
89       }
90 
91       return error;
92     }
93 
OptionParsingStarting(ExecutionContext * execution_context)94     void OptionParsingStarting(ExecutionContext *execution_context) override {
95       m_stop_on_error.Clear();
96       m_silent_run.Clear();
97       m_stop_on_continue.Clear();
98       m_cmd_relative_to_command_file.Clear();
99     }
100 
GetDefinitions()101     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
102       return llvm::ArrayRef(g_source_options);
103     }
104 
105     // Instance variables to hold the values for command options.
106 
107     OptionValueBoolean m_stop_on_error;
108     OptionValueBoolean m_silent_run;
109     OptionValueBoolean m_stop_on_continue;
110     OptionValueBoolean m_cmd_relative_to_command_file;
111   };
112 
DoExecute(Args & command,CommandReturnObject & result)113   void DoExecute(Args &command, CommandReturnObject &result) override {
114     if (command.GetArgumentCount() != 1) {
115       result.AppendErrorWithFormat(
116           "'%s' takes exactly one executable filename argument.\n",
117           GetCommandName().str().c_str());
118       return;
119     }
120 
121     FileSpec source_dir = {};
122     if (m_options.m_cmd_relative_to_command_file) {
123       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
124       if (!source_dir) {
125         result.AppendError("command source -C can only be specified "
126                            "from a command file");
127         result.SetStatus(eReturnStatusFailed);
128         return;
129       }
130     }
131 
132     FileSpec cmd_file(command[0].ref());
133     if (source_dir) {
134       // Prepend the source_dir to the cmd_file path:
135       if (!cmd_file.IsRelative()) {
136         result.AppendError("command source -C can only be used "
137                            "with a relative path.");
138         result.SetStatus(eReturnStatusFailed);
139         return;
140       }
141       cmd_file.MakeAbsolute(source_dir);
142     }
143 
144     FileSystem::Instance().Resolve(cmd_file);
145 
146     CommandInterpreterRunOptions options;
147     // If any options were set, then use them
148     if (m_options.m_stop_on_error.OptionWasSet() ||
149         m_options.m_silent_run.OptionWasSet() ||
150         m_options.m_stop_on_continue.OptionWasSet()) {
151       if (m_options.m_stop_on_continue.OptionWasSet())
152         options.SetStopOnContinue(
153             m_options.m_stop_on_continue.GetCurrentValue());
154 
155       if (m_options.m_stop_on_error.OptionWasSet())
156         options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
157 
158       // Individual silent setting is override for global command echo settings.
159       if (m_options.m_silent_run.GetCurrentValue()) {
160         options.SetSilent(true);
161       } else {
162         options.SetPrintResults(true);
163         options.SetPrintErrors(true);
164         options.SetEchoCommands(m_interpreter.GetEchoCommands());
165         options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
166       }
167     }
168 
169     m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
170   }
171 
172   CommandOptions m_options;
173 };
174 
175 #pragma mark CommandObjectCommandsAlias
176 // CommandObjectCommandsAlias
177 
178 #define LLDB_OPTIONS_alias
179 #include "CommandOptions.inc"
180 
181 static const char *g_python_command_instructions =
182     "Enter your Python command(s). Type 'DONE' to end.\n"
183     "You must define a Python function with this signature:\n"
184     "def my_command_impl(debugger, args, exe_ctx, result, internal_dict):\n";
185 
186 class CommandObjectCommandsAlias : public CommandObjectRaw {
187 protected:
188   class CommandOptions : public OptionGroup {
189   public:
190     CommandOptions() = default;
191 
192     ~CommandOptions() override = default;
193 
GetDefinitions()194     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
195       return llvm::ArrayRef(g_alias_options);
196     }
197 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)198     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
199                           ExecutionContext *execution_context) override {
200       Status error;
201 
202       const int short_option = GetDefinitions()[option_idx].short_option;
203       std::string option_str(option_value);
204 
205       switch (short_option) {
206       case 'h':
207         m_help.SetCurrentValue(option_str);
208         m_help.SetOptionWasSet();
209         break;
210 
211       case 'H':
212         m_long_help.SetCurrentValue(option_str);
213         m_long_help.SetOptionWasSet();
214         break;
215 
216       default:
217         llvm_unreachable("Unimplemented option");
218       }
219 
220       return error;
221     }
222 
OptionParsingStarting(ExecutionContext * execution_context)223     void OptionParsingStarting(ExecutionContext *execution_context) override {
224       m_help.Clear();
225       m_long_help.Clear();
226     }
227 
228     OptionValueString m_help;
229     OptionValueString m_long_help;
230   };
231 
232   OptionGroupOptions m_option_group;
233   CommandOptions m_command_options;
234 
235 public:
GetOptions()236   Options *GetOptions() override { return &m_option_group; }
237 
CommandObjectCommandsAlias(CommandInterpreter & interpreter)238   CommandObjectCommandsAlias(CommandInterpreter &interpreter)
239       : CommandObjectRaw(
240             interpreter, "command alias",
241             "Define a custom command in terms of an existing command.") {
242     m_option_group.Append(&m_command_options);
243     m_option_group.Finalize();
244 
245     SetHelpLong(
246         "'alias' allows the user to create a short-cut or abbreviation for long \
247 commands, multi-word commands, and commands that take particular options.  \
248 Below are some simple examples of how one might use the 'alias' command:"
249         R"(
250 
251 (lldb) command alias sc script
252 
253     Creates the abbreviation 'sc' for the 'script' command.
254 
255 (lldb) command alias bp breakpoint
256 
257 )"
258         "    Creates the abbreviation 'bp' for the 'breakpoint' command.  Since \
259 breakpoint commands are two-word commands, the user would still need to \
260 enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
261         R"(
262 
263 (lldb) command alias bpl breakpoint list
264 
265     Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
266 
267 )"
268         "An alias can include some options for the command, with the values either \
269 filled in at the time the alias is created, or specified as positional \
270 arguments, to be filled in when the alias is invoked.  The following example \
271 shows how to create aliases with options:"
272         R"(
273 
274 (lldb) command alias bfl breakpoint set -f %1 -l %2
275 
276 )"
277         "    Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
278 options already part of the alias.  So if the user wants to set a breakpoint \
279 by file and line without explicitly having to use the -f and -l options, the \
280 user can now use 'bfl' instead.  The '%1' and '%2' are positional placeholders \
281 for the actual arguments that will be passed when the alias command is used.  \
282 The number in the placeholder refers to the position/order the actual value \
283 occupies when the alias is used.  All the occurrences of '%1' in the alias \
284 will be replaced with the first argument, all the occurrences of '%2' in the \
285 alias will be replaced with the second argument, and so on.  This also allows \
286 actual arguments to be used multiple times within an alias (see 'process \
287 launch' example below)."
288         R"(
289 
290 )"
291         "Note: the positional arguments must substitute as whole words in the resultant \
292 command, so you can't at present do something like this to append the file extension \
293 \".cpp\":"
294         R"(
295 
296 (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
297 
298 )"
299         "For more complex aliasing, use the \"command regex\" command instead.  In the \
300 'bfl' case above, the actual file value will be filled in with the first argument \
301 following 'bfl' and the actual line number value will be filled in with the second \
302 argument.  The user would use this alias as follows:"
303         R"(
304 
305 (lldb) command alias bfl breakpoint set -f %1 -l %2
306 (lldb) bfl my-file.c 137
307 
308 This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
309 
310 Another example:
311 
312 (lldb) command alias pltty process launch -s -o %1 -e %1
313 (lldb) pltty /dev/tty0
314 
315     Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
316 
317 )"
318         "If the user always wanted to pass the same value to a particular option, the \
319 alias could be defined with that value directly in the alias as a constant, \
320 rather than using a positional placeholder:"
321         R"(
322 
323 (lldb) command alias bl3 breakpoint set -f %1 -l 3
324 
325     Always sets a breakpoint on line 3 of whatever file is indicated.)");
326 
327     CommandArgumentEntry arg1;
328     CommandArgumentEntry arg2;
329     CommandArgumentEntry arg3;
330     CommandArgumentData alias_arg;
331     CommandArgumentData cmd_arg;
332     CommandArgumentData options_arg;
333 
334     // Define the first (and only) variant of this arg.
335     alias_arg.arg_type = eArgTypeAliasName;
336     alias_arg.arg_repetition = eArgRepeatPlain;
337 
338     // There is only one variant this argument could be; put it into the
339     // argument entry.
340     arg1.push_back(alias_arg);
341 
342     // Define the first (and only) variant of this arg.
343     cmd_arg.arg_type = eArgTypeCommandName;
344     cmd_arg.arg_repetition = eArgRepeatPlain;
345 
346     // There is only one variant this argument could be; put it into the
347     // argument entry.
348     arg2.push_back(cmd_arg);
349 
350     // Define the first (and only) variant of this arg.
351     options_arg.arg_type = eArgTypeAliasOptions;
352     options_arg.arg_repetition = eArgRepeatOptional;
353 
354     // There is only one variant this argument could be; put it into the
355     // argument entry.
356     arg3.push_back(options_arg);
357 
358     // Push the data for the first argument into the m_arguments vector.
359     m_arguments.push_back(arg1);
360     m_arguments.push_back(arg2);
361     m_arguments.push_back(arg3);
362   }
363 
364   ~CommandObjectCommandsAlias() override = default;
365 
366 protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)367   void DoExecute(llvm::StringRef raw_command_line,
368                  CommandReturnObject &result) override {
369     if (raw_command_line.empty()) {
370       result.AppendError("'command alias' requires at least two arguments");
371       return;
372     }
373 
374     ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
375     m_option_group.NotifyOptionParsingStarting(&exe_ctx);
376 
377     OptionsWithRaw args_with_suffix(raw_command_line);
378 
379     if (args_with_suffix.HasArgs())
380       if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result,
381                                  m_option_group, exe_ctx))
382         return;
383 
384     llvm::StringRef raw_command_string = args_with_suffix.GetRawPart();
385     Args args(raw_command_string);
386 
387     if (args.GetArgumentCount() < 2) {
388       result.AppendError("'command alias' requires at least two arguments");
389       return;
390     }
391 
392     // Get the alias command.
393 
394     auto alias_command = args[0].ref();
395     if (alias_command.starts_with("-")) {
396       result.AppendError("aliases starting with a dash are not supported");
397       if (alias_command == "--help" || alias_command == "--long-help") {
398         result.AppendWarning("if trying to pass options to 'command alias' add "
399                              "a -- at the end of the options");
400       }
401       return;
402     }
403 
404     // Strip the new alias name off 'raw_command_string'  (leave it on args,
405     // which gets passed to 'Execute', which does the stripping itself.
406     size_t pos = raw_command_string.find(alias_command);
407     if (pos == 0) {
408       raw_command_string = raw_command_string.substr(alias_command.size());
409       pos = raw_command_string.find_first_not_of(' ');
410       if ((pos != std::string::npos) && (pos > 0))
411         raw_command_string = raw_command_string.substr(pos);
412     } else {
413       result.AppendError("Error parsing command string.  No alias created.");
414       return;
415     }
416 
417     // Verify that the command is alias-able.
418     if (m_interpreter.CommandExists(alias_command)) {
419       result.AppendErrorWithFormat(
420           "'%s' is a permanent debugger command and cannot be redefined.\n",
421           args[0].c_str());
422       return;
423     }
424 
425     if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
426       result.AppendErrorWithFormat(
427           "'%s' is a user container command and cannot be overwritten.\n"
428           "Delete it first with 'command container delete'\n",
429           args[0].c_str());
430       return;
431     }
432 
433     // Get CommandObject that is being aliased. The command name is read from
434     // the front of raw_command_string. raw_command_string is returned with the
435     // name of the command object stripped off the front.
436     llvm::StringRef original_raw_command_string = raw_command_string;
437     CommandObject *cmd_obj =
438         m_interpreter.GetCommandObjectForCommand(raw_command_string);
439 
440     if (!cmd_obj) {
441       result.AppendErrorWithFormat("invalid command given to 'command alias'. "
442                                    "'%s' does not begin with a valid command."
443                                    "  No alias created.",
444                                    original_raw_command_string.str().c_str());
445     } else if (!cmd_obj->WantsRawCommandString()) {
446       // Note that args was initialized with the original command, and has not
447       // been updated to this point. Therefore can we pass it to the version of
448       // Execute that does not need/expect raw input in the alias.
449       HandleAliasingNormalCommand(args, result);
450     } else {
451       HandleAliasingRawCommand(alias_command, raw_command_string, *cmd_obj,
452                                result);
453     }
454   }
455 
HandleAliasingRawCommand(llvm::StringRef alias_command,llvm::StringRef raw_command_string,CommandObject & cmd_obj,CommandReturnObject & result)456   bool HandleAliasingRawCommand(llvm::StringRef alias_command,
457                                 llvm::StringRef raw_command_string,
458                                 CommandObject &cmd_obj,
459                                 CommandReturnObject &result) {
460     // Verify & handle any options/arguments passed to the alias command
461 
462     OptionArgVectorSP option_arg_vector_sp =
463         OptionArgVectorSP(new OptionArgVector);
464 
465     const bool include_aliases = true;
466     // Look up the command using command's name first.  This is to resolve
467     // aliases when you are making nested aliases.  But if you don't find
468     // it that way, then it wasn't an alias and we can just use the object
469     // we were passed in.
470     CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact(
471             cmd_obj.GetCommandName(), include_aliases);
472     if (!cmd_obj_sp)
473       cmd_obj_sp = cmd_obj.shared_from_this();
474 
475     if (m_interpreter.AliasExists(alias_command) ||
476         m_interpreter.UserCommandExists(alias_command)) {
477       result.AppendWarningWithFormat(
478           "Overwriting existing definition for '%s'.\n",
479           alias_command.str().c_str());
480     }
481     if (CommandAlias *alias = m_interpreter.AddAlias(
482             alias_command, cmd_obj_sp, raw_command_string)) {
483       if (m_command_options.m_help.OptionWasSet())
484         alias->SetHelp(m_command_options.m_help.GetCurrentValue());
485       if (m_command_options.m_long_help.OptionWasSet())
486         alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
487       result.SetStatus(eReturnStatusSuccessFinishNoResult);
488     } else {
489       result.AppendError("Unable to create requested alias.\n");
490     }
491     return result.Succeeded();
492   }
493 
HandleAliasingNormalCommand(Args & args,CommandReturnObject & result)494   bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
495     size_t argc = args.GetArgumentCount();
496 
497     if (argc < 2) {
498       result.AppendError("'command alias' requires at least two arguments");
499       return false;
500     }
501 
502     // Save these in std::strings since we're going to shift them off.
503     const std::string alias_command(std::string(args[0].ref()));
504     const std::string actual_command(std::string(args[1].ref()));
505 
506     args.Shift(); // Shift the alias command word off the argument vector.
507     args.Shift(); // Shift the old command word off the argument vector.
508 
509     // Verify that the command is alias'able, and get the appropriate command
510     // object.
511 
512     if (m_interpreter.CommandExists(alias_command)) {
513       result.AppendErrorWithFormat(
514           "'%s' is a permanent debugger command and cannot be redefined.\n",
515           alias_command.c_str());
516       return false;
517     }
518 
519     if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
520       result.AppendErrorWithFormat(
521           "'%s' is user container command and cannot be overwritten.\n"
522           "Delete it first with 'command container delete'",
523           alias_command.c_str());
524       return false;
525     }
526 
527     CommandObjectSP command_obj_sp(
528         m_interpreter.GetCommandSPExact(actual_command, true));
529     CommandObjectSP subcommand_obj_sp;
530     bool use_subcommand = false;
531     if (!command_obj_sp) {
532       result.AppendErrorWithFormat("'%s' is not an existing command.\n",
533                                    actual_command.c_str());
534       return false;
535     }
536     CommandObject *cmd_obj = command_obj_sp.get();
537     CommandObject *sub_cmd_obj = nullptr;
538     OptionArgVectorSP option_arg_vector_sp =
539         OptionArgVectorSP(new OptionArgVector);
540 
541     while (cmd_obj->IsMultiwordObject() && !args.empty()) {
542       auto sub_command = args[0].ref();
543       assert(!sub_command.empty());
544       subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
545       if (!subcommand_obj_sp) {
546         result.AppendErrorWithFormat(
547             "'%s' is not a valid sub-command of '%s'.  "
548             "Unable to create alias.\n",
549             args[0].c_str(), actual_command.c_str());
550         return false;
551       }
552 
553       sub_cmd_obj = subcommand_obj_sp.get();
554       use_subcommand = true;
555       args.Shift(); // Shift the sub_command word off the argument vector.
556       cmd_obj = sub_cmd_obj;
557     }
558 
559     // Verify & handle any options/arguments passed to the alias command
560 
561     std::string args_string;
562 
563     if (!args.empty()) {
564       CommandObjectSP tmp_sp =
565           m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName());
566       if (use_subcommand)
567         tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName());
568 
569       args.GetCommandString(args_string);
570     }
571 
572     if (m_interpreter.AliasExists(alias_command) ||
573         m_interpreter.UserCommandExists(alias_command)) {
574       result.AppendWarningWithFormat(
575           "Overwriting existing definition for '%s'.\n", alias_command.c_str());
576     }
577 
578     if (CommandAlias *alias = m_interpreter.AddAlias(
579             alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
580             args_string)) {
581       if (m_command_options.m_help.OptionWasSet())
582         alias->SetHelp(m_command_options.m_help.GetCurrentValue());
583       if (m_command_options.m_long_help.OptionWasSet())
584         alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
585       result.SetStatus(eReturnStatusSuccessFinishNoResult);
586     } else {
587       result.AppendError("Unable to create requested alias.\n");
588       return false;
589     }
590 
591     return result.Succeeded();
592   }
593 };
594 
595 #pragma mark CommandObjectCommandsUnalias
596 // CommandObjectCommandsUnalias
597 
598 class CommandObjectCommandsUnalias : public CommandObjectParsed {
599 public:
CommandObjectCommandsUnalias(CommandInterpreter & interpreter)600   CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
601       : CommandObjectParsed(
602             interpreter, "command unalias",
603             "Delete one or more custom commands defined by 'command alias'.",
604             nullptr) {
605     AddSimpleArgumentList(eArgTypeAliasName);
606   }
607 
608   ~CommandObjectCommandsUnalias() override = default;
609 
610   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)611   HandleArgumentCompletion(CompletionRequest &request,
612                            OptionElementVector &opt_element_vector) override {
613     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
614       return;
615 
616     for (const auto &ent : m_interpreter.GetAliases()) {
617       request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
618     }
619   }
620 
621 protected:
DoExecute(Args & args,CommandReturnObject & result)622   void DoExecute(Args &args, CommandReturnObject &result) override {
623     CommandObject::CommandMap::iterator pos;
624     CommandObject *cmd_obj;
625 
626     if (args.empty()) {
627       result.AppendError("must call 'unalias' with a valid alias");
628       return;
629     }
630 
631     auto command_name = args[0].ref();
632     cmd_obj = m_interpreter.GetCommandObject(command_name);
633     if (!cmd_obj) {
634       result.AppendErrorWithFormat(
635           "'%s' is not a known command.\nTry 'help' to see a "
636           "current list of commands.\n",
637           args[0].c_str());
638       return;
639     }
640 
641     if (m_interpreter.CommandExists(command_name)) {
642       if (cmd_obj->IsRemovable()) {
643         result.AppendErrorWithFormat(
644             "'%s' is not an alias, it is a debugger command which can be "
645             "removed using the 'command delete' command.\n",
646             args[0].c_str());
647       } else {
648         result.AppendErrorWithFormat(
649             "'%s' is a permanent debugger command and cannot be removed.\n",
650             args[0].c_str());
651       }
652       return;
653     }
654 
655     if (!m_interpreter.RemoveAlias(command_name)) {
656       if (m_interpreter.AliasExists(command_name))
657         result.AppendErrorWithFormat(
658             "Error occurred while attempting to unalias '%s'.\n",
659             args[0].c_str());
660       else
661         result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
662                                      args[0].c_str());
663       return;
664     }
665 
666     result.SetStatus(eReturnStatusSuccessFinishNoResult);
667   }
668 };
669 
670 #pragma mark CommandObjectCommandsDelete
671 // CommandObjectCommandsDelete
672 
673 class CommandObjectCommandsDelete : public CommandObjectParsed {
674 public:
CommandObjectCommandsDelete(CommandInterpreter & interpreter)675   CommandObjectCommandsDelete(CommandInterpreter &interpreter)
676       : CommandObjectParsed(
677             interpreter, "command delete",
678             "Delete one or more custom commands defined by 'command regex'.",
679             nullptr) {
680     AddSimpleArgumentList(eArgTypeCommandName);
681   }
682 
683   ~CommandObjectCommandsDelete() override = default;
684 
685   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)686   HandleArgumentCompletion(CompletionRequest &request,
687                            OptionElementVector &opt_element_vector) override {
688     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
689       return;
690 
691     for (const auto &ent : m_interpreter.GetCommands()) {
692       if (ent.second->IsRemovable())
693         request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
694     }
695   }
696 
697 protected:
DoExecute(Args & args,CommandReturnObject & result)698   void DoExecute(Args &args, CommandReturnObject &result) override {
699     CommandObject::CommandMap::iterator pos;
700 
701     if (args.empty()) {
702       result.AppendErrorWithFormat("must call '%s' with one or more valid user "
703                                    "defined regular expression command names",
704                                    GetCommandName().str().c_str());
705       return;
706     }
707 
708     auto command_name = args[0].ref();
709     if (!m_interpreter.CommandExists(command_name)) {
710       StreamString error_msg_stream;
711       const bool generate_upropos = true;
712       const bool generate_type_lookup = false;
713       CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
714           &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
715           generate_upropos, generate_type_lookup);
716       result.AppendError(error_msg_stream.GetString());
717       return;
718     }
719 
720     if (!m_interpreter.RemoveCommand(command_name)) {
721       result.AppendErrorWithFormat(
722           "'%s' is a permanent debugger command and cannot be removed.\n",
723           args[0].c_str());
724       return;
725     }
726 
727     result.SetStatus(eReturnStatusSuccessFinishNoResult);
728   }
729 };
730 
731 // CommandObjectCommandsAddRegex
732 
733 #define LLDB_OPTIONS_regex
734 #include "CommandOptions.inc"
735 
736 #pragma mark CommandObjectCommandsAddRegex
737 
738 class CommandObjectCommandsAddRegex : public CommandObjectParsed,
739                                       public IOHandlerDelegateMultiline {
740 public:
CommandObjectCommandsAddRegex(CommandInterpreter & interpreter)741   CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
742       : CommandObjectParsed(
743             interpreter, "command regex",
744             "Define a custom command in terms of "
745             "existing commands by matching "
746             "regular expressions.",
747             "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
748         IOHandlerDelegateMultiline("",
749                                    IOHandlerDelegate::Completion::LLDBCommand) {
750     SetHelpLong(
751         R"(
752 )"
753         "This command allows the user to create powerful regular expression commands \
754 with substitutions. The regular expressions and substitutions are specified \
755 using the regular expression substitution format of:"
756         R"(
757 
758     s/<regex>/<subst>/
759 
760 )"
761         "<regex> is a regular expression that can use parenthesis to capture regular \
762 expression input and substitute the captured matches in the output using %1 \
763 for the first match, %2 for the second, and so on."
764         R"(
765 
766 )"
767         "The regular expressions can all be specified on the command line if more than \
768 one argument is provided. If just the command name is provided on the command \
769 line, then the regular expressions and substitutions can be entered on separate \
770 lines, followed by an empty line to terminate the command definition."
771         R"(
772 
773 EXAMPLES
774 
775 )"
776         "The following example will define a regular expression command named 'f' that \
777 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
778 a number follows 'f':"
779         R"(
780 
781     (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
782     AddSimpleArgumentList(eArgTypeSEDStylePair, eArgRepeatOptional);
783   }
784 
785   ~CommandObjectCommandsAddRegex() override = default;
786 
787 protected:
IOHandlerActivated(IOHandler & io_handler,bool interactive)788   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
789     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
790     if (output_sp && interactive) {
791       output_sp->PutCString("Enter one or more sed substitution commands in "
792                             "the form: 's/<regex>/<subst>/'.\nTerminate the "
793                             "substitution list with an empty line.\n");
794       output_sp->Flush();
795     }
796   }
797 
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)798   void IOHandlerInputComplete(IOHandler &io_handler,
799                               std::string &data) override {
800     io_handler.SetIsDone(true);
801     if (m_regex_cmd_up) {
802       StringList lines;
803       if (lines.SplitIntoLines(data)) {
804         bool check_only = false;
805         for (const std::string &line : lines) {
806           Status error = AppendRegexSubstitution(line, check_only);
807           if (error.Fail()) {
808             if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) {
809               StreamSP out_stream = GetDebugger().GetAsyncOutputStream();
810               out_stream->Printf("error: %s\n", error.AsCString());
811             }
812           }
813         }
814       }
815       if (m_regex_cmd_up->HasRegexEntries()) {
816         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
817         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
818       }
819     }
820   }
821 
DoExecute(Args & command,CommandReturnObject & result)822   void DoExecute(Args &command, CommandReturnObject &result) override {
823     const size_t argc = command.GetArgumentCount();
824     if (argc == 0) {
825       result.AppendError("usage: 'command regex <command-name> "
826                          "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
827       return;
828     }
829 
830     Status error;
831     auto name = command[0].ref();
832     m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
833         m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 0,
834         true);
835 
836     if (argc == 1) {
837       Debugger &debugger = GetDebugger();
838       bool color_prompt = debugger.GetUseColor();
839       const bool multiple_lines = true; // Get multiple lines
840       IOHandlerSP io_handler_sp(new IOHandlerEditline(
841           debugger, IOHandler::Type::Other,
842           "lldb-regex",          // Name of input reader for history
843           llvm::StringRef("> "), // Prompt
844           llvm::StringRef(),     // Continuation prompt
845           multiple_lines, color_prompt,
846           0, // Don't show line numbers
847           *this));
848 
849       if (io_handler_sp) {
850         debugger.RunIOHandlerAsync(io_handler_sp);
851         result.SetStatus(eReturnStatusSuccessFinishNoResult);
852       }
853     } else {
854       for (auto &entry : command.entries().drop_front()) {
855         bool check_only = false;
856         error = AppendRegexSubstitution(entry.ref(), check_only);
857         if (error.Fail())
858           break;
859       }
860 
861       if (error.Success()) {
862         AddRegexCommandToInterpreter();
863       }
864     }
865     if (error.Fail()) {
866       result.AppendError(error.AsCString());
867     }
868   }
869 
AppendRegexSubstitution(const llvm::StringRef & regex_sed,bool check_only)870   Status AppendRegexSubstitution(const llvm::StringRef &regex_sed,
871                                  bool check_only) {
872     Status error;
873 
874     if (!m_regex_cmd_up) {
875       error.SetErrorStringWithFormat(
876           "invalid regular expression command object for: '%.*s'",
877           (int)regex_sed.size(), regex_sed.data());
878       return error;
879     }
880 
881     size_t regex_sed_size = regex_sed.size();
882 
883     if (regex_sed_size <= 1) {
884       error.SetErrorStringWithFormat(
885           "regular expression substitution string is too short: '%.*s'",
886           (int)regex_sed.size(), regex_sed.data());
887       return error;
888     }
889 
890     if (regex_sed[0] != 's') {
891       error.SetErrorStringWithFormat("regular expression substitution string "
892                                      "doesn't start with 's': '%.*s'",
893                                      (int)regex_sed.size(), regex_sed.data());
894       return error;
895     }
896     const size_t first_separator_char_pos = 1;
897     // use the char that follows 's' as the regex separator character so we can
898     // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
899     const char separator_char = regex_sed[first_separator_char_pos];
900     const size_t second_separator_char_pos =
901         regex_sed.find(separator_char, first_separator_char_pos + 1);
902 
903     if (second_separator_char_pos == std::string::npos) {
904       error.SetErrorStringWithFormat(
905           "missing second '%c' separator char after '%.*s' in '%.*s'",
906           separator_char,
907           (int)(regex_sed.size() - first_separator_char_pos - 1),
908           regex_sed.data() + (first_separator_char_pos + 1),
909           (int)regex_sed.size(), regex_sed.data());
910       return error;
911     }
912 
913     const size_t third_separator_char_pos =
914         regex_sed.find(separator_char, second_separator_char_pos + 1);
915 
916     if (third_separator_char_pos == std::string::npos) {
917       error.SetErrorStringWithFormat(
918           "missing third '%c' separator char after '%.*s' in '%.*s'",
919           separator_char,
920           (int)(regex_sed.size() - second_separator_char_pos - 1),
921           regex_sed.data() + (second_separator_char_pos + 1),
922           (int)regex_sed.size(), regex_sed.data());
923       return error;
924     }
925 
926     if (third_separator_char_pos != regex_sed_size - 1) {
927       // Make sure that everything that follows the last regex separator char
928       if (regex_sed.find_first_not_of("\t\n\v\f\r ",
929                                       third_separator_char_pos + 1) !=
930           std::string::npos) {
931         error.SetErrorStringWithFormat(
932             "extra data found after the '%.*s' regular expression substitution "
933             "string: '%.*s'",
934             (int)third_separator_char_pos + 1, regex_sed.data(),
935             (int)(regex_sed.size() - third_separator_char_pos - 1),
936             regex_sed.data() + (third_separator_char_pos + 1));
937         return error;
938       }
939     } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
940       error.SetErrorStringWithFormat(
941           "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
942           separator_char, separator_char, separator_char, (int)regex_sed.size(),
943           regex_sed.data());
944       return error;
945     } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
946       error.SetErrorStringWithFormat(
947           "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
948           separator_char, separator_char, separator_char, (int)regex_sed.size(),
949           regex_sed.data());
950       return error;
951     }
952 
953     if (!check_only) {
954       std::string regex(std::string(regex_sed.substr(
955           first_separator_char_pos + 1,
956           second_separator_char_pos - first_separator_char_pos - 1)));
957       std::string subst(std::string(regex_sed.substr(
958           second_separator_char_pos + 1,
959           third_separator_char_pos - second_separator_char_pos - 1)));
960       m_regex_cmd_up->AddRegexCommand(regex, subst);
961     }
962     return error;
963   }
964 
AddRegexCommandToInterpreter()965   void AddRegexCommandToInterpreter() {
966     if (m_regex_cmd_up) {
967       if (m_regex_cmd_up->HasRegexEntries()) {
968         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
969         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
970       }
971     }
972   }
973 
974 private:
975   std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
976 
977   class CommandOptions : public Options {
978   public:
979     CommandOptions() = default;
980 
981     ~CommandOptions() override = default;
982 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)983     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
984                           ExecutionContext *execution_context) override {
985       Status error;
986       const int short_option = m_getopt_table[option_idx].val;
987 
988       switch (short_option) {
989       case 'h':
990         m_help.assign(std::string(option_arg));
991         break;
992       case 's':
993         m_syntax.assign(std::string(option_arg));
994         break;
995       default:
996         llvm_unreachable("Unimplemented option");
997       }
998 
999       return error;
1000     }
1001 
OptionParsingStarting(ExecutionContext * execution_context)1002     void OptionParsingStarting(ExecutionContext *execution_context) override {
1003       m_help.clear();
1004       m_syntax.clear();
1005     }
1006 
GetDefinitions()1007     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1008       return llvm::ArrayRef(g_regex_options);
1009     }
1010 
GetHelp()1011     llvm::StringRef GetHelp() { return m_help; }
1012 
GetSyntax()1013     llvm::StringRef GetSyntax() { return m_syntax; }
1014 
1015   protected:
1016     // Instance variables to hold the values for command options.
1017 
1018     std::string m_help;
1019     std::string m_syntax;
1020   };
1021 
GetOptions()1022   Options *GetOptions() override { return &m_options; }
1023 
1024   CommandOptions m_options;
1025 };
1026 
1027 class CommandObjectPythonFunction : public CommandObjectRaw {
1028 public:
CommandObjectPythonFunction(CommandInterpreter & interpreter,std::string name,std::string funct,std::string help,ScriptedCommandSynchronicity synch,CompletionType completion_type)1029   CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
1030                               std::string funct, std::string help,
1031                               ScriptedCommandSynchronicity synch,
1032                               CompletionType completion_type)
1033       : CommandObjectRaw(interpreter, name), m_function_name(funct),
1034         m_synchro(synch), m_completion_type(completion_type) {
1035     if (!help.empty())
1036       SetHelp(help);
1037     else {
1038       StreamString stream;
1039       stream.Printf("For more information run 'help %s'", name.c_str());
1040       SetHelp(stream.GetString());
1041     }
1042   }
1043 
1044   ~CommandObjectPythonFunction() override = default;
1045 
IsRemovable() const1046   bool IsRemovable() const override { return true; }
1047 
GetFunctionName()1048   const std::string &GetFunctionName() { return m_function_name; }
1049 
GetSynchronicity()1050   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1051 
GetHelpLong()1052   llvm::StringRef GetHelpLong() override {
1053     if (m_fetched_help_long)
1054       return CommandObjectRaw::GetHelpLong();
1055 
1056     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1057     if (!scripter)
1058       return CommandObjectRaw::GetHelpLong();
1059 
1060     std::string docstring;
1061     m_fetched_help_long =
1062         scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
1063     if (!docstring.empty())
1064       SetHelpLong(docstring);
1065     return CommandObjectRaw::GetHelpLong();
1066   }
1067 
1068   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1069   HandleArgumentCompletion(CompletionRequest &request,
1070                            OptionElementVector &opt_element_vector) override {
1071     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1072         GetCommandInterpreter(), m_completion_type, request, nullptr);
1073   }
1074 
WantsCompletion()1075   bool WantsCompletion() override { return true; }
1076 
1077 protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1078   void DoExecute(llvm::StringRef raw_command_line,
1079                  CommandReturnObject &result) override {
1080     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1081 
1082     m_interpreter.IncreaseCommandUsage(*this);
1083 
1084     Status error;
1085 
1086     result.SetStatus(eReturnStatusInvalid);
1087 
1088     if (!scripter || !scripter->RunScriptBasedCommand(
1089                          m_function_name.c_str(), raw_command_line, m_synchro,
1090                          result, error, m_exe_ctx)) {
1091       result.AppendError(error.AsCString());
1092     } else {
1093       // Don't change the status if the command already set it...
1094       if (result.GetStatus() == eReturnStatusInvalid) {
1095         if (result.GetOutputData().empty())
1096           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1097         else
1098           result.SetStatus(eReturnStatusSuccessFinishResult);
1099       }
1100     }
1101   }
1102 
1103 private:
1104   std::string m_function_name;
1105   ScriptedCommandSynchronicity m_synchro;
1106   bool m_fetched_help_long = false;
1107   CompletionType m_completion_type = eNoCompletion;
1108 };
1109 
1110 /// This class implements a "raw" scripted command.  lldb does no parsing of the
1111 /// command line, instead passing the line unaltered (except for backtick
1112 /// substitution).
1113 class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
1114 public:
CommandObjectScriptingObjectRaw(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch,CompletionType completion_type)1115   CommandObjectScriptingObjectRaw(CommandInterpreter &interpreter,
1116                                   std::string name,
1117                                   StructuredData::GenericSP cmd_obj_sp,
1118                                   ScriptedCommandSynchronicity synch,
1119                                   CompletionType completion_type)
1120       : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1121         m_synchro(synch), m_fetched_help_short(false),
1122         m_fetched_help_long(false), m_completion_type(completion_type) {
1123     StreamString stream;
1124     stream.Printf("For more information run 'help %s'", name.c_str());
1125     SetHelp(stream.GetString());
1126     if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
1127       GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1128   }
1129 
1130   ~CommandObjectScriptingObjectRaw() override = default;
1131 
1132   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1133   HandleArgumentCompletion(CompletionRequest &request,
1134                            OptionElementVector &opt_element_vector) override {
1135     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1136         GetCommandInterpreter(), m_completion_type, request, nullptr);
1137   }
1138 
WantsCompletion()1139   bool WantsCompletion() override { return true; }
1140 
IsRemovable() const1141   bool IsRemovable() const override { return true; }
1142 
GetSynchronicity()1143   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1144 
GetRepeatCommand(Args & args,uint32_t index)1145   std::optional<std::string> GetRepeatCommand(Args &args,
1146                                               uint32_t index) override {
1147     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1148     if (!scripter)
1149       return std::nullopt;
1150 
1151     return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
1152   }
1153 
GetHelp()1154   llvm::StringRef GetHelp() override {
1155     if (m_fetched_help_short)
1156       return CommandObjectRaw::GetHelp();
1157     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1158     if (!scripter)
1159       return CommandObjectRaw::GetHelp();
1160     std::string docstring;
1161     m_fetched_help_short =
1162         scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1163     if (!docstring.empty())
1164       SetHelp(docstring);
1165 
1166     return CommandObjectRaw::GetHelp();
1167   }
1168 
GetHelpLong()1169   llvm::StringRef GetHelpLong() override {
1170     if (m_fetched_help_long)
1171       return CommandObjectRaw::GetHelpLong();
1172 
1173     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1174     if (!scripter)
1175       return CommandObjectRaw::GetHelpLong();
1176 
1177     std::string docstring;
1178     m_fetched_help_long =
1179         scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1180     if (!docstring.empty())
1181       SetHelpLong(docstring);
1182     return CommandObjectRaw::GetHelpLong();
1183   }
1184 
1185 protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1186   void DoExecute(llvm::StringRef raw_command_line,
1187                  CommandReturnObject &result) override {
1188     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1189 
1190     Status error;
1191 
1192     result.SetStatus(eReturnStatusInvalid);
1193 
1194     if (!scripter ||
1195         !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
1196                                          m_synchro, result, error, m_exe_ctx)) {
1197       result.AppendError(error.AsCString());
1198     } else {
1199       // Don't change the status if the command already set it...
1200       if (result.GetStatus() == eReturnStatusInvalid) {
1201         if (result.GetOutputData().empty())
1202           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1203         else
1204           result.SetStatus(eReturnStatusSuccessFinishResult);
1205       }
1206     }
1207   }
1208 
1209 private:
1210   StructuredData::GenericSP m_cmd_obj_sp;
1211   ScriptedCommandSynchronicity m_synchro;
1212   bool m_fetched_help_short : 1;
1213   bool m_fetched_help_long : 1;
1214   CompletionType m_completion_type = eNoCompletion;
1215 };
1216 
1217 
1218 /// This command implements a lldb parsed scripted command.  The command
1219 /// provides a definition of the options and arguments, and a option value
1220 /// setting callback, and then the command's execution function gets passed
1221 /// just the parsed arguments.
1222 /// Note, implementing a command in Python using these base interfaces is a bit
1223 /// of a pain, but it is much easier to export this low level interface, and
1224 /// then make it nicer on the Python side, than to try to do that in a
1225 /// script language neutral way.
1226 /// So I've also added a base class in Python that provides a table-driven
1227 /// way of defining the options and arguments, which automatically fills the
1228 /// option values, making them available as properties in Python.
1229 ///
1230 class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
1231 private:
1232   class CommandOptions : public Options {
1233   public:
CommandOptions(CommandInterpreter & interpreter,StructuredData::GenericSP cmd_obj_sp)1234     CommandOptions(CommandInterpreter &interpreter,
1235         StructuredData::GenericSP cmd_obj_sp) : m_interpreter(interpreter),
1236             m_cmd_obj_sp(cmd_obj_sp) {}
1237 
1238     ~CommandOptions() override = default;
1239 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1240     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1241                           ExecutionContext *execution_context) override {
1242       Status error;
1243       ScriptInterpreter *scripter =
1244         m_interpreter.GetDebugger().GetScriptInterpreter();
1245       if (!scripter) {
1246         error.SetErrorString("No script interpreter for SetOptionValue.");
1247         return error;
1248       }
1249       if (!m_cmd_obj_sp) {
1250         error.SetErrorString("SetOptionValue called with empty cmd_obj.");
1251         return error;
1252       }
1253       if (!m_options_definition_up) {
1254         error.SetErrorString("SetOptionValue called before options definitions "
1255                              "were created.");
1256         return error;
1257       }
1258       // Pass the long option, since you aren't actually required to have a
1259       // short_option, and for those options the index or short option character
1260       // aren't meaningful on the python side.
1261       const char * long_option =
1262         m_options_definition_up.get()[option_idx].long_option;
1263       bool success = scripter->SetOptionValueForCommandObject(m_cmd_obj_sp,
1264         execution_context, long_option, option_arg);
1265       if (!success)
1266         error.SetErrorStringWithFormatv("Error setting option: {0} to {1}",
1267                                         long_option, option_arg);
1268       return error;
1269     }
1270 
OptionParsingStarting(ExecutionContext * execution_context)1271     void OptionParsingStarting(ExecutionContext *execution_context) override {
1272       ScriptInterpreter *scripter =
1273         m_interpreter.GetDebugger().GetScriptInterpreter();
1274       if (!scripter || !m_cmd_obj_sp)
1275         return;
1276 
1277       scripter->OptionParsingStartedForCommandObject(m_cmd_obj_sp);
1278     }
1279 
GetDefinitions()1280     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1281       if (!m_options_definition_up)
1282         return {};
1283       return llvm::ArrayRef(m_options_definition_up.get(), m_num_options);
1284     }
1285 
ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp,size_t counter,uint32_t & usage_mask)1286     static Status ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp,
1287         size_t counter, uint32_t &usage_mask) {
1288       // If the usage entry is not provided, we use LLDB_OPT_SET_ALL.
1289       // If the usage mask is a UINT, the option belongs to that group.
1290       // If the usage mask is a vector of UINT's, the option belongs to all the
1291       // groups listed.
1292       // If a subelement of the vector is a vector of two ints, then the option
1293       // belongs to the inclusive range from the first to the second element.
1294       Status error;
1295       if (!obj_sp) {
1296         usage_mask = LLDB_OPT_SET_ALL;
1297         return error;
1298       }
1299 
1300       usage_mask = 0;
1301 
1302       StructuredData::UnsignedInteger *uint_val =
1303           obj_sp->GetAsUnsignedInteger();
1304       if (uint_val) {
1305         // If this is an integer, then this specifies a single group:
1306         uint32_t value = uint_val->GetValue();
1307         if (value == 0) {
1308           error.SetErrorStringWithFormatv(
1309               "0 is not a valid group for option {0}", counter);
1310           return error;
1311         }
1312         usage_mask = (1 << (value - 1));
1313         return error;
1314       }
1315       // Otherwise it has to be an array:
1316       StructuredData::Array *array_val = obj_sp->GetAsArray();
1317       if (!array_val) {
1318         error.SetErrorStringWithFormatv(
1319             "required field is not a array for option {0}", counter);
1320         return error;
1321       }
1322       // This is the array ForEach for accumulating a group usage mask from
1323       // an array of string descriptions of groups.
1324       auto groups_accumulator
1325           = [counter, &usage_mask, &error]
1326             (StructuredData::Object *obj) -> bool {
1327         StructuredData::UnsignedInteger *int_val = obj->GetAsUnsignedInteger();
1328         if (int_val) {
1329           uint32_t value = int_val->GetValue();
1330           if (value == 0) {
1331             error.SetErrorStringWithFormatv(
1332                 "0 is not a valid group for element {0}", counter);
1333             return false;
1334           }
1335           usage_mask |= (1 << (value - 1));
1336           return true;
1337         }
1338         StructuredData::Array *arr_val = obj->GetAsArray();
1339         if (!arr_val) {
1340           error.SetErrorStringWithFormatv(
1341               "Group element not an int or array of integers for element {0}",
1342               counter);
1343           return false;
1344         }
1345         size_t num_range_elem = arr_val->GetSize();
1346         if (num_range_elem != 2) {
1347           error.SetErrorStringWithFormatv(
1348               "Subranges of a group not a start and a stop for element {0}",
1349               counter);
1350           return false;
1351         }
1352         int_val = arr_val->GetItemAtIndex(0)->GetAsUnsignedInteger();
1353         if (!int_val) {
1354           error.SetErrorStringWithFormatv("Start element of a subrange of a "
1355               "group not unsigned int for element {0}", counter);
1356           return false;
1357         }
1358         uint32_t start = int_val->GetValue();
1359         int_val = arr_val->GetItemAtIndex(1)->GetAsUnsignedInteger();
1360         if (!int_val) {
1361           error.SetErrorStringWithFormatv("End element of a subrange of a group"
1362               " not unsigned int for element {0}", counter);
1363           return false;
1364         }
1365         uint32_t end = int_val->GetValue();
1366         if (start == 0 || end == 0 || start > end) {
1367           error.SetErrorStringWithFormatv("Invalid subrange of a group: {0} - "
1368               "{1} for element {2}", start, end, counter);
1369           return false;
1370         }
1371         for (uint32_t i = start; i <= end; i++) {
1372           usage_mask |= (1 << (i - 1));
1373         }
1374         return true;
1375       };
1376       array_val->ForEach(groups_accumulator);
1377       return error;
1378     }
1379 
1380 
SetOptionsFromArray(StructuredData::Dictionary & options)1381     Status SetOptionsFromArray(StructuredData::Dictionary &options) {
1382       Status error;
1383       m_num_options = options.GetSize();
1384       m_options_definition_up.reset(new OptionDefinition[m_num_options]);
1385       // We need to hand out pointers to contents of these vectors; we reserve
1386       // as much as we'll need up front so they don't get freed on resize...
1387       m_usage_container.resize(m_num_options);
1388       m_enum_storage.resize(m_num_options);
1389       m_enum_vector.resize(m_num_options);
1390 
1391       size_t counter = 0;
1392       size_t short_opt_counter = 0;
1393       // This is the Array::ForEach function for adding option elements:
1394       auto add_element = [this, &error, &counter, &short_opt_counter]
1395           (llvm::StringRef long_option, StructuredData::Object *object) -> bool {
1396         StructuredData::Dictionary *opt_dict = object->GetAsDictionary();
1397         if (!opt_dict) {
1398           error.SetErrorString("Value in options dictionary is not a dictionary");
1399           return false;
1400         }
1401         OptionDefinition &option_def = m_options_definition_up.get()[counter];
1402 
1403         // We aren't exposing the validator yet, set it to null
1404         option_def.validator = nullptr;
1405         // We don't require usage masks, so set it to one group by default:
1406         option_def.usage_mask = 1;
1407 
1408         // Now set the fields of the OptionDefinition Array from the dictionary:
1409         //
1410         // Note that I don't check for unknown fields in the option dictionaries
1411         // so a scriptor can add extra elements that are helpful when they go to
1412         // do "set_option_value"
1413 
1414         // Usage Mask:
1415         StructuredData::ObjectSP obj_sp = opt_dict->GetValueForKey("groups");
1416         if (obj_sp) {
1417           error = ParseUsageMaskFromArray(obj_sp, counter,
1418                                           option_def.usage_mask);
1419           if (error.Fail())
1420             return false;
1421         }
1422 
1423         // Required:
1424         option_def.required = false;
1425         obj_sp = opt_dict->GetValueForKey("required");
1426         if (obj_sp) {
1427           StructuredData::Boolean *boolean_val = obj_sp->GetAsBoolean();
1428           if (!boolean_val) {
1429             error.SetErrorStringWithFormatv("'required' field is not a boolean "
1430                 "for option {0}", counter);
1431             return false;
1432           }
1433           option_def.required = boolean_val->GetValue();
1434         }
1435 
1436         // Short Option:
1437         int short_option;
1438         obj_sp = opt_dict->GetValueForKey("short_option");
1439         if (obj_sp) {
1440           // The value is a string, so pull the
1441           llvm::StringRef short_str = obj_sp->GetStringValue();
1442           if (short_str.empty()) {
1443             error.SetErrorStringWithFormatv("short_option field empty for "
1444                 "option {0}", counter);
1445             return false;
1446           } else if (short_str.size() != 1) {
1447             error.SetErrorStringWithFormatv("short_option field has extra "
1448                 "characters for option {0}", counter);
1449             return false;
1450           }
1451           short_option = (int) short_str[0];
1452         } else {
1453           // If the short option is not provided, then we need a unique value
1454           // less than the lowest printable ASCII character.
1455           short_option = short_opt_counter++;
1456         }
1457         option_def.short_option = short_option;
1458 
1459         // Long Option is the key from the outer dict:
1460         if (long_option.empty()) {
1461           error.SetErrorStringWithFormatv("empty long_option for option {0}",
1462               counter);
1463           return false;
1464         }
1465         auto inserted = g_string_storer.insert(long_option.str());
1466         option_def.long_option = ((*(inserted.first)).data());
1467 
1468         // Value Type:
1469         obj_sp = opt_dict->GetValueForKey("value_type");
1470         if (obj_sp) {
1471           StructuredData::UnsignedInteger *uint_val
1472               = obj_sp->GetAsUnsignedInteger();
1473           if (!uint_val) {
1474             error.SetErrorStringWithFormatv("Value type must be an unsigned "
1475                 "integer");
1476             return false;
1477           }
1478           uint64_t val_type = uint_val->GetValue();
1479           if (val_type >= eArgTypeLastArg) {
1480             error.SetErrorStringWithFormatv("Value type {0} beyond the "
1481                 "CommandArgumentType bounds", val_type);
1482             return false;
1483           }
1484           option_def.argument_type = (CommandArgumentType) val_type;
1485           option_def.option_has_arg = true;
1486         } else {
1487           option_def.argument_type = eArgTypeNone;
1488           option_def.option_has_arg = false;
1489         }
1490 
1491         // Completion Type:
1492         obj_sp = opt_dict->GetValueForKey("completion_type");
1493         if (obj_sp) {
1494           StructuredData::UnsignedInteger *uint_val = obj_sp->GetAsUnsignedInteger();
1495           if (!uint_val) {
1496             error.SetErrorStringWithFormatv("Completion type must be an "
1497                 "unsigned integer for option {0}", counter);
1498             return false;
1499           }
1500           uint64_t completion_type = uint_val->GetValue();
1501           if (completion_type > eCustomCompletion) {
1502             error.SetErrorStringWithFormatv("Completion type for option {0} "
1503                 "beyond the CompletionType bounds", completion_type);
1504             return false;
1505           }
1506           option_def.completion_type = (CommandArgumentType) completion_type;
1507         } else
1508           option_def.completion_type = eNoCompletion;
1509 
1510         // Usage Text:
1511         std::string usage_text;
1512         obj_sp = opt_dict->GetValueForKey("help");
1513         if (!obj_sp) {
1514           error.SetErrorStringWithFormatv("required usage missing from option "
1515               "{0}", counter);
1516           return false;
1517         }
1518         llvm::StringRef usage_stref;
1519         usage_stref = obj_sp->GetStringValue();
1520         if (usage_stref.empty()) {
1521           error.SetErrorStringWithFormatv("empty usage text for option {0}",
1522               counter);
1523           return false;
1524         }
1525         m_usage_container[counter] = usage_stref.str().c_str();
1526         option_def.usage_text = m_usage_container[counter].data();
1527 
1528         // Enum Values:
1529 
1530         obj_sp = opt_dict->GetValueForKey("enum_values");
1531         if (obj_sp) {
1532           StructuredData::Array *array = obj_sp->GetAsArray();
1533           if (!array) {
1534             error.SetErrorStringWithFormatv("enum values must be an array for "
1535                 "option {0}", counter);
1536             return false;
1537           }
1538           size_t num_elem = array->GetSize();
1539           size_t enum_ctr = 0;
1540           m_enum_storage[counter] = std::vector<EnumValueStorage>(num_elem);
1541           std::vector<EnumValueStorage> &curr_elem = m_enum_storage[counter];
1542 
1543           // This is the Array::ForEach function for adding enum elements:
1544           // Since there are only two fields to specify the enum, use a simple
1545           // two element array with value first, usage second.
1546           // counter is only used for reporting so I pass it by value here.
1547           auto add_enum = [&enum_ctr, &curr_elem, counter, &error]
1548               (StructuredData::Object *object) -> bool {
1549             StructuredData::Array *enum_arr = object->GetAsArray();
1550             if (!enum_arr) {
1551               error.SetErrorStringWithFormatv("Enum values for option {0} not "
1552                   "an array", counter);
1553               return false;
1554             }
1555             size_t num_enum_elements = enum_arr->GetSize();
1556             if (num_enum_elements != 2) {
1557               error.SetErrorStringWithFormatv("Wrong number of elements: {0} "
1558                   "for enum {1} in option {2}",
1559                   num_enum_elements, enum_ctr, counter);
1560               return false;
1561             }
1562             // Enum Value:
1563             StructuredData::ObjectSP obj_sp = enum_arr->GetItemAtIndex(0);
1564             llvm::StringRef val_stref = obj_sp->GetStringValue();
1565             std::string value_cstr_str = val_stref.str().c_str();
1566 
1567             // Enum Usage:
1568             obj_sp = enum_arr->GetItemAtIndex(1);
1569             if (!obj_sp) {
1570               error.SetErrorStringWithFormatv("No usage for enum {0} in option "
1571                   "{1}",  enum_ctr, counter);
1572               return false;
1573             }
1574             llvm::StringRef usage_stref = obj_sp->GetStringValue();
1575             std::string usage_cstr_str = usage_stref.str().c_str();
1576             curr_elem[enum_ctr] = EnumValueStorage(value_cstr_str,
1577                 usage_cstr_str, enum_ctr);
1578 
1579             enum_ctr++;
1580             return true;
1581           }; // end of add_enum
1582 
1583           array->ForEach(add_enum);
1584           if (!error.Success())
1585             return false;
1586           // We have to have a vector of elements to set in the options, make
1587           // that here:
1588           for (auto &elem : curr_elem)
1589             m_enum_vector[counter].emplace_back(elem.element);
1590 
1591           option_def.enum_values = llvm::ArrayRef(m_enum_vector[counter]);
1592         }
1593         counter++;
1594         return true;
1595       }; // end of add_element
1596 
1597       options.ForEach(add_element);
1598       return error;
1599     }
1600 
GetNumOptions()1601     size_t GetNumOptions() { return m_num_options; }
1602 
1603   private:
1604     struct EnumValueStorage {
EnumValueStorageCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1605       EnumValueStorage() {
1606         element.string_value = "value not set";
1607         element.usage = "usage not set";
1608         element.value = 0;
1609       }
1610 
EnumValueStorageCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1611       EnumValueStorage(std::string in_str_val, std::string in_usage,
1612           size_t in_value) : value(std::move(in_str_val)), usage(std::move(in_usage)) {
1613         SetElement(in_value);
1614       }
1615 
EnumValueStorageCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1616       EnumValueStorage(const EnumValueStorage &in) : value(in.value),
1617           usage(in.usage) {
1618         SetElement(in.element.value);
1619       }
1620 
operator =CommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1621       EnumValueStorage &operator=(const EnumValueStorage &in) {
1622         value = in.value;
1623         usage = in.usage;
1624         SetElement(in.element.value);
1625         return *this;
1626       }
1627 
SetElementCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1628       void SetElement(size_t in_value) {
1629         element.value = in_value;
1630         element.string_value = value.data();
1631         element.usage = usage.data();
1632       }
1633 
1634       std::string value;
1635       std::string usage;
1636       OptionEnumValueElement element;
1637     };
1638     // We have to provide char * values for the long option, usage and enum
1639     // values, that's what the option definitions hold.
1640     // The long option strings are quite likely to be reused in other added
1641     // commands, so those are stored in a global set: g_string_storer.
1642     // But the usages are much less likely to be reused, so those are stored in
1643     // a vector in the command instance.  It gets resized to the correct size
1644     // and then filled with null-terminated strings in the std::string, so the
1645     // are valid C-strings that won't move around.
1646     // The enum values and descriptions are treated similarly - these aren't
1647     // all that common so it's not worth the effort to dedup them.
1648     size_t m_num_options = 0;
1649     std::unique_ptr<OptionDefinition> m_options_definition_up;
1650     std::vector<std::vector<EnumValueStorage>> m_enum_storage;
1651     std::vector<std::vector<OptionEnumValueElement>> m_enum_vector;
1652     std::vector<std::string> m_usage_container;
1653     CommandInterpreter &m_interpreter;
1654     StructuredData::GenericSP m_cmd_obj_sp;
1655     static std::unordered_set<std::string> g_string_storer;
1656   };
1657 
1658 public:
Create(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch,CommandReturnObject & result)1659   static CommandObjectSP Create(CommandInterpreter &interpreter,
1660                 std::string name,
1661                 StructuredData::GenericSP cmd_obj_sp,
1662                 ScriptedCommandSynchronicity synch,
1663                 CommandReturnObject &result) {
1664     CommandObjectSP new_cmd_sp(new CommandObjectScriptingObjectParsed(
1665         interpreter, name, cmd_obj_sp, synch));
1666 
1667     CommandObjectScriptingObjectParsed *parsed_cmd
1668         = static_cast<CommandObjectScriptingObjectParsed *>(new_cmd_sp.get());
1669     // Now check all the failure modes, and report if found.
1670     Status opt_error = parsed_cmd->GetOptionsError();
1671     Status arg_error = parsed_cmd->GetArgsError();
1672 
1673     if (opt_error.Fail())
1674       result.AppendErrorWithFormat("failed to parse option definitions: %s",
1675                                    opt_error.AsCString());
1676     if (arg_error.Fail())
1677       result.AppendErrorWithFormat("%sfailed to parse argument definitions: %s",
1678                                    opt_error.Fail() ? ", also " : "",
1679                                    arg_error.AsCString());
1680 
1681     if (!result.Succeeded())
1682       return {};
1683 
1684     return new_cmd_sp;
1685   }
1686 
CommandObjectScriptingObjectParsed(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch)1687   CommandObjectScriptingObjectParsed(CommandInterpreter &interpreter,
1688                                std::string name,
1689                                StructuredData::GenericSP cmd_obj_sp,
1690                                ScriptedCommandSynchronicity synch)
1691       : CommandObjectParsed(interpreter, name.c_str()),
1692         m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch),
1693         m_options(interpreter, cmd_obj_sp), m_fetched_help_short(false),
1694         m_fetched_help_long(false) {
1695     StreamString stream;
1696     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1697     if (!scripter) {
1698       m_options_error.SetErrorString("No script interpreter");
1699       return;
1700     }
1701 
1702     // Set the flags:
1703     GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1704 
1705     // Now set up the options definitions from the options:
1706     StructuredData::ObjectSP options_object_sp
1707         = scripter->GetOptionsForCommandObject(cmd_obj_sp);
1708     // It's okay not to have an options dict.
1709     if (options_object_sp) {
1710       // The options come as a dictionary of dictionaries.  The key of the
1711       // outer dict is the long option name (since that's required).  The
1712       // value holds all the other option specification bits.
1713       StructuredData::Dictionary *options_dict
1714           = options_object_sp->GetAsDictionary();
1715       // but if it exists, it has to be an array.
1716       if (options_dict) {
1717         m_options_error = m_options.SetOptionsFromArray(*(options_dict));
1718         // If we got an error don't bother with the arguments...
1719         if (m_options_error.Fail())
1720           return;
1721       } else {
1722         m_options_error.SetErrorString("Options array not an array");
1723         return;
1724       }
1725     }
1726     // Then fetch the args.  Since the arguments can have usage masks you need
1727     // an array of arrays.
1728     StructuredData::ObjectSP args_object_sp
1729       = scripter->GetArgumentsForCommandObject(cmd_obj_sp);
1730     if (args_object_sp) {
1731       StructuredData::Array *args_array = args_object_sp->GetAsArray();
1732       if (!args_array) {
1733         m_args_error.SetErrorString("Argument specification is not an array");
1734         return;
1735       }
1736       size_t counter = 0;
1737 
1738       // This is the Array::ForEach function that handles the
1739       // CommandArgumentEntry arrays one by one:
1740       auto arg_array_adder = [this, &counter] (StructuredData::Object *object)
1741           -> bool {
1742         // This is the Array::ForEach function to add argument entries:
1743         CommandArgumentEntry this_entry;
1744         size_t elem_counter = 0;
1745         auto args_adder = [this, counter, &elem_counter, &this_entry]
1746             (StructuredData::Object *object) -> bool {
1747           // The arguments definition has three fields, the argument type, the
1748           // repeat and the usage mask.
1749           CommandArgumentType arg_type = eArgTypeNone;
1750           ArgumentRepetitionType arg_repetition = eArgRepeatOptional;
1751           uint32_t arg_opt_set_association;
1752 
1753           auto report_error = [this, elem_counter, counter]
1754               (const char *err_txt) -> bool {
1755             m_args_error.SetErrorStringWithFormatv("Element {0} of arguments "
1756                 "list element {1}: %s.", elem_counter, counter, err_txt);
1757             return false;
1758           };
1759 
1760           StructuredData::Dictionary *arg_dict = object->GetAsDictionary();
1761           if (!arg_dict) {
1762             report_error("is not a dictionary.");
1763             return false;
1764           }
1765           // Argument Type:
1766           StructuredData::ObjectSP obj_sp
1767               = arg_dict->GetValueForKey("arg_type");
1768           if (obj_sp) {
1769             StructuredData::UnsignedInteger *uint_val
1770                 = obj_sp->GetAsUnsignedInteger();
1771             if (!uint_val) {
1772               report_error("value type must be an unsigned integer");
1773               return false;
1774             }
1775             uint64_t arg_type_int = uint_val->GetValue();
1776             if (arg_type_int >= eArgTypeLastArg) {
1777               report_error("value type beyond ArgumentRepetitionType bounds");
1778               return false;
1779             }
1780             arg_type = (CommandArgumentType) arg_type_int;
1781           }
1782           // Repeat Value:
1783           obj_sp = arg_dict->GetValueForKey("repeat");
1784           std::optional<ArgumentRepetitionType> repeat;
1785           if (obj_sp) {
1786             llvm::StringRef repeat_str = obj_sp->GetStringValue();
1787             if (repeat_str.empty()) {
1788               report_error("repeat value is empty");
1789               return false;
1790             }
1791             repeat = ArgRepetitionFromString(repeat_str);
1792             if (!repeat) {
1793               report_error("invalid repeat value");
1794               return false;
1795             }
1796             arg_repetition = *repeat;
1797           }
1798 
1799           // Usage Mask:
1800           obj_sp = arg_dict->GetValueForKey("groups");
1801           m_args_error = CommandOptions::ParseUsageMaskFromArray(obj_sp,
1802               counter, arg_opt_set_association);
1803           this_entry.emplace_back(arg_type, arg_repetition,
1804               arg_opt_set_association);
1805           elem_counter++;
1806           return true;
1807         };
1808         StructuredData::Array *args_array = object->GetAsArray();
1809         if (!args_array) {
1810           m_args_error.SetErrorStringWithFormatv("Argument definition element "
1811               "{0} is not an array", counter);
1812         }
1813 
1814         args_array->ForEach(args_adder);
1815         if (m_args_error.Fail())
1816           return false;
1817         if (this_entry.empty()) {
1818           m_args_error.SetErrorStringWithFormatv("Argument definition element "
1819               "{0} is empty", counter);
1820           return false;
1821         }
1822         m_arguments.push_back(this_entry);
1823         counter++;
1824         return true;
1825       }; // end of arg_array_adder
1826       // Here we actually parse the args definition:
1827       args_array->ForEach(arg_array_adder);
1828     }
1829   }
1830 
1831   ~CommandObjectScriptingObjectParsed() override = default;
1832 
GetOptionsError()1833   Status GetOptionsError() { return m_options_error; }
GetArgsError()1834   Status GetArgsError() { return m_args_error; }
WantsCompletion()1835   bool WantsCompletion() override { return true; }
1836 
IsRemovable() const1837   bool IsRemovable() const override { return true; }
1838 
GetSynchronicity()1839   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1840 
GetRepeatCommand(Args & args,uint32_t index)1841   std::optional<std::string> GetRepeatCommand(Args &args,
1842                                               uint32_t index) override {
1843     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1844     if (!scripter)
1845       return std::nullopt;
1846 
1847     return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
1848   }
1849 
GetHelp()1850   llvm::StringRef GetHelp() override {
1851     if (m_fetched_help_short)
1852       return CommandObjectParsed::GetHelp();
1853     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1854     if (!scripter)
1855       return CommandObjectParsed::GetHelp();
1856     std::string docstring;
1857     m_fetched_help_short =
1858         scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1859     if (!docstring.empty())
1860       SetHelp(docstring);
1861 
1862     return CommandObjectParsed::GetHelp();
1863   }
1864 
GetHelpLong()1865   llvm::StringRef GetHelpLong() override {
1866     if (m_fetched_help_long)
1867       return CommandObjectParsed::GetHelpLong();
1868 
1869     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1870     if (!scripter)
1871       return CommandObjectParsed::GetHelpLong();
1872 
1873     std::string docstring;
1874     m_fetched_help_long =
1875         scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1876     if (!docstring.empty())
1877       SetHelpLong(docstring);
1878     return CommandObjectParsed::GetHelpLong();
1879   }
1880 
GetOptions()1881   Options *GetOptions() override {
1882     // CommandObjectParsed requires that a command with no options return
1883     // nullptr.
1884     if (m_options.GetNumOptions() == 0)
1885       return nullptr;
1886     return &m_options;
1887   }
1888 
1889 protected:
DoExecute(Args & args,CommandReturnObject & result)1890   void DoExecute(Args &args,
1891                  CommandReturnObject &result) override {
1892     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1893 
1894     Status error;
1895 
1896     result.SetStatus(eReturnStatusInvalid);
1897 
1898     if (!scripter ||
1899         !scripter->RunScriptBasedParsedCommand(m_cmd_obj_sp, args,
1900                                          m_synchro, result, error, m_exe_ctx)) {
1901       result.AppendError(error.AsCString());
1902     } else {
1903       // Don't change the status if the command already set it...
1904       if (result.GetStatus() == eReturnStatusInvalid) {
1905         if (result.GetOutputData().empty())
1906           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1907         else
1908           result.SetStatus(eReturnStatusSuccessFinishResult);
1909       }
1910     }
1911   }
1912 
1913 private:
1914   StructuredData::GenericSP m_cmd_obj_sp;
1915   ScriptedCommandSynchronicity m_synchro;
1916   CommandOptions m_options;
1917   Status m_options_error;
1918   Status m_args_error;
1919   bool m_fetched_help_short : 1;
1920   bool m_fetched_help_long : 1;
1921 };
1922 
1923 std::unordered_set<std::string>
1924     CommandObjectScriptingObjectParsed::CommandOptions::g_string_storer;
1925 
1926 // CommandObjectCommandsScriptImport
1927 #define LLDB_OPTIONS_script_import
1928 #include "CommandOptions.inc"
1929 
1930 class CommandObjectCommandsScriptImport : public CommandObjectParsed {
1931 public:
CommandObjectCommandsScriptImport(CommandInterpreter & interpreter)1932   CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
1933       : CommandObjectParsed(interpreter, "command script import",
1934                             "Import a scripting module in LLDB.", nullptr) {
1935     AddSimpleArgumentList(eArgTypeFilename, eArgRepeatPlus);
1936   }
1937 
1938   ~CommandObjectCommandsScriptImport() override = default;
1939 
GetOptions()1940   Options *GetOptions() override { return &m_options; }
1941 
1942 protected:
1943   class CommandOptions : public Options {
1944   public:
1945     CommandOptions() = default;
1946 
1947     ~CommandOptions() override = default;
1948 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1949     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1950                           ExecutionContext *execution_context) override {
1951       Status error;
1952       const int short_option = m_getopt_table[option_idx].val;
1953 
1954       switch (short_option) {
1955       case 'r':
1956         // NO-OP
1957         break;
1958       case 'c':
1959         relative_to_command_file = true;
1960         break;
1961       case 's':
1962         silent = true;
1963         break;
1964       default:
1965         llvm_unreachable("Unimplemented option");
1966       }
1967 
1968       return error;
1969     }
1970 
OptionParsingStarting(ExecutionContext * execution_context)1971     void OptionParsingStarting(ExecutionContext *execution_context) override {
1972       relative_to_command_file = false;
1973     }
1974 
GetDefinitions()1975     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1976       return llvm::ArrayRef(g_script_import_options);
1977     }
1978     bool relative_to_command_file = false;
1979     bool silent = false;
1980   };
1981 
DoExecute(Args & command,CommandReturnObject & result)1982   void DoExecute(Args &command, CommandReturnObject &result) override {
1983     if (command.empty()) {
1984       result.AppendError("command script import needs one or more arguments");
1985       return;
1986     }
1987 
1988     FileSpec source_dir = {};
1989     if (m_options.relative_to_command_file) {
1990       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
1991       if (!source_dir) {
1992         result.AppendError("command script import -c can only be specified "
1993                            "from a command file");
1994         return;
1995       }
1996     }
1997 
1998     for (auto &entry : command.entries()) {
1999       Status error;
2000 
2001       LoadScriptOptions options;
2002       options.SetInitSession(true);
2003       options.SetSilent(m_options.silent);
2004 
2005       // FIXME: this is necessary because CommandObject::CheckRequirements()
2006       // assumes that commands won't ever be recursively invoked, but it's
2007       // actually possible to craft a Python script that does other "command
2008       // script imports" in __lldb_init_module the real fix is to have
2009       // recursive commands possible with a CommandInvocation object separate
2010       // from the CommandObject itself, so that recursive command invocations
2011       // won't stomp on each other (wrt to execution contents, options, and
2012       // more)
2013       m_exe_ctx.Clear();
2014       if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
2015               entry.c_str(), options, error, /*module_sp=*/nullptr,
2016               source_dir)) {
2017         result.SetStatus(eReturnStatusSuccessFinishNoResult);
2018       } else {
2019         result.AppendErrorWithFormat("module importing failed: %s",
2020                                      error.AsCString());
2021       }
2022     }
2023   }
2024 
2025   CommandOptions m_options;
2026 };
2027 
2028 #define LLDB_OPTIONS_script_add
2029 #include "CommandOptions.inc"
2030 
2031 class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
2032                                        public IOHandlerDelegateMultiline {
2033 public:
CommandObjectCommandsScriptAdd(CommandInterpreter & interpreter)2034   CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
2035       : CommandObjectParsed(interpreter, "command script add",
2036                             "Add a scripted function as an LLDB command.",
2037                             "Add a scripted function as an lldb command. "
2038                             "If you provide a single argument, the command "
2039                             "will be added at the root level of the command "
2040                             "hierarchy.  If there are more arguments they "
2041                             "must be a path to a user-added container "
2042                             "command, and the last element will be the new "
2043                             "command name."),
2044         IOHandlerDelegateMultiline("DONE") {
2045     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2046   }
2047 
2048   ~CommandObjectCommandsScriptAdd() override = default;
2049 
GetOptions()2050   Options *GetOptions() override { return &m_options; }
2051 
2052   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2053   HandleArgumentCompletion(CompletionRequest &request,
2054                            OptionElementVector &opt_element_vector) override {
2055     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
2056                                                       opt_element_vector);
2057   }
2058 
2059 protected:
2060   class CommandOptions : public Options {
2061   public:
2062     CommandOptions() = default;
2063 
2064     ~CommandOptions() override = default;
2065 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2066     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2067                           ExecutionContext *execution_context) override {
2068       Status error;
2069       const int short_option = m_getopt_table[option_idx].val;
2070 
2071       switch (short_option) {
2072       case 'f':
2073         if (!option_arg.empty())
2074           m_funct_name = std::string(option_arg);
2075         break;
2076       case 'c':
2077         if (!option_arg.empty())
2078           m_class_name = std::string(option_arg);
2079         break;
2080       case 'h':
2081         if (!option_arg.empty())
2082           m_short_help = std::string(option_arg);
2083         break;
2084       case 'o':
2085         m_overwrite_lazy = eLazyBoolYes;
2086         break;
2087       case 'p':
2088         m_parsed_command = true;
2089         break;
2090       case 's':
2091         m_synchronicity =
2092             (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
2093                 option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
2094         if (!error.Success())
2095           error.SetErrorStringWithFormat(
2096               "unrecognized value for synchronicity '%s'",
2097               option_arg.str().c_str());
2098         break;
2099       case 'C': {
2100         Status error;
2101         OptionDefinition definition = GetDefinitions()[option_idx];
2102         lldb::CompletionType completion_type =
2103             static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum(
2104                 option_arg, definition.enum_values, eNoCompletion, error));
2105         if (!error.Success())
2106           error.SetErrorStringWithFormat(
2107               "unrecognized value for command completion type '%s'",
2108               option_arg.str().c_str());
2109         m_completion_type = completion_type;
2110       } break;
2111       default:
2112         llvm_unreachable("Unimplemented option");
2113       }
2114 
2115       return error;
2116     }
2117 
OptionParsingStarting(ExecutionContext * execution_context)2118     void OptionParsingStarting(ExecutionContext *execution_context) override {
2119       m_class_name.clear();
2120       m_funct_name.clear();
2121       m_short_help.clear();
2122       m_completion_type = eNoCompletion;
2123       m_overwrite_lazy = eLazyBoolCalculate;
2124       m_synchronicity = eScriptedCommandSynchronicitySynchronous;
2125       m_parsed_command = false;
2126     }
2127 
GetDefinitions()2128     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2129       return llvm::ArrayRef(g_script_add_options);
2130     }
2131 
2132     // Instance variables to hold the values for command options.
2133 
2134     std::string m_class_name;
2135     std::string m_funct_name;
2136     std::string m_short_help;
2137     LazyBool m_overwrite_lazy = eLazyBoolCalculate;
2138     ScriptedCommandSynchronicity m_synchronicity =
2139         eScriptedCommandSynchronicitySynchronous;
2140     CompletionType m_completion_type = eNoCompletion;
2141     bool m_parsed_command = false;
2142   };
2143 
IOHandlerActivated(IOHandler & io_handler,bool interactive)2144   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
2145     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
2146     if (output_sp && interactive) {
2147       output_sp->PutCString(g_python_command_instructions);
2148       output_sp->Flush();
2149     }
2150   }
2151 
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)2152   void IOHandlerInputComplete(IOHandler &io_handler,
2153                               std::string &data) override {
2154     StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
2155 
2156     ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2157     if (interpreter) {
2158       StringList lines;
2159       lines.SplitIntoLines(data);
2160       if (lines.GetSize() > 0) {
2161         std::string funct_name_str;
2162         if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
2163           if (funct_name_str.empty()) {
2164             error_sp->Printf("error: unable to obtain a function name, didn't "
2165                              "add python command.\n");
2166             error_sp->Flush();
2167           } else {
2168             // everything should be fine now, let's add this alias
2169 
2170             CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
2171                 m_interpreter, m_cmd_name, funct_name_str, m_short_help,
2172                 m_synchronicity, m_completion_type));
2173             if (!m_container) {
2174               Status error = m_interpreter.AddUserCommand(
2175                   m_cmd_name, command_obj_sp, m_overwrite);
2176               if (error.Fail()) {
2177                 error_sp->Printf("error: unable to add selected command: '%s'",
2178                                  error.AsCString());
2179                 error_sp->Flush();
2180               }
2181             } else {
2182               llvm::Error llvm_error = m_container->LoadUserSubcommand(
2183                   m_cmd_name, command_obj_sp, m_overwrite);
2184               if (llvm_error) {
2185                 error_sp->Printf("error: unable to add selected command: '%s'",
2186                                llvm::toString(std::move(llvm_error)).c_str());
2187                 error_sp->Flush();
2188               }
2189             }
2190           }
2191         } else {
2192           error_sp->Printf(
2193               "error: unable to create function, didn't add python command\n");
2194           error_sp->Flush();
2195         }
2196       } else {
2197         error_sp->Printf("error: empty function, didn't add python command\n");
2198         error_sp->Flush();
2199       }
2200     } else {
2201       error_sp->Printf(
2202           "error: script interpreter missing, didn't add python command\n");
2203       error_sp->Flush();
2204     }
2205 
2206     io_handler.SetIsDone(true);
2207   }
2208 
DoExecute(Args & command,CommandReturnObject & result)2209   void DoExecute(Args &command, CommandReturnObject &result) override {
2210     if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
2211       result.AppendError("only scripting language supported for scripted "
2212                          "commands is currently Python");
2213       return;
2214     }
2215 
2216     if (command.GetArgumentCount() == 0) {
2217       result.AppendError("'command script add' requires at least one argument");
2218       return;
2219     }
2220     // Store the options in case we get multi-line input, also figure out the
2221     // default if not user supplied:
2222     switch (m_options.m_overwrite_lazy) {
2223       case eLazyBoolCalculate:
2224         m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite();
2225         break;
2226       case eLazyBoolYes:
2227         m_overwrite = true;
2228         break;
2229       case eLazyBoolNo:
2230         m_overwrite = false;
2231     }
2232 
2233     Status path_error;
2234     m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath(
2235         command, true, path_error);
2236 
2237     if (path_error.Fail()) {
2238       result.AppendErrorWithFormat("error in command path: %s",
2239                                    path_error.AsCString());
2240       return;
2241     }
2242 
2243     if (!m_container) {
2244       // This is getting inserted into the root of the interpreter.
2245       m_cmd_name = std::string(command[0].ref());
2246     } else {
2247       size_t num_args = command.GetArgumentCount();
2248       m_cmd_name = std::string(command[num_args - 1].ref());
2249     }
2250 
2251     m_short_help.assign(m_options.m_short_help);
2252     m_synchronicity = m_options.m_synchronicity;
2253     m_completion_type = m_options.m_completion_type;
2254 
2255     // Handle the case where we prompt for the script code first:
2256     if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) {
2257       m_interpreter.GetPythonCommandsFromIOHandler("     ", // Prompt
2258                                                    *this);  // IOHandlerDelegate
2259       return;
2260     }
2261 
2262     CommandObjectSP new_cmd_sp;
2263     if (m_options.m_class_name.empty()) {
2264       new_cmd_sp.reset(new CommandObjectPythonFunction(
2265           m_interpreter, m_cmd_name, m_options.m_funct_name,
2266           m_options.m_short_help, m_synchronicity, m_completion_type));
2267     } else {
2268       ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2269       if (!interpreter) {
2270         result.AppendError("cannot find ScriptInterpreter");
2271         return;
2272       }
2273 
2274       auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
2275           m_options.m_class_name.c_str());
2276       if (!cmd_obj_sp) {
2277         result.AppendErrorWithFormatv("cannot create helper object for: "
2278                                       "'{0}'", m_options.m_class_name);
2279         return;
2280       }
2281 
2282       if (m_options.m_parsed_command) {
2283         new_cmd_sp = CommandObjectScriptingObjectParsed::Create(m_interpreter,
2284             m_cmd_name, cmd_obj_sp, m_synchronicity, result);
2285         if (!result.Succeeded())
2286           return;
2287       } else
2288         new_cmd_sp.reset(new CommandObjectScriptingObjectRaw(
2289             m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity,
2290             m_completion_type));
2291     }
2292 
2293     // Assume we're going to succeed...
2294     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2295     if (!m_container) {
2296       Status add_error =
2297           m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite);
2298       if (add_error.Fail())
2299         result.AppendErrorWithFormat("cannot add command: %s",
2300                                      add_error.AsCString());
2301     } else {
2302       llvm::Error llvm_error =
2303           m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite);
2304       if (llvm_error)
2305         result.AppendErrorWithFormat(
2306             "cannot add command: %s",
2307             llvm::toString(std::move(llvm_error)).c_str());
2308     }
2309   }
2310 
2311   CommandOptions m_options;
2312   std::string m_cmd_name;
2313   CommandObjectMultiword *m_container = nullptr;
2314   std::string m_short_help;
2315   bool m_overwrite = false;
2316   ScriptedCommandSynchronicity m_synchronicity =
2317       eScriptedCommandSynchronicitySynchronous;
2318   CompletionType m_completion_type = eNoCompletion;
2319 };
2320 
2321 // CommandObjectCommandsScriptList
2322 
2323 class CommandObjectCommandsScriptList : public CommandObjectParsed {
2324 public:
CommandObjectCommandsScriptList(CommandInterpreter & interpreter)2325   CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
2326       : CommandObjectParsed(interpreter, "command script list",
2327                             "List defined top-level scripted commands.",
2328                             nullptr) {}
2329 
2330   ~CommandObjectCommandsScriptList() override = default;
2331 
DoExecute(Args & command,CommandReturnObject & result)2332   void DoExecute(Args &command, CommandReturnObject &result) override {
2333     m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
2334 
2335     result.SetStatus(eReturnStatusSuccessFinishResult);
2336   }
2337 };
2338 
2339 // CommandObjectCommandsScriptClear
2340 
2341 class CommandObjectCommandsScriptClear : public CommandObjectParsed {
2342 public:
CommandObjectCommandsScriptClear(CommandInterpreter & interpreter)2343   CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
2344       : CommandObjectParsed(interpreter, "command script clear",
2345                             "Delete all scripted commands.", nullptr) {}
2346 
2347   ~CommandObjectCommandsScriptClear() override = default;
2348 
2349 protected:
DoExecute(Args & command,CommandReturnObject & result)2350   void DoExecute(Args &command, CommandReturnObject &result) override {
2351     m_interpreter.RemoveAllUser();
2352 
2353     result.SetStatus(eReturnStatusSuccessFinishResult);
2354   }
2355 };
2356 
2357 // CommandObjectCommandsScriptDelete
2358 
2359 class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
2360 public:
CommandObjectCommandsScriptDelete(CommandInterpreter & interpreter)2361   CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
2362       : CommandObjectParsed(
2363             interpreter, "command script delete",
2364             "Delete a scripted command by specifying the path to the command.",
2365             nullptr) {
2366     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2367   }
2368 
2369   ~CommandObjectCommandsScriptDelete() override = default;
2370 
2371   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2372   HandleArgumentCompletion(CompletionRequest &request,
2373                            OptionElementVector &opt_element_vector) override {
2374     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2375         m_interpreter, request, opt_element_vector);
2376   }
2377 
2378 protected:
DoExecute(Args & command,CommandReturnObject & result)2379   void DoExecute(Args &command, CommandReturnObject &result) override {
2380 
2381     llvm::StringRef root_cmd = command[0].ref();
2382     size_t num_args = command.GetArgumentCount();
2383 
2384     if (root_cmd.empty()) {
2385       result.AppendErrorWithFormat("empty root command name");
2386       return;
2387     }
2388     if (!m_interpreter.HasUserCommands() &&
2389         !m_interpreter.HasUserMultiwordCommands()) {
2390       result.AppendErrorWithFormat("can only delete user defined commands, "
2391                                    "but no user defined commands found");
2392       return;
2393     }
2394 
2395     CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd);
2396     if (!cmd_sp) {
2397       result.AppendErrorWithFormat("command '%s' not found.",
2398                                    command[0].c_str());
2399       return;
2400     }
2401     if (!cmd_sp->IsUserCommand()) {
2402       result.AppendErrorWithFormat("command '%s' is not a user command.",
2403                                    command[0].c_str());
2404       return;
2405     }
2406     if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) {
2407       result.AppendErrorWithFormat("command '%s' is a multi-word command.\n "
2408                                    "Delete with \"command container delete\"",
2409                                    command[0].c_str());
2410       return;
2411     }
2412 
2413     if (command.GetArgumentCount() == 1) {
2414       m_interpreter.RemoveUser(root_cmd);
2415       result.SetStatus(eReturnStatusSuccessFinishResult);
2416       return;
2417     }
2418     // We're deleting a command from a multiword command.  Verify the command
2419     // path:
2420     Status error;
2421     CommandObjectMultiword *container =
2422         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2423                                                            error);
2424     if (error.Fail()) {
2425       result.AppendErrorWithFormat("could not resolve command path: %s",
2426                                    error.AsCString());
2427       return;
2428     }
2429     if (!container) {
2430       // This means that command only had a leaf command, so the container is
2431       // the root.  That should have been handled above.
2432       result.AppendErrorWithFormat("could not find a container for '%s'",
2433                                    command[0].c_str());
2434       return;
2435     }
2436     const char *leaf_cmd = command[num_args - 1].c_str();
2437     llvm::Error llvm_error =
2438         container->RemoveUserSubcommand(leaf_cmd,
2439                                         /* multiword not okay */ false);
2440     if (llvm_error) {
2441       result.AppendErrorWithFormat(
2442           "could not delete command '%s': %s", leaf_cmd,
2443           llvm::toString(std::move(llvm_error)).c_str());
2444       return;
2445     }
2446 
2447     Stream &out_stream = result.GetOutputStream();
2448 
2449     out_stream << "Deleted command:";
2450     for (size_t idx = 0; idx < num_args; idx++) {
2451       out_stream << ' ';
2452       out_stream << command[idx].c_str();
2453     }
2454     out_stream << '\n';
2455     result.SetStatus(eReturnStatusSuccessFinishResult);
2456   }
2457 };
2458 
2459 #pragma mark CommandObjectMultiwordCommandsScript
2460 
2461 // CommandObjectMultiwordCommandsScript
2462 
2463 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
2464 public:
CommandObjectMultiwordCommandsScript(CommandInterpreter & interpreter)2465   CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
2466       : CommandObjectMultiword(
2467             interpreter, "command script",
2468             "Commands for managing custom "
2469             "commands implemented by "
2470             "interpreter scripts.",
2471             "command script <subcommand> [<subcommand-options>]") {
2472     LoadSubCommand("add", CommandObjectSP(
2473                               new CommandObjectCommandsScriptAdd(interpreter)));
2474     LoadSubCommand(
2475         "delete",
2476         CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
2477     LoadSubCommand(
2478         "clear",
2479         CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
2480     LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
2481                                interpreter)));
2482     LoadSubCommand(
2483         "import",
2484         CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
2485   }
2486 
2487   ~CommandObjectMultiwordCommandsScript() override = default;
2488 };
2489 
2490 #pragma mark CommandObjectCommandContainer
2491 #define LLDB_OPTIONS_container_add
2492 #include "CommandOptions.inc"
2493 
2494 class CommandObjectCommandsContainerAdd : public CommandObjectParsed {
2495 public:
CommandObjectCommandsContainerAdd(CommandInterpreter & interpreter)2496   CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter)
2497       : CommandObjectParsed(
2498             interpreter, "command container add",
2499             "Add a container command to lldb.  Adding to built-"
2500             "in container commands is not allowed.",
2501             "command container add [[path1]...] container-name") {
2502     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2503   }
2504 
2505   ~CommandObjectCommandsContainerAdd() override = default;
2506 
GetOptions()2507   Options *GetOptions() override { return &m_options; }
2508 
2509   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2510   HandleArgumentCompletion(CompletionRequest &request,
2511                            OptionElementVector &opt_element_vector) override {
2512     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2513         m_interpreter, request, opt_element_vector);
2514   }
2515 
2516 protected:
2517   class CommandOptions : public Options {
2518   public:
2519     CommandOptions() = default;
2520 
2521     ~CommandOptions() override = default;
2522 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2523     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2524                           ExecutionContext *execution_context) override {
2525       Status error;
2526       const int short_option = m_getopt_table[option_idx].val;
2527 
2528       switch (short_option) {
2529       case 'h':
2530         if (!option_arg.empty())
2531           m_short_help = std::string(option_arg);
2532         break;
2533       case 'o':
2534         m_overwrite = true;
2535         break;
2536       case 'H':
2537         if (!option_arg.empty())
2538           m_long_help = std::string(option_arg);
2539         break;
2540       default:
2541         llvm_unreachable("Unimplemented option");
2542       }
2543 
2544       return error;
2545     }
2546 
OptionParsingStarting(ExecutionContext * execution_context)2547     void OptionParsingStarting(ExecutionContext *execution_context) override {
2548       m_short_help.clear();
2549       m_long_help.clear();
2550       m_overwrite = false;
2551     }
2552 
GetDefinitions()2553     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2554       return llvm::ArrayRef(g_container_add_options);
2555     }
2556 
2557     // Instance variables to hold the values for command options.
2558 
2559     std::string m_short_help;
2560     std::string m_long_help;
2561     bool m_overwrite = false;
2562   };
DoExecute(Args & command,CommandReturnObject & result)2563   void DoExecute(Args &command, CommandReturnObject &result) override {
2564     size_t num_args = command.GetArgumentCount();
2565 
2566     if (num_args == 0) {
2567       result.AppendError("no command was specified");
2568       return;
2569     }
2570 
2571     if (num_args == 1) {
2572       // We're adding this as a root command, so use the interpreter.
2573       const char *cmd_name = command.GetArgumentAtIndex(0);
2574       auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
2575           GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
2576           m_options.m_long_help.c_str()));
2577       cmd_sp->GetAsMultiwordCommand()->SetRemovable(true);
2578       Status add_error = GetCommandInterpreter().AddUserCommand(
2579           cmd_name, cmd_sp, m_options.m_overwrite);
2580       if (add_error.Fail()) {
2581         result.AppendErrorWithFormat("error adding command: %s",
2582                                      add_error.AsCString());
2583         return;
2584       }
2585       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2586       return;
2587     }
2588 
2589     // We're adding this to a subcommand, first find the subcommand:
2590     Status path_error;
2591     CommandObjectMultiword *add_to_me =
2592         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2593                                                            path_error);
2594 
2595     if (!add_to_me) {
2596       result.AppendErrorWithFormat("error adding command: %s",
2597                                    path_error.AsCString());
2598       return;
2599     }
2600 
2601     const char *cmd_name = command.GetArgumentAtIndex(num_args - 1);
2602     auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
2603         GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
2604         m_options.m_long_help.c_str()));
2605     llvm::Error llvm_error =
2606         add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite);
2607     if (llvm_error) {
2608       result.AppendErrorWithFormat("error adding subcommand: %s",
2609                                    llvm::toString(std::move(llvm_error)).c_str());
2610       return;
2611     }
2612 
2613     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2614   }
2615 
2616 private:
2617   CommandOptions m_options;
2618 };
2619 
2620 #define LLDB_OPTIONS_multiword_delete
2621 #include "CommandOptions.inc"
2622 class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
2623 public:
CommandObjectCommandsContainerDelete(CommandInterpreter & interpreter)2624   CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter)
2625       : CommandObjectParsed(
2626             interpreter, "command container delete",
2627             "Delete a container command previously added to "
2628             "lldb.",
2629             "command container delete [[path1] ...] container-cmd") {
2630     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2631   }
2632 
2633   ~CommandObjectCommandsContainerDelete() override = default;
2634 
2635   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2636   HandleArgumentCompletion(CompletionRequest &request,
2637                            OptionElementVector &opt_element_vector) override {
2638     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2639         m_interpreter, request, opt_element_vector);
2640   }
2641 
2642 protected:
DoExecute(Args & command,CommandReturnObject & result)2643   void DoExecute(Args &command, CommandReturnObject &result) override {
2644     size_t num_args = command.GetArgumentCount();
2645 
2646     if (num_args == 0) {
2647       result.AppendError("No command was specified.");
2648       return;
2649     }
2650 
2651     if (num_args == 1) {
2652       // We're removing a root command, so we need to delete it from the
2653       // interpreter.
2654       const char *cmd_name = command.GetArgumentAtIndex(0);
2655       // Let's do a little more work here so we can do better error reporting.
2656       CommandInterpreter &interp = GetCommandInterpreter();
2657       CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name);
2658       if (!cmd_sp) {
2659         result.AppendErrorWithFormat("container command %s doesn't exist.",
2660                                      cmd_name);
2661         return;
2662       }
2663       if (!cmd_sp->IsUserCommand()) {
2664         result.AppendErrorWithFormat(
2665             "container command %s is not a user command", cmd_name);
2666         return;
2667       }
2668       if (!cmd_sp->GetAsMultiwordCommand()) {
2669         result.AppendErrorWithFormat("command %s is not a container command",
2670                                      cmd_name);
2671         return;
2672       }
2673 
2674       bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name);
2675       if (!did_remove) {
2676         result.AppendErrorWithFormat("error removing command %s.", cmd_name);
2677         return;
2678       }
2679 
2680       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2681       return;
2682     }
2683 
2684     // We're removing a subcommand, first find the subcommand's owner:
2685     Status path_error;
2686     CommandObjectMultiword *container =
2687         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2688                                                            path_error);
2689 
2690     if (!container) {
2691       result.AppendErrorWithFormat("error removing container command: %s",
2692                                    path_error.AsCString());
2693       return;
2694     }
2695     const char *leaf = command.GetArgumentAtIndex(num_args - 1);
2696     llvm::Error llvm_error =
2697         container->RemoveUserSubcommand(leaf, /* multiword okay */ true);
2698     if (llvm_error) {
2699       result.AppendErrorWithFormat("error removing container command: %s",
2700                                    llvm::toString(std::move(llvm_error)).c_str());
2701       return;
2702     }
2703     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2704   }
2705 };
2706 
2707 class CommandObjectCommandContainer : public CommandObjectMultiword {
2708 public:
CommandObjectCommandContainer(CommandInterpreter & interpreter)2709   CommandObjectCommandContainer(CommandInterpreter &interpreter)
2710       : CommandObjectMultiword(
2711             interpreter, "command container",
2712             "Commands for adding container commands to lldb.  "
2713             "Container commands are containers for other commands.  You can "
2714             "add nested container commands by specifying a command path, "
2715             "but you can't add commands into the built-in command hierarchy.",
2716             "command container <subcommand> [<subcommand-options>]") {
2717     LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd(
2718                               interpreter)));
2719     LoadSubCommand(
2720         "delete",
2721         CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter)));
2722   }
2723 
2724   ~CommandObjectCommandContainer() override = default;
2725 };
2726 
2727 #pragma mark CommandObjectMultiwordCommands
2728 
2729 // CommandObjectMultiwordCommands
2730 
CommandObjectMultiwordCommands(CommandInterpreter & interpreter)2731 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
2732     CommandInterpreter &interpreter)
2733     : CommandObjectMultiword(interpreter, "command",
2734                              "Commands for managing custom LLDB commands.",
2735                              "command <subcommand> [<subcommand-options>]") {
2736   LoadSubCommand("source",
2737                  CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
2738   LoadSubCommand("alias",
2739                  CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
2740   LoadSubCommand("unalias", CommandObjectSP(
2741                                 new CommandObjectCommandsUnalias(interpreter)));
2742   LoadSubCommand("delete",
2743                  CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
2744   LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer(
2745                                   interpreter)));
2746   LoadSubCommand(
2747       "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
2748   LoadSubCommand(
2749       "script",
2750       CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
2751 }
2752 
2753 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
2754