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