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   }
828 
829   ~CommandObjectCommandsAddRegex() override = default;
830 
831 protected:
832   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
833     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
834     if (output_sp && interactive) {
835       output_sp->PutCString("Enter one or more sed substitution commands in "
836                             "the form: 's/<regex>/<subst>/'.\nTerminate the "
837                             "substitution list with an empty line.\n");
838       output_sp->Flush();
839     }
840   }
841 
842   void IOHandlerInputComplete(IOHandler &io_handler,
843                               std::string &data) override {
844     io_handler.SetIsDone(true);
845     if (m_regex_cmd_up) {
846       StringList lines;
847       if (lines.SplitIntoLines(data)) {
848         bool check_only = false;
849         for (const std::string &line : lines) {
850           Status error = AppendRegexSubstitution(line, check_only);
851           if (error.Fail()) {
852             if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) {
853               StreamSP out_stream = GetDebugger().GetAsyncOutputStream();
854               out_stream->Printf("error: %s\n", error.AsCString());
855             }
856           }
857         }
858       }
859       if (m_regex_cmd_up->HasRegexEntries()) {
860         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
861         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
862       }
863     }
864   }
865 
866   bool DoExecute(Args &command, CommandReturnObject &result) override {
867     const size_t argc = command.GetArgumentCount();
868     if (argc == 0) {
869       result.AppendError("usage: 'command regex <command-name> "
870                          "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
871       return false;
872     }
873 
874     Status error;
875     auto name = command[0].ref();
876     m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
877         m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0,
878         true);
879 
880     if (argc == 1) {
881       Debugger &debugger = GetDebugger();
882       bool color_prompt = debugger.GetUseColor();
883       const bool multiple_lines = true; // Get multiple lines
884       IOHandlerSP io_handler_sp(new IOHandlerEditline(
885           debugger, IOHandler::Type::Other,
886           "lldb-regex",          // Name of input reader for history
887           llvm::StringRef("> "), // Prompt
888           llvm::StringRef(),     // Continuation prompt
889           multiple_lines, color_prompt,
890           0, // Don't show line numbers
891           *this, nullptr));
892 
893       if (io_handler_sp) {
894         debugger.RunIOHandlerAsync(io_handler_sp);
895         result.SetStatus(eReturnStatusSuccessFinishNoResult);
896       }
897     } else {
898       for (auto &entry : command.entries().drop_front()) {
899         bool check_only = false;
900         error = AppendRegexSubstitution(entry.ref(), check_only);
901         if (error.Fail())
902           break;
903       }
904 
905       if (error.Success()) {
906         AddRegexCommandToInterpreter();
907       }
908     }
909     if (error.Fail()) {
910       result.AppendError(error.AsCString());
911     }
912 
913     return result.Succeeded();
914   }
915 
916   Status AppendRegexSubstitution(const llvm::StringRef &regex_sed,
917                                  bool check_only) {
918     Status error;
919 
920     if (!m_regex_cmd_up) {
921       error.SetErrorStringWithFormat(
922           "invalid regular expression command object for: '%.*s'",
923           (int)regex_sed.size(), regex_sed.data());
924       return error;
925     }
926 
927     size_t regex_sed_size = regex_sed.size();
928 
929     if (regex_sed_size <= 1) {
930       error.SetErrorStringWithFormat(
931           "regular expression substitution string is too short: '%.*s'",
932           (int)regex_sed.size(), regex_sed.data());
933       return error;
934     }
935 
936     if (regex_sed[0] != 's') {
937       error.SetErrorStringWithFormat("regular expression substitution string "
938                                      "doesn't start with 's': '%.*s'",
939                                      (int)regex_sed.size(), regex_sed.data());
940       return error;
941     }
942     const size_t first_separator_char_pos = 1;
943     // use the char that follows 's' as the regex separator character so we can
944     // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
945     const char separator_char = regex_sed[first_separator_char_pos];
946     const size_t second_separator_char_pos =
947         regex_sed.find(separator_char, first_separator_char_pos + 1);
948 
949     if (second_separator_char_pos == std::string::npos) {
950       error.SetErrorStringWithFormat(
951           "missing second '%c' separator char after '%.*s' in '%.*s'",
952           separator_char,
953           (int)(regex_sed.size() - first_separator_char_pos - 1),
954           regex_sed.data() + (first_separator_char_pos + 1),
955           (int)regex_sed.size(), regex_sed.data());
956       return error;
957     }
958 
959     const size_t third_separator_char_pos =
960         regex_sed.find(separator_char, second_separator_char_pos + 1);
961 
962     if (third_separator_char_pos == std::string::npos) {
963       error.SetErrorStringWithFormat(
964           "missing third '%c' separator char after '%.*s' in '%.*s'",
965           separator_char,
966           (int)(regex_sed.size() - second_separator_char_pos - 1),
967           regex_sed.data() + (second_separator_char_pos + 1),
968           (int)regex_sed.size(), regex_sed.data());
969       return error;
970     }
971 
972     if (third_separator_char_pos != regex_sed_size - 1) {
973       // Make sure that everything that follows the last regex separator char
974       if (regex_sed.find_first_not_of("\t\n\v\f\r ",
975                                       third_separator_char_pos + 1) !=
976           std::string::npos) {
977         error.SetErrorStringWithFormat(
978             "extra data found after the '%.*s' regular expression substitution "
979             "string: '%.*s'",
980             (int)third_separator_char_pos + 1, regex_sed.data(),
981             (int)(regex_sed.size() - third_separator_char_pos - 1),
982             regex_sed.data() + (third_separator_char_pos + 1));
983         return error;
984       }
985     } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
986       error.SetErrorStringWithFormat(
987           "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
988           separator_char, separator_char, separator_char, (int)regex_sed.size(),
989           regex_sed.data());
990       return error;
991     } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
992       error.SetErrorStringWithFormat(
993           "<subst> 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     }
998 
999     if (!check_only) {
1000       std::string regex(std::string(regex_sed.substr(
1001           first_separator_char_pos + 1,
1002           second_separator_char_pos - first_separator_char_pos - 1)));
1003       std::string subst(std::string(regex_sed.substr(
1004           second_separator_char_pos + 1,
1005           third_separator_char_pos - second_separator_char_pos - 1)));
1006       m_regex_cmd_up->AddRegexCommand(regex, subst);
1007     }
1008     return error;
1009   }
1010 
1011   void AddRegexCommandToInterpreter() {
1012     if (m_regex_cmd_up) {
1013       if (m_regex_cmd_up->HasRegexEntries()) {
1014         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
1015         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
1016       }
1017     }
1018   }
1019 
1020 private:
1021   std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
1022 
1023   class CommandOptions : public Options {
1024   public:
1025     CommandOptions() = default;
1026 
1027     ~CommandOptions() override = default;
1028 
1029     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1030                           ExecutionContext *execution_context) override {
1031       Status error;
1032       const int short_option = m_getopt_table[option_idx].val;
1033 
1034       switch (short_option) {
1035       case 'h':
1036         m_help.assign(std::string(option_arg));
1037         break;
1038       case 's':
1039         m_syntax.assign(std::string(option_arg));
1040         break;
1041       default:
1042         llvm_unreachable("Unimplemented option");
1043       }
1044 
1045       return error;
1046     }
1047 
1048     void OptionParsingStarting(ExecutionContext *execution_context) override {
1049       m_help.clear();
1050       m_syntax.clear();
1051     }
1052 
1053     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1054       return llvm::makeArrayRef(g_regex_options);
1055     }
1056 
1057     llvm::StringRef GetHelp() { return m_help; }
1058 
1059     llvm::StringRef GetSyntax() { return m_syntax; }
1060 
1061   protected:
1062     // Instance variables to hold the values for command options.
1063 
1064     std::string m_help;
1065     std::string m_syntax;
1066   };
1067 
1068   Options *GetOptions() override { return &m_options; }
1069 
1070   CommandOptions m_options;
1071 };
1072 
1073 class CommandObjectPythonFunction : public CommandObjectRaw {
1074 public:
1075   CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
1076                               std::string funct, std::string help,
1077                               ScriptedCommandSynchronicity synch)
1078       : CommandObjectRaw(interpreter, name), m_function_name(funct),
1079         m_synchro(synch) {
1080     if (!help.empty())
1081       SetHelp(help);
1082     else {
1083       StreamString stream;
1084       stream.Printf("For more information run 'help %s'", name.c_str());
1085       SetHelp(stream.GetString());
1086     }
1087   }
1088 
1089   ~CommandObjectPythonFunction() override = default;
1090 
1091   bool IsRemovable() const override { return true; }
1092 
1093   const std::string &GetFunctionName() { return m_function_name; }
1094 
1095   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1096 
1097   llvm::StringRef GetHelpLong() override {
1098     if (m_fetched_help_long)
1099       return CommandObjectRaw::GetHelpLong();
1100 
1101     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1102     if (!scripter)
1103       return CommandObjectRaw::GetHelpLong();
1104 
1105     std::string docstring;
1106     m_fetched_help_long =
1107         scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
1108     if (!docstring.empty())
1109       SetHelpLong(docstring);
1110     return CommandObjectRaw::GetHelpLong();
1111   }
1112 
1113 protected:
1114   bool DoExecute(llvm::StringRef raw_command_line,
1115                  CommandReturnObject &result) override {
1116     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1117 
1118     Status error;
1119 
1120     result.SetStatus(eReturnStatusInvalid);
1121 
1122     if (!scripter || !scripter->RunScriptBasedCommand(
1123                          m_function_name.c_str(), raw_command_line, m_synchro,
1124                          result, error, m_exe_ctx)) {
1125       result.AppendError(error.AsCString());
1126     } else {
1127       // Don't change the status if the command already set it...
1128       if (result.GetStatus() == eReturnStatusInvalid) {
1129         if (result.GetOutputData().empty())
1130           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1131         else
1132           result.SetStatus(eReturnStatusSuccessFinishResult);
1133       }
1134     }
1135 
1136     return result.Succeeded();
1137   }
1138 
1139 private:
1140   std::string m_function_name;
1141   ScriptedCommandSynchronicity m_synchro;
1142   bool m_fetched_help_long = false;
1143 };
1144 
1145 class CommandObjectScriptingObject : public CommandObjectRaw {
1146 public:
1147   CommandObjectScriptingObject(CommandInterpreter &interpreter,
1148                                std::string name,
1149                                StructuredData::GenericSP cmd_obj_sp,
1150                                ScriptedCommandSynchronicity synch)
1151       : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1152         m_synchro(synch), m_fetched_help_short(false),
1153         m_fetched_help_long(false) {
1154     StreamString stream;
1155     stream.Printf("For more information run 'help %s'", name.c_str());
1156     SetHelp(stream.GetString());
1157     if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
1158       GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1159   }
1160 
1161   ~CommandObjectScriptingObject() override = default;
1162 
1163   bool IsRemovable() const override { return true; }
1164 
1165   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1166 
1167   llvm::StringRef GetHelp() override {
1168     if (m_fetched_help_short)
1169       return CommandObjectRaw::GetHelp();
1170     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1171     if (!scripter)
1172       return CommandObjectRaw::GetHelp();
1173     std::string docstring;
1174     m_fetched_help_short =
1175         scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1176     if (!docstring.empty())
1177       SetHelp(docstring);
1178 
1179     return CommandObjectRaw::GetHelp();
1180   }
1181 
1182   llvm::StringRef GetHelpLong() override {
1183     if (m_fetched_help_long)
1184       return CommandObjectRaw::GetHelpLong();
1185 
1186     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1187     if (!scripter)
1188       return CommandObjectRaw::GetHelpLong();
1189 
1190     std::string docstring;
1191     m_fetched_help_long =
1192         scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1193     if (!docstring.empty())
1194       SetHelpLong(docstring);
1195     return CommandObjectRaw::GetHelpLong();
1196   }
1197 
1198 protected:
1199   bool DoExecute(llvm::StringRef raw_command_line,
1200                  CommandReturnObject &result) override {
1201     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1202 
1203     Status error;
1204 
1205     result.SetStatus(eReturnStatusInvalid);
1206 
1207     if (!scripter ||
1208         !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
1209                                          m_synchro, result, error, m_exe_ctx)) {
1210       result.AppendError(error.AsCString());
1211     } else {
1212       // Don't change the status if the command already set it...
1213       if (result.GetStatus() == eReturnStatusInvalid) {
1214         if (result.GetOutputData().empty())
1215           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1216         else
1217           result.SetStatus(eReturnStatusSuccessFinishResult);
1218       }
1219     }
1220 
1221     return result.Succeeded();
1222   }
1223 
1224 private:
1225   StructuredData::GenericSP m_cmd_obj_sp;
1226   ScriptedCommandSynchronicity m_synchro;
1227   bool m_fetched_help_short : 1;
1228   bool m_fetched_help_long : 1;
1229 };
1230 
1231 // CommandObjectCommandsScriptImport
1232 #define LLDB_OPTIONS_script_import
1233 #include "CommandOptions.inc"
1234 
1235 class CommandObjectCommandsScriptImport : public CommandObjectParsed {
1236 public:
1237   CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
1238       : CommandObjectParsed(interpreter, "command script import",
1239                             "Import a scripting module in LLDB.", nullptr) {
1240     CommandArgumentEntry arg1;
1241     CommandArgumentData cmd_arg;
1242 
1243     // Define the first (and only) variant of this arg.
1244     cmd_arg.arg_type = eArgTypeFilename;
1245     cmd_arg.arg_repetition = eArgRepeatPlus;
1246 
1247     // There is only one variant this argument could be; put it into the
1248     // argument entry.
1249     arg1.push_back(cmd_arg);
1250 
1251     // Push the data for the first argument into the m_arguments vector.
1252     m_arguments.push_back(arg1);
1253   }
1254 
1255   ~CommandObjectCommandsScriptImport() override = default;
1256 
1257   void
1258   HandleArgumentCompletion(CompletionRequest &request,
1259                            OptionElementVector &opt_element_vector) override {
1260     CommandCompletions::InvokeCommonCompletionCallbacks(
1261         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
1262         request, nullptr);
1263   }
1264 
1265   Options *GetOptions() override { return &m_options; }
1266 
1267 protected:
1268   class CommandOptions : public Options {
1269   public:
1270     CommandOptions() = default;
1271 
1272     ~CommandOptions() override = default;
1273 
1274     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1275                           ExecutionContext *execution_context) override {
1276       Status error;
1277       const int short_option = m_getopt_table[option_idx].val;
1278 
1279       switch (short_option) {
1280       case 'r':
1281         // NO-OP
1282         break;
1283       case 'c':
1284         relative_to_command_file = true;
1285         break;
1286       case 's':
1287         silent = true;
1288         break;
1289       default:
1290         llvm_unreachable("Unimplemented option");
1291       }
1292 
1293       return error;
1294     }
1295 
1296     void OptionParsingStarting(ExecutionContext *execution_context) override {
1297       relative_to_command_file = false;
1298     }
1299 
1300     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1301       return llvm::makeArrayRef(g_script_import_options);
1302     }
1303     bool relative_to_command_file = false;
1304     bool silent = false;
1305   };
1306 
1307   bool DoExecute(Args &command, CommandReturnObject &result) override {
1308     if (command.empty()) {
1309       result.AppendError("command script import needs one or more arguments");
1310       return false;
1311     }
1312 
1313     FileSpec source_dir = {};
1314     if (m_options.relative_to_command_file) {
1315       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
1316       if (!source_dir) {
1317         result.AppendError("command script import -c can only be specified "
1318                            "from a command file");
1319         return false;
1320       }
1321     }
1322 
1323     for (auto &entry : command.entries()) {
1324       Status error;
1325 
1326       LoadScriptOptions options;
1327       options.SetInitSession(true);
1328       options.SetSilent(m_options.silent);
1329 
1330       // FIXME: this is necessary because CommandObject::CheckRequirements()
1331       // assumes that commands won't ever be recursively invoked, but it's
1332       // actually possible to craft a Python script that does other "command
1333       // script imports" in __lldb_init_module the real fix is to have
1334       // recursive commands possible with a CommandInvocation object separate
1335       // from the CommandObject itself, so that recursive command invocations
1336       // won't stomp on each other (wrt to execution contents, options, and
1337       // more)
1338       m_exe_ctx.Clear();
1339       if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
1340               entry.c_str(), options, error, /*module_sp=*/nullptr,
1341               source_dir)) {
1342         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1343       } else {
1344         result.AppendErrorWithFormat("module importing failed: %s",
1345                                      error.AsCString());
1346       }
1347     }
1348 
1349     return result.Succeeded();
1350   }
1351 
1352   CommandOptions m_options;
1353 };
1354 
1355 // CommandObjectCommandsScriptAdd
1356 static constexpr OptionEnumValueElement g_script_synchro_type[] = {
1357     {
1358         eScriptedCommandSynchronicitySynchronous,
1359         "synchronous",
1360         "Run synchronous",
1361     },
1362     {
1363         eScriptedCommandSynchronicityAsynchronous,
1364         "asynchronous",
1365         "Run asynchronous",
1366     },
1367     {
1368         eScriptedCommandSynchronicityCurrentValue,
1369         "current",
1370         "Do not alter current setting",
1371     },
1372 };
1373 
1374 static constexpr OptionEnumValues ScriptSynchroType() {
1375   return OptionEnumValues(g_script_synchro_type);
1376 }
1377 
1378 #define LLDB_OPTIONS_script_add
1379 #include "CommandOptions.inc"
1380 
1381 class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
1382                                        public IOHandlerDelegateMultiline {
1383 public:
1384   CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
1385       : CommandObjectParsed(interpreter, "command script add",
1386                             "Add a scripted function as an LLDB command.",
1387                             "Add a scripted function as an lldb command. "
1388                             "If you provide a single argument, the command "
1389                             "will be added at the root level of the command "
1390                             "hierarchy.  If there are more arguments they "
1391                             "must be a path to a user-added container "
1392                             "command, and the last element will be the new "
1393                             "command name."),
1394         IOHandlerDelegateMultiline("DONE") {
1395     CommandArgumentEntry arg1;
1396     CommandArgumentData cmd_arg;
1397 
1398     // This is one or more command names, which form the path to the command
1399     // you want to add.
1400     cmd_arg.arg_type = eArgTypeCommand;
1401     cmd_arg.arg_repetition = eArgRepeatPlus;
1402 
1403     // There is only one variant this argument could be; put it into the
1404     // argument entry.
1405     arg1.push_back(cmd_arg);
1406 
1407     // Push the data for the first argument into the m_arguments vector.
1408     m_arguments.push_back(arg1);
1409   }
1410 
1411   ~CommandObjectCommandsScriptAdd() override = default;
1412 
1413   Options *GetOptions() override { return &m_options; }
1414 
1415   void
1416   HandleArgumentCompletion(CompletionRequest &request,
1417                            OptionElementVector &opt_element_vector) override {
1418     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1419                                                       opt_element_vector);
1420   }
1421 
1422 protected:
1423   class CommandOptions : public Options {
1424   public:
1425     CommandOptions() = default;
1426 
1427     ~CommandOptions() override = default;
1428 
1429     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1430                           ExecutionContext *execution_context) override {
1431       Status error;
1432       const int short_option = m_getopt_table[option_idx].val;
1433 
1434       switch (short_option) {
1435       case 'f':
1436         if (!option_arg.empty())
1437           m_funct_name = std::string(option_arg);
1438         break;
1439       case 'c':
1440         if (!option_arg.empty())
1441           m_class_name = std::string(option_arg);
1442         break;
1443       case 'h':
1444         if (!option_arg.empty())
1445           m_short_help = std::string(option_arg);
1446         break;
1447       case 'o':
1448         m_overwrite_lazy = eLazyBoolYes;
1449         break;
1450       case 's':
1451         m_synchronicity =
1452             (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
1453                 option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
1454         if (!error.Success())
1455           error.SetErrorStringWithFormat(
1456               "unrecognized value for synchronicity '%s'",
1457               option_arg.str().c_str());
1458         break;
1459       default:
1460         llvm_unreachable("Unimplemented option");
1461       }
1462 
1463       return error;
1464     }
1465 
1466     void OptionParsingStarting(ExecutionContext *execution_context) override {
1467       m_class_name.clear();
1468       m_funct_name.clear();
1469       m_short_help.clear();
1470       m_overwrite_lazy = eLazyBoolCalculate;
1471       m_synchronicity = eScriptedCommandSynchronicitySynchronous;
1472     }
1473 
1474     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1475       return llvm::makeArrayRef(g_script_add_options);
1476     }
1477 
1478     // Instance variables to hold the values for command options.
1479 
1480     std::string m_class_name;
1481     std::string m_funct_name;
1482     std::string m_short_help;
1483     LazyBool m_overwrite_lazy;
1484     ScriptedCommandSynchronicity m_synchronicity =
1485         eScriptedCommandSynchronicitySynchronous;
1486   };
1487 
1488   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
1489     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
1490     if (output_sp && interactive) {
1491       output_sp->PutCString(g_python_command_instructions);
1492       output_sp->Flush();
1493     }
1494   }
1495 
1496   void IOHandlerInputComplete(IOHandler &io_handler,
1497                               std::string &data) override {
1498     StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
1499 
1500     ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1501     if (interpreter) {
1502       StringList lines;
1503       lines.SplitIntoLines(data);
1504       if (lines.GetSize() > 0) {
1505         std::string funct_name_str;
1506         if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
1507           if (funct_name_str.empty()) {
1508             error_sp->Printf("error: unable to obtain a function name, didn't "
1509                              "add python command.\n");
1510             error_sp->Flush();
1511           } else {
1512             // everything should be fine now, let's add this alias
1513 
1514             CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
1515                 m_interpreter, m_cmd_name, funct_name_str, m_short_help,
1516                 m_synchronicity));
1517             if (!m_container) {
1518               Status error = m_interpreter.AddUserCommand(
1519                   m_cmd_name, command_obj_sp, m_overwrite);
1520               if (error.Fail()) {
1521                 error_sp->Printf("error: unable to add selected command: '%s'",
1522                                  error.AsCString());
1523                 error_sp->Flush();
1524               }
1525             } else {
1526               llvm::Error llvm_error = m_container->LoadUserSubcommand(
1527                   m_cmd_name, command_obj_sp, m_overwrite);
1528               if (llvm_error) {
1529                 error_sp->Printf("error: unable to add selected command: '%s'",
1530                                llvm::toString(std::move(llvm_error)).c_str());
1531                 error_sp->Flush();
1532               }
1533             }
1534           }
1535         } else {
1536           error_sp->Printf(
1537               "error: unable to create function, didn't add python command\n");
1538           error_sp->Flush();
1539         }
1540       } else {
1541         error_sp->Printf("error: empty function, didn't add python command\n");
1542         error_sp->Flush();
1543       }
1544     } else {
1545       error_sp->Printf(
1546           "error: script interpreter missing, didn't add python command\n");
1547       error_sp->Flush();
1548     }
1549 
1550     io_handler.SetIsDone(true);
1551   }
1552 
1553   bool DoExecute(Args &command, CommandReturnObject &result) override {
1554     if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
1555       result.AppendError("only scripting language supported for scripted "
1556                          "commands is currently Python");
1557       return false;
1558     }
1559 
1560     if (command.GetArgumentCount() == 0) {
1561       result.AppendError("'command script add' requires at least one argument");
1562       return false;
1563     }
1564     // Store the options in case we get multi-line input, also figure out the
1565     // default if not user supplied:
1566     switch (m_options.m_overwrite_lazy) {
1567       case eLazyBoolCalculate:
1568         m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite();
1569         break;
1570       case eLazyBoolYes:
1571         m_overwrite = true;
1572         break;
1573       case eLazyBoolNo:
1574         m_overwrite = false;
1575     }
1576 
1577     Status path_error;
1578     m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath(
1579         command, true, path_error);
1580 
1581     if (path_error.Fail()) {
1582       result.AppendErrorWithFormat("error in command path: %s",
1583                                    path_error.AsCString());
1584       return false;
1585     }
1586 
1587     if (!m_container) {
1588       // This is getting inserted into the root of the interpreter.
1589       m_cmd_name = std::string(command[0].ref());
1590     } else {
1591       size_t num_args = command.GetArgumentCount();
1592       m_cmd_name = std::string(command[num_args - 1].ref());
1593     }
1594 
1595     m_short_help.assign(m_options.m_short_help);
1596     m_synchronicity = m_options.m_synchronicity;
1597 
1598     // Handle the case where we prompt for the script code first:
1599     if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) {
1600       m_interpreter.GetPythonCommandsFromIOHandler("     ", // Prompt
1601                                                    *this);  // IOHandlerDelegate
1602       return result.Succeeded();
1603     }
1604 
1605     CommandObjectSP new_cmd_sp;
1606     if (m_options.m_class_name.empty()) {
1607       new_cmd_sp.reset(new CommandObjectPythonFunction(
1608           m_interpreter, m_cmd_name, m_options.m_funct_name,
1609           m_options.m_short_help, m_synchronicity));
1610     } else {
1611       ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1612       if (!interpreter) {
1613         result.AppendError("cannot find ScriptInterpreter");
1614         return false;
1615       }
1616 
1617       auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
1618           m_options.m_class_name.c_str());
1619       if (!cmd_obj_sp) {
1620         result.AppendError("cannot create helper object");
1621         return false;
1622       }
1623 
1624       new_cmd_sp.reset(new CommandObjectScriptingObject(
1625           m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity));
1626     }
1627 
1628     // Assume we're going to succeed...
1629     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1630     if (!m_container) {
1631       Status add_error =
1632           m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite);
1633       if (add_error.Fail())
1634         result.AppendErrorWithFormat("cannot add command: %s",
1635                                      add_error.AsCString());
1636     } else {
1637       llvm::Error llvm_error =
1638           m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite);
1639       if (llvm_error)
1640         result.AppendErrorWithFormat("cannot add command: %s",
1641                                      llvm::toString(std::move(llvm_error)).c_str());
1642     }
1643     return result.Succeeded();
1644   }
1645 
1646   CommandOptions m_options;
1647   std::string m_cmd_name;
1648   CommandObjectMultiword *m_container = nullptr;
1649   std::string m_short_help;
1650   bool m_overwrite = eLazyBoolCalculate;
1651   ScriptedCommandSynchronicity m_synchronicity =
1652       eScriptedCommandSynchronicitySynchronous;
1653 };
1654 
1655 // CommandObjectCommandsScriptList
1656 
1657 class CommandObjectCommandsScriptList : public CommandObjectParsed {
1658 public:
1659   CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
1660       : CommandObjectParsed(interpreter, "command script list",
1661                             "List defined top-level scripted commands.",
1662                             nullptr) {}
1663 
1664   ~CommandObjectCommandsScriptList() override = default;
1665 
1666   bool DoExecute(Args &command, CommandReturnObject &result) override {
1667     if (command.GetArgumentCount() != 0) {
1668       result.AppendError("'command script list' doesn't take any arguments");
1669       return false;
1670     }
1671 
1672     m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
1673 
1674     result.SetStatus(eReturnStatusSuccessFinishResult);
1675 
1676     return true;
1677   }
1678 };
1679 
1680 // CommandObjectCommandsScriptClear
1681 
1682 class CommandObjectCommandsScriptClear : public CommandObjectParsed {
1683 public:
1684   CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
1685       : CommandObjectParsed(interpreter, "command script clear",
1686                             "Delete all scripted commands.", nullptr) {}
1687 
1688   ~CommandObjectCommandsScriptClear() override = default;
1689 
1690 protected:
1691   bool DoExecute(Args &command, CommandReturnObject &result) override {
1692     if (command.GetArgumentCount() != 0) {
1693       result.AppendError("'command script clear' doesn't take any arguments");
1694       return false;
1695     }
1696 
1697     m_interpreter.RemoveAllUser();
1698 
1699     result.SetStatus(eReturnStatusSuccessFinishResult);
1700 
1701     return true;
1702   }
1703 };
1704 
1705 // CommandObjectCommandsScriptDelete
1706 
1707 class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
1708 public:
1709   CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
1710       : CommandObjectParsed(
1711             interpreter, "command script delete",
1712             "Delete a scripted command by specifying the path to the command.",
1713             nullptr) {
1714     CommandArgumentEntry arg1;
1715     CommandArgumentData cmd_arg;
1716 
1717     // This is a list of command names forming the path to the command
1718     // to be deleted.
1719     cmd_arg.arg_type = eArgTypeCommand;
1720     cmd_arg.arg_repetition = eArgRepeatPlus;
1721 
1722     // There is only one variant this argument could be; put it into the
1723     // argument entry.
1724     arg1.push_back(cmd_arg);
1725 
1726     // Push the data for the first argument into the m_arguments vector.
1727     m_arguments.push_back(arg1);
1728   }
1729 
1730   ~CommandObjectCommandsScriptDelete() override = default;
1731 
1732   void
1733   HandleArgumentCompletion(CompletionRequest &request,
1734                            OptionElementVector &opt_element_vector) override {
1735     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1736                                                       opt_element_vector);
1737   }
1738 
1739 protected:
1740   bool DoExecute(Args &command, CommandReturnObject &result) override {
1741 
1742     llvm::StringRef root_cmd = command[0].ref();
1743     size_t num_args = command.GetArgumentCount();
1744 
1745     if (root_cmd.empty()) {
1746       result.AppendErrorWithFormat("empty root command name");
1747       return false;
1748     }
1749     if (!m_interpreter.HasUserCommands() &&
1750         !m_interpreter.HasUserMultiwordCommands()) {
1751       result.AppendErrorWithFormat("can only delete user defined commands, "
1752                                    "but no user defined commands found");
1753       return false;
1754     }
1755 
1756     CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd);
1757     if (!cmd_sp) {
1758       result.AppendErrorWithFormat("command '%s' not found.",
1759                                    command[0].c_str());
1760       return false;
1761     }
1762     if (!cmd_sp->IsUserCommand()) {
1763       result.AppendErrorWithFormat("command '%s' is not a user command.",
1764                                    command[0].c_str());
1765       return false;
1766     }
1767     if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) {
1768       result.AppendErrorWithFormat("command '%s' is a multi-word command.\n "
1769                                    "Delete with \"command container delete\"",
1770                                    command[0].c_str());
1771       return false;
1772     }
1773 
1774     if (command.GetArgumentCount() == 1) {
1775       m_interpreter.RemoveUser(root_cmd);
1776       result.SetStatus(eReturnStatusSuccessFinishResult);
1777       return true;
1778     }
1779     // We're deleting a command from a multiword command.  Verify the command
1780     // path:
1781     Status error;
1782     CommandObjectMultiword *container =
1783         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
1784                                                            error);
1785     if (error.Fail()) {
1786       result.AppendErrorWithFormat("could not resolve command path: %s",
1787                                    error.AsCString());
1788       return false;
1789     }
1790     if (!container) {
1791       // This means that command only had a leaf command, so the container is
1792       // the root.  That should have been handled above.
1793       result.AppendErrorWithFormat("could not find a container for '%s'",
1794                                    command[0].c_str());
1795       return false;
1796     }
1797     const char *leaf_cmd = command[num_args - 1].c_str();
1798     llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd,
1799                                             /* multiword not okay */ false);
1800     if (llvm_error) {
1801       result.AppendErrorWithFormat("could not delete command '%s': %s",
1802                                    leaf_cmd,
1803                                    llvm::toString(std::move(llvm_error)).c_str());
1804       return false;
1805     }
1806 
1807     Stream &out_stream = result.GetOutputStream();
1808 
1809     out_stream << "Deleted command:";
1810     for (size_t idx = 0; idx < num_args; idx++) {
1811       out_stream << ' ';
1812       out_stream << command[idx].c_str();
1813     }
1814     out_stream << '\n';
1815     result.SetStatus(eReturnStatusSuccessFinishResult);
1816     return true;
1817   }
1818 };
1819 
1820 #pragma mark CommandObjectMultiwordCommandsScript
1821 
1822 // CommandObjectMultiwordCommandsScript
1823 
1824 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
1825 public:
1826   CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
1827       : CommandObjectMultiword(
1828             interpreter, "command script",
1829             "Commands for managing custom "
1830             "commands implemented by "
1831             "interpreter scripts.",
1832             "command script <subcommand> [<subcommand-options>]") {
1833     LoadSubCommand("add", CommandObjectSP(
1834                               new CommandObjectCommandsScriptAdd(interpreter)));
1835     LoadSubCommand(
1836         "delete",
1837         CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
1838     LoadSubCommand(
1839         "clear",
1840         CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
1841     LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
1842                                interpreter)));
1843     LoadSubCommand(
1844         "import",
1845         CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
1846   }
1847 
1848   ~CommandObjectMultiwordCommandsScript() override = default;
1849 };
1850 
1851 #pragma mark CommandObjectCommandContainer
1852 #define LLDB_OPTIONS_container_add
1853 #include "CommandOptions.inc"
1854 
1855 class CommandObjectCommandsContainerAdd : public CommandObjectParsed {
1856 public:
1857   CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter)
1858       : CommandObjectParsed(
1859             interpreter, "command container add",
1860             "Add a container command to lldb.  Adding to built-"
1861             "in container commands is not allowed.",
1862             "command container add [[path1]...] container-name") {
1863     CommandArgumentEntry arg1;
1864     CommandArgumentData cmd_arg;
1865 
1866     // This is one or more command names, which form the path to the command
1867     // you want to add.
1868     cmd_arg.arg_type = eArgTypeCommand;
1869     cmd_arg.arg_repetition = eArgRepeatPlus;
1870 
1871     // There is only one variant this argument could be; put it into the
1872     // argument entry.
1873     arg1.push_back(cmd_arg);
1874 
1875     // Push the data for the first argument into the m_arguments vector.
1876     m_arguments.push_back(arg1);
1877   }
1878 
1879   ~CommandObjectCommandsContainerAdd() override = default;
1880 
1881   Options *GetOptions() override { return &m_options; }
1882 
1883   void
1884   HandleArgumentCompletion(CompletionRequest &request,
1885                            OptionElementVector &opt_element_vector) override {
1886     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1887                                                       opt_element_vector);
1888   }
1889 
1890 protected:
1891   class CommandOptions : public Options {
1892   public:
1893     CommandOptions() = default;
1894 
1895     ~CommandOptions() override = default;
1896 
1897     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1898                           ExecutionContext *execution_context) override {
1899       Status error;
1900       const int short_option = m_getopt_table[option_idx].val;
1901 
1902       switch (short_option) {
1903       case 'h':
1904         if (!option_arg.empty())
1905           m_short_help = std::string(option_arg);
1906         break;
1907       case 'o':
1908         m_overwrite = true;
1909         break;
1910       case 'H':
1911         if (!option_arg.empty())
1912           m_long_help = std::string(option_arg);
1913         break;
1914       default:
1915         llvm_unreachable("Unimplemented option");
1916       }
1917 
1918       return error;
1919     }
1920 
1921     void OptionParsingStarting(ExecutionContext *execution_context) override {
1922       m_short_help.clear();
1923       m_long_help.clear();
1924       m_overwrite = false;
1925     }
1926 
1927     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1928       return llvm::makeArrayRef(g_container_add_options);
1929     }
1930 
1931     // Instance variables to hold the values for command options.
1932 
1933     std::string m_short_help;
1934     std::string m_long_help;
1935     bool m_overwrite = false;
1936   };
1937   bool DoExecute(Args &command, CommandReturnObject &result) override {
1938     size_t num_args = command.GetArgumentCount();
1939 
1940     if (num_args == 0) {
1941       result.AppendError("no command was specified");
1942       return false;
1943     }
1944 
1945     if (num_args == 1) {
1946       // We're adding this as a root command, so use the interpreter.
1947       const char *cmd_name = command.GetArgumentAtIndex(0);
1948       auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
1949           GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
1950           m_options.m_long_help.c_str()));
1951       cmd_sp->GetAsMultiwordCommand()->SetRemovable(true);
1952       Status add_error = GetCommandInterpreter().AddUserCommand(
1953           cmd_name, cmd_sp, m_options.m_overwrite);
1954       if (add_error.Fail()) {
1955         result.AppendErrorWithFormat("error adding command: %s",
1956                                      add_error.AsCString());
1957         return false;
1958       }
1959       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1960       return true;
1961     }
1962 
1963     // We're adding this to a subcommand, first find the subcommand:
1964     Status path_error;
1965     CommandObjectMultiword *add_to_me =
1966         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
1967                                                            path_error);
1968 
1969     if (!add_to_me) {
1970       result.AppendErrorWithFormat("error adding command: %s",
1971                                    path_error.AsCString());
1972       return false;
1973     }
1974 
1975     const char *cmd_name = command.GetArgumentAtIndex(num_args - 1);
1976     auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
1977         GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
1978         m_options.m_long_help.c_str()));
1979     llvm::Error llvm_error =
1980         add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite);
1981     if (llvm_error) {
1982       result.AppendErrorWithFormat("error adding subcommand: %s",
1983                                    llvm::toString(std::move(llvm_error)).c_str());
1984       return false;
1985     }
1986 
1987     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1988     return true;
1989   }
1990 
1991 private:
1992   CommandOptions m_options;
1993 };
1994 
1995 #define LLDB_OPTIONS_multiword_delete
1996 #include "CommandOptions.inc"
1997 class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
1998 public:
1999   CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter)
2000       : CommandObjectParsed(
2001             interpreter, "command container delete",
2002             "Delete a container command previously added to "
2003             "lldb.",
2004             "command container delete [[path1] ...] container-cmd") {
2005     CommandArgumentEntry arg1;
2006     CommandArgumentData cmd_arg;
2007 
2008     // This is one or more command names, which form the path to the command
2009     // you want to add.
2010     cmd_arg.arg_type = eArgTypeCommand;
2011     cmd_arg.arg_repetition = eArgRepeatPlus;
2012 
2013     // There is only one variant this argument could be; put it into the
2014     // argument entry.
2015     arg1.push_back(cmd_arg);
2016 
2017     // Push the data for the first argument into the m_arguments vector.
2018     m_arguments.push_back(arg1);
2019   }
2020 
2021   ~CommandObjectCommandsContainerDelete() override = default;
2022 
2023   void
2024   HandleArgumentCompletion(CompletionRequest &request,
2025                            OptionElementVector &opt_element_vector) override {
2026     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
2027                                                       opt_element_vector);
2028   }
2029 
2030 protected:
2031   bool DoExecute(Args &command, CommandReturnObject &result) override {
2032     size_t num_args = command.GetArgumentCount();
2033 
2034     if (num_args == 0) {
2035       result.AppendError("No command was specified.");
2036       return false;
2037     }
2038 
2039     if (num_args == 1) {
2040       // We're removing a root command, so we need to delete it from the
2041       // interpreter.
2042       const char *cmd_name = command.GetArgumentAtIndex(0);
2043       // Let's do a little more work here so we can do better error reporting.
2044       CommandInterpreter &interp = GetCommandInterpreter();
2045       CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name);
2046       if (!cmd_sp) {
2047         result.AppendErrorWithFormat("container command %s doesn't exist.",
2048                                      cmd_name);
2049         return false;
2050       }
2051       if (!cmd_sp->IsUserCommand()) {
2052         result.AppendErrorWithFormat(
2053             "container command %s is not a user command", cmd_name);
2054         return false;
2055       }
2056       if (!cmd_sp->GetAsMultiwordCommand()) {
2057         result.AppendErrorWithFormat("command %s is not a container command",
2058                                      cmd_name);
2059         return false;
2060       }
2061 
2062       bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name);
2063       if (!did_remove) {
2064         result.AppendErrorWithFormat("error removing command %s.", cmd_name);
2065         return false;
2066       }
2067 
2068       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2069       return true;
2070     }
2071 
2072     // We're removing a subcommand, first find the subcommand's owner:
2073     Status path_error;
2074     CommandObjectMultiword *container =
2075         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2076                                                            path_error);
2077 
2078     if (!container) {
2079       result.AppendErrorWithFormat("error removing container command: %s",
2080                                    path_error.AsCString());
2081       return false;
2082     }
2083     const char *leaf = command.GetArgumentAtIndex(num_args - 1);
2084     llvm::Error llvm_error =
2085         container->RemoveUserSubcommand(leaf, /* multiword okay */ true);
2086     if (llvm_error) {
2087       result.AppendErrorWithFormat("error removing container command: %s",
2088                                    llvm::toString(std::move(llvm_error)).c_str());
2089       return false;
2090     }
2091     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2092     return true;
2093   }
2094 };
2095 
2096 class CommandObjectCommandContainer : public CommandObjectMultiword {
2097 public:
2098   CommandObjectCommandContainer(CommandInterpreter &interpreter)
2099       : CommandObjectMultiword(
2100             interpreter, "command container",
2101             "Commands for adding container commands to lldb.  "
2102             "Container commands are containers for other commands.  You can"
2103             "add nested container commands by specifying a command path, but "
2104             "but you can't add commands into the built-in command hierarchy.",
2105             "command container <subcommand> [<subcommand-options>]") {
2106     LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd(
2107                               interpreter)));
2108     LoadSubCommand(
2109         "delete",
2110         CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter)));
2111   }
2112 
2113   ~CommandObjectCommandContainer() override = default;
2114 };
2115 
2116 #pragma mark CommandObjectMultiwordCommands
2117 
2118 // CommandObjectMultiwordCommands
2119 
2120 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
2121     CommandInterpreter &interpreter)
2122     : CommandObjectMultiword(interpreter, "command",
2123                              "Commands for managing custom LLDB commands.",
2124                              "command <subcommand> [<subcommand-options>]") {
2125   LoadSubCommand("source",
2126                  CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
2127   LoadSubCommand("alias",
2128                  CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
2129   LoadSubCommand("unalias", CommandObjectSP(
2130                                 new CommandObjectCommandsUnalias(interpreter)));
2131   LoadSubCommand("delete",
2132                  CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
2133   LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer(
2134                                   interpreter)));
2135   LoadSubCommand(
2136       "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
2137   LoadSubCommand(
2138       "script",
2139       CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
2140 }
2141 
2142 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
2143