1 //===-- CommandObjectCommands.cpp -----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CommandObjectCommands.h"
10 #include "CommandObjectHelp.h"
11 #include "CommandObjectRegexCommand.h"
12 #include "lldb/Core/Debugger.h"
13 #include "lldb/Core/IOHandler.h"
14 #include "lldb/Interpreter/CommandHistory.h"
15 #include "lldb/Interpreter/CommandInterpreter.h"
16 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17 #include "lldb/Interpreter/CommandReturnObject.h"
18 #include "lldb/Interpreter/OptionArgParser.h"
19 #include "lldb/Interpreter/OptionValueBoolean.h"
20 #include "lldb/Interpreter/OptionValueString.h"
21 #include "lldb/Interpreter/OptionValueUInt64.h"
22 #include "lldb/Interpreter/Options.h"
23 #include "lldb/Interpreter/ScriptInterpreter.h"
24 #include "lldb/Utility/Args.h"
25 #include "lldb/Utility/StringList.h"
26 #include "llvm/ADT/StringRef.h"
27 #include <optional>
28 
29 using namespace lldb;
30 using namespace lldb_private;
31 
32 // CommandObjectCommandsSource
33 
34 #define LLDB_OPTIONS_source
35 #include "CommandOptions.inc"
36 
37 class CommandObjectCommandsSource : public CommandObjectParsed {
38 public:
CommandObjectCommandsSource(CommandInterpreter & interpreter)39   CommandObjectCommandsSource(CommandInterpreter &interpreter)
40       : CommandObjectParsed(
41             interpreter, "command source",
42             "Read and execute LLDB commands from the file <filename>.",
43             nullptr) {
44     CommandArgumentEntry arg;
45     CommandArgumentData file_arg;
46 
47     // Define the first (and only) variant of this arg.
48     file_arg.arg_type = eArgTypeFilename;
49     file_arg.arg_repetition = eArgRepeatPlain;
50 
51     // There is only one variant this argument could be; put it into the
52     // argument entry.
53     arg.push_back(file_arg);
54 
55     // Push the data for the first argument into the m_arguments vector.
56     m_arguments.push_back(arg);
57   }
58 
59   ~CommandObjectCommandsSource() override = default;
60 
GetRepeatCommand(Args & current_command_args,uint32_t index)61   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
62                                               uint32_t index) override {
63     return std::string("");
64   }
65 
66   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)67   HandleArgumentCompletion(CompletionRequest &request,
68                            OptionElementVector &opt_element_vector) override {
69     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
70         GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);
71   }
72 
GetOptions()73   Options *GetOptions() override { return &m_options; }
74 
75 protected:
76   class CommandOptions : public Options {
77   public:
CommandOptions()78     CommandOptions()
79         : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true),
80           m_cmd_relative_to_command_file(false) {}
81 
82     ~CommandOptions() override = default;
83 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)84     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
85                           ExecutionContext *execution_context) override {
86       Status error;
87       const int short_option = m_getopt_table[option_idx].val;
88 
89       switch (short_option) {
90       case 'e':
91         error = m_stop_on_error.SetValueFromString(option_arg);
92         break;
93 
94       case 'c':
95         error = m_stop_on_continue.SetValueFromString(option_arg);
96         break;
97 
98       case 'C':
99         m_cmd_relative_to_command_file = true;
100         break;
101 
102       case 's':
103         error = m_silent_run.SetValueFromString(option_arg);
104         break;
105 
106       default:
107         llvm_unreachable("Unimplemented option");
108       }
109 
110       return error;
111     }
112 
OptionParsingStarting(ExecutionContext * execution_context)113     void OptionParsingStarting(ExecutionContext *execution_context) override {
114       m_stop_on_error.Clear();
115       m_silent_run.Clear();
116       m_stop_on_continue.Clear();
117       m_cmd_relative_to_command_file.Clear();
118     }
119 
GetDefinitions()120     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
121       return llvm::ArrayRef(g_source_options);
122     }
123 
124     // Instance variables to hold the values for command options.
125 
126     OptionValueBoolean m_stop_on_error;
127     OptionValueBoolean m_silent_run;
128     OptionValueBoolean m_stop_on_continue;
129     OptionValueBoolean m_cmd_relative_to_command_file;
130   };
131 
DoExecute(Args & command,CommandReturnObject & result)132   void DoExecute(Args &command, CommandReturnObject &result) override {
133     if (command.GetArgumentCount() != 1) {
134       result.AppendErrorWithFormat(
135           "'%s' takes exactly one executable filename argument.\n",
136           GetCommandName().str().c_str());
137       return;
138     }
139 
140     FileSpec source_dir = {};
141     if (m_options.m_cmd_relative_to_command_file) {
142       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
143       if (!source_dir) {
144         result.AppendError("command source -C can only be specified "
145                            "from a command file");
146         result.SetStatus(eReturnStatusFailed);
147         return;
148       }
149     }
150 
151     FileSpec cmd_file(command[0].ref());
152     if (source_dir) {
153       // Prepend the source_dir to the cmd_file path:
154       if (!cmd_file.IsRelative()) {
155         result.AppendError("command source -C can only be used "
156                            "with a relative path.");
157         result.SetStatus(eReturnStatusFailed);
158         return;
159       }
160       cmd_file.MakeAbsolute(source_dir);
161     }
162 
163     FileSystem::Instance().Resolve(cmd_file);
164 
165     CommandInterpreterRunOptions options;
166     // If any options were set, then use them
167     if (m_options.m_stop_on_error.OptionWasSet() ||
168         m_options.m_silent_run.OptionWasSet() ||
169         m_options.m_stop_on_continue.OptionWasSet()) {
170       if (m_options.m_stop_on_continue.OptionWasSet())
171         options.SetStopOnContinue(
172             m_options.m_stop_on_continue.GetCurrentValue());
173 
174       if (m_options.m_stop_on_error.OptionWasSet())
175         options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
176 
177       // Individual silent setting is override for global command echo settings.
178       if (m_options.m_silent_run.GetCurrentValue()) {
179         options.SetSilent(true);
180       } else {
181         options.SetPrintResults(true);
182         options.SetPrintErrors(true);
183         options.SetEchoCommands(m_interpreter.GetEchoCommands());
184         options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
185       }
186     }
187 
188     m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
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, exe_ctx, 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 
GetDefinitions()213     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
214       return llvm::ArrayRef(g_alias_options);
215     }
216 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)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 
OptionParsingStarting(ExecutionContext * execution_context)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:
GetOptions()255   Options *GetOptions() override { return &m_option_group; }
256 
CommandObjectCommandsAlias(CommandInterpreter & interpreter)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:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)386   void 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;
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;
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;
409     }
410 
411     // Get the alias command.
412 
413     auto alias_command = args[0].ref();
414     if (alias_command.starts_with("-")) {
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;
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;
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;
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;
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     } else if (!cmd_obj->WantsRawCommandString()) {
465       // Note that args was initialized with the original command, and has not
466       // been updated to this point. Therefore can we pass it to the version of
467       // Execute that does not need/expect raw input in the alias.
468       HandleAliasingNormalCommand(args, result);
469     } else {
470       HandleAliasingRawCommand(alias_command, raw_command_string, *cmd_obj,
471                                result);
472     }
473   }
474 
HandleAliasingRawCommand(llvm::StringRef alias_command,llvm::StringRef raw_command_string,CommandObject & cmd_obj,CommandReturnObject & result)475   bool HandleAliasingRawCommand(llvm::StringRef alias_command,
476                                 llvm::StringRef raw_command_string,
477                                 CommandObject &cmd_obj,
478                                 CommandReturnObject &result) {
479     // Verify & handle any options/arguments passed to the alias command
480 
481     OptionArgVectorSP option_arg_vector_sp =
482         OptionArgVectorSP(new OptionArgVector);
483 
484     const bool include_aliases = true;
485     // Look up the command using command's name first.  This is to resolve
486     // aliases when you are making nested aliases.  But if you don't find
487     // it that way, then it wasn't an alias and we can just use the object
488     // we were passed in.
489     CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact(
490             cmd_obj.GetCommandName(), include_aliases);
491     if (!cmd_obj_sp)
492       cmd_obj_sp = cmd_obj.shared_from_this();
493 
494     if (m_interpreter.AliasExists(alias_command) ||
495         m_interpreter.UserCommandExists(alias_command)) {
496       result.AppendWarningWithFormat(
497           "Overwriting existing definition for '%s'.\n",
498           alias_command.str().c_str());
499     }
500     if (CommandAlias *alias = m_interpreter.AddAlias(
501             alias_command, cmd_obj_sp, raw_command_string)) {
502       if (m_command_options.m_help.OptionWasSet())
503         alias->SetHelp(m_command_options.m_help.GetCurrentValue());
504       if (m_command_options.m_long_help.OptionWasSet())
505         alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
506       result.SetStatus(eReturnStatusSuccessFinishNoResult);
507     } else {
508       result.AppendError("Unable to create requested alias.\n");
509     }
510     return result.Succeeded();
511   }
512 
HandleAliasingNormalCommand(Args & args,CommandReturnObject & result)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:
CommandObjectCommandsUnalias(CommandInterpreter & interpreter)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
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)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:
DoExecute(Args & args,CommandReturnObject & result)653   void 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;
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;
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;
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;
695     }
696 
697     result.SetStatus(eReturnStatusSuccessFinishNoResult);
698   }
699 };
700 
701 #pragma mark CommandObjectCommandsDelete
702 // CommandObjectCommandsDelete
703 
704 class CommandObjectCommandsDelete : public CommandObjectParsed {
705 public:
CommandObjectCommandsDelete(CommandInterpreter & interpreter)706   CommandObjectCommandsDelete(CommandInterpreter &interpreter)
707       : CommandObjectParsed(
708             interpreter, "command delete",
709             "Delete one or more custom commands defined by 'command regex'.",
710             nullptr) {
711     CommandArgumentEntry arg;
712     CommandArgumentData alias_arg;
713 
714     // Define the first (and only) variant of this arg.
715     alias_arg.arg_type = eArgTypeCommandName;
716     alias_arg.arg_repetition = eArgRepeatPlain;
717 
718     // There is only one variant this argument could be; put it into the
719     // argument entry.
720     arg.push_back(alias_arg);
721 
722     // Push the data for the first argument into the m_arguments vector.
723     m_arguments.push_back(arg);
724   }
725 
726   ~CommandObjectCommandsDelete() override = default;
727 
728   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)729   HandleArgumentCompletion(CompletionRequest &request,
730                            OptionElementVector &opt_element_vector) override {
731     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
732       return;
733 
734     for (const auto &ent : m_interpreter.GetCommands()) {
735       if (ent.second->IsRemovable())
736         request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
737     }
738   }
739 
740 protected:
DoExecute(Args & args,CommandReturnObject & result)741   void DoExecute(Args &args, CommandReturnObject &result) override {
742     CommandObject::CommandMap::iterator pos;
743 
744     if (args.empty()) {
745       result.AppendErrorWithFormat("must call '%s' with one or more valid user "
746                                    "defined regular expression command names",
747                                    GetCommandName().str().c_str());
748       return;
749     }
750 
751     auto command_name = args[0].ref();
752     if (!m_interpreter.CommandExists(command_name)) {
753       StreamString error_msg_stream;
754       const bool generate_upropos = true;
755       const bool generate_type_lookup = false;
756       CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
757           &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
758           generate_upropos, generate_type_lookup);
759       result.AppendError(error_msg_stream.GetString());
760       return;
761     }
762 
763     if (!m_interpreter.RemoveCommand(command_name)) {
764       result.AppendErrorWithFormat(
765           "'%s' is a permanent debugger command and cannot be removed.\n",
766           args[0].c_str());
767       return;
768     }
769 
770     result.SetStatus(eReturnStatusSuccessFinishNoResult);
771   }
772 };
773 
774 // CommandObjectCommandsAddRegex
775 
776 #define LLDB_OPTIONS_regex
777 #include "CommandOptions.inc"
778 
779 #pragma mark CommandObjectCommandsAddRegex
780 
781 class CommandObjectCommandsAddRegex : public CommandObjectParsed,
782                                       public IOHandlerDelegateMultiline {
783 public:
CommandObjectCommandsAddRegex(CommandInterpreter & interpreter)784   CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
785       : CommandObjectParsed(
786             interpreter, "command regex",
787             "Define a custom command in terms of "
788             "existing commands by matching "
789             "regular expressions.",
790             "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
791         IOHandlerDelegateMultiline("",
792                                    IOHandlerDelegate::Completion::LLDBCommand) {
793     SetHelpLong(
794         R"(
795 )"
796         "This command allows the user to create powerful regular expression commands \
797 with substitutions. The regular expressions and substitutions are specified \
798 using the regular expression substitution format of:"
799         R"(
800 
801     s/<regex>/<subst>/
802 
803 )"
804         "<regex> is a regular expression that can use parenthesis to capture regular \
805 expression input and substitute the captured matches in the output using %1 \
806 for the first match, %2 for the second, and so on."
807         R"(
808 
809 )"
810         "The regular expressions can all be specified on the command line if more than \
811 one argument is provided. If just the command name is provided on the command \
812 line, then the regular expressions and substitutions can be entered on separate \
813 lines, followed by an empty line to terminate the command definition."
814         R"(
815 
816 EXAMPLES
817 
818 )"
819         "The following example will define a regular expression command named 'f' that \
820 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
821 a number follows 'f':"
822         R"(
823 
824     (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
825     CommandArgumentData thread_arg{eArgTypeSEDStylePair, eArgRepeatOptional};
826     m_arguments.push_back({thread_arg});
827   }
828 
829   ~CommandObjectCommandsAddRegex() override = default;
830 
831 protected:
IOHandlerActivated(IOHandler & io_handler,bool interactive)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 
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)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 
DoExecute(Args & command,CommandReturnObject & result)866   void 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;
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(), 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));
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 
AppendRegexSubstitution(const llvm::StringRef & regex_sed,bool check_only)914   Status AppendRegexSubstitution(const llvm::StringRef &regex_sed,
915                                  bool check_only) {
916     Status error;
917 
918     if (!m_regex_cmd_up) {
919       error.SetErrorStringWithFormat(
920           "invalid regular expression command object for: '%.*s'",
921           (int)regex_sed.size(), regex_sed.data());
922       return error;
923     }
924 
925     size_t regex_sed_size = regex_sed.size();
926 
927     if (regex_sed_size <= 1) {
928       error.SetErrorStringWithFormat(
929           "regular expression substitution string is too short: '%.*s'",
930           (int)regex_sed.size(), regex_sed.data());
931       return error;
932     }
933 
934     if (regex_sed[0] != 's') {
935       error.SetErrorStringWithFormat("regular expression substitution string "
936                                      "doesn't start with 's': '%.*s'",
937                                      (int)regex_sed.size(), regex_sed.data());
938       return error;
939     }
940     const size_t first_separator_char_pos = 1;
941     // use the char that follows 's' as the regex separator character so we can
942     // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
943     const char separator_char = regex_sed[first_separator_char_pos];
944     const size_t second_separator_char_pos =
945         regex_sed.find(separator_char, first_separator_char_pos + 1);
946 
947     if (second_separator_char_pos == std::string::npos) {
948       error.SetErrorStringWithFormat(
949           "missing second '%c' separator char after '%.*s' in '%.*s'",
950           separator_char,
951           (int)(regex_sed.size() - first_separator_char_pos - 1),
952           regex_sed.data() + (first_separator_char_pos + 1),
953           (int)regex_sed.size(), regex_sed.data());
954       return error;
955     }
956 
957     const size_t third_separator_char_pos =
958         regex_sed.find(separator_char, second_separator_char_pos + 1);
959 
960     if (third_separator_char_pos == std::string::npos) {
961       error.SetErrorStringWithFormat(
962           "missing third '%c' separator char after '%.*s' in '%.*s'",
963           separator_char,
964           (int)(regex_sed.size() - second_separator_char_pos - 1),
965           regex_sed.data() + (second_separator_char_pos + 1),
966           (int)regex_sed.size(), regex_sed.data());
967       return error;
968     }
969 
970     if (third_separator_char_pos != regex_sed_size - 1) {
971       // Make sure that everything that follows the last regex separator char
972       if (regex_sed.find_first_not_of("\t\n\v\f\r ",
973                                       third_separator_char_pos + 1) !=
974           std::string::npos) {
975         error.SetErrorStringWithFormat(
976             "extra data found after the '%.*s' regular expression substitution "
977             "string: '%.*s'",
978             (int)third_separator_char_pos + 1, regex_sed.data(),
979             (int)(regex_sed.size() - third_separator_char_pos - 1),
980             regex_sed.data() + (third_separator_char_pos + 1));
981         return error;
982       }
983     } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
984       error.SetErrorStringWithFormat(
985           "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
986           separator_char, separator_char, separator_char, (int)regex_sed.size(),
987           regex_sed.data());
988       return error;
989     } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
990       error.SetErrorStringWithFormat(
991           "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
992           separator_char, separator_char, separator_char, (int)regex_sed.size(),
993           regex_sed.data());
994       return error;
995     }
996 
997     if (!check_only) {
998       std::string regex(std::string(regex_sed.substr(
999           first_separator_char_pos + 1,
1000           second_separator_char_pos - first_separator_char_pos - 1)));
1001       std::string subst(std::string(regex_sed.substr(
1002           second_separator_char_pos + 1,
1003           third_separator_char_pos - second_separator_char_pos - 1)));
1004       m_regex_cmd_up->AddRegexCommand(regex, subst);
1005     }
1006     return error;
1007   }
1008 
AddRegexCommandToInterpreter()1009   void AddRegexCommandToInterpreter() {
1010     if (m_regex_cmd_up) {
1011       if (m_regex_cmd_up->HasRegexEntries()) {
1012         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
1013         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
1014       }
1015     }
1016   }
1017 
1018 private:
1019   std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
1020 
1021   class CommandOptions : public Options {
1022   public:
1023     CommandOptions() = default;
1024 
1025     ~CommandOptions() override = default;
1026 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1027     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1028                           ExecutionContext *execution_context) override {
1029       Status error;
1030       const int short_option = m_getopt_table[option_idx].val;
1031 
1032       switch (short_option) {
1033       case 'h':
1034         m_help.assign(std::string(option_arg));
1035         break;
1036       case 's':
1037         m_syntax.assign(std::string(option_arg));
1038         break;
1039       default:
1040         llvm_unreachable("Unimplemented option");
1041       }
1042 
1043       return error;
1044     }
1045 
OptionParsingStarting(ExecutionContext * execution_context)1046     void OptionParsingStarting(ExecutionContext *execution_context) override {
1047       m_help.clear();
1048       m_syntax.clear();
1049     }
1050 
GetDefinitions()1051     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1052       return llvm::ArrayRef(g_regex_options);
1053     }
1054 
GetHelp()1055     llvm::StringRef GetHelp() { return m_help; }
1056 
GetSyntax()1057     llvm::StringRef GetSyntax() { return m_syntax; }
1058 
1059   protected:
1060     // Instance variables to hold the values for command options.
1061 
1062     std::string m_help;
1063     std::string m_syntax;
1064   };
1065 
GetOptions()1066   Options *GetOptions() override { return &m_options; }
1067 
1068   CommandOptions m_options;
1069 };
1070 
1071 class CommandObjectPythonFunction : public CommandObjectRaw {
1072 public:
CommandObjectPythonFunction(CommandInterpreter & interpreter,std::string name,std::string funct,std::string help,ScriptedCommandSynchronicity synch,CompletionType completion_type)1073   CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
1074                               std::string funct, std::string help,
1075                               ScriptedCommandSynchronicity synch,
1076                               CompletionType completion_type)
1077       : CommandObjectRaw(interpreter, name), m_function_name(funct),
1078         m_synchro(synch), m_completion_type(completion_type) {
1079     if (!help.empty())
1080       SetHelp(help);
1081     else {
1082       StreamString stream;
1083       stream.Printf("For more information run 'help %s'", name.c_str());
1084       SetHelp(stream.GetString());
1085     }
1086   }
1087 
1088   ~CommandObjectPythonFunction() override = default;
1089 
IsRemovable() const1090   bool IsRemovable() const override { return true; }
1091 
GetFunctionName()1092   const std::string &GetFunctionName() { return m_function_name; }
1093 
GetSynchronicity()1094   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1095 
GetHelpLong()1096   llvm::StringRef GetHelpLong() override {
1097     if (m_fetched_help_long)
1098       return CommandObjectRaw::GetHelpLong();
1099 
1100     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1101     if (!scripter)
1102       return CommandObjectRaw::GetHelpLong();
1103 
1104     std::string docstring;
1105     m_fetched_help_long =
1106         scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
1107     if (!docstring.empty())
1108       SetHelpLong(docstring);
1109     return CommandObjectRaw::GetHelpLong();
1110   }
1111 
1112   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1113   HandleArgumentCompletion(CompletionRequest &request,
1114                            OptionElementVector &opt_element_vector) override {
1115     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1116         GetCommandInterpreter(), m_completion_type, request, nullptr);
1117   }
1118 
WantsCompletion()1119   bool WantsCompletion() override { return true; }
1120 
1121 protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1122   void DoExecute(llvm::StringRef raw_command_line,
1123                  CommandReturnObject &result) override {
1124     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1125 
1126     Status error;
1127 
1128     result.SetStatus(eReturnStatusInvalid);
1129 
1130     if (!scripter || !scripter->RunScriptBasedCommand(
1131                          m_function_name.c_str(), raw_command_line, m_synchro,
1132                          result, error, m_exe_ctx)) {
1133       result.AppendError(error.AsCString());
1134     } else {
1135       // Don't change the status if the command already set it...
1136       if (result.GetStatus() == eReturnStatusInvalid) {
1137         if (result.GetOutputData().empty())
1138           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1139         else
1140           result.SetStatus(eReturnStatusSuccessFinishResult);
1141       }
1142     }
1143   }
1144 
1145 private:
1146   std::string m_function_name;
1147   ScriptedCommandSynchronicity m_synchro;
1148   bool m_fetched_help_long = false;
1149   CompletionType m_completion_type = eNoCompletion;
1150 };
1151 
1152 class CommandObjectScriptingObject : public CommandObjectRaw {
1153 public:
CommandObjectScriptingObject(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch,CompletionType completion_type)1154   CommandObjectScriptingObject(CommandInterpreter &interpreter,
1155                                std::string name,
1156                                StructuredData::GenericSP cmd_obj_sp,
1157                                ScriptedCommandSynchronicity synch,
1158                                CompletionType completion_type)
1159       : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1160         m_synchro(synch), m_fetched_help_short(false),
1161         m_fetched_help_long(false), m_completion_type(completion_type) {
1162     StreamString stream;
1163     stream.Printf("For more information run 'help %s'", name.c_str());
1164     SetHelp(stream.GetString());
1165     if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
1166       GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1167   }
1168 
1169   ~CommandObjectScriptingObject() override = default;
1170 
1171   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1172   HandleArgumentCompletion(CompletionRequest &request,
1173                            OptionElementVector &opt_element_vector) override {
1174     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1175         GetCommandInterpreter(), m_completion_type, request, nullptr);
1176   }
1177 
WantsCompletion()1178   bool WantsCompletion() override { return true; }
1179 
IsRemovable() const1180   bool IsRemovable() const override { return true; }
1181 
GetSynchronicity()1182   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1183 
GetHelp()1184   llvm::StringRef GetHelp() override {
1185     if (m_fetched_help_short)
1186       return CommandObjectRaw::GetHelp();
1187     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1188     if (!scripter)
1189       return CommandObjectRaw::GetHelp();
1190     std::string docstring;
1191     m_fetched_help_short =
1192         scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1193     if (!docstring.empty())
1194       SetHelp(docstring);
1195 
1196     return CommandObjectRaw::GetHelp();
1197   }
1198 
GetHelpLong()1199   llvm::StringRef GetHelpLong() override {
1200     if (m_fetched_help_long)
1201       return CommandObjectRaw::GetHelpLong();
1202 
1203     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1204     if (!scripter)
1205       return CommandObjectRaw::GetHelpLong();
1206 
1207     std::string docstring;
1208     m_fetched_help_long =
1209         scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1210     if (!docstring.empty())
1211       SetHelpLong(docstring);
1212     return CommandObjectRaw::GetHelpLong();
1213   }
1214 
1215 protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1216   void DoExecute(llvm::StringRef raw_command_line,
1217                  CommandReturnObject &result) override {
1218     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1219 
1220     Status error;
1221 
1222     result.SetStatus(eReturnStatusInvalid);
1223 
1224     if (!scripter ||
1225         !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
1226                                          m_synchro, result, error, m_exe_ctx)) {
1227       result.AppendError(error.AsCString());
1228     } else {
1229       // Don't change the status if the command already set it...
1230       if (result.GetStatus() == eReturnStatusInvalid) {
1231         if (result.GetOutputData().empty())
1232           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1233         else
1234           result.SetStatus(eReturnStatusSuccessFinishResult);
1235       }
1236     }
1237   }
1238 
1239 private:
1240   StructuredData::GenericSP m_cmd_obj_sp;
1241   ScriptedCommandSynchronicity m_synchro;
1242   bool m_fetched_help_short : 1;
1243   bool m_fetched_help_long : 1;
1244   CompletionType m_completion_type = eNoCompletion;
1245 };
1246 
1247 // CommandObjectCommandsScriptImport
1248 #define LLDB_OPTIONS_script_import
1249 #include "CommandOptions.inc"
1250 
1251 class CommandObjectCommandsScriptImport : public CommandObjectParsed {
1252 public:
CommandObjectCommandsScriptImport(CommandInterpreter & interpreter)1253   CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
1254       : CommandObjectParsed(interpreter, "command script import",
1255                             "Import a scripting module in LLDB.", nullptr) {
1256     CommandArgumentEntry arg1;
1257     CommandArgumentData cmd_arg;
1258 
1259     // Define the first (and only) variant of this arg.
1260     cmd_arg.arg_type = eArgTypeFilename;
1261     cmd_arg.arg_repetition = eArgRepeatPlus;
1262 
1263     // There is only one variant this argument could be; put it into the
1264     // argument entry.
1265     arg1.push_back(cmd_arg);
1266 
1267     // Push the data for the first argument into the m_arguments vector.
1268     m_arguments.push_back(arg1);
1269   }
1270 
1271   ~CommandObjectCommandsScriptImport() override = default;
1272 
1273   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1274   HandleArgumentCompletion(CompletionRequest &request,
1275                            OptionElementVector &opt_element_vector) override {
1276     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1277         GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);
1278   }
1279 
GetOptions()1280   Options *GetOptions() override { return &m_options; }
1281 
1282 protected:
1283   class CommandOptions : public Options {
1284   public:
1285     CommandOptions() = default;
1286 
1287     ~CommandOptions() override = default;
1288 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1289     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1290                           ExecutionContext *execution_context) override {
1291       Status error;
1292       const int short_option = m_getopt_table[option_idx].val;
1293 
1294       switch (short_option) {
1295       case 'r':
1296         // NO-OP
1297         break;
1298       case 'c':
1299         relative_to_command_file = true;
1300         break;
1301       case 's':
1302         silent = true;
1303         break;
1304       default:
1305         llvm_unreachable("Unimplemented option");
1306       }
1307 
1308       return error;
1309     }
1310 
OptionParsingStarting(ExecutionContext * execution_context)1311     void OptionParsingStarting(ExecutionContext *execution_context) override {
1312       relative_to_command_file = false;
1313     }
1314 
GetDefinitions()1315     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1316       return llvm::ArrayRef(g_script_import_options);
1317     }
1318     bool relative_to_command_file = false;
1319     bool silent = false;
1320   };
1321 
DoExecute(Args & command,CommandReturnObject & result)1322   void DoExecute(Args &command, CommandReturnObject &result) override {
1323     if (command.empty()) {
1324       result.AppendError("command script import needs one or more arguments");
1325       return;
1326     }
1327 
1328     FileSpec source_dir = {};
1329     if (m_options.relative_to_command_file) {
1330       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
1331       if (!source_dir) {
1332         result.AppendError("command script import -c can only be specified "
1333                            "from a command file");
1334         return;
1335       }
1336     }
1337 
1338     for (auto &entry : command.entries()) {
1339       Status error;
1340 
1341       LoadScriptOptions options;
1342       options.SetInitSession(true);
1343       options.SetSilent(m_options.silent);
1344 
1345       // FIXME: this is necessary because CommandObject::CheckRequirements()
1346       // assumes that commands won't ever be recursively invoked, but it's
1347       // actually possible to craft a Python script that does other "command
1348       // script imports" in __lldb_init_module the real fix is to have
1349       // recursive commands possible with a CommandInvocation object separate
1350       // from the CommandObject itself, so that recursive command invocations
1351       // won't stomp on each other (wrt to execution contents, options, and
1352       // more)
1353       m_exe_ctx.Clear();
1354       if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
1355               entry.c_str(), options, error, /*module_sp=*/nullptr,
1356               source_dir)) {
1357         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1358       } else {
1359         result.AppendErrorWithFormat("module importing failed: %s",
1360                                      error.AsCString());
1361       }
1362     }
1363   }
1364 
1365   CommandOptions m_options;
1366 };
1367 
1368 #define LLDB_OPTIONS_script_add
1369 #include "CommandOptions.inc"
1370 
1371 class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
1372                                        public IOHandlerDelegateMultiline {
1373 public:
CommandObjectCommandsScriptAdd(CommandInterpreter & interpreter)1374   CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
1375       : CommandObjectParsed(interpreter, "command script add",
1376                             "Add a scripted function as an LLDB command.",
1377                             "Add a scripted function as an lldb command. "
1378                             "If you provide a single argument, the command "
1379                             "will be added at the root level of the command "
1380                             "hierarchy.  If there are more arguments they "
1381                             "must be a path to a user-added container "
1382                             "command, and the last element will be the new "
1383                             "command name."),
1384         IOHandlerDelegateMultiline("DONE") {
1385     CommandArgumentEntry arg1;
1386     CommandArgumentData cmd_arg;
1387 
1388     // This is one or more command names, which form the path to the command
1389     // you want to add.
1390     cmd_arg.arg_type = eArgTypeCommand;
1391     cmd_arg.arg_repetition = eArgRepeatPlus;
1392 
1393     // There is only one variant this argument could be; put it into the
1394     // argument entry.
1395     arg1.push_back(cmd_arg);
1396 
1397     // Push the data for the first argument into the m_arguments vector.
1398     m_arguments.push_back(arg1);
1399   }
1400 
1401   ~CommandObjectCommandsScriptAdd() override = default;
1402 
GetOptions()1403   Options *GetOptions() override { return &m_options; }
1404 
1405   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1406   HandleArgumentCompletion(CompletionRequest &request,
1407                            OptionElementVector &opt_element_vector) override {
1408     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1409                                                       opt_element_vector);
1410   }
1411 
1412 protected:
1413   class CommandOptions : public Options {
1414   public:
1415     CommandOptions() = default;
1416 
1417     ~CommandOptions() override = default;
1418 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1419     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1420                           ExecutionContext *execution_context) override {
1421       Status error;
1422       const int short_option = m_getopt_table[option_idx].val;
1423 
1424       switch (short_option) {
1425       case 'f':
1426         if (!option_arg.empty())
1427           m_funct_name = std::string(option_arg);
1428         break;
1429       case 'c':
1430         if (!option_arg.empty())
1431           m_class_name = std::string(option_arg);
1432         break;
1433       case 'h':
1434         if (!option_arg.empty())
1435           m_short_help = std::string(option_arg);
1436         break;
1437       case 'o':
1438         m_overwrite_lazy = eLazyBoolYes;
1439         break;
1440       case 's':
1441         m_synchronicity =
1442             (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
1443                 option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
1444         if (!error.Success())
1445           error.SetErrorStringWithFormat(
1446               "unrecognized value for synchronicity '%s'",
1447               option_arg.str().c_str());
1448         break;
1449       case 'C': {
1450         Status error;
1451         OptionDefinition definition = GetDefinitions()[option_idx];
1452         lldb::CompletionType completion_type =
1453             static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum(
1454                 option_arg, definition.enum_values, eNoCompletion, error));
1455         if (!error.Success())
1456           error.SetErrorStringWithFormat(
1457               "unrecognized value for command completion type '%s'",
1458               option_arg.str().c_str());
1459         m_completion_type = completion_type;
1460       } break;
1461       default:
1462         llvm_unreachable("Unimplemented option");
1463       }
1464 
1465       return error;
1466     }
1467 
OptionParsingStarting(ExecutionContext * execution_context)1468     void OptionParsingStarting(ExecutionContext *execution_context) override {
1469       m_class_name.clear();
1470       m_funct_name.clear();
1471       m_short_help.clear();
1472       m_completion_type = eNoCompletion;
1473       m_overwrite_lazy = eLazyBoolCalculate;
1474       m_synchronicity = eScriptedCommandSynchronicitySynchronous;
1475     }
1476 
GetDefinitions()1477     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1478       return llvm::ArrayRef(g_script_add_options);
1479     }
1480 
1481     // Instance variables to hold the values for command options.
1482 
1483     std::string m_class_name;
1484     std::string m_funct_name;
1485     std::string m_short_help;
1486     LazyBool m_overwrite_lazy = eLazyBoolCalculate;
1487     ScriptedCommandSynchronicity m_synchronicity =
1488         eScriptedCommandSynchronicitySynchronous;
1489     CompletionType m_completion_type = eNoCompletion;
1490   };
1491 
IOHandlerActivated(IOHandler & io_handler,bool interactive)1492   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
1493     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
1494     if (output_sp && interactive) {
1495       output_sp->PutCString(g_python_command_instructions);
1496       output_sp->Flush();
1497     }
1498   }
1499 
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)1500   void IOHandlerInputComplete(IOHandler &io_handler,
1501                               std::string &data) override {
1502     StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
1503 
1504     ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1505     if (interpreter) {
1506       StringList lines;
1507       lines.SplitIntoLines(data);
1508       if (lines.GetSize() > 0) {
1509         std::string funct_name_str;
1510         if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
1511           if (funct_name_str.empty()) {
1512             error_sp->Printf("error: unable to obtain a function name, didn't "
1513                              "add python command.\n");
1514             error_sp->Flush();
1515           } else {
1516             // everything should be fine now, let's add this alias
1517 
1518             CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
1519                 m_interpreter, m_cmd_name, funct_name_str, m_short_help,
1520                 m_synchronicity, m_completion_type));
1521             if (!m_container) {
1522               Status error = m_interpreter.AddUserCommand(
1523                   m_cmd_name, command_obj_sp, m_overwrite);
1524               if (error.Fail()) {
1525                 error_sp->Printf("error: unable to add selected command: '%s'",
1526                                  error.AsCString());
1527                 error_sp->Flush();
1528               }
1529             } else {
1530               llvm::Error llvm_error = m_container->LoadUserSubcommand(
1531                   m_cmd_name, command_obj_sp, m_overwrite);
1532               if (llvm_error) {
1533                 error_sp->Printf("error: unable to add selected command: '%s'",
1534                                llvm::toString(std::move(llvm_error)).c_str());
1535                 error_sp->Flush();
1536               }
1537             }
1538           }
1539         } else {
1540           error_sp->Printf(
1541               "error: unable to create function, didn't add python command\n");
1542           error_sp->Flush();
1543         }
1544       } else {
1545         error_sp->Printf("error: empty function, didn't add python command\n");
1546         error_sp->Flush();
1547       }
1548     } else {
1549       error_sp->Printf(
1550           "error: script interpreter missing, didn't add python command\n");
1551       error_sp->Flush();
1552     }
1553 
1554     io_handler.SetIsDone(true);
1555   }
1556 
DoExecute(Args & command,CommandReturnObject & result)1557   void DoExecute(Args &command, CommandReturnObject &result) override {
1558     if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
1559       result.AppendError("only scripting language supported for scripted "
1560                          "commands is currently Python");
1561       return;
1562     }
1563 
1564     if (command.GetArgumentCount() == 0) {
1565       result.AppendError("'command script add' requires at least one argument");
1566       return;
1567     }
1568     // Store the options in case we get multi-line input, also figure out the
1569     // default if not user supplied:
1570     switch (m_options.m_overwrite_lazy) {
1571       case eLazyBoolCalculate:
1572         m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite();
1573         break;
1574       case eLazyBoolYes:
1575         m_overwrite = true;
1576         break;
1577       case eLazyBoolNo:
1578         m_overwrite = false;
1579     }
1580 
1581     Status path_error;
1582     m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath(
1583         command, true, path_error);
1584 
1585     if (path_error.Fail()) {
1586       result.AppendErrorWithFormat("error in command path: %s",
1587                                    path_error.AsCString());
1588       return;
1589     }
1590 
1591     if (!m_container) {
1592       // This is getting inserted into the root of the interpreter.
1593       m_cmd_name = std::string(command[0].ref());
1594     } else {
1595       size_t num_args = command.GetArgumentCount();
1596       m_cmd_name = std::string(command[num_args - 1].ref());
1597     }
1598 
1599     m_short_help.assign(m_options.m_short_help);
1600     m_synchronicity = m_options.m_synchronicity;
1601     m_completion_type = m_options.m_completion_type;
1602 
1603     // Handle the case where we prompt for the script code first:
1604     if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) {
1605       m_interpreter.GetPythonCommandsFromIOHandler("     ", // Prompt
1606                                                    *this);  // IOHandlerDelegate
1607       return;
1608     }
1609 
1610     CommandObjectSP new_cmd_sp;
1611     if (m_options.m_class_name.empty()) {
1612       new_cmd_sp.reset(new CommandObjectPythonFunction(
1613           m_interpreter, m_cmd_name, m_options.m_funct_name,
1614           m_options.m_short_help, m_synchronicity, m_completion_type));
1615     } else {
1616       ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1617       if (!interpreter) {
1618         result.AppendError("cannot find ScriptInterpreter");
1619         return;
1620       }
1621 
1622       auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
1623           m_options.m_class_name.c_str());
1624       if (!cmd_obj_sp) {
1625         result.AppendErrorWithFormatv("cannot create helper object for: "
1626                                       "'{0}'", m_options.m_class_name);
1627         return;
1628       }
1629 
1630       new_cmd_sp.reset(new CommandObjectScriptingObject(
1631           m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity,
1632           m_completion_type));
1633     }
1634 
1635     // Assume we're going to succeed...
1636     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1637     if (!m_container) {
1638       Status add_error =
1639           m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite);
1640       if (add_error.Fail())
1641         result.AppendErrorWithFormat("cannot add command: %s",
1642                                      add_error.AsCString());
1643     } else {
1644       llvm::Error llvm_error =
1645           m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite);
1646       if (llvm_error)
1647         result.AppendErrorWithFormat("cannot add command: %s",
1648                                      llvm::toString(std::move(llvm_error)).c_str());
1649     }
1650   }
1651 
1652   CommandOptions m_options;
1653   std::string m_cmd_name;
1654   CommandObjectMultiword *m_container = nullptr;
1655   std::string m_short_help;
1656   bool m_overwrite = false;
1657   ScriptedCommandSynchronicity m_synchronicity =
1658       eScriptedCommandSynchronicitySynchronous;
1659   CompletionType m_completion_type = eNoCompletion;
1660 };
1661 
1662 // CommandObjectCommandsScriptList
1663 
1664 class CommandObjectCommandsScriptList : public CommandObjectParsed {
1665 public:
CommandObjectCommandsScriptList(CommandInterpreter & interpreter)1666   CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
1667       : CommandObjectParsed(interpreter, "command script list",
1668                             "List defined top-level scripted commands.",
1669                             nullptr) {}
1670 
1671   ~CommandObjectCommandsScriptList() override = default;
1672 
DoExecute(Args & command,CommandReturnObject & result)1673   void DoExecute(Args &command, CommandReturnObject &result) override {
1674     m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
1675 
1676     result.SetStatus(eReturnStatusSuccessFinishResult);
1677   }
1678 };
1679 
1680 // CommandObjectCommandsScriptClear
1681 
1682 class CommandObjectCommandsScriptClear : public CommandObjectParsed {
1683 public:
CommandObjectCommandsScriptClear(CommandInterpreter & interpreter)1684   CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
1685       : CommandObjectParsed(interpreter, "command script clear",
1686                             "Delete all scripted commands.", nullptr) {}
1687 
1688   ~CommandObjectCommandsScriptClear() override = default;
1689 
1690 protected:
DoExecute(Args & command,CommandReturnObject & result)1691   void DoExecute(Args &command, CommandReturnObject &result) override {
1692     m_interpreter.RemoveAllUser();
1693 
1694     result.SetStatus(eReturnStatusSuccessFinishResult);
1695   }
1696 };
1697 
1698 // CommandObjectCommandsScriptDelete
1699 
1700 class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
1701 public:
CommandObjectCommandsScriptDelete(CommandInterpreter & interpreter)1702   CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
1703       : CommandObjectParsed(
1704             interpreter, "command script delete",
1705             "Delete a scripted command by specifying the path to the command.",
1706             nullptr) {
1707     CommandArgumentEntry arg1;
1708     CommandArgumentData cmd_arg;
1709 
1710     // This is a list of command names forming the path to the command
1711     // to be deleted.
1712     cmd_arg.arg_type = eArgTypeCommand;
1713     cmd_arg.arg_repetition = eArgRepeatPlus;
1714 
1715     // There is only one variant this argument could be; put it into the
1716     // argument entry.
1717     arg1.push_back(cmd_arg);
1718 
1719     // Push the data for the first argument into the m_arguments vector.
1720     m_arguments.push_back(arg1);
1721   }
1722 
1723   ~CommandObjectCommandsScriptDelete() override = default;
1724 
1725   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1726   HandleArgumentCompletion(CompletionRequest &request,
1727                            OptionElementVector &opt_element_vector) override {
1728     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
1729         m_interpreter, request, opt_element_vector);
1730   }
1731 
1732 protected:
DoExecute(Args & command,CommandReturnObject & result)1733   void DoExecute(Args &command, CommandReturnObject &result) override {
1734 
1735     llvm::StringRef root_cmd = command[0].ref();
1736     size_t num_args = command.GetArgumentCount();
1737 
1738     if (root_cmd.empty()) {
1739       result.AppendErrorWithFormat("empty root command name");
1740       return;
1741     }
1742     if (!m_interpreter.HasUserCommands() &&
1743         !m_interpreter.HasUserMultiwordCommands()) {
1744       result.AppendErrorWithFormat("can only delete user defined commands, "
1745                                    "but no user defined commands found");
1746       return;
1747     }
1748 
1749     CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd);
1750     if (!cmd_sp) {
1751       result.AppendErrorWithFormat("command '%s' not found.",
1752                                    command[0].c_str());
1753       return;
1754     }
1755     if (!cmd_sp->IsUserCommand()) {
1756       result.AppendErrorWithFormat("command '%s' is not a user command.",
1757                                    command[0].c_str());
1758       return;
1759     }
1760     if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) {
1761       result.AppendErrorWithFormat("command '%s' is a multi-word command.\n "
1762                                    "Delete with \"command container delete\"",
1763                                    command[0].c_str());
1764       return;
1765     }
1766 
1767     if (command.GetArgumentCount() == 1) {
1768       m_interpreter.RemoveUser(root_cmd);
1769       result.SetStatus(eReturnStatusSuccessFinishResult);
1770       return;
1771     }
1772     // We're deleting a command from a multiword command.  Verify the command
1773     // path:
1774     Status error;
1775     CommandObjectMultiword *container =
1776         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
1777                                                            error);
1778     if (error.Fail()) {
1779       result.AppendErrorWithFormat("could not resolve command path: %s",
1780                                    error.AsCString());
1781       return;
1782     }
1783     if (!container) {
1784       // This means that command only had a leaf command, so the container is
1785       // the root.  That should have been handled above.
1786       result.AppendErrorWithFormat("could not find a container for '%s'",
1787                                    command[0].c_str());
1788       return;
1789     }
1790     const char *leaf_cmd = command[num_args - 1].c_str();
1791     llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd,
1792                                             /* multiword not okay */ false);
1793     if (llvm_error) {
1794       result.AppendErrorWithFormat("could not delete command '%s': %s",
1795                                    leaf_cmd,
1796                                    llvm::toString(std::move(llvm_error)).c_str());
1797       return;
1798     }
1799 
1800     Stream &out_stream = result.GetOutputStream();
1801 
1802     out_stream << "Deleted command:";
1803     for (size_t idx = 0; idx < num_args; idx++) {
1804       out_stream << ' ';
1805       out_stream << command[idx].c_str();
1806     }
1807     out_stream << '\n';
1808     result.SetStatus(eReturnStatusSuccessFinishResult);
1809   }
1810 };
1811 
1812 #pragma mark CommandObjectMultiwordCommandsScript
1813 
1814 // CommandObjectMultiwordCommandsScript
1815 
1816 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
1817 public:
CommandObjectMultiwordCommandsScript(CommandInterpreter & interpreter)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:
CommandObjectCommandsContainerAdd(CommandInterpreter & interpreter)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 
GetOptions()1873   Options *GetOptions() override { return &m_options; }
1874 
1875   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1876   HandleArgumentCompletion(CompletionRequest &request,
1877                            OptionElementVector &opt_element_vector) override {
1878     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
1879         m_interpreter, request, opt_element_vector);
1880   }
1881 
1882 protected:
1883   class CommandOptions : public Options {
1884   public:
1885     CommandOptions() = default;
1886 
1887     ~CommandOptions() override = default;
1888 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)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 
OptionParsingStarting(ExecutionContext * execution_context)1913     void OptionParsingStarting(ExecutionContext *execution_context) override {
1914       m_short_help.clear();
1915       m_long_help.clear();
1916       m_overwrite = false;
1917     }
1918 
GetDefinitions()1919     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1920       return llvm::ArrayRef(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   };
DoExecute(Args & command,CommandReturnObject & result)1929   void 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;
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;
1950       }
1951       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1952       return;
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;
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;
1977     }
1978 
1979     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1980   }
1981 
1982 private:
1983   CommandOptions m_options;
1984 };
1985 
1986 #define LLDB_OPTIONS_multiword_delete
1987 #include "CommandOptions.inc"
1988 class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
1989 public:
CommandObjectCommandsContainerDelete(CommandInterpreter & interpreter)1990   CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter)
1991       : CommandObjectParsed(
1992             interpreter, "command container delete",
1993             "Delete a container command previously added to "
1994             "lldb.",
1995             "command container delete [[path1] ...] container-cmd") {
1996     CommandArgumentEntry arg1;
1997     CommandArgumentData cmd_arg;
1998 
1999     // This is one or more command names, which form the path to the command
2000     // you want to add.
2001     cmd_arg.arg_type = eArgTypeCommand;
2002     cmd_arg.arg_repetition = eArgRepeatPlus;
2003 
2004     // There is only one variant this argument could be; put it into the
2005     // argument entry.
2006     arg1.push_back(cmd_arg);
2007 
2008     // Push the data for the first argument into the m_arguments vector.
2009     m_arguments.push_back(arg1);
2010   }
2011 
2012   ~CommandObjectCommandsContainerDelete() override = default;
2013 
2014   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2015   HandleArgumentCompletion(CompletionRequest &request,
2016                            OptionElementVector &opt_element_vector) override {
2017     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2018         m_interpreter, request, opt_element_vector);
2019   }
2020 
2021 protected:
DoExecute(Args & command,CommandReturnObject & result)2022   void DoExecute(Args &command, CommandReturnObject &result) override {
2023     size_t num_args = command.GetArgumentCount();
2024 
2025     if (num_args == 0) {
2026       result.AppendError("No command was specified.");
2027       return;
2028     }
2029 
2030     if (num_args == 1) {
2031       // We're removing a root command, so we need to delete it from the
2032       // interpreter.
2033       const char *cmd_name = command.GetArgumentAtIndex(0);
2034       // Let's do a little more work here so we can do better error reporting.
2035       CommandInterpreter &interp = GetCommandInterpreter();
2036       CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name);
2037       if (!cmd_sp) {
2038         result.AppendErrorWithFormat("container command %s doesn't exist.",
2039                                      cmd_name);
2040         return;
2041       }
2042       if (!cmd_sp->IsUserCommand()) {
2043         result.AppendErrorWithFormat(
2044             "container command %s is not a user command", cmd_name);
2045         return;
2046       }
2047       if (!cmd_sp->GetAsMultiwordCommand()) {
2048         result.AppendErrorWithFormat("command %s is not a container command",
2049                                      cmd_name);
2050         return;
2051       }
2052 
2053       bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name);
2054       if (!did_remove) {
2055         result.AppendErrorWithFormat("error removing command %s.", cmd_name);
2056         return;
2057       }
2058 
2059       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2060       return;
2061     }
2062 
2063     // We're removing a subcommand, first find the subcommand's owner:
2064     Status path_error;
2065     CommandObjectMultiword *container =
2066         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2067                                                            path_error);
2068 
2069     if (!container) {
2070       result.AppendErrorWithFormat("error removing container command: %s",
2071                                    path_error.AsCString());
2072       return;
2073     }
2074     const char *leaf = command.GetArgumentAtIndex(num_args - 1);
2075     llvm::Error llvm_error =
2076         container->RemoveUserSubcommand(leaf, /* multiword okay */ true);
2077     if (llvm_error) {
2078       result.AppendErrorWithFormat("error removing container command: %s",
2079                                    llvm::toString(std::move(llvm_error)).c_str());
2080       return;
2081     }
2082     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2083   }
2084 };
2085 
2086 class CommandObjectCommandContainer : public CommandObjectMultiword {
2087 public:
CommandObjectCommandContainer(CommandInterpreter & interpreter)2088   CommandObjectCommandContainer(CommandInterpreter &interpreter)
2089       : CommandObjectMultiword(
2090             interpreter, "command container",
2091             "Commands for adding container commands to lldb.  "
2092             "Container commands are containers for other commands.  You can "
2093             "add nested container commands by specifying a command path, "
2094             "but you can't add commands into the built-in command hierarchy.",
2095             "command container <subcommand> [<subcommand-options>]") {
2096     LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd(
2097                               interpreter)));
2098     LoadSubCommand(
2099         "delete",
2100         CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter)));
2101   }
2102 
2103   ~CommandObjectCommandContainer() override = default;
2104 };
2105 
2106 #pragma mark CommandObjectMultiwordCommands
2107 
2108 // CommandObjectMultiwordCommands
2109 
CommandObjectMultiwordCommands(CommandInterpreter & interpreter)2110 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
2111     CommandInterpreter &interpreter)
2112     : CommandObjectMultiword(interpreter, "command",
2113                              "Commands for managing custom LLDB commands.",
2114                              "command <subcommand> [<subcommand-options>]") {
2115   LoadSubCommand("source",
2116                  CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
2117   LoadSubCommand("alias",
2118                  CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
2119   LoadSubCommand("unalias", CommandObjectSP(
2120                                 new CommandObjectCommandsUnalias(interpreter)));
2121   LoadSubCommand("delete",
2122                  CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
2123   LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer(
2124                                   interpreter)));
2125   LoadSubCommand(
2126       "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
2127   LoadSubCommand(
2128       "script",
2129       CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
2130 }
2131 
2132 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
2133