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