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