xref: /llvm-project/lldb/source/Commands/CommandObjectCommands.cpp (revision 9093f3c39b8fa8ef836c627e1db329cd7349e9bb)
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:
39   CommandObjectCommandsSource(CommandInterpreter &interpreter)
40       : CommandObjectParsed(
41             interpreter, "command source",
42             "Read and execute LLDB commands from the file <filename>.",
43             nullptr) {
44     CommandArgumentEntry arg;
45     CommandArgumentData file_arg;
46 
47     // Define the first (and only) variant of this arg.
48     file_arg.arg_type = eArgTypeFilename;
49     file_arg.arg_repetition = eArgRepeatPlain;
50 
51     // There is only one variant this argument could be; put it into the
52     // argument entry.
53     arg.push_back(file_arg);
54 
55     // Push the data for the first argument into the m_arguments vector.
56     m_arguments.push_back(arg);
57   }
58 
59   ~CommandObjectCommandsSource() override = default;
60 
61   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
62                                               uint32_t index) override {
63     return std::string("");
64   }
65 
66   void
67   HandleArgumentCompletion(CompletionRequest &request,
68                            OptionElementVector &opt_element_vector) override {
69     CommandCompletions::InvokeCommonCompletionCallbacks(
70         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
71         request, nullptr);
72   }
73 
74   Options *GetOptions() override { return &m_options; }
75 
76 protected:
77   class CommandOptions : public Options {
78   public:
79     CommandOptions()
80         : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true),
81           m_cmd_relative_to_command_file(false) {}
82 
83     ~CommandOptions() override = default;
84 
85     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
86                           ExecutionContext *execution_context) override {
87       Status error;
88       const int short_option = m_getopt_table[option_idx].val;
89 
90       switch (short_option) {
91       case 'e':
92         error = m_stop_on_error.SetValueFromString(option_arg);
93         break;
94 
95       case 'c':
96         error = m_stop_on_continue.SetValueFromString(option_arg);
97         break;
98 
99       case 'C':
100         m_cmd_relative_to_command_file = true;
101         break;
102 
103       case 's':
104         error = m_silent_run.SetValueFromString(option_arg);
105         break;
106 
107       default:
108         llvm_unreachable("Unimplemented option");
109       }
110 
111       return error;
112     }
113 
114     void OptionParsingStarting(ExecutionContext *execution_context) override {
115       m_stop_on_error.Clear();
116       m_silent_run.Clear();
117       m_stop_on_continue.Clear();
118       m_cmd_relative_to_command_file.Clear();
119     }
120 
121     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
122       return llvm::ArrayRef(g_source_options);
123     }
124 
125     // Instance variables to hold the values for command options.
126 
127     OptionValueBoolean m_stop_on_error;
128     OptionValueBoolean m_silent_run;
129     OptionValueBoolean m_stop_on_continue;
130     OptionValueBoolean m_cmd_relative_to_command_file;
131   };
132 
133   bool DoExecute(Args &command, CommandReturnObject &result) override {
134     if (command.GetArgumentCount() != 1) {
135       result.AppendErrorWithFormat(
136           "'%s' takes exactly one executable filename argument.\n",
137           GetCommandName().str().c_str());
138       return false;
139     }
140 
141     FileSpec source_dir = {};
142     if (m_options.m_cmd_relative_to_command_file) {
143       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
144       if (!source_dir) {
145         result.AppendError("command source -C can only be specified "
146                            "from a command file");
147         result.SetStatus(eReturnStatusFailed);
148         return false;
149       }
150     }
151 
152     FileSpec cmd_file(command[0].ref());
153     if (source_dir) {
154       // Prepend the source_dir to the cmd_file path:
155       if (!cmd_file.IsRelative()) {
156         result.AppendError("command source -C can only be used "
157                            "with a relative path.");
158         result.SetStatus(eReturnStatusFailed);
159         return false;
160       }
161       cmd_file.MakeAbsolute(source_dir);
162     }
163 
164     FileSystem::Instance().Resolve(cmd_file);
165 
166     CommandInterpreterRunOptions options;
167     // If any options were set, then use them
168     if (m_options.m_stop_on_error.OptionWasSet() ||
169         m_options.m_silent_run.OptionWasSet() ||
170         m_options.m_stop_on_continue.OptionWasSet()) {
171       if (m_options.m_stop_on_continue.OptionWasSet())
172         options.SetStopOnContinue(
173             m_options.m_stop_on_continue.GetCurrentValue());
174 
175       if (m_options.m_stop_on_error.OptionWasSet())
176         options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
177 
178       // Individual silent setting is override for global command echo settings.
179       if (m_options.m_silent_run.GetCurrentValue()) {
180         options.SetSilent(true);
181       } else {
182         options.SetPrintResults(true);
183         options.SetPrintErrors(true);
184         options.SetEchoCommands(m_interpreter.GetEchoCommands());
185         options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
186       }
187     }
188 
189     m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
190     return result.Succeeded();
191   }
192 
193   CommandOptions m_options;
194 };
195 
196 #pragma mark CommandObjectCommandsAlias
197 // CommandObjectCommandsAlias
198 
199 #define LLDB_OPTIONS_alias
200 #include "CommandOptions.inc"
201 
202 static const char *g_python_command_instructions =
203     "Enter your Python command(s). Type 'DONE' to end.\n"
204     "You must define a Python function with this signature:\n"
205     "def my_command_impl(debugger, args, exe_ctx, result, internal_dict):\n";
206 
207 class CommandObjectCommandsAlias : public CommandObjectRaw {
208 protected:
209   class CommandOptions : public OptionGroup {
210   public:
211     CommandOptions() = default;
212 
213     ~CommandOptions() override = default;
214 
215     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
216       return llvm::ArrayRef(g_alias_options);
217     }
218 
219     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
220                           ExecutionContext *execution_context) override {
221       Status error;
222 
223       const int short_option = GetDefinitions()[option_idx].short_option;
224       std::string option_str(option_value);
225 
226       switch (short_option) {
227       case 'h':
228         m_help.SetCurrentValue(option_str);
229         m_help.SetOptionWasSet();
230         break;
231 
232       case 'H':
233         m_long_help.SetCurrentValue(option_str);
234         m_long_help.SetOptionWasSet();
235         break;
236 
237       default:
238         llvm_unreachable("Unimplemented option");
239       }
240 
241       return error;
242     }
243 
244     void OptionParsingStarting(ExecutionContext *execution_context) override {
245       m_help.Clear();
246       m_long_help.Clear();
247     }
248 
249     OptionValueString m_help;
250     OptionValueString m_long_help;
251   };
252 
253   OptionGroupOptions m_option_group;
254   CommandOptions m_command_options;
255 
256 public:
257   Options *GetOptions() override { return &m_option_group; }
258 
259   CommandObjectCommandsAlias(CommandInterpreter &interpreter)
260       : CommandObjectRaw(
261             interpreter, "command alias",
262             "Define a custom command in terms of an existing command.") {
263     m_option_group.Append(&m_command_options);
264     m_option_group.Finalize();
265 
266     SetHelpLong(
267         "'alias' allows the user to create a short-cut or abbreviation for long \
268 commands, multi-word commands, and commands that take particular options.  \
269 Below are some simple examples of how one might use the 'alias' command:"
270         R"(
271 
272 (lldb) command alias sc script
273 
274     Creates the abbreviation 'sc' for the 'script' command.
275 
276 (lldb) command alias bp breakpoint
277 
278 )"
279         "    Creates the abbreviation 'bp' for the 'breakpoint' command.  Since \
280 breakpoint commands are two-word commands, the user would still need to \
281 enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
282         R"(
283 
284 (lldb) command alias bpl breakpoint list
285 
286     Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
287 
288 )"
289         "An alias can include some options for the command, with the values either \
290 filled in at the time the alias is created, or specified as positional \
291 arguments, to be filled in when the alias is invoked.  The following example \
292 shows how to create aliases with options:"
293         R"(
294 
295 (lldb) command alias bfl breakpoint set -f %1 -l %2
296 
297 )"
298         "    Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
299 options already part of the alias.  So if the user wants to set a breakpoint \
300 by file and line without explicitly having to use the -f and -l options, the \
301 user can now use 'bfl' instead.  The '%1' and '%2' are positional placeholders \
302 for the actual arguments that will be passed when the alias command is used.  \
303 The number in the placeholder refers to the position/order the actual value \
304 occupies when the alias is used.  All the occurrences of '%1' in the alias \
305 will be replaced with the first argument, all the occurrences of '%2' in the \
306 alias will be replaced with the second argument, and so on.  This also allows \
307 actual arguments to be used multiple times within an alias (see 'process \
308 launch' example below)."
309         R"(
310 
311 )"
312         "Note: the positional arguments must substitute as whole words in the resultant \
313 command, so you can't at present do something like this to append the file extension \
314 \".cpp\":"
315         R"(
316 
317 (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
318 
319 )"
320         "For more complex aliasing, use the \"command regex\" command instead.  In the \
321 'bfl' case above, the actual file value will be filled in with the first argument \
322 following 'bfl' and the actual line number value will be filled in with the second \
323 argument.  The user would use this alias as follows:"
324         R"(
325 
326 (lldb) command alias bfl breakpoint set -f %1 -l %2
327 (lldb) bfl my-file.c 137
328 
329 This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
330 
331 Another example:
332 
333 (lldb) command alias pltty process launch -s -o %1 -e %1
334 (lldb) pltty /dev/tty0
335 
336     Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
337 
338 )"
339         "If the user always wanted to pass the same value to a particular option, the \
340 alias could be defined with that value directly in the alias as a constant, \
341 rather than using a positional placeholder:"
342         R"(
343 
344 (lldb) command alias bl3 breakpoint set -f %1 -l 3
345 
346     Always sets a breakpoint on line 3 of whatever file is indicated.)");
347 
348     CommandArgumentEntry arg1;
349     CommandArgumentEntry arg2;
350     CommandArgumentEntry arg3;
351     CommandArgumentData alias_arg;
352     CommandArgumentData cmd_arg;
353     CommandArgumentData options_arg;
354 
355     // Define the first (and only) variant of this arg.
356     alias_arg.arg_type = eArgTypeAliasName;
357     alias_arg.arg_repetition = eArgRepeatPlain;
358 
359     // There is only one variant this argument could be; put it into the
360     // argument entry.
361     arg1.push_back(alias_arg);
362 
363     // Define the first (and only) variant of this arg.
364     cmd_arg.arg_type = eArgTypeCommandName;
365     cmd_arg.arg_repetition = eArgRepeatPlain;
366 
367     // There is only one variant this argument could be; put it into the
368     // argument entry.
369     arg2.push_back(cmd_arg);
370 
371     // Define the first (and only) variant of this arg.
372     options_arg.arg_type = eArgTypeAliasOptions;
373     options_arg.arg_repetition = eArgRepeatOptional;
374 
375     // There is only one variant this argument could be; put it into the
376     // argument entry.
377     arg3.push_back(options_arg);
378 
379     // Push the data for the first argument into the m_arguments vector.
380     m_arguments.push_back(arg1);
381     m_arguments.push_back(arg2);
382     m_arguments.push_back(arg3);
383   }
384 
385   ~CommandObjectCommandsAlias() override = default;
386 
387 protected:
388   bool DoExecute(llvm::StringRef raw_command_line,
389                  CommandReturnObject &result) override {
390     if (raw_command_line.empty()) {
391       result.AppendError("'command alias' requires at least two arguments");
392       return false;
393     }
394 
395     ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
396     m_option_group.NotifyOptionParsingStarting(&exe_ctx);
397 
398     OptionsWithRaw args_with_suffix(raw_command_line);
399 
400     if (args_with_suffix.HasArgs())
401       if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result,
402                                  m_option_group, exe_ctx))
403         return false;
404 
405     llvm::StringRef raw_command_string = args_with_suffix.GetRawPart();
406     Args args(raw_command_string);
407 
408     if (args.GetArgumentCount() < 2) {
409       result.AppendError("'command alias' requires at least two arguments");
410       return false;
411     }
412 
413     // Get the alias command.
414 
415     auto alias_command = args[0].ref();
416     if (alias_command.startswith("-")) {
417       result.AppendError("aliases starting with a dash are not supported");
418       if (alias_command == "--help" || alias_command == "--long-help") {
419         result.AppendWarning("if trying to pass options to 'command alias' add "
420                              "a -- at the end of the options");
421       }
422       return false;
423     }
424 
425     // Strip the new alias name off 'raw_command_string'  (leave it on args,
426     // which gets passed to 'Execute', which does the stripping itself.
427     size_t pos = raw_command_string.find(alias_command);
428     if (pos == 0) {
429       raw_command_string = raw_command_string.substr(alias_command.size());
430       pos = raw_command_string.find_first_not_of(' ');
431       if ((pos != std::string::npos) && (pos > 0))
432         raw_command_string = raw_command_string.substr(pos);
433     } else {
434       result.AppendError("Error parsing command string.  No alias created.");
435       return false;
436     }
437 
438     // Verify that the command is alias-able.
439     if (m_interpreter.CommandExists(alias_command)) {
440       result.AppendErrorWithFormat(
441           "'%s' is a permanent debugger command and cannot be redefined.\n",
442           args[0].c_str());
443       return false;
444     }
445 
446     if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
447       result.AppendErrorWithFormat(
448           "'%s' is a user container command and cannot be overwritten.\n"
449           "Delete it first with 'command container delete'\n",
450           args[0].c_str());
451       return false;
452     }
453 
454     // Get CommandObject that is being aliased. The command name is read from
455     // the front of raw_command_string. raw_command_string is returned with the
456     // name of the command object stripped off the front.
457     llvm::StringRef original_raw_command_string = raw_command_string;
458     CommandObject *cmd_obj =
459         m_interpreter.GetCommandObjectForCommand(raw_command_string);
460 
461     if (!cmd_obj) {
462       result.AppendErrorWithFormat("invalid command given to 'command alias'. "
463                                    "'%s' does not begin with a valid command."
464                                    "  No alias created.",
465                                    original_raw_command_string.str().c_str());
466       return false;
467     } else if (!cmd_obj->WantsRawCommandString()) {
468       // Note that args was initialized with the original command, and has not
469       // been updated to this point. Therefore can we pass it to the version of
470       // Execute that does not need/expect raw input in the alias.
471       return HandleAliasingNormalCommand(args, result);
472     } else {
473       return HandleAliasingRawCommand(alias_command, raw_command_string,
474                                       *cmd_obj, result);
475     }
476     return result.Succeeded();
477   }
478 
479   bool HandleAliasingRawCommand(llvm::StringRef alias_command,
480                                 llvm::StringRef raw_command_string,
481                                 CommandObject &cmd_obj,
482                                 CommandReturnObject &result) {
483     // Verify & handle any options/arguments passed to the alias command
484 
485     OptionArgVectorSP option_arg_vector_sp =
486         OptionArgVectorSP(new OptionArgVector);
487 
488     const bool include_aliases = true;
489     // Look up the command using command's name first.  This is to resolve
490     // aliases when you are making nested aliases.  But if you don't find
491     // it that way, then it wasn't an alias and we can just use the object
492     // we were passed in.
493     CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact(
494             cmd_obj.GetCommandName(), include_aliases);
495     if (!cmd_obj_sp)
496       cmd_obj_sp = cmd_obj.shared_from_this();
497 
498     if (m_interpreter.AliasExists(alias_command) ||
499         m_interpreter.UserCommandExists(alias_command)) {
500       result.AppendWarningWithFormat(
501           "Overwriting existing definition for '%s'.\n",
502           alias_command.str().c_str());
503     }
504     if (CommandAlias *alias = m_interpreter.AddAlias(
505             alias_command, cmd_obj_sp, raw_command_string)) {
506       if (m_command_options.m_help.OptionWasSet())
507         alias->SetHelp(m_command_options.m_help.GetCurrentValue());
508       if (m_command_options.m_long_help.OptionWasSet())
509         alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
510       result.SetStatus(eReturnStatusSuccessFinishNoResult);
511     } else {
512       result.AppendError("Unable to create requested alias.\n");
513     }
514     return result.Succeeded();
515   }
516 
517   bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
518     size_t argc = args.GetArgumentCount();
519 
520     if (argc < 2) {
521       result.AppendError("'command alias' requires at least two arguments");
522       return false;
523     }
524 
525     // Save these in std::strings since we're going to shift them off.
526     const std::string alias_command(std::string(args[0].ref()));
527     const std::string actual_command(std::string(args[1].ref()));
528 
529     args.Shift(); // Shift the alias command word off the argument vector.
530     args.Shift(); // Shift the old command word off the argument vector.
531 
532     // Verify that the command is alias'able, and get the appropriate command
533     // object.
534 
535     if (m_interpreter.CommandExists(alias_command)) {
536       result.AppendErrorWithFormat(
537           "'%s' is a permanent debugger command and cannot be redefined.\n",
538           alias_command.c_str());
539       return false;
540     }
541 
542     if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
543       result.AppendErrorWithFormat(
544           "'%s' is user container command and cannot be overwritten.\n"
545           "Delete it first with 'command container delete'",
546           alias_command.c_str());
547       return false;
548     }
549 
550     CommandObjectSP command_obj_sp(
551         m_interpreter.GetCommandSPExact(actual_command, true));
552     CommandObjectSP subcommand_obj_sp;
553     bool use_subcommand = false;
554     if (!command_obj_sp) {
555       result.AppendErrorWithFormat("'%s' is not an existing command.\n",
556                                    actual_command.c_str());
557       return false;
558     }
559     CommandObject *cmd_obj = command_obj_sp.get();
560     CommandObject *sub_cmd_obj = nullptr;
561     OptionArgVectorSP option_arg_vector_sp =
562         OptionArgVectorSP(new OptionArgVector);
563 
564     while (cmd_obj->IsMultiwordObject() && !args.empty()) {
565       auto sub_command = args[0].ref();
566       assert(!sub_command.empty());
567       subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
568       if (!subcommand_obj_sp) {
569         result.AppendErrorWithFormat(
570             "'%s' is not a valid sub-command of '%s'.  "
571             "Unable to create alias.\n",
572             args[0].c_str(), actual_command.c_str());
573         return false;
574       }
575 
576       sub_cmd_obj = subcommand_obj_sp.get();
577       use_subcommand = true;
578       args.Shift(); // Shift the sub_command word off the argument vector.
579       cmd_obj = sub_cmd_obj;
580     }
581 
582     // Verify & handle any options/arguments passed to the alias command
583 
584     std::string args_string;
585 
586     if (!args.empty()) {
587       CommandObjectSP tmp_sp =
588           m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName());
589       if (use_subcommand)
590         tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName());
591 
592       args.GetCommandString(args_string);
593     }
594 
595     if (m_interpreter.AliasExists(alias_command) ||
596         m_interpreter.UserCommandExists(alias_command)) {
597       result.AppendWarningWithFormat(
598           "Overwriting existing definition for '%s'.\n", alias_command.c_str());
599     }
600 
601     if (CommandAlias *alias = m_interpreter.AddAlias(
602             alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
603             args_string)) {
604       if (m_command_options.m_help.OptionWasSet())
605         alias->SetHelp(m_command_options.m_help.GetCurrentValue());
606       if (m_command_options.m_long_help.OptionWasSet())
607         alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
608       result.SetStatus(eReturnStatusSuccessFinishNoResult);
609     } else {
610       result.AppendError("Unable to create requested alias.\n");
611       return false;
612     }
613 
614     return result.Succeeded();
615   }
616 };
617 
618 #pragma mark CommandObjectCommandsUnalias
619 // CommandObjectCommandsUnalias
620 
621 class CommandObjectCommandsUnalias : public CommandObjectParsed {
622 public:
623   CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
624       : CommandObjectParsed(
625             interpreter, "command unalias",
626             "Delete one or more custom commands defined by 'command alias'.",
627             nullptr) {
628     CommandArgumentEntry arg;
629     CommandArgumentData alias_arg;
630 
631     // Define the first (and only) variant of this arg.
632     alias_arg.arg_type = eArgTypeAliasName;
633     alias_arg.arg_repetition = eArgRepeatPlain;
634 
635     // There is only one variant this argument could be; put it into the
636     // argument entry.
637     arg.push_back(alias_arg);
638 
639     // Push the data for the first argument into the m_arguments vector.
640     m_arguments.push_back(arg);
641   }
642 
643   ~CommandObjectCommandsUnalias() override = default;
644 
645   void
646   HandleArgumentCompletion(CompletionRequest &request,
647                            OptionElementVector &opt_element_vector) override {
648     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
649       return;
650 
651     for (const auto &ent : m_interpreter.GetAliases()) {
652       request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
653     }
654   }
655 
656 protected:
657   bool DoExecute(Args &args, CommandReturnObject &result) override {
658     CommandObject::CommandMap::iterator pos;
659     CommandObject *cmd_obj;
660 
661     if (args.empty()) {
662       result.AppendError("must call 'unalias' with a valid alias");
663       return false;
664     }
665 
666     auto command_name = args[0].ref();
667     cmd_obj = m_interpreter.GetCommandObject(command_name);
668     if (!cmd_obj) {
669       result.AppendErrorWithFormat(
670           "'%s' is not a known command.\nTry 'help' to see a "
671           "current list of commands.\n",
672           args[0].c_str());
673       return false;
674     }
675 
676     if (m_interpreter.CommandExists(command_name)) {
677       if (cmd_obj->IsRemovable()) {
678         result.AppendErrorWithFormat(
679             "'%s' is not an alias, it is a debugger command which can be "
680             "removed using the 'command delete' command.\n",
681             args[0].c_str());
682       } else {
683         result.AppendErrorWithFormat(
684             "'%s' is a permanent debugger command and cannot be removed.\n",
685             args[0].c_str());
686       }
687       return false;
688     }
689 
690     if (!m_interpreter.RemoveAlias(command_name)) {
691       if (m_interpreter.AliasExists(command_name))
692         result.AppendErrorWithFormat(
693             "Error occurred while attempting to unalias '%s'.\n",
694             args[0].c_str());
695       else
696         result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
697                                      args[0].c_str());
698       return false;
699     }
700 
701     result.SetStatus(eReturnStatusSuccessFinishNoResult);
702     return result.Succeeded();
703   }
704 };
705 
706 #pragma mark CommandObjectCommandsDelete
707 // CommandObjectCommandsDelete
708 
709 class CommandObjectCommandsDelete : public CommandObjectParsed {
710 public:
711   CommandObjectCommandsDelete(CommandInterpreter &interpreter)
712       : CommandObjectParsed(
713             interpreter, "command delete",
714             "Delete one or more custom commands defined by 'command regex'.",
715             nullptr) {
716     CommandArgumentEntry arg;
717     CommandArgumentData alias_arg;
718 
719     // Define the first (and only) variant of this arg.
720     alias_arg.arg_type = eArgTypeCommandName;
721     alias_arg.arg_repetition = eArgRepeatPlain;
722 
723     // There is only one variant this argument could be; put it into the
724     // argument entry.
725     arg.push_back(alias_arg);
726 
727     // Push the data for the first argument into the m_arguments vector.
728     m_arguments.push_back(arg);
729   }
730 
731   ~CommandObjectCommandsDelete() override = default;
732 
733   void
734   HandleArgumentCompletion(CompletionRequest &request,
735                            OptionElementVector &opt_element_vector) override {
736     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
737       return;
738 
739     for (const auto &ent : m_interpreter.GetCommands()) {
740       if (ent.second->IsRemovable())
741         request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
742     }
743   }
744 
745 protected:
746   bool DoExecute(Args &args, CommandReturnObject &result) override {
747     CommandObject::CommandMap::iterator pos;
748 
749     if (args.empty()) {
750       result.AppendErrorWithFormat("must call '%s' with one or more valid user "
751                                    "defined regular expression command names",
752                                    GetCommandName().str().c_str());
753       return false;
754     }
755 
756     auto command_name = args[0].ref();
757     if (!m_interpreter.CommandExists(command_name)) {
758       StreamString error_msg_stream;
759       const bool generate_upropos = true;
760       const bool generate_type_lookup = false;
761       CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
762           &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
763           generate_upropos, generate_type_lookup);
764       result.AppendError(error_msg_stream.GetString());
765       return false;
766     }
767 
768     if (!m_interpreter.RemoveCommand(command_name)) {
769       result.AppendErrorWithFormat(
770           "'%s' is a permanent debugger command and cannot be removed.\n",
771           args[0].c_str());
772       return false;
773     }
774 
775     result.SetStatus(eReturnStatusSuccessFinishNoResult);
776     return true;
777   }
778 };
779 
780 // CommandObjectCommandsAddRegex
781 
782 #define LLDB_OPTIONS_regex
783 #include "CommandOptions.inc"
784 
785 #pragma mark CommandObjectCommandsAddRegex
786 
787 class CommandObjectCommandsAddRegex : public CommandObjectParsed,
788                                       public IOHandlerDelegateMultiline {
789 public:
790   CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
791       : CommandObjectParsed(
792             interpreter, "command regex",
793             "Define a custom command in terms of "
794             "existing commands by matching "
795             "regular expressions.",
796             "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
797         IOHandlerDelegateMultiline("",
798                                    IOHandlerDelegate::Completion::LLDBCommand) {
799     SetHelpLong(
800         R"(
801 )"
802         "This command allows the user to create powerful regular expression commands \
803 with substitutions. The regular expressions and substitutions are specified \
804 using the regular expression substitution format of:"
805         R"(
806 
807     s/<regex>/<subst>/
808 
809 )"
810         "<regex> is a regular expression that can use parenthesis to capture regular \
811 expression input and substitute the captured matches in the output using %1 \
812 for the first match, %2 for the second, and so on."
813         R"(
814 
815 )"
816         "The regular expressions can all be specified on the command line if more than \
817 one argument is provided. If just the command name is provided on the command \
818 line, then the regular expressions and substitutions can be entered on separate \
819 lines, followed by an empty line to terminate the command definition."
820         R"(
821 
822 EXAMPLES
823 
824 )"
825         "The following example will define a regular expression command named 'f' that \
826 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
827 a number follows 'f':"
828         R"(
829 
830     (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
831     CommandArgumentData thread_arg{eArgTypeSEDStylePair, eArgRepeatOptional};
832     m_arguments.push_back({thread_arg});
833   }
834 
835   ~CommandObjectCommandsAddRegex() override = default;
836 
837 protected:
838   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
839     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
840     if (output_sp && interactive) {
841       output_sp->PutCString("Enter one or more sed substitution commands in "
842                             "the form: 's/<regex>/<subst>/'.\nTerminate the "
843                             "substitution list with an empty line.\n");
844       output_sp->Flush();
845     }
846   }
847 
848   void IOHandlerInputComplete(IOHandler &io_handler,
849                               std::string &data) override {
850     io_handler.SetIsDone(true);
851     if (m_regex_cmd_up) {
852       StringList lines;
853       if (lines.SplitIntoLines(data)) {
854         bool check_only = false;
855         for (const std::string &line : lines) {
856           Status error = AppendRegexSubstitution(line, check_only);
857           if (error.Fail()) {
858             if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) {
859               StreamSP out_stream = GetDebugger().GetAsyncOutputStream();
860               out_stream->Printf("error: %s\n", error.AsCString());
861             }
862           }
863         }
864       }
865       if (m_regex_cmd_up->HasRegexEntries()) {
866         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
867         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
868       }
869     }
870   }
871 
872   bool DoExecute(Args &command, CommandReturnObject &result) override {
873     const size_t argc = command.GetArgumentCount();
874     if (argc == 0) {
875       result.AppendError("usage: 'command regex <command-name> "
876                          "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
877       return false;
878     }
879 
880     Status error;
881     auto name = command[0].ref();
882     m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
883         m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 0,
884         true);
885 
886     if (argc == 1) {
887       Debugger &debugger = GetDebugger();
888       bool color_prompt = debugger.GetUseColor();
889       const bool multiple_lines = true; // Get multiple lines
890       IOHandlerSP io_handler_sp(new IOHandlerEditline(
891           debugger, IOHandler::Type::Other,
892           "lldb-regex",          // Name of input reader for history
893           llvm::StringRef("> "), // Prompt
894           llvm::StringRef(),     // Continuation prompt
895           multiple_lines, color_prompt,
896           0, // Don't show line numbers
897           *this));
898 
899       if (io_handler_sp) {
900         debugger.RunIOHandlerAsync(io_handler_sp);
901         result.SetStatus(eReturnStatusSuccessFinishNoResult);
902       }
903     } else {
904       for (auto &entry : command.entries().drop_front()) {
905         bool check_only = false;
906         error = AppendRegexSubstitution(entry.ref(), check_only);
907         if (error.Fail())
908           break;
909       }
910 
911       if (error.Success()) {
912         AddRegexCommandToInterpreter();
913       }
914     }
915     if (error.Fail()) {
916       result.AppendError(error.AsCString());
917     }
918 
919     return result.Succeeded();
920   }
921 
922   Status AppendRegexSubstitution(const llvm::StringRef &regex_sed,
923                                  bool check_only) {
924     Status error;
925 
926     if (!m_regex_cmd_up) {
927       error.SetErrorStringWithFormat(
928           "invalid regular expression command object for: '%.*s'",
929           (int)regex_sed.size(), regex_sed.data());
930       return error;
931     }
932 
933     size_t regex_sed_size = regex_sed.size();
934 
935     if (regex_sed_size <= 1) {
936       error.SetErrorStringWithFormat(
937           "regular expression substitution string is too short: '%.*s'",
938           (int)regex_sed.size(), regex_sed.data());
939       return error;
940     }
941 
942     if (regex_sed[0] != 's') {
943       error.SetErrorStringWithFormat("regular expression substitution string "
944                                      "doesn't start with 's': '%.*s'",
945                                      (int)regex_sed.size(), regex_sed.data());
946       return error;
947     }
948     const size_t first_separator_char_pos = 1;
949     // use the char that follows 's' as the regex separator character so we can
950     // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
951     const char separator_char = regex_sed[first_separator_char_pos];
952     const size_t second_separator_char_pos =
953         regex_sed.find(separator_char, first_separator_char_pos + 1);
954 
955     if (second_separator_char_pos == std::string::npos) {
956       error.SetErrorStringWithFormat(
957           "missing second '%c' separator char after '%.*s' in '%.*s'",
958           separator_char,
959           (int)(regex_sed.size() - first_separator_char_pos - 1),
960           regex_sed.data() + (first_separator_char_pos + 1),
961           (int)regex_sed.size(), regex_sed.data());
962       return error;
963     }
964 
965     const size_t third_separator_char_pos =
966         regex_sed.find(separator_char, second_separator_char_pos + 1);
967 
968     if (third_separator_char_pos == std::string::npos) {
969       error.SetErrorStringWithFormat(
970           "missing third '%c' separator char after '%.*s' in '%.*s'",
971           separator_char,
972           (int)(regex_sed.size() - second_separator_char_pos - 1),
973           regex_sed.data() + (second_separator_char_pos + 1),
974           (int)regex_sed.size(), regex_sed.data());
975       return error;
976     }
977 
978     if (third_separator_char_pos != regex_sed_size - 1) {
979       // Make sure that everything that follows the last regex separator char
980       if (regex_sed.find_first_not_of("\t\n\v\f\r ",
981                                       third_separator_char_pos + 1) !=
982           std::string::npos) {
983         error.SetErrorStringWithFormat(
984             "extra data found after the '%.*s' regular expression substitution "
985             "string: '%.*s'",
986             (int)third_separator_char_pos + 1, regex_sed.data(),
987             (int)(regex_sed.size() - third_separator_char_pos - 1),
988             regex_sed.data() + (third_separator_char_pos + 1));
989         return error;
990       }
991     } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
992       error.SetErrorStringWithFormat(
993           "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
994           separator_char, separator_char, separator_char, (int)regex_sed.size(),
995           regex_sed.data());
996       return error;
997     } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
998       error.SetErrorStringWithFormat(
999           "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
1000           separator_char, separator_char, separator_char, (int)regex_sed.size(),
1001           regex_sed.data());
1002       return error;
1003     }
1004 
1005     if (!check_only) {
1006       std::string regex(std::string(regex_sed.substr(
1007           first_separator_char_pos + 1,
1008           second_separator_char_pos - first_separator_char_pos - 1)));
1009       std::string subst(std::string(regex_sed.substr(
1010           second_separator_char_pos + 1,
1011           third_separator_char_pos - second_separator_char_pos - 1)));
1012       m_regex_cmd_up->AddRegexCommand(regex, subst);
1013     }
1014     return error;
1015   }
1016 
1017   void AddRegexCommandToInterpreter() {
1018     if (m_regex_cmd_up) {
1019       if (m_regex_cmd_up->HasRegexEntries()) {
1020         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
1021         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
1022       }
1023     }
1024   }
1025 
1026 private:
1027   std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
1028 
1029   class CommandOptions : public Options {
1030   public:
1031     CommandOptions() = default;
1032 
1033     ~CommandOptions() override = default;
1034 
1035     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1036                           ExecutionContext *execution_context) override {
1037       Status error;
1038       const int short_option = m_getopt_table[option_idx].val;
1039 
1040       switch (short_option) {
1041       case 'h':
1042         m_help.assign(std::string(option_arg));
1043         break;
1044       case 's':
1045         m_syntax.assign(std::string(option_arg));
1046         break;
1047       default:
1048         llvm_unreachable("Unimplemented option");
1049       }
1050 
1051       return error;
1052     }
1053 
1054     void OptionParsingStarting(ExecutionContext *execution_context) override {
1055       m_help.clear();
1056       m_syntax.clear();
1057     }
1058 
1059     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1060       return llvm::ArrayRef(g_regex_options);
1061     }
1062 
1063     llvm::StringRef GetHelp() { return m_help; }
1064 
1065     llvm::StringRef GetSyntax() { return m_syntax; }
1066 
1067   protected:
1068     // Instance variables to hold the values for command options.
1069 
1070     std::string m_help;
1071     std::string m_syntax;
1072   };
1073 
1074   Options *GetOptions() override { return &m_options; }
1075 
1076   CommandOptions m_options;
1077 };
1078 
1079 class CommandObjectPythonFunction : public CommandObjectRaw {
1080 public:
1081   CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
1082                               std::string funct, std::string help,
1083                               ScriptedCommandSynchronicity synch)
1084       : CommandObjectRaw(interpreter, name), m_function_name(funct),
1085         m_synchro(synch) {
1086     if (!help.empty())
1087       SetHelp(help);
1088     else {
1089       StreamString stream;
1090       stream.Printf("For more information run 'help %s'", name.c_str());
1091       SetHelp(stream.GetString());
1092     }
1093   }
1094 
1095   ~CommandObjectPythonFunction() override = default;
1096 
1097   bool IsRemovable() const override { return true; }
1098 
1099   const std::string &GetFunctionName() { return m_function_name; }
1100 
1101   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1102 
1103   llvm::StringRef GetHelpLong() override {
1104     if (m_fetched_help_long)
1105       return CommandObjectRaw::GetHelpLong();
1106 
1107     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1108     if (!scripter)
1109       return CommandObjectRaw::GetHelpLong();
1110 
1111     std::string docstring;
1112     m_fetched_help_long =
1113         scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
1114     if (!docstring.empty())
1115       SetHelpLong(docstring);
1116     return CommandObjectRaw::GetHelpLong();
1117   }
1118 
1119 protected:
1120   bool DoExecute(llvm::StringRef raw_command_line,
1121                  CommandReturnObject &result) override {
1122     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1123 
1124     Status error;
1125 
1126     result.SetStatus(eReturnStatusInvalid);
1127 
1128     if (!scripter || !scripter->RunScriptBasedCommand(
1129                          m_function_name.c_str(), raw_command_line, m_synchro,
1130                          result, error, m_exe_ctx)) {
1131       result.AppendError(error.AsCString());
1132     } else {
1133       // Don't change the status if the command already set it...
1134       if (result.GetStatus() == eReturnStatusInvalid) {
1135         if (result.GetOutputData().empty())
1136           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1137         else
1138           result.SetStatus(eReturnStatusSuccessFinishResult);
1139       }
1140     }
1141 
1142     return result.Succeeded();
1143   }
1144 
1145 private:
1146   std::string m_function_name;
1147   ScriptedCommandSynchronicity m_synchro;
1148   bool m_fetched_help_long = false;
1149 };
1150 
1151 class CommandObjectScriptingObject : public CommandObjectRaw {
1152 public:
1153   CommandObjectScriptingObject(CommandInterpreter &interpreter,
1154                                std::string name,
1155                                StructuredData::GenericSP cmd_obj_sp,
1156                                ScriptedCommandSynchronicity synch)
1157       : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1158         m_synchro(synch), m_fetched_help_short(false),
1159         m_fetched_help_long(false) {
1160     StreamString stream;
1161     stream.Printf("For more information run 'help %s'", name.c_str());
1162     SetHelp(stream.GetString());
1163     if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
1164       GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1165   }
1166 
1167   ~CommandObjectScriptingObject() override = default;
1168 
1169   bool IsRemovable() const override { return true; }
1170 
1171   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1172 
1173   llvm::StringRef GetHelp() override {
1174     if (m_fetched_help_short)
1175       return CommandObjectRaw::GetHelp();
1176     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1177     if (!scripter)
1178       return CommandObjectRaw::GetHelp();
1179     std::string docstring;
1180     m_fetched_help_short =
1181         scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1182     if (!docstring.empty())
1183       SetHelp(docstring);
1184 
1185     return CommandObjectRaw::GetHelp();
1186   }
1187 
1188   llvm::StringRef GetHelpLong() override {
1189     if (m_fetched_help_long)
1190       return CommandObjectRaw::GetHelpLong();
1191 
1192     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1193     if (!scripter)
1194       return CommandObjectRaw::GetHelpLong();
1195 
1196     std::string docstring;
1197     m_fetched_help_long =
1198         scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1199     if (!docstring.empty())
1200       SetHelpLong(docstring);
1201     return CommandObjectRaw::GetHelpLong();
1202   }
1203 
1204 protected:
1205   bool DoExecute(llvm::StringRef raw_command_line,
1206                  CommandReturnObject &result) override {
1207     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1208 
1209     Status error;
1210 
1211     result.SetStatus(eReturnStatusInvalid);
1212 
1213     if (!scripter ||
1214         !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
1215                                          m_synchro, result, error, m_exe_ctx)) {
1216       result.AppendError(error.AsCString());
1217     } else {
1218       // Don't change the status if the command already set it...
1219       if (result.GetStatus() == eReturnStatusInvalid) {
1220         if (result.GetOutputData().empty())
1221           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1222         else
1223           result.SetStatus(eReturnStatusSuccessFinishResult);
1224       }
1225     }
1226 
1227     return result.Succeeded();
1228   }
1229 
1230 private:
1231   StructuredData::GenericSP m_cmd_obj_sp;
1232   ScriptedCommandSynchronicity m_synchro;
1233   bool m_fetched_help_short : 1;
1234   bool m_fetched_help_long : 1;
1235 };
1236 
1237 // CommandObjectCommandsScriptImport
1238 #define LLDB_OPTIONS_script_import
1239 #include "CommandOptions.inc"
1240 
1241 class CommandObjectCommandsScriptImport : public CommandObjectParsed {
1242 public:
1243   CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
1244       : CommandObjectParsed(interpreter, "command script import",
1245                             "Import a scripting module in LLDB.", nullptr) {
1246     CommandArgumentEntry arg1;
1247     CommandArgumentData cmd_arg;
1248 
1249     // Define the first (and only) variant of this arg.
1250     cmd_arg.arg_type = eArgTypeFilename;
1251     cmd_arg.arg_repetition = eArgRepeatPlus;
1252 
1253     // There is only one variant this argument could be; put it into the
1254     // argument entry.
1255     arg1.push_back(cmd_arg);
1256 
1257     // Push the data for the first argument into the m_arguments vector.
1258     m_arguments.push_back(arg1);
1259   }
1260 
1261   ~CommandObjectCommandsScriptImport() override = default;
1262 
1263   void
1264   HandleArgumentCompletion(CompletionRequest &request,
1265                            OptionElementVector &opt_element_vector) override {
1266     CommandCompletions::InvokeCommonCompletionCallbacks(
1267         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
1268         request, nullptr);
1269   }
1270 
1271   Options *GetOptions() override { return &m_options; }
1272 
1273 protected:
1274   class CommandOptions : public Options {
1275   public:
1276     CommandOptions() = default;
1277 
1278     ~CommandOptions() override = default;
1279 
1280     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1281                           ExecutionContext *execution_context) override {
1282       Status error;
1283       const int short_option = m_getopt_table[option_idx].val;
1284 
1285       switch (short_option) {
1286       case 'r':
1287         // NO-OP
1288         break;
1289       case 'c':
1290         relative_to_command_file = true;
1291         break;
1292       case 's':
1293         silent = true;
1294         break;
1295       default:
1296         llvm_unreachable("Unimplemented option");
1297       }
1298 
1299       return error;
1300     }
1301 
1302     void OptionParsingStarting(ExecutionContext *execution_context) override {
1303       relative_to_command_file = false;
1304     }
1305 
1306     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1307       return llvm::ArrayRef(g_script_import_options);
1308     }
1309     bool relative_to_command_file = false;
1310     bool silent = false;
1311   };
1312 
1313   bool DoExecute(Args &command, CommandReturnObject &result) override {
1314     if (command.empty()) {
1315       result.AppendError("command script import needs one or more arguments");
1316       return false;
1317     }
1318 
1319     FileSpec source_dir = {};
1320     if (m_options.relative_to_command_file) {
1321       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
1322       if (!source_dir) {
1323         result.AppendError("command script import -c can only be specified "
1324                            "from a command file");
1325         return false;
1326       }
1327     }
1328 
1329     for (auto &entry : command.entries()) {
1330       Status error;
1331 
1332       LoadScriptOptions options;
1333       options.SetInitSession(true);
1334       options.SetSilent(m_options.silent);
1335 
1336       // FIXME: this is necessary because CommandObject::CheckRequirements()
1337       // assumes that commands won't ever be recursively invoked, but it's
1338       // actually possible to craft a Python script that does other "command
1339       // script imports" in __lldb_init_module the real fix is to have
1340       // recursive commands possible with a CommandInvocation object separate
1341       // from the CommandObject itself, so that recursive command invocations
1342       // won't stomp on each other (wrt to execution contents, options, and
1343       // more)
1344       m_exe_ctx.Clear();
1345       if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
1346               entry.c_str(), options, error, /*module_sp=*/nullptr,
1347               source_dir)) {
1348         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1349       } else {
1350         result.AppendErrorWithFormat("module importing failed: %s",
1351                                      error.AsCString());
1352       }
1353     }
1354 
1355     return result.Succeeded();
1356   }
1357 
1358   CommandOptions m_options;
1359 };
1360 
1361 #define LLDB_OPTIONS_script_add
1362 #include "CommandOptions.inc"
1363 
1364 class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
1365                                        public IOHandlerDelegateMultiline {
1366 public:
1367   CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
1368       : CommandObjectParsed(interpreter, "command script add",
1369                             "Add a scripted function as an LLDB command.",
1370                             "Add a scripted function as an lldb command. "
1371                             "If you provide a single argument, the command "
1372                             "will be added at the root level of the command "
1373                             "hierarchy.  If there are more arguments they "
1374                             "must be a path to a user-added container "
1375                             "command, and the last element will be the new "
1376                             "command name."),
1377         IOHandlerDelegateMultiline("DONE") {
1378     CommandArgumentEntry arg1;
1379     CommandArgumentData cmd_arg;
1380 
1381     // This is one or more command names, which form the path to the command
1382     // you want to add.
1383     cmd_arg.arg_type = eArgTypeCommand;
1384     cmd_arg.arg_repetition = eArgRepeatPlus;
1385 
1386     // There is only one variant this argument could be; put it into the
1387     // argument entry.
1388     arg1.push_back(cmd_arg);
1389 
1390     // Push the data for the first argument into the m_arguments vector.
1391     m_arguments.push_back(arg1);
1392   }
1393 
1394   ~CommandObjectCommandsScriptAdd() override = default;
1395 
1396   Options *GetOptions() override { return &m_options; }
1397 
1398   void
1399   HandleArgumentCompletion(CompletionRequest &request,
1400                            OptionElementVector &opt_element_vector) override {
1401     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1402                                                       opt_element_vector);
1403   }
1404 
1405 protected:
1406   class CommandOptions : public Options {
1407   public:
1408     CommandOptions() = default;
1409 
1410     ~CommandOptions() override = default;
1411 
1412     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1413                           ExecutionContext *execution_context) override {
1414       Status error;
1415       const int short_option = m_getopt_table[option_idx].val;
1416 
1417       switch (short_option) {
1418       case 'f':
1419         if (!option_arg.empty())
1420           m_funct_name = std::string(option_arg);
1421         break;
1422       case 'c':
1423         if (!option_arg.empty())
1424           m_class_name = std::string(option_arg);
1425         break;
1426       case 'h':
1427         if (!option_arg.empty())
1428           m_short_help = std::string(option_arg);
1429         break;
1430       case 'o':
1431         m_overwrite_lazy = eLazyBoolYes;
1432         break;
1433       case 's':
1434         m_synchronicity =
1435             (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
1436                 option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
1437         if (!error.Success())
1438           error.SetErrorStringWithFormat(
1439               "unrecognized value for synchronicity '%s'",
1440               option_arg.str().c_str());
1441         break;
1442       default:
1443         llvm_unreachable("Unimplemented option");
1444       }
1445 
1446       return error;
1447     }
1448 
1449     void OptionParsingStarting(ExecutionContext *execution_context) override {
1450       m_class_name.clear();
1451       m_funct_name.clear();
1452       m_short_help.clear();
1453       m_overwrite_lazy = eLazyBoolCalculate;
1454       m_synchronicity = eScriptedCommandSynchronicitySynchronous;
1455     }
1456 
1457     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1458       return llvm::ArrayRef(g_script_add_options);
1459     }
1460 
1461     // Instance variables to hold the values for command options.
1462 
1463     std::string m_class_name;
1464     std::string m_funct_name;
1465     std::string m_short_help;
1466     LazyBool m_overwrite_lazy = eLazyBoolCalculate;
1467     ScriptedCommandSynchronicity m_synchronicity =
1468         eScriptedCommandSynchronicitySynchronous;
1469   };
1470 
1471   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
1472     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
1473     if (output_sp && interactive) {
1474       output_sp->PutCString(g_python_command_instructions);
1475       output_sp->Flush();
1476     }
1477   }
1478 
1479   void IOHandlerInputComplete(IOHandler &io_handler,
1480                               std::string &data) override {
1481     StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
1482 
1483     ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1484     if (interpreter) {
1485       StringList lines;
1486       lines.SplitIntoLines(data);
1487       if (lines.GetSize() > 0) {
1488         std::string funct_name_str;
1489         if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
1490           if (funct_name_str.empty()) {
1491             error_sp->Printf("error: unable to obtain a function name, didn't "
1492                              "add python command.\n");
1493             error_sp->Flush();
1494           } else {
1495             // everything should be fine now, let's add this alias
1496 
1497             CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
1498                 m_interpreter, m_cmd_name, funct_name_str, m_short_help,
1499                 m_synchronicity));
1500             if (!m_container) {
1501               Status error = m_interpreter.AddUserCommand(
1502                   m_cmd_name, command_obj_sp, m_overwrite);
1503               if (error.Fail()) {
1504                 error_sp->Printf("error: unable to add selected command: '%s'",
1505                                  error.AsCString());
1506                 error_sp->Flush();
1507               }
1508             } else {
1509               llvm::Error llvm_error = m_container->LoadUserSubcommand(
1510                   m_cmd_name, command_obj_sp, m_overwrite);
1511               if (llvm_error) {
1512                 error_sp->Printf("error: unable to add selected command: '%s'",
1513                                llvm::toString(std::move(llvm_error)).c_str());
1514                 error_sp->Flush();
1515               }
1516             }
1517           }
1518         } else {
1519           error_sp->Printf(
1520               "error: unable to create function, didn't add python command\n");
1521           error_sp->Flush();
1522         }
1523       } else {
1524         error_sp->Printf("error: empty function, didn't add python command\n");
1525         error_sp->Flush();
1526       }
1527     } else {
1528       error_sp->Printf(
1529           "error: script interpreter missing, didn't add python command\n");
1530       error_sp->Flush();
1531     }
1532 
1533     io_handler.SetIsDone(true);
1534   }
1535 
1536   bool DoExecute(Args &command, CommandReturnObject &result) override {
1537     if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
1538       result.AppendError("only scripting language supported for scripted "
1539                          "commands is currently Python");
1540       return false;
1541     }
1542 
1543     if (command.GetArgumentCount() == 0) {
1544       result.AppendError("'command script add' requires at least one argument");
1545       return false;
1546     }
1547     // Store the options in case we get multi-line input, also figure out the
1548     // default if not user supplied:
1549     switch (m_options.m_overwrite_lazy) {
1550       case eLazyBoolCalculate:
1551         m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite();
1552         break;
1553       case eLazyBoolYes:
1554         m_overwrite = true;
1555         break;
1556       case eLazyBoolNo:
1557         m_overwrite = false;
1558     }
1559 
1560     Status path_error;
1561     m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath(
1562         command, true, path_error);
1563 
1564     if (path_error.Fail()) {
1565       result.AppendErrorWithFormat("error in command path: %s",
1566                                    path_error.AsCString());
1567       return false;
1568     }
1569 
1570     if (!m_container) {
1571       // This is getting inserted into the root of the interpreter.
1572       m_cmd_name = std::string(command[0].ref());
1573     } else {
1574       size_t num_args = command.GetArgumentCount();
1575       m_cmd_name = std::string(command[num_args - 1].ref());
1576     }
1577 
1578     m_short_help.assign(m_options.m_short_help);
1579     m_synchronicity = m_options.m_synchronicity;
1580 
1581     // Handle the case where we prompt for the script code first:
1582     if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) {
1583       m_interpreter.GetPythonCommandsFromIOHandler("     ", // Prompt
1584                                                    *this);  // IOHandlerDelegate
1585       return result.Succeeded();
1586     }
1587 
1588     CommandObjectSP new_cmd_sp;
1589     if (m_options.m_class_name.empty()) {
1590       new_cmd_sp.reset(new CommandObjectPythonFunction(
1591           m_interpreter, m_cmd_name, m_options.m_funct_name,
1592           m_options.m_short_help, m_synchronicity));
1593     } else {
1594       ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1595       if (!interpreter) {
1596         result.AppendError("cannot find ScriptInterpreter");
1597         return false;
1598       }
1599 
1600       auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
1601           m_options.m_class_name.c_str());
1602       if (!cmd_obj_sp) {
1603         result.AppendErrorWithFormatv("cannot create helper object for: "
1604                                       "'{0}'", m_options.m_class_name);
1605         return false;
1606       }
1607 
1608       new_cmd_sp.reset(new CommandObjectScriptingObject(
1609           m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity));
1610     }
1611 
1612     // Assume we're going to succeed...
1613     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1614     if (!m_container) {
1615       Status add_error =
1616           m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite);
1617       if (add_error.Fail())
1618         result.AppendErrorWithFormat("cannot add command: %s",
1619                                      add_error.AsCString());
1620     } else {
1621       llvm::Error llvm_error =
1622           m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite);
1623       if (llvm_error)
1624         result.AppendErrorWithFormat("cannot add command: %s",
1625                                      llvm::toString(std::move(llvm_error)).c_str());
1626     }
1627     return result.Succeeded();
1628   }
1629 
1630   CommandOptions m_options;
1631   std::string m_cmd_name;
1632   CommandObjectMultiword *m_container = nullptr;
1633   std::string m_short_help;
1634   bool m_overwrite = false;
1635   ScriptedCommandSynchronicity m_synchronicity =
1636       eScriptedCommandSynchronicitySynchronous;
1637 };
1638 
1639 // CommandObjectCommandsScriptList
1640 
1641 class CommandObjectCommandsScriptList : public CommandObjectParsed {
1642 public:
1643   CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
1644       : CommandObjectParsed(interpreter, "command script list",
1645                             "List defined top-level scripted commands.",
1646                             nullptr) {}
1647 
1648   ~CommandObjectCommandsScriptList() override = default;
1649 
1650   bool DoExecute(Args &command, CommandReturnObject &result) override {
1651     m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
1652 
1653     result.SetStatus(eReturnStatusSuccessFinishResult);
1654 
1655     return true;
1656   }
1657 };
1658 
1659 // CommandObjectCommandsScriptClear
1660 
1661 class CommandObjectCommandsScriptClear : public CommandObjectParsed {
1662 public:
1663   CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
1664       : CommandObjectParsed(interpreter, "command script clear",
1665                             "Delete all scripted commands.", nullptr) {}
1666 
1667   ~CommandObjectCommandsScriptClear() override = default;
1668 
1669 protected:
1670   bool DoExecute(Args &command, CommandReturnObject &result) override {
1671     m_interpreter.RemoveAllUser();
1672 
1673     result.SetStatus(eReturnStatusSuccessFinishResult);
1674 
1675     return true;
1676   }
1677 };
1678 
1679 // CommandObjectCommandsScriptDelete
1680 
1681 class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
1682 public:
1683   CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
1684       : CommandObjectParsed(
1685             interpreter, "command script delete",
1686             "Delete a scripted command by specifying the path to the command.",
1687             nullptr) {
1688     CommandArgumentEntry arg1;
1689     CommandArgumentData cmd_arg;
1690 
1691     // This is a list of command names forming the path to the command
1692     // to be deleted.
1693     cmd_arg.arg_type = eArgTypeCommand;
1694     cmd_arg.arg_repetition = eArgRepeatPlus;
1695 
1696     // There is only one variant this argument could be; put it into the
1697     // argument entry.
1698     arg1.push_back(cmd_arg);
1699 
1700     // Push the data for the first argument into the m_arguments vector.
1701     m_arguments.push_back(arg1);
1702   }
1703 
1704   ~CommandObjectCommandsScriptDelete() override = default;
1705 
1706   void
1707   HandleArgumentCompletion(CompletionRequest &request,
1708                            OptionElementVector &opt_element_vector) override {
1709     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1710                                                       opt_element_vector);
1711   }
1712 
1713 protected:
1714   bool DoExecute(Args &command, CommandReturnObject &result) override {
1715 
1716     llvm::StringRef root_cmd = command[0].ref();
1717     size_t num_args = command.GetArgumentCount();
1718 
1719     if (root_cmd.empty()) {
1720       result.AppendErrorWithFormat("empty root command name");
1721       return false;
1722     }
1723     if (!m_interpreter.HasUserCommands() &&
1724         !m_interpreter.HasUserMultiwordCommands()) {
1725       result.AppendErrorWithFormat("can only delete user defined commands, "
1726                                    "but no user defined commands found");
1727       return false;
1728     }
1729 
1730     CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd);
1731     if (!cmd_sp) {
1732       result.AppendErrorWithFormat("command '%s' not found.",
1733                                    command[0].c_str());
1734       return false;
1735     }
1736     if (!cmd_sp->IsUserCommand()) {
1737       result.AppendErrorWithFormat("command '%s' is not a user command.",
1738                                    command[0].c_str());
1739       return false;
1740     }
1741     if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) {
1742       result.AppendErrorWithFormat("command '%s' is a multi-word command.\n "
1743                                    "Delete with \"command container delete\"",
1744                                    command[0].c_str());
1745       return false;
1746     }
1747 
1748     if (command.GetArgumentCount() == 1) {
1749       m_interpreter.RemoveUser(root_cmd);
1750       result.SetStatus(eReturnStatusSuccessFinishResult);
1751       return true;
1752     }
1753     // We're deleting a command from a multiword command.  Verify the command
1754     // path:
1755     Status error;
1756     CommandObjectMultiword *container =
1757         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
1758                                                            error);
1759     if (error.Fail()) {
1760       result.AppendErrorWithFormat("could not resolve command path: %s",
1761                                    error.AsCString());
1762       return false;
1763     }
1764     if (!container) {
1765       // This means that command only had a leaf command, so the container is
1766       // the root.  That should have been handled above.
1767       result.AppendErrorWithFormat("could not find a container for '%s'",
1768                                    command[0].c_str());
1769       return false;
1770     }
1771     const char *leaf_cmd = command[num_args - 1].c_str();
1772     llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd,
1773                                             /* multiword not okay */ false);
1774     if (llvm_error) {
1775       result.AppendErrorWithFormat("could not delete command '%s': %s",
1776                                    leaf_cmd,
1777                                    llvm::toString(std::move(llvm_error)).c_str());
1778       return false;
1779     }
1780 
1781     Stream &out_stream = result.GetOutputStream();
1782 
1783     out_stream << "Deleted command:";
1784     for (size_t idx = 0; idx < num_args; idx++) {
1785       out_stream << ' ';
1786       out_stream << command[idx].c_str();
1787     }
1788     out_stream << '\n';
1789     result.SetStatus(eReturnStatusSuccessFinishResult);
1790     return true;
1791   }
1792 };
1793 
1794 #pragma mark CommandObjectMultiwordCommandsScript
1795 
1796 // CommandObjectMultiwordCommandsScript
1797 
1798 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
1799 public:
1800   CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
1801       : CommandObjectMultiword(
1802             interpreter, "command script",
1803             "Commands for managing custom "
1804             "commands implemented by "
1805             "interpreter scripts.",
1806             "command script <subcommand> [<subcommand-options>]") {
1807     LoadSubCommand("add", CommandObjectSP(
1808                               new CommandObjectCommandsScriptAdd(interpreter)));
1809     LoadSubCommand(
1810         "delete",
1811         CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
1812     LoadSubCommand(
1813         "clear",
1814         CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
1815     LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
1816                                interpreter)));
1817     LoadSubCommand(
1818         "import",
1819         CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
1820   }
1821 
1822   ~CommandObjectMultiwordCommandsScript() override = default;
1823 };
1824 
1825 #pragma mark CommandObjectCommandContainer
1826 #define LLDB_OPTIONS_container_add
1827 #include "CommandOptions.inc"
1828 
1829 class CommandObjectCommandsContainerAdd : public CommandObjectParsed {
1830 public:
1831   CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter)
1832       : CommandObjectParsed(
1833             interpreter, "command container add",
1834             "Add a container command to lldb.  Adding to built-"
1835             "in container commands is not allowed.",
1836             "command container add [[path1]...] container-name") {
1837     CommandArgumentEntry arg1;
1838     CommandArgumentData cmd_arg;
1839 
1840     // This is one or more command names, which form the path to the command
1841     // you want to add.
1842     cmd_arg.arg_type = eArgTypeCommand;
1843     cmd_arg.arg_repetition = eArgRepeatPlus;
1844 
1845     // There is only one variant this argument could be; put it into the
1846     // argument entry.
1847     arg1.push_back(cmd_arg);
1848 
1849     // Push the data for the first argument into the m_arguments vector.
1850     m_arguments.push_back(arg1);
1851   }
1852 
1853   ~CommandObjectCommandsContainerAdd() override = default;
1854 
1855   Options *GetOptions() override { return &m_options; }
1856 
1857   void
1858   HandleArgumentCompletion(CompletionRequest &request,
1859                            OptionElementVector &opt_element_vector) override {
1860     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1861                                                       opt_element_vector);
1862   }
1863 
1864 protected:
1865   class CommandOptions : public Options {
1866   public:
1867     CommandOptions() = default;
1868 
1869     ~CommandOptions() override = default;
1870 
1871     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1872                           ExecutionContext *execution_context) override {
1873       Status error;
1874       const int short_option = m_getopt_table[option_idx].val;
1875 
1876       switch (short_option) {
1877       case 'h':
1878         if (!option_arg.empty())
1879           m_short_help = std::string(option_arg);
1880         break;
1881       case 'o':
1882         m_overwrite = true;
1883         break;
1884       case 'H':
1885         if (!option_arg.empty())
1886           m_long_help = std::string(option_arg);
1887         break;
1888       default:
1889         llvm_unreachable("Unimplemented option");
1890       }
1891 
1892       return error;
1893     }
1894 
1895     void OptionParsingStarting(ExecutionContext *execution_context) override {
1896       m_short_help.clear();
1897       m_long_help.clear();
1898       m_overwrite = false;
1899     }
1900 
1901     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1902       return llvm::ArrayRef(g_container_add_options);
1903     }
1904 
1905     // Instance variables to hold the values for command options.
1906 
1907     std::string m_short_help;
1908     std::string m_long_help;
1909     bool m_overwrite = false;
1910   };
1911   bool DoExecute(Args &command, CommandReturnObject &result) override {
1912     size_t num_args = command.GetArgumentCount();
1913 
1914     if (num_args == 0) {
1915       result.AppendError("no command was specified");
1916       return false;
1917     }
1918 
1919     if (num_args == 1) {
1920       // We're adding this as a root command, so use the interpreter.
1921       const char *cmd_name = command.GetArgumentAtIndex(0);
1922       auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
1923           GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
1924           m_options.m_long_help.c_str()));
1925       cmd_sp->GetAsMultiwordCommand()->SetRemovable(true);
1926       Status add_error = GetCommandInterpreter().AddUserCommand(
1927           cmd_name, cmd_sp, m_options.m_overwrite);
1928       if (add_error.Fail()) {
1929         result.AppendErrorWithFormat("error adding command: %s",
1930                                      add_error.AsCString());
1931         return false;
1932       }
1933       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1934       return true;
1935     }
1936 
1937     // We're adding this to a subcommand, first find the subcommand:
1938     Status path_error;
1939     CommandObjectMultiword *add_to_me =
1940         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
1941                                                            path_error);
1942 
1943     if (!add_to_me) {
1944       result.AppendErrorWithFormat("error adding command: %s",
1945                                    path_error.AsCString());
1946       return false;
1947     }
1948 
1949     const char *cmd_name = command.GetArgumentAtIndex(num_args - 1);
1950     auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
1951         GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
1952         m_options.m_long_help.c_str()));
1953     llvm::Error llvm_error =
1954         add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite);
1955     if (llvm_error) {
1956       result.AppendErrorWithFormat("error adding subcommand: %s",
1957                                    llvm::toString(std::move(llvm_error)).c_str());
1958       return false;
1959     }
1960 
1961     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1962     return true;
1963   }
1964 
1965 private:
1966   CommandOptions m_options;
1967 };
1968 
1969 #define LLDB_OPTIONS_multiword_delete
1970 #include "CommandOptions.inc"
1971 class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
1972 public:
1973   CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter)
1974       : CommandObjectParsed(
1975             interpreter, "command container delete",
1976             "Delete a container command previously added to "
1977             "lldb.",
1978             "command container delete [[path1] ...] container-cmd") {
1979     CommandArgumentEntry arg1;
1980     CommandArgumentData cmd_arg;
1981 
1982     // This is one or more command names, which form the path to the command
1983     // you want to add.
1984     cmd_arg.arg_type = eArgTypeCommand;
1985     cmd_arg.arg_repetition = eArgRepeatPlus;
1986 
1987     // There is only one variant this argument could be; put it into the
1988     // argument entry.
1989     arg1.push_back(cmd_arg);
1990 
1991     // Push the data for the first argument into the m_arguments vector.
1992     m_arguments.push_back(arg1);
1993   }
1994 
1995   ~CommandObjectCommandsContainerDelete() override = default;
1996 
1997   void
1998   HandleArgumentCompletion(CompletionRequest &request,
1999                            OptionElementVector &opt_element_vector) override {
2000     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
2001                                                       opt_element_vector);
2002   }
2003 
2004 protected:
2005   bool DoExecute(Args &command, CommandReturnObject &result) override {
2006     size_t num_args = command.GetArgumentCount();
2007 
2008     if (num_args == 0) {
2009       result.AppendError("No command was specified.");
2010       return false;
2011     }
2012 
2013     if (num_args == 1) {
2014       // We're removing a root command, so we need to delete it from the
2015       // interpreter.
2016       const char *cmd_name = command.GetArgumentAtIndex(0);
2017       // Let's do a little more work here so we can do better error reporting.
2018       CommandInterpreter &interp = GetCommandInterpreter();
2019       CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name);
2020       if (!cmd_sp) {
2021         result.AppendErrorWithFormat("container command %s doesn't exist.",
2022                                      cmd_name);
2023         return false;
2024       }
2025       if (!cmd_sp->IsUserCommand()) {
2026         result.AppendErrorWithFormat(
2027             "container command %s is not a user command", cmd_name);
2028         return false;
2029       }
2030       if (!cmd_sp->GetAsMultiwordCommand()) {
2031         result.AppendErrorWithFormat("command %s is not a container command",
2032                                      cmd_name);
2033         return false;
2034       }
2035 
2036       bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name);
2037       if (!did_remove) {
2038         result.AppendErrorWithFormat("error removing command %s.", cmd_name);
2039         return false;
2040       }
2041 
2042       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2043       return true;
2044     }
2045 
2046     // We're removing a subcommand, first find the subcommand's owner:
2047     Status path_error;
2048     CommandObjectMultiword *container =
2049         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2050                                                            path_error);
2051 
2052     if (!container) {
2053       result.AppendErrorWithFormat("error removing container command: %s",
2054                                    path_error.AsCString());
2055       return false;
2056     }
2057     const char *leaf = command.GetArgumentAtIndex(num_args - 1);
2058     llvm::Error llvm_error =
2059         container->RemoveUserSubcommand(leaf, /* multiword okay */ true);
2060     if (llvm_error) {
2061       result.AppendErrorWithFormat("error removing container command: %s",
2062                                    llvm::toString(std::move(llvm_error)).c_str());
2063       return false;
2064     }
2065     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2066     return true;
2067   }
2068 };
2069 
2070 class CommandObjectCommandContainer : public CommandObjectMultiword {
2071 public:
2072   CommandObjectCommandContainer(CommandInterpreter &interpreter)
2073       : CommandObjectMultiword(
2074             interpreter, "command container",
2075             "Commands for adding container commands to lldb.  "
2076             "Container commands are containers for other commands.  You can "
2077             "add nested container commands by specifying a command path, "
2078             "but you can't add commands into the built-in command hierarchy.",
2079             "command container <subcommand> [<subcommand-options>]") {
2080     LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd(
2081                               interpreter)));
2082     LoadSubCommand(
2083         "delete",
2084         CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter)));
2085   }
2086 
2087   ~CommandObjectCommandContainer() override = default;
2088 };
2089 
2090 #pragma mark CommandObjectMultiwordCommands
2091 
2092 // CommandObjectMultiwordCommands
2093 
2094 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
2095     CommandInterpreter &interpreter)
2096     : CommandObjectMultiword(interpreter, "command",
2097                              "Commands for managing custom LLDB commands.",
2098                              "command <subcommand> [<subcommand-options>]") {
2099   LoadSubCommand("source",
2100                  CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
2101   LoadSubCommand("alias",
2102                  CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
2103   LoadSubCommand("unalias", CommandObjectSP(
2104                                 new CommandObjectCommandsUnalias(interpreter)));
2105   LoadSubCommand("delete",
2106                  CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
2107   LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer(
2108                                   interpreter)));
2109   LoadSubCommand(
2110       "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
2111   LoadSubCommand(
2112       "script",
2113       CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
2114 }
2115 
2116 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
2117