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