xref: /freebsd/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/Host/StreamFile.h"
15 #include "lldb/Interpreter/CommandHistory.h"
16 #include "lldb/Interpreter/CommandInterpreter.h"
17 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
18 #include "lldb/Interpreter/CommandReturnObject.h"
19 #include "lldb/Interpreter/OptionArgParser.h"
20 #include "lldb/Interpreter/OptionValueBoolean.h"
21 #include "lldb/Interpreter/OptionValueString.h"
22 #include "lldb/Interpreter/OptionValueUInt64.h"
23 #include "lldb/Interpreter/Options.h"
24 #include "lldb/Interpreter/ScriptInterpreter.h"
25 #include "lldb/Utility/Args.h"
26 #include "lldb/Utility/StringList.h"
27 #include "llvm/ADT/StringRef.h"
28 #include <optional>
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 // CommandObjectCommandsSource
34 
35 #define LLDB_OPTIONS_source
36 #include "CommandOptions.inc"
37 
38 class CommandObjectCommandsSource : public CommandObjectParsed {
39 public:
CommandObjectCommandsSource(CommandInterpreter & interpreter)40   CommandObjectCommandsSource(CommandInterpreter &interpreter)
41       : CommandObjectParsed(
42             interpreter, "command source",
43             "Read and execute LLDB commands from the file <filename>.",
44             nullptr) {
45     AddSimpleArgumentList(eArgTypeFilename);
46   }
47 
48   ~CommandObjectCommandsSource() override = default;
49 
GetRepeatCommand(Args & current_command_args,uint32_t index)50   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
51                                               uint32_t index) override {
52     return std::string("");
53   }
54 
GetOptions()55   Options *GetOptions() override { return &m_options; }
56 
57 protected:
58   class CommandOptions : public Options {
59   public:
CommandOptions()60     CommandOptions()
61         : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true),
62           m_cmd_relative_to_command_file(false) {}
63 
64     ~CommandOptions() override = default;
65 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)66     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
67                           ExecutionContext *execution_context) override {
68       Status error;
69       const int short_option = m_getopt_table[option_idx].val;
70 
71       switch (short_option) {
72       case 'e':
73         error = m_stop_on_error.SetValueFromString(option_arg);
74         break;
75 
76       case 'c':
77         error = m_stop_on_continue.SetValueFromString(option_arg);
78         break;
79 
80       case 'C':
81         m_cmd_relative_to_command_file = true;
82         break;
83 
84       case 's':
85         error = m_silent_run.SetValueFromString(option_arg);
86         break;
87 
88       default:
89         llvm_unreachable("Unimplemented option");
90       }
91 
92       return error;
93     }
94 
OptionParsingStarting(ExecutionContext * execution_context)95     void OptionParsingStarting(ExecutionContext *execution_context) override {
96       m_stop_on_error.Clear();
97       m_silent_run.Clear();
98       m_stop_on_continue.Clear();
99       m_cmd_relative_to_command_file.Clear();
100     }
101 
GetDefinitions()102     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
103       return llvm::ArrayRef(g_source_options);
104     }
105 
106     // Instance variables to hold the values for command options.
107 
108     OptionValueBoolean m_stop_on_error;
109     OptionValueBoolean m_silent_run;
110     OptionValueBoolean m_stop_on_continue;
111     OptionValueBoolean m_cmd_relative_to_command_file;
112   };
113 
DoExecute(Args & command,CommandReturnObject & result)114   void DoExecute(Args &command, CommandReturnObject &result) override {
115     if (command.GetArgumentCount() != 1) {
116       result.AppendErrorWithFormat(
117           "'%s' takes exactly one executable filename argument.\n",
118           GetCommandName().str().c_str());
119       return;
120     }
121 
122     FileSpec source_dir = {};
123     if (m_options.m_cmd_relative_to_command_file) {
124       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
125       if (!source_dir) {
126         result.AppendError("command source -C can only be specified "
127                            "from a command file");
128         result.SetStatus(eReturnStatusFailed);
129         return;
130       }
131     }
132 
133     FileSpec cmd_file(command[0].ref());
134     if (source_dir) {
135       // Prepend the source_dir to the cmd_file path:
136       if (!cmd_file.IsRelative()) {
137         result.AppendError("command source -C can only be used "
138                            "with a relative path.");
139         result.SetStatus(eReturnStatusFailed);
140         return;
141       }
142       cmd_file.MakeAbsolute(source_dir);
143     }
144 
145     FileSystem::Instance().Resolve(cmd_file);
146 
147     CommandInterpreterRunOptions options;
148     // If any options were set, then use them
149     if (m_options.m_stop_on_error.OptionWasSet() ||
150         m_options.m_silent_run.OptionWasSet() ||
151         m_options.m_stop_on_continue.OptionWasSet()) {
152       if (m_options.m_stop_on_continue.OptionWasSet())
153         options.SetStopOnContinue(
154             m_options.m_stop_on_continue.GetCurrentValue());
155 
156       if (m_options.m_stop_on_error.OptionWasSet())
157         options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
158 
159       // Individual silent setting is override for global command echo settings.
160       if (m_options.m_silent_run.GetCurrentValue()) {
161         options.SetSilent(true);
162       } else {
163         options.SetPrintResults(true);
164         options.SetPrintErrors(true);
165         options.SetEchoCommands(m_interpreter.GetEchoCommands());
166         options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
167       }
168     }
169 
170     m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
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, exe_ctx, result, internal_dict):\n";
186 
187 class CommandObjectCommandsAlias : public CommandObjectRaw {
188 protected:
189   class CommandOptions : public OptionGroup {
190   public:
191     CommandOptions() = default;
192 
193     ~CommandOptions() override = default;
194 
GetDefinitions()195     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
196       return llvm::ArrayRef(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.Append(&m_command_options);
244     m_option_group.Finalize();
245 
246     SetHelpLong(
247         "'alias' allows the user to create a short-cut or abbreviation for long \
248 commands, multi-word commands, and commands that take particular options.  \
249 Below are some simple examples of how one might use the 'alias' command:"
250         R"(
251 
252 (lldb) command alias sc script
253 
254     Creates the abbreviation 'sc' for the 'script' command.
255 
256 (lldb) command alias bp breakpoint
257 
258 )"
259         "    Creates the abbreviation 'bp' for the 'breakpoint' command.  Since \
260 breakpoint commands are two-word commands, the user would still need to \
261 enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
262         R"(
263 
264 (lldb) command alias bpl breakpoint list
265 
266     Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
267 
268 )"
269         "An alias can include some options for the command, with the values either \
270 filled in at the time the alias is created, or specified as positional \
271 arguments, to be filled in when the alias is invoked.  The following example \
272 shows how to create aliases with options:"
273         R"(
274 
275 (lldb) command alias bfl breakpoint set -f %1 -l %2
276 
277 )"
278         "    Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
279 options already part of the alias.  So if the user wants to set a breakpoint \
280 by file and line without explicitly having to use the -f and -l options, the \
281 user can now use 'bfl' instead.  The '%1' and '%2' are positional placeholders \
282 for the actual arguments that will be passed when the alias command is used.  \
283 The number in the placeholder refers to the position/order the actual value \
284 occupies when the alias is used.  All the occurrences of '%1' in the alias \
285 will be replaced with the first argument, all the occurrences of '%2' in the \
286 alias will be replaced with the second argument, and so on.  This also allows \
287 actual arguments to be used multiple times within an alias (see 'process \
288 launch' example below)."
289         R"(
290 
291 )"
292         "Note: the positional arguments must substitute as whole words in the resultant \
293 command, so you can't at present do something like this to append the file extension \
294 \".cpp\":"
295         R"(
296 
297 (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
298 
299 )"
300         "For more complex aliasing, use the \"command regex\" command instead.  In the \
301 'bfl' case above, the actual file value will be filled in with the first argument \
302 following 'bfl' and the actual line number value will be filled in with the second \
303 argument.  The user would use this alias as follows:"
304         R"(
305 
306 (lldb) command alias bfl breakpoint set -f %1 -l %2
307 (lldb) bfl my-file.c 137
308 
309 This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
310 
311 Another example:
312 
313 (lldb) command alias pltty process launch -s -o %1 -e %1
314 (lldb) pltty /dev/tty0
315 
316     Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
317 
318 )"
319         "If the user always wanted to pass the same value to a particular option, the \
320 alias could be defined with that value directly in the alias as a constant, \
321 rather than using a positional placeholder:"
322         R"(
323 
324 (lldb) command alias bl3 breakpoint set -f %1 -l 3
325 
326     Always sets a breakpoint on line 3 of whatever file is indicated.
327 
328 )"
329 
330         "If the alias abbreviation or the full alias command collides with another \
331 existing command, the command resolver will prefer to use the alias over any \
332 other command as far as there is only one alias command match.");
333 
334     CommandArgumentEntry arg1;
335     CommandArgumentEntry arg2;
336     CommandArgumentEntry arg3;
337     CommandArgumentData alias_arg;
338     CommandArgumentData cmd_arg;
339     CommandArgumentData options_arg;
340 
341     // Define the first (and only) variant of this arg.
342     alias_arg.arg_type = eArgTypeAliasName;
343     alias_arg.arg_repetition = eArgRepeatPlain;
344 
345     // There is only one variant this argument could be; put it into the
346     // argument entry.
347     arg1.push_back(alias_arg);
348 
349     // Define the first (and only) variant of this arg.
350     cmd_arg.arg_type = eArgTypeCommandName;
351     cmd_arg.arg_repetition = eArgRepeatPlain;
352 
353     // There is only one variant this argument could be; put it into the
354     // argument entry.
355     arg2.push_back(cmd_arg);
356 
357     // Define the first (and only) variant of this arg.
358     options_arg.arg_type = eArgTypeAliasOptions;
359     options_arg.arg_repetition = eArgRepeatOptional;
360 
361     // There is only one variant this argument could be; put it into the
362     // argument entry.
363     arg3.push_back(options_arg);
364 
365     // Push the data for the first argument into the m_arguments vector.
366     m_arguments.push_back(arg1);
367     m_arguments.push_back(arg2);
368     m_arguments.push_back(arg3);
369   }
370 
371   ~CommandObjectCommandsAlias() override = default;
372 
373 protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)374   void DoExecute(llvm::StringRef raw_command_line,
375                  CommandReturnObject &result) override {
376     if (raw_command_line.empty()) {
377       result.AppendError("'command alias' requires at least two arguments");
378       return;
379     }
380 
381     ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
382     m_option_group.NotifyOptionParsingStarting(&exe_ctx);
383 
384     OptionsWithRaw args_with_suffix(raw_command_line);
385 
386     if (args_with_suffix.HasArgs())
387       if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result,
388                                  m_option_group, exe_ctx))
389         return;
390 
391     llvm::StringRef raw_command_string = args_with_suffix.GetRawPart();
392     Args args(raw_command_string);
393 
394     if (args.GetArgumentCount() < 2) {
395       result.AppendError("'command alias' requires at least two arguments");
396       return;
397     }
398 
399     // Get the alias command.
400 
401     auto alias_command = args[0].ref();
402     if (alias_command.starts_with("-")) {
403       result.AppendError("aliases starting with a dash are not supported");
404       if (alias_command == "--help" || alias_command == "--long-help") {
405         result.AppendWarning("if trying to pass options to 'command alias' add "
406                              "a -- at the end of the options");
407       }
408       return;
409     }
410 
411     // Strip the new alias name off 'raw_command_string'  (leave it on args,
412     // which gets passed to 'Execute', which does the stripping itself.
413     size_t pos = raw_command_string.find(alias_command);
414     if (pos == 0) {
415       raw_command_string = raw_command_string.substr(alias_command.size());
416       pos = raw_command_string.find_first_not_of(' ');
417       if ((pos != std::string::npos) && (pos > 0))
418         raw_command_string = raw_command_string.substr(pos);
419     } else {
420       result.AppendError("Error parsing command string.  No alias created.");
421       return;
422     }
423 
424     // Verify that the command is alias-able.
425     if (m_interpreter.CommandExists(alias_command)) {
426       result.AppendErrorWithFormat(
427           "'%s' is a permanent debugger command and cannot be redefined.\n",
428           args[0].c_str());
429       return;
430     }
431 
432     if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
433       result.AppendErrorWithFormat(
434           "'%s' is a user container command and cannot be overwritten.\n"
435           "Delete it first with 'command container delete'\n",
436           args[0].c_str());
437       return;
438     }
439 
440     // Get CommandObject that is being aliased. The command name is read from
441     // the front of raw_command_string. raw_command_string is returned with the
442     // name of the command object stripped off the front.
443     llvm::StringRef original_raw_command_string = raw_command_string;
444     CommandObject *cmd_obj =
445         m_interpreter.GetCommandObjectForCommand(raw_command_string);
446 
447     if (!cmd_obj) {
448       result.AppendErrorWithFormat("invalid command given to 'command alias'. "
449                                    "'%s' does not begin with a valid command."
450                                    "  No alias created.",
451                                    original_raw_command_string.str().c_str());
452     } else if (!cmd_obj->WantsRawCommandString()) {
453       // Note that args was initialized with the original command, and has not
454       // been updated to this point. Therefore can we pass it to the version of
455       // Execute that does not need/expect raw input in the alias.
456       HandleAliasingNormalCommand(args, result);
457     } else {
458       HandleAliasingRawCommand(alias_command, raw_command_string, *cmd_obj,
459                                result);
460     }
461   }
462 
HandleAliasingRawCommand(llvm::StringRef alias_command,llvm::StringRef raw_command_string,CommandObject & cmd_obj,CommandReturnObject & result)463   bool HandleAliasingRawCommand(llvm::StringRef alias_command,
464                                 llvm::StringRef raw_command_string,
465                                 CommandObject &cmd_obj,
466                                 CommandReturnObject &result) {
467     // Verify & handle any options/arguments passed to the alias command
468 
469     OptionArgVectorSP option_arg_vector_sp =
470         OptionArgVectorSP(new OptionArgVector);
471 
472     const bool include_aliases = true;
473     // Look up the command using command's name first.  This is to resolve
474     // aliases when you are making nested aliases.  But if you don't find
475     // it that way, then it wasn't an alias and we can just use the object
476     // we were passed in.
477     CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact(
478             cmd_obj.GetCommandName(), include_aliases);
479     if (!cmd_obj_sp)
480       cmd_obj_sp = cmd_obj.shared_from_this();
481 
482     if (m_interpreter.AliasExists(alias_command) ||
483         m_interpreter.UserCommandExists(alias_command)) {
484       result.AppendWarningWithFormat(
485           "Overwriting existing definition for '%s'.\n",
486           alias_command.str().c_str());
487     }
488     if (CommandAlias *alias = m_interpreter.AddAlias(
489             alias_command, cmd_obj_sp, raw_command_string)) {
490       if (m_command_options.m_help.OptionWasSet())
491         alias->SetHelp(m_command_options.m_help.GetCurrentValue());
492       if (m_command_options.m_long_help.OptionWasSet())
493         alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
494       result.SetStatus(eReturnStatusSuccessFinishNoResult);
495     } else {
496       result.AppendError("Unable to create requested alias.\n");
497     }
498     return result.Succeeded();
499   }
500 
HandleAliasingNormalCommand(Args & args,CommandReturnObject & result)501   bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
502     size_t argc = args.GetArgumentCount();
503 
504     if (argc < 2) {
505       result.AppendError("'command alias' requires at least two arguments");
506       return false;
507     }
508 
509     // Save these in std::strings since we're going to shift them off.
510     const std::string alias_command(std::string(args[0].ref()));
511     const std::string actual_command(std::string(args[1].ref()));
512 
513     args.Shift(); // Shift the alias command word off the argument vector.
514     args.Shift(); // Shift the old command word off the argument vector.
515 
516     // Verify that the command is alias'able, and get the appropriate command
517     // object.
518 
519     if (m_interpreter.CommandExists(alias_command)) {
520       result.AppendErrorWithFormat(
521           "'%s' is a permanent debugger command and cannot be redefined.\n",
522           alias_command.c_str());
523       return false;
524     }
525 
526     if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
527       result.AppendErrorWithFormat(
528           "'%s' is user container command and cannot be overwritten.\n"
529           "Delete it first with 'command container delete'",
530           alias_command.c_str());
531       return false;
532     }
533 
534     CommandObjectSP command_obj_sp(
535         m_interpreter.GetCommandSPExact(actual_command, true));
536     CommandObjectSP subcommand_obj_sp;
537     bool use_subcommand = false;
538     if (!command_obj_sp) {
539       result.AppendErrorWithFormat("'%s' is not an existing command.\n",
540                                    actual_command.c_str());
541       return false;
542     }
543     CommandObject *cmd_obj = command_obj_sp.get();
544     CommandObject *sub_cmd_obj = nullptr;
545     OptionArgVectorSP option_arg_vector_sp =
546         OptionArgVectorSP(new OptionArgVector);
547 
548     while (cmd_obj->IsMultiwordObject() && !args.empty()) {
549       auto sub_command = args[0].ref();
550       assert(!sub_command.empty());
551       subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
552       if (!subcommand_obj_sp) {
553         result.AppendErrorWithFormat(
554             "'%s' is not a valid sub-command of '%s'.  "
555             "Unable to create alias.\n",
556             args[0].c_str(), actual_command.c_str());
557         return false;
558       }
559 
560       sub_cmd_obj = subcommand_obj_sp.get();
561       use_subcommand = true;
562       args.Shift(); // Shift the sub_command word off the argument vector.
563       cmd_obj = sub_cmd_obj;
564     }
565 
566     // Verify & handle any options/arguments passed to the alias command
567 
568     std::string args_string;
569 
570     if (!args.empty()) {
571       CommandObjectSP tmp_sp =
572           m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName());
573       if (use_subcommand)
574         tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName());
575 
576       args.GetCommandString(args_string);
577     }
578 
579     if (m_interpreter.AliasExists(alias_command) ||
580         m_interpreter.UserCommandExists(alias_command)) {
581       result.AppendWarningWithFormat(
582           "Overwriting existing definition for '%s'.\n", alias_command.c_str());
583     }
584 
585     if (CommandAlias *alias = m_interpreter.AddAlias(
586             alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
587             args_string)) {
588       if (m_command_options.m_help.OptionWasSet())
589         alias->SetHelp(m_command_options.m_help.GetCurrentValue());
590       if (m_command_options.m_long_help.OptionWasSet())
591         alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
592       result.SetStatus(eReturnStatusSuccessFinishNoResult);
593     } else {
594       result.AppendError("Unable to create requested alias.\n");
595       return false;
596     }
597 
598     return result.Succeeded();
599   }
600 };
601 
602 #pragma mark CommandObjectCommandsUnalias
603 // CommandObjectCommandsUnalias
604 
605 class CommandObjectCommandsUnalias : public CommandObjectParsed {
606 public:
CommandObjectCommandsUnalias(CommandInterpreter & interpreter)607   CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
608       : CommandObjectParsed(
609             interpreter, "command unalias",
610             "Delete one or more custom commands defined by 'command alias'.",
611             nullptr) {
612     AddSimpleArgumentList(eArgTypeAliasName);
613   }
614 
615   ~CommandObjectCommandsUnalias() override = default;
616 
617   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)618   HandleArgumentCompletion(CompletionRequest &request,
619                            OptionElementVector &opt_element_vector) override {
620     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
621       return;
622 
623     for (const auto &ent : m_interpreter.GetAliases()) {
624       request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
625     }
626   }
627 
628 protected:
DoExecute(Args & args,CommandReturnObject & result)629   void DoExecute(Args &args, CommandReturnObject &result) override {
630     CommandObject::CommandMap::iterator pos;
631     CommandObject *cmd_obj;
632 
633     if (args.empty()) {
634       result.AppendError("must call 'unalias' with a valid alias");
635       return;
636     }
637 
638     auto command_name = args[0].ref();
639     cmd_obj = m_interpreter.GetCommandObject(command_name);
640     if (!cmd_obj) {
641       result.AppendErrorWithFormat(
642           "'%s' is not a known command.\nTry 'help' to see a "
643           "current list of commands.\n",
644           args[0].c_str());
645       return;
646     }
647 
648     if (m_interpreter.CommandExists(command_name)) {
649       if (cmd_obj->IsRemovable()) {
650         result.AppendErrorWithFormat(
651             "'%s' is not an alias, it is a debugger command which can be "
652             "removed using the 'command delete' command.\n",
653             args[0].c_str());
654       } else {
655         result.AppendErrorWithFormat(
656             "'%s' is a permanent debugger command and cannot be removed.\n",
657             args[0].c_str());
658       }
659       return;
660     }
661 
662     if (!m_interpreter.RemoveAlias(command_name)) {
663       if (m_interpreter.AliasExists(command_name))
664         result.AppendErrorWithFormat(
665             "Error occurred while attempting to unalias '%s'.\n",
666             args[0].c_str());
667       else
668         result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
669                                      args[0].c_str());
670       return;
671     }
672 
673     result.SetStatus(eReturnStatusSuccessFinishNoResult);
674   }
675 };
676 
677 #pragma mark CommandObjectCommandsDelete
678 // CommandObjectCommandsDelete
679 
680 class CommandObjectCommandsDelete : public CommandObjectParsed {
681 public:
CommandObjectCommandsDelete(CommandInterpreter & interpreter)682   CommandObjectCommandsDelete(CommandInterpreter &interpreter)
683       : CommandObjectParsed(
684             interpreter, "command delete",
685             "Delete one or more custom commands defined by 'command regex'.",
686             nullptr) {
687     AddSimpleArgumentList(eArgTypeCommandName);
688   }
689 
690   ~CommandObjectCommandsDelete() override = default;
691 
692   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)693   HandleArgumentCompletion(CompletionRequest &request,
694                            OptionElementVector &opt_element_vector) override {
695     if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
696       return;
697 
698     for (const auto &ent : m_interpreter.GetCommands()) {
699       if (ent.second->IsRemovable())
700         request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
701     }
702   }
703 
704 protected:
DoExecute(Args & args,CommandReturnObject & result)705   void DoExecute(Args &args, CommandReturnObject &result) override {
706     CommandObject::CommandMap::iterator pos;
707 
708     if (args.empty()) {
709       result.AppendErrorWithFormat("must call '%s' with one or more valid user "
710                                    "defined regular expression command names",
711                                    GetCommandName().str().c_str());
712       return;
713     }
714 
715     auto command_name = args[0].ref();
716     if (!m_interpreter.CommandExists(command_name)) {
717       StreamString error_msg_stream;
718       const bool generate_upropos = true;
719       const bool generate_type_lookup = false;
720       CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
721           &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
722           generate_upropos, generate_type_lookup);
723       result.AppendError(error_msg_stream.GetString());
724       return;
725     }
726 
727     if (!m_interpreter.RemoveCommand(command_name)) {
728       result.AppendErrorWithFormat(
729           "'%s' is a permanent debugger command and cannot be removed.\n",
730           args[0].c_str());
731       return;
732     }
733 
734     result.SetStatus(eReturnStatusSuccessFinishNoResult);
735   }
736 };
737 
738 // CommandObjectCommandsAddRegex
739 
740 #define LLDB_OPTIONS_regex
741 #include "CommandOptions.inc"
742 
743 #pragma mark CommandObjectCommandsAddRegex
744 
745 class CommandObjectCommandsAddRegex : public CommandObjectParsed,
746                                       public IOHandlerDelegateMultiline {
747 public:
CommandObjectCommandsAddRegex(CommandInterpreter & interpreter)748   CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
749       : CommandObjectParsed(
750             interpreter, "command regex",
751             "Define a custom command in terms of "
752             "existing commands by matching "
753             "regular expressions.",
754             "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
755         IOHandlerDelegateMultiline("",
756                                    IOHandlerDelegate::Completion::LLDBCommand) {
757     SetHelpLong(
758         R"(
759 )"
760         "This command allows the user to create powerful regular expression commands \
761 with substitutions. The regular expressions and substitutions are specified \
762 using the regular expression substitution format of:"
763         R"(
764 
765     s/<regex>/<subst>/
766 
767 )"
768         "<regex> is a regular expression that can use parenthesis to capture regular \
769 expression input and substitute the captured matches in the output using %1 \
770 for the first match, %2 for the second, and so on."
771         R"(
772 
773 )"
774         "The regular expressions can all be specified on the command line if more than \
775 one argument is provided. If just the command name is provided on the command \
776 line, then the regular expressions and substitutions can be entered on separate \
777 lines, followed by an empty line to terminate the command definition."
778         R"(
779 
780 EXAMPLES
781 
782 )"
783         "The following example will define a regular expression command named 'f' that \
784 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
785 a number follows 'f':"
786         R"(
787 
788     (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
789     AddSimpleArgumentList(eArgTypeSEDStylePair, eArgRepeatOptional);
790   }
791 
792   ~CommandObjectCommandsAddRegex() override = default;
793 
794 protected:
IOHandlerActivated(IOHandler & io_handler,bool interactive)795   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
796     if (interactive) {
797       if (lldb::LockableStreamFileSP output_sp =
798               io_handler.GetOutputStreamFileSP()) {
799         LockedStreamFile locked_stream = output_sp->Lock();
800         locked_stream.PutCString(
801             "Enter one or more sed substitution commands in "
802             "the form: 's/<regex>/<subst>/'.\nTerminate the "
803             "substitution list with an empty line.\n");
804       }
805     }
806   }
807 
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)808   void IOHandlerInputComplete(IOHandler &io_handler,
809                               std::string &data) override {
810     io_handler.SetIsDone(true);
811     if (m_regex_cmd_up) {
812       StringList lines;
813       if (lines.SplitIntoLines(data)) {
814         bool check_only = false;
815         for (const std::string &line : lines) {
816           Status error = AppendRegexSubstitution(line, check_only);
817           if (error.Fail()) {
818             if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode())
819               GetDebugger().GetAsyncOutputStream()->Printf("error: %s\n",
820                                                            error.AsCString());
821           }
822         }
823       }
824       if (m_regex_cmd_up->HasRegexEntries()) {
825         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
826         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
827       }
828     }
829   }
830 
DoExecute(Args & command,CommandReturnObject & result)831   void DoExecute(Args &command, CommandReturnObject &result) override {
832     const size_t argc = command.GetArgumentCount();
833     if (argc == 0) {
834       result.AppendError("usage: 'command regex <command-name> "
835                          "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
836       return;
837     }
838 
839     Status error;
840     auto name = command[0].ref();
841     m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
842         m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 0,
843         true);
844 
845     if (argc == 1) {
846       Debugger &debugger = GetDebugger();
847       bool color_prompt = debugger.GetUseColor();
848       const bool multiple_lines = true; // Get multiple lines
849       IOHandlerSP io_handler_sp(new IOHandlerEditline(
850           debugger, IOHandler::Type::Other,
851           "lldb-regex",          // Name of input reader for history
852           llvm::StringRef("> "), // Prompt
853           llvm::StringRef(),     // Continuation prompt
854           multiple_lines, color_prompt,
855           0, // Don't show line numbers
856           *this));
857 
858       if (io_handler_sp) {
859         debugger.RunIOHandlerAsync(io_handler_sp);
860         result.SetStatus(eReturnStatusSuccessFinishNoResult);
861       }
862     } else {
863       for (auto &entry : command.entries().drop_front()) {
864         bool check_only = false;
865         error = AppendRegexSubstitution(entry.ref(), check_only);
866         if (error.Fail())
867           break;
868       }
869 
870       if (error.Success()) {
871         AddRegexCommandToInterpreter();
872       }
873     }
874     if (error.Fail()) {
875       result.AppendError(error.AsCString());
876     }
877   }
878 
AppendRegexSubstitution(const llvm::StringRef & regex_sed,bool check_only)879   Status AppendRegexSubstitution(const llvm::StringRef &regex_sed,
880                                  bool check_only) {
881     Status error;
882 
883     if (!m_regex_cmd_up) {
884       return Status::FromErrorStringWithFormat(
885           "invalid regular expression command object for: '%.*s'",
886           (int)regex_sed.size(), regex_sed.data());
887       return error;
888     }
889 
890     size_t regex_sed_size = regex_sed.size();
891 
892     if (regex_sed_size <= 1) {
893       return Status::FromErrorStringWithFormat(
894           "regular expression substitution string is too short: '%.*s'",
895           (int)regex_sed.size(), regex_sed.data());
896       return error;
897     }
898 
899     if (regex_sed[0] != 's') {
900       return Status::FromErrorStringWithFormat(
901           "regular expression substitution string "
902           "doesn't start with 's': '%.*s'",
903           (int)regex_sed.size(), regex_sed.data());
904       return error;
905     }
906     const size_t first_separator_char_pos = 1;
907     // use the char that follows 's' as the regex separator character so we can
908     // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
909     const char separator_char = regex_sed[first_separator_char_pos];
910     const size_t second_separator_char_pos =
911         regex_sed.find(separator_char, first_separator_char_pos + 1);
912 
913     if (second_separator_char_pos == std::string::npos) {
914       return Status::FromErrorStringWithFormat(
915           "missing second '%c' separator char after '%.*s' in '%.*s'",
916           separator_char,
917           (int)(regex_sed.size() - first_separator_char_pos - 1),
918           regex_sed.data() + (first_separator_char_pos + 1),
919           (int)regex_sed.size(), regex_sed.data());
920       return error;
921     }
922 
923     const size_t third_separator_char_pos =
924         regex_sed.find(separator_char, second_separator_char_pos + 1);
925 
926     if (third_separator_char_pos == std::string::npos) {
927       return Status::FromErrorStringWithFormat(
928           "missing third '%c' separator char after '%.*s' in '%.*s'",
929           separator_char,
930           (int)(regex_sed.size() - second_separator_char_pos - 1),
931           regex_sed.data() + (second_separator_char_pos + 1),
932           (int)regex_sed.size(), regex_sed.data());
933       return error;
934     }
935 
936     if (third_separator_char_pos != regex_sed_size - 1) {
937       // Make sure that everything that follows the last regex separator char
938       if (regex_sed.find_first_not_of("\t\n\v\f\r ",
939                                       third_separator_char_pos + 1) !=
940           std::string::npos) {
941         return Status::FromErrorStringWithFormat(
942             "extra data found after the '%.*s' regular expression substitution "
943             "string: '%.*s'",
944             (int)third_separator_char_pos + 1, regex_sed.data(),
945             (int)(regex_sed.size() - third_separator_char_pos - 1),
946             regex_sed.data() + (third_separator_char_pos + 1));
947         return error;
948       }
949     } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
950       return Status::FromErrorStringWithFormat(
951           "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
952           separator_char, separator_char, separator_char, (int)regex_sed.size(),
953           regex_sed.data());
954       return error;
955     } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
956       return Status::FromErrorStringWithFormat(
957           "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
958           separator_char, separator_char, separator_char, (int)regex_sed.size(),
959           regex_sed.data());
960       return error;
961     }
962 
963     if (!check_only) {
964       std::string regex(std::string(regex_sed.substr(
965           first_separator_char_pos + 1,
966           second_separator_char_pos - first_separator_char_pos - 1)));
967       std::string subst(std::string(regex_sed.substr(
968           second_separator_char_pos + 1,
969           third_separator_char_pos - second_separator_char_pos - 1)));
970       m_regex_cmd_up->AddRegexCommand(regex, subst);
971     }
972     return error;
973   }
974 
AddRegexCommandToInterpreter()975   void AddRegexCommandToInterpreter() {
976     if (m_regex_cmd_up) {
977       if (m_regex_cmd_up->HasRegexEntries()) {
978         CommandObjectSP cmd_sp(m_regex_cmd_up.release());
979         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
980       }
981     }
982   }
983 
984 private:
985   std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
986 
987   class CommandOptions : public Options {
988   public:
989     CommandOptions() = default;
990 
991     ~CommandOptions() override = default;
992 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)993     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
994                           ExecutionContext *execution_context) override {
995       Status error;
996       const int short_option = m_getopt_table[option_idx].val;
997 
998       switch (short_option) {
999       case 'h':
1000         m_help.assign(std::string(option_arg));
1001         break;
1002       case 's':
1003         m_syntax.assign(std::string(option_arg));
1004         break;
1005       default:
1006         llvm_unreachable("Unimplemented option");
1007       }
1008 
1009       return error;
1010     }
1011 
OptionParsingStarting(ExecutionContext * execution_context)1012     void OptionParsingStarting(ExecutionContext *execution_context) override {
1013       m_help.clear();
1014       m_syntax.clear();
1015     }
1016 
GetDefinitions()1017     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1018       return llvm::ArrayRef(g_regex_options);
1019     }
1020 
GetHelp()1021     llvm::StringRef GetHelp() { return m_help; }
1022 
GetSyntax()1023     llvm::StringRef GetSyntax() { return m_syntax; }
1024 
1025   protected:
1026     // Instance variables to hold the values for command options.
1027 
1028     std::string m_help;
1029     std::string m_syntax;
1030   };
1031 
GetOptions()1032   Options *GetOptions() override { return &m_options; }
1033 
1034   CommandOptions m_options;
1035 };
1036 
1037 class CommandObjectPythonFunction : public CommandObjectRaw {
1038 public:
CommandObjectPythonFunction(CommandInterpreter & interpreter,std::string name,std::string funct,std::string help,ScriptedCommandSynchronicity synch,CompletionType completion_type)1039   CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
1040                               std::string funct, std::string help,
1041                               ScriptedCommandSynchronicity synch,
1042                               CompletionType completion_type)
1043       : CommandObjectRaw(interpreter, name), m_function_name(funct),
1044         m_synchro(synch), m_completion_type(completion_type) {
1045     if (!help.empty())
1046       SetHelp(help);
1047     else {
1048       StreamString stream;
1049       stream.Printf("For more information run 'help %s'", name.c_str());
1050       SetHelp(stream.GetString());
1051     }
1052   }
1053 
1054   ~CommandObjectPythonFunction() override = default;
1055 
IsRemovable() const1056   bool IsRemovable() const override { return true; }
1057 
GetFunctionName()1058   const std::string &GetFunctionName() { return m_function_name; }
1059 
GetSynchronicity()1060   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1061 
GetHelpLong()1062   llvm::StringRef GetHelpLong() override {
1063     if (m_fetched_help_long)
1064       return CommandObjectRaw::GetHelpLong();
1065 
1066     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1067     if (!scripter)
1068       return CommandObjectRaw::GetHelpLong();
1069 
1070     std::string docstring;
1071     m_fetched_help_long =
1072         scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
1073     if (!docstring.empty())
1074       SetHelpLong(docstring);
1075     return CommandObjectRaw::GetHelpLong();
1076   }
1077 
1078   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1079   HandleArgumentCompletion(CompletionRequest &request,
1080                            OptionElementVector &opt_element_vector) override {
1081     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1082         GetCommandInterpreter(), m_completion_type, request, nullptr);
1083   }
1084 
WantsCompletion()1085   bool WantsCompletion() override { return true; }
1086 
1087 protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1088   void DoExecute(llvm::StringRef raw_command_line,
1089                  CommandReturnObject &result) override {
1090     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1091 
1092     m_interpreter.IncreaseCommandUsage(*this);
1093 
1094     Status error;
1095 
1096     result.SetStatus(eReturnStatusInvalid);
1097 
1098     if (!scripter || !scripter->RunScriptBasedCommand(
1099                          m_function_name.c_str(), raw_command_line, m_synchro,
1100                          result, error, m_exe_ctx)) {
1101       result.AppendError(error.AsCString());
1102     } else {
1103       // Don't change the status if the command already set it...
1104       if (result.GetStatus() == eReturnStatusInvalid) {
1105         if (result.GetOutputString().empty())
1106           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1107         else
1108           result.SetStatus(eReturnStatusSuccessFinishResult);
1109       }
1110     }
1111   }
1112 
1113 private:
1114   std::string m_function_name;
1115   ScriptedCommandSynchronicity m_synchro;
1116   bool m_fetched_help_long = false;
1117   CompletionType m_completion_type = eNoCompletion;
1118 };
1119 
1120 /// This class implements a "raw" scripted command.  lldb does no parsing of the
1121 /// command line, instead passing the line unaltered (except for backtick
1122 /// substitution).
1123 class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
1124 public:
CommandObjectScriptingObjectRaw(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch,CompletionType completion_type)1125   CommandObjectScriptingObjectRaw(CommandInterpreter &interpreter,
1126                                   std::string name,
1127                                   StructuredData::GenericSP cmd_obj_sp,
1128                                   ScriptedCommandSynchronicity synch,
1129                                   CompletionType completion_type)
1130       : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1131         m_synchro(synch), m_fetched_help_short(false),
1132         m_fetched_help_long(false), m_completion_type(completion_type) {
1133     StreamString stream;
1134     stream.Printf("For more information run 'help %s'", name.c_str());
1135     SetHelp(stream.GetString());
1136     if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
1137       GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1138   }
1139 
1140   ~CommandObjectScriptingObjectRaw() override = default;
1141 
1142   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1143   HandleArgumentCompletion(CompletionRequest &request,
1144                            OptionElementVector &opt_element_vector) override {
1145     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1146         GetCommandInterpreter(), m_completion_type, request, nullptr);
1147   }
1148 
WantsCompletion()1149   bool WantsCompletion() override { return true; }
1150 
IsRemovable() const1151   bool IsRemovable() const override { return true; }
1152 
GetSynchronicity()1153   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1154 
GetRepeatCommand(Args & args,uint32_t index)1155   std::optional<std::string> GetRepeatCommand(Args &args,
1156                                               uint32_t index) override {
1157     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1158     if (!scripter)
1159       return std::nullopt;
1160 
1161     return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
1162   }
1163 
GetHelp()1164   llvm::StringRef GetHelp() override {
1165     if (m_fetched_help_short)
1166       return CommandObjectRaw::GetHelp();
1167     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1168     if (!scripter)
1169       return CommandObjectRaw::GetHelp();
1170     std::string docstring;
1171     m_fetched_help_short =
1172         scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1173     if (!docstring.empty())
1174       SetHelp(docstring);
1175 
1176     return CommandObjectRaw::GetHelp();
1177   }
1178 
GetHelpLong()1179   llvm::StringRef GetHelpLong() override {
1180     if (m_fetched_help_long)
1181       return CommandObjectRaw::GetHelpLong();
1182 
1183     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1184     if (!scripter)
1185       return CommandObjectRaw::GetHelpLong();
1186 
1187     std::string docstring;
1188     m_fetched_help_long =
1189         scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1190     if (!docstring.empty())
1191       SetHelpLong(docstring);
1192     return CommandObjectRaw::GetHelpLong();
1193   }
1194 
1195 protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1196   void DoExecute(llvm::StringRef raw_command_line,
1197                  CommandReturnObject &result) override {
1198     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1199 
1200     Status error;
1201 
1202     result.SetStatus(eReturnStatusInvalid);
1203 
1204     if (!scripter ||
1205         !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
1206                                          m_synchro, result, error, m_exe_ctx)) {
1207       result.AppendError(error.AsCString());
1208     } else {
1209       // Don't change the status if the command already set it...
1210       if (result.GetStatus() == eReturnStatusInvalid) {
1211         if (result.GetOutputString().empty())
1212           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1213         else
1214           result.SetStatus(eReturnStatusSuccessFinishResult);
1215       }
1216     }
1217   }
1218 
1219 private:
1220   StructuredData::GenericSP m_cmd_obj_sp;
1221   ScriptedCommandSynchronicity m_synchro;
1222   bool m_fetched_help_short : 1;
1223   bool m_fetched_help_long : 1;
1224   CompletionType m_completion_type = eNoCompletion;
1225 };
1226 
1227 
1228 /// This command implements a lldb parsed scripted command.  The command
1229 /// provides a definition of the options and arguments, and a option value
1230 /// setting callback, and then the command's execution function gets passed
1231 /// just the parsed arguments.
1232 /// Note, implementing a command in Python using these base interfaces is a bit
1233 /// of a pain, but it is much easier to export this low level interface, and
1234 /// then make it nicer on the Python side, than to try to do that in a
1235 /// script language neutral way.
1236 /// So I've also added a base class in Python that provides a table-driven
1237 /// way of defining the options and arguments, which automatically fills the
1238 /// option values, making them available as properties in Python.
1239 ///
1240 class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
1241 private:
1242   class CommandOptions : public Options {
1243   public:
CommandOptions(CommandInterpreter & interpreter,StructuredData::GenericSP cmd_obj_sp)1244     CommandOptions(CommandInterpreter &interpreter,
1245         StructuredData::GenericSP cmd_obj_sp) : m_interpreter(interpreter),
1246             m_cmd_obj_sp(cmd_obj_sp) {}
1247 
1248     ~CommandOptions() override = default;
1249 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1250     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1251                           ExecutionContext *execution_context) override {
1252       Status error;
1253       ScriptInterpreter *scripter =
1254         m_interpreter.GetDebugger().GetScriptInterpreter();
1255       if (!scripter) {
1256         return Status::FromErrorString(
1257             "No script interpreter for SetOptionValue.");
1258         return error;
1259       }
1260       if (!m_cmd_obj_sp) {
1261         return Status::FromErrorString(
1262             "SetOptionValue called with empty cmd_obj.");
1263         return error;
1264       }
1265       if (!m_options_definition_up) {
1266         return Status::FromErrorString(
1267             "SetOptionValue called before options definitions "
1268             "were created.");
1269         return error;
1270       }
1271       // Pass the long option, since you aren't actually required to have a
1272       // short_option, and for those options the index or short option character
1273       // aren't meaningful on the python side.
1274       const char * long_option =
1275         m_options_definition_up.get()[option_idx].long_option;
1276       bool success = scripter->SetOptionValueForCommandObject(m_cmd_obj_sp,
1277         execution_context, long_option, option_arg);
1278       if (!success)
1279         return Status::FromErrorStringWithFormatv(
1280             "Error setting option: {0} to {1}", long_option, option_arg);
1281       return error;
1282     }
1283 
OptionParsingStarting(ExecutionContext * execution_context)1284     void OptionParsingStarting(ExecutionContext *execution_context) override {
1285       ScriptInterpreter *scripter =
1286         m_interpreter.GetDebugger().GetScriptInterpreter();
1287       if (!scripter || !m_cmd_obj_sp)
1288         return;
1289 
1290       scripter->OptionParsingStartedForCommandObject(m_cmd_obj_sp);
1291     }
1292 
GetDefinitions()1293     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1294       if (!m_options_definition_up)
1295         return {};
1296       return llvm::ArrayRef(m_options_definition_up.get(), m_num_options);
1297     }
1298 
ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp,size_t counter,uint32_t & usage_mask)1299     static Status ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp,
1300         size_t counter, uint32_t &usage_mask) {
1301       // If the usage entry is not provided, we use LLDB_OPT_SET_ALL.
1302       // If the usage mask is a UINT, the option belongs to that group.
1303       // If the usage mask is a vector of UINT's, the option belongs to all the
1304       // groups listed.
1305       // If a subelement of the vector is a vector of two ints, then the option
1306       // belongs to the inclusive range from the first to the second element.
1307       Status error;
1308       if (!obj_sp) {
1309         usage_mask = LLDB_OPT_SET_ALL;
1310         return error;
1311       }
1312 
1313       usage_mask = 0;
1314 
1315       StructuredData::UnsignedInteger *uint_val =
1316           obj_sp->GetAsUnsignedInteger();
1317       if (uint_val) {
1318         // If this is an integer, then this specifies a single group:
1319         uint32_t value = uint_val->GetValue();
1320         if (value == 0) {
1321           return Status::FromErrorStringWithFormatv(
1322               "0 is not a valid group for option {0}", counter);
1323         }
1324         usage_mask = (1 << (value - 1));
1325         return error;
1326       }
1327       // Otherwise it has to be an array:
1328       StructuredData::Array *array_val = obj_sp->GetAsArray();
1329       if (!array_val) {
1330         return Status::FromErrorStringWithFormatv(
1331             "required field is not a array for option {0}", counter);
1332       }
1333       // This is the array ForEach for accumulating a group usage mask from
1334       // an array of string descriptions of groups.
1335       auto groups_accumulator
1336           = [counter, &usage_mask, &error]
1337             (StructuredData::Object *obj) -> bool {
1338         StructuredData::UnsignedInteger *int_val = obj->GetAsUnsignedInteger();
1339         if (int_val) {
1340           uint32_t value = int_val->GetValue();
1341           if (value == 0) {
1342             error = Status::FromErrorStringWithFormatv(
1343                 "0 is not a valid group for element {0}", counter);
1344             return false;
1345           }
1346           usage_mask |= (1 << (value - 1));
1347           return true;
1348         }
1349         StructuredData::Array *arr_val = obj->GetAsArray();
1350         if (!arr_val) {
1351           error = Status::FromErrorStringWithFormatv(
1352               "Group element not an int or array of integers for element {0}",
1353               counter);
1354           return false;
1355         }
1356         size_t num_range_elem = arr_val->GetSize();
1357         if (num_range_elem != 2) {
1358           error = Status::FromErrorStringWithFormatv(
1359               "Subranges of a group not a start and a stop for element {0}",
1360               counter);
1361           return false;
1362         }
1363         int_val = arr_val->GetItemAtIndex(0)->GetAsUnsignedInteger();
1364         if (!int_val) {
1365           error = Status::FromErrorStringWithFormatv(
1366               "Start element of a subrange of a "
1367               "group not unsigned int for element {0}",
1368               counter);
1369           return false;
1370         }
1371         uint32_t start = int_val->GetValue();
1372         int_val = arr_val->GetItemAtIndex(1)->GetAsUnsignedInteger();
1373         if (!int_val) {
1374           error = Status::FromErrorStringWithFormatv(
1375               "End element of a subrange of a group"
1376               " not unsigned int for element {0}",
1377               counter);
1378           return false;
1379         }
1380         uint32_t end = int_val->GetValue();
1381         if (start == 0 || end == 0 || start > end) {
1382           error = Status::FromErrorStringWithFormatv(
1383               "Invalid subrange of a group: {0} - "
1384               "{1} for element {2}",
1385               start, end, counter);
1386           return false;
1387         }
1388         for (uint32_t i = start; i <= end; i++) {
1389           usage_mask |= (1 << (i - 1));
1390         }
1391         return true;
1392       };
1393       array_val->ForEach(groups_accumulator);
1394       return error;
1395     }
1396 
1397 
SetOptionsFromArray(StructuredData::Dictionary & options)1398     Status SetOptionsFromArray(StructuredData::Dictionary &options) {
1399       Status error;
1400       m_num_options = options.GetSize();
1401       m_options_definition_up.reset(new OptionDefinition[m_num_options]);
1402       // We need to hand out pointers to contents of these vectors; we reserve
1403       // as much as we'll need up front so they don't get freed on resize...
1404       m_usage_container.resize(m_num_options);
1405       m_enum_storage.resize(m_num_options);
1406       m_enum_vector.resize(m_num_options);
1407 
1408       size_t counter = 0;
1409       size_t short_opt_counter = 0;
1410       // This is the Array::ForEach function for adding option elements:
1411       auto add_element = [this, &error, &counter, &short_opt_counter]
1412           (llvm::StringRef long_option, StructuredData::Object *object) -> bool {
1413         StructuredData::Dictionary *opt_dict = object->GetAsDictionary();
1414         if (!opt_dict) {
1415           error = Status::FromErrorString(
1416               "Value in options dictionary is not a dictionary");
1417           return false;
1418         }
1419         OptionDefinition &option_def = m_options_definition_up.get()[counter];
1420 
1421         // We aren't exposing the validator yet, set it to null
1422         option_def.validator = nullptr;
1423         // We don't require usage masks, so set it to one group by default:
1424         option_def.usage_mask = 1;
1425 
1426         // Now set the fields of the OptionDefinition Array from the dictionary:
1427         //
1428         // Note that I don't check for unknown fields in the option dictionaries
1429         // so a scriptor can add extra elements that are helpful when they go to
1430         // do "set_option_value"
1431 
1432         // Usage Mask:
1433         StructuredData::ObjectSP obj_sp = opt_dict->GetValueForKey("groups");
1434         if (obj_sp) {
1435           error = ParseUsageMaskFromArray(obj_sp, counter,
1436                                           option_def.usage_mask);
1437           if (error.Fail())
1438             return false;
1439         }
1440 
1441         // Required:
1442         option_def.required = false;
1443         obj_sp = opt_dict->GetValueForKey("required");
1444         if (obj_sp) {
1445           StructuredData::Boolean *boolean_val = obj_sp->GetAsBoolean();
1446           if (!boolean_val) {
1447             error = Status::FromErrorStringWithFormatv(
1448                 "'required' field is not a boolean "
1449                 "for option {0}",
1450                 counter);
1451             return false;
1452           }
1453           option_def.required = boolean_val->GetValue();
1454         }
1455 
1456         // Short Option:
1457         int short_option;
1458         obj_sp = opt_dict->GetValueForKey("short_option");
1459         if (obj_sp) {
1460           // The value is a string, so pull the
1461           llvm::StringRef short_str = obj_sp->GetStringValue();
1462           if (short_str.empty()) {
1463             error = Status::FromErrorStringWithFormatv(
1464                 "short_option field empty for "
1465                 "option {0}",
1466                 counter);
1467             return false;
1468           } else if (short_str.size() != 1) {
1469             error = Status::FromErrorStringWithFormatv(
1470                 "short_option field has extra "
1471                 "characters for option {0}",
1472                 counter);
1473             return false;
1474           }
1475           short_option = (int) short_str[0];
1476         } else {
1477           // If the short option is not provided, then we need a unique value
1478           // less than the lowest printable ASCII character.
1479           short_option = short_opt_counter++;
1480         }
1481         option_def.short_option = short_option;
1482 
1483         // Long Option is the key from the outer dict:
1484         if (long_option.empty()) {
1485           error = Status::FromErrorStringWithFormatv(
1486               "empty long_option for option {0}", counter);
1487           return false;
1488         }
1489         auto inserted = g_string_storer.insert(long_option.str());
1490         option_def.long_option = ((*(inserted.first)).data());
1491 
1492         // Value Type:
1493         obj_sp = opt_dict->GetValueForKey("value_type");
1494         if (obj_sp) {
1495           StructuredData::UnsignedInteger *uint_val
1496               = obj_sp->GetAsUnsignedInteger();
1497           if (!uint_val) {
1498             error = Status::FromErrorStringWithFormatv(
1499                 "Value type must be an unsigned "
1500                 "integer");
1501             return false;
1502           }
1503           uint64_t val_type = uint_val->GetValue();
1504           if (val_type >= eArgTypeLastArg) {
1505             error =
1506                 Status::FromErrorStringWithFormatv("Value type {0} beyond the "
1507                                                    "CommandArgumentType bounds",
1508                                                    val_type);
1509             return false;
1510           }
1511           option_def.argument_type = (CommandArgumentType) val_type;
1512           option_def.option_has_arg = true;
1513         } else {
1514           option_def.argument_type = eArgTypeNone;
1515           option_def.option_has_arg = false;
1516         }
1517 
1518         // Completion Type:
1519         obj_sp = opt_dict->GetValueForKey("completion_type");
1520         if (obj_sp) {
1521           StructuredData::UnsignedInteger *uint_val = obj_sp->GetAsUnsignedInteger();
1522           if (!uint_val) {
1523             error = Status::FromErrorStringWithFormatv(
1524                 "Completion type must be an "
1525                 "unsigned integer for option {0}",
1526                 counter);
1527             return false;
1528           }
1529           uint64_t completion_type = uint_val->GetValue();
1530           if (completion_type > eCustomCompletion) {
1531             error = Status::FromErrorStringWithFormatv(
1532                 "Completion type for option {0} "
1533                 "beyond the CompletionType bounds",
1534                 completion_type);
1535             return false;
1536           }
1537           option_def.completion_type = (CommandArgumentType) completion_type;
1538         } else
1539           option_def.completion_type = eNoCompletion;
1540 
1541         // Usage Text:
1542         obj_sp = opt_dict->GetValueForKey("help");
1543         if (!obj_sp) {
1544           error = Status::FromErrorStringWithFormatv(
1545               "required usage missing from option "
1546               "{0}",
1547               counter);
1548           return false;
1549         }
1550         llvm::StringRef usage_stref;
1551         usage_stref = obj_sp->GetStringValue();
1552         if (usage_stref.empty()) {
1553           error = Status::FromErrorStringWithFormatv(
1554               "empty usage text for option {0}", counter);
1555           return false;
1556         }
1557         m_usage_container[counter] = usage_stref.str().c_str();
1558         option_def.usage_text = m_usage_container[counter].data();
1559 
1560         // Enum Values:
1561 
1562         obj_sp = opt_dict->GetValueForKey("enum_values");
1563         if (obj_sp) {
1564           StructuredData::Array *array = obj_sp->GetAsArray();
1565           if (!array) {
1566             error = Status::FromErrorStringWithFormatv(
1567                 "enum values must be an array for "
1568                 "option {0}",
1569                 counter);
1570             return false;
1571           }
1572           size_t num_elem = array->GetSize();
1573           size_t enum_ctr = 0;
1574           m_enum_storage[counter] = std::vector<EnumValueStorage>(num_elem);
1575           std::vector<EnumValueStorage> &curr_elem = m_enum_storage[counter];
1576 
1577           // This is the Array::ForEach function for adding enum elements:
1578           // Since there are only two fields to specify the enum, use a simple
1579           // two element array with value first, usage second.
1580           // counter is only used for reporting so I pass it by value here.
1581           auto add_enum = [&enum_ctr, &curr_elem, counter, &error]
1582               (StructuredData::Object *object) -> bool {
1583             StructuredData::Array *enum_arr = object->GetAsArray();
1584             if (!enum_arr) {
1585               error = Status::FromErrorStringWithFormatv(
1586                   "Enum values for option {0} not "
1587                   "an array",
1588                   counter);
1589               return false;
1590             }
1591             size_t num_enum_elements = enum_arr->GetSize();
1592             if (num_enum_elements != 2) {
1593               error = Status::FromErrorStringWithFormatv(
1594                   "Wrong number of elements: {0} "
1595                   "for enum {1} in option {2}",
1596                   num_enum_elements, enum_ctr, counter);
1597               return false;
1598             }
1599             // Enum Value:
1600             StructuredData::ObjectSP obj_sp = enum_arr->GetItemAtIndex(0);
1601             llvm::StringRef val_stref = obj_sp->GetStringValue();
1602             std::string value_cstr_str = val_stref.str().c_str();
1603 
1604             // Enum Usage:
1605             obj_sp = enum_arr->GetItemAtIndex(1);
1606             if (!obj_sp) {
1607               error = Status::FromErrorStringWithFormatv(
1608                   "No usage for enum {0} in option "
1609                   "{1}",
1610                   enum_ctr, counter);
1611               return false;
1612             }
1613             llvm::StringRef usage_stref = obj_sp->GetStringValue();
1614             std::string usage_cstr_str = usage_stref.str().c_str();
1615             curr_elem[enum_ctr] = EnumValueStorage(value_cstr_str,
1616                 usage_cstr_str, enum_ctr);
1617 
1618             enum_ctr++;
1619             return true;
1620           }; // end of add_enum
1621 
1622           array->ForEach(add_enum);
1623           if (!error.Success())
1624             return false;
1625           // We have to have a vector of elements to set in the options, make
1626           // that here:
1627           for (auto &elem : curr_elem)
1628             m_enum_vector[counter].emplace_back(elem.element);
1629 
1630           option_def.enum_values = llvm::ArrayRef(m_enum_vector[counter]);
1631         }
1632         counter++;
1633         return true;
1634       }; // end of add_element
1635 
1636       options.ForEach(add_element);
1637       return error;
1638     }
1639 
GetNumOptions()1640     size_t GetNumOptions() { return m_num_options; }
1641 
PrepareOptionsForCompletion(CompletionRequest & request,OptionElementVector & option_vec,ExecutionContext * exe_ctx)1642     void PrepareOptionsForCompletion(CompletionRequest &request,
1643                                      OptionElementVector &option_vec,
1644                                      ExecutionContext *exe_ctx) {
1645       // I'm not sure if we'll get into trouble doing an option parsing start
1646       // and end in this context.  If so, then I'll have to directly tell the
1647       // scripter to do this.
1648       OptionParsingStarting(exe_ctx);
1649       auto opt_defs = GetDefinitions();
1650 
1651       // Iterate through the options we found so far, and push them into
1652       // the scripted side.
1653       for (auto option_elem : option_vec) {
1654         int cur_defs_index = option_elem.opt_defs_index;
1655         // If we don't recognize this option we can't set it.
1656         if (cur_defs_index == OptionArgElement::eUnrecognizedArg ||
1657             cur_defs_index == OptionArgElement::eBareDash ||
1658             cur_defs_index == OptionArgElement::eBareDoubleDash)
1659           continue;
1660         bool option_has_arg = opt_defs[cur_defs_index].option_has_arg;
1661         llvm::StringRef cur_arg_value;
1662         if (option_has_arg) {
1663           int cur_arg_pos = option_elem.opt_arg_pos;
1664           if (cur_arg_pos != OptionArgElement::eUnrecognizedArg &&
1665               cur_arg_pos != OptionArgElement::eBareDash &&
1666               cur_arg_pos != OptionArgElement::eBareDoubleDash) {
1667             cur_arg_value =
1668                 request.GetParsedLine().GetArgumentAtIndex(cur_arg_pos);
1669           }
1670         }
1671         SetOptionValue(cur_defs_index, cur_arg_value, exe_ctx);
1672       }
1673       OptionParsingFinished(exe_ctx);
1674     }
1675 
1676     void
ProcessCompletionDict(CompletionRequest & request,StructuredData::DictionarySP & completion_dict_sp)1677     ProcessCompletionDict(CompletionRequest &request,
1678                           StructuredData::DictionarySP &completion_dict_sp) {
1679       // We don't know how to process an empty completion dict, our callers have
1680       // to do that.
1681       assert(completion_dict_sp && "Must have valid completion dict");
1682       // First handle the case of a single completion:
1683       llvm::StringRef completion;
1684       // If the dictionary has one element "no-completion" then we return here
1685       if (completion_dict_sp->GetValueForKeyAsString("no-completion",
1686                                                      completion))
1687         return;
1688 
1689       if (completion_dict_sp->GetValueForKeyAsString("completion",
1690                                                      completion)) {
1691         llvm::StringRef mode_str;
1692         CompletionMode mode = CompletionMode::Normal;
1693         if (completion_dict_sp->GetValueForKeyAsString("mode", mode_str)) {
1694           if (mode_str == "complete")
1695             mode = CompletionMode::Normal;
1696           else if (mode_str == "partial")
1697             mode = CompletionMode::Partial;
1698           else {
1699             // FIXME - how do I report errors here?
1700             return;
1701           }
1702         }
1703         request.AddCompletion(completion, "", mode);
1704         return;
1705       }
1706       // The completions are required, the descriptions are not:
1707       StructuredData::Array *completions;
1708       StructuredData::Array *descriptions;
1709       if (completion_dict_sp->GetValueForKeyAsArray("values", completions)) {
1710         completion_dict_sp->GetValueForKeyAsArray("descriptions", descriptions);
1711         size_t num_completions = completions->GetSize();
1712         for (size_t idx = 0; idx < num_completions; idx++) {
1713           auto val = completions->GetItemAtIndexAsString(idx);
1714           if (!val)
1715             // FIXME: How do I report this error?
1716             return;
1717 
1718           if (descriptions) {
1719             auto desc = descriptions->GetItemAtIndexAsString(idx);
1720             request.AddCompletion(*val, desc ? *desc : "");
1721           } else
1722             request.AddCompletion(*val);
1723         }
1724       }
1725     }
1726 
1727     void
HandleOptionArgumentCompletion(lldb_private::CompletionRequest & request,OptionElementVector & option_vec,int opt_element_index,CommandInterpreter & interpreter)1728     HandleOptionArgumentCompletion(lldb_private::CompletionRequest &request,
1729                                    OptionElementVector &option_vec,
1730                                    int opt_element_index,
1731                                    CommandInterpreter &interpreter) override {
1732       ScriptInterpreter *scripter =
1733           interpreter.GetDebugger().GetScriptInterpreter();
1734 
1735       if (!scripter)
1736         return;
1737 
1738       ExecutionContext exe_ctx = interpreter.GetExecutionContext();
1739       PrepareOptionsForCompletion(request, option_vec, &exe_ctx);
1740 
1741       auto defs = GetDefinitions();
1742 
1743       size_t defs_index = option_vec[opt_element_index].opt_defs_index;
1744       llvm::StringRef option_name = defs[defs_index].long_option;
1745       bool is_enum = defs[defs_index].enum_values.size() != 0;
1746       if (option_name.empty())
1747         return;
1748       // If this is an enum, we don't call the custom completer, just let the
1749       // regular option completer handle that:
1750       StructuredData::DictionarySP completion_dict_sp;
1751       if (!is_enum)
1752         completion_dict_sp =
1753             scripter->HandleOptionArgumentCompletionForScriptedCommand(
1754                 m_cmd_obj_sp, option_name, request.GetCursorCharPos());
1755 
1756       if (!completion_dict_sp) {
1757         Options::HandleOptionArgumentCompletion(request, option_vec,
1758                                                 opt_element_index, interpreter);
1759         return;
1760       }
1761 
1762       ProcessCompletionDict(request, completion_dict_sp);
1763     }
1764 
1765   private:
1766     struct EnumValueStorage {
EnumValueStorageCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1767       EnumValueStorage() {
1768         element.string_value = "value not set";
1769         element.usage = "usage not set";
1770         element.value = 0;
1771       }
1772 
EnumValueStorageCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1773       EnumValueStorage(std::string in_str_val, std::string in_usage,
1774           size_t in_value) : value(std::move(in_str_val)), usage(std::move(in_usage)) {
1775         SetElement(in_value);
1776       }
1777 
EnumValueStorageCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1778       EnumValueStorage(const EnumValueStorage &in) : value(in.value),
1779           usage(in.usage) {
1780         SetElement(in.element.value);
1781       }
1782 
operator =CommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1783       EnumValueStorage &operator=(const EnumValueStorage &in) {
1784         value = in.value;
1785         usage = in.usage;
1786         SetElement(in.element.value);
1787         return *this;
1788       }
1789 
SetElementCommandObjectScriptingObjectParsed::CommandOptions::EnumValueStorage1790       void SetElement(size_t in_value) {
1791         element.value = in_value;
1792         element.string_value = value.data();
1793         element.usage = usage.data();
1794       }
1795 
1796       std::string value;
1797       std::string usage;
1798       OptionEnumValueElement element;
1799     };
1800     // We have to provide char * values for the long option, usage and enum
1801     // values, that's what the option definitions hold.
1802     // The long option strings are quite likely to be reused in other added
1803     // commands, so those are stored in a global set: g_string_storer.
1804     // But the usages are much less likely to be reused, so those are stored in
1805     // a vector in the command instance.  It gets resized to the correct size
1806     // and then filled with null-terminated strings in the std::string, so the
1807     // are valid C-strings that won't move around.
1808     // The enum values and descriptions are treated similarly - these aren't
1809     // all that common so it's not worth the effort to dedup them.
1810     size_t m_num_options = 0;
1811     std::unique_ptr<OptionDefinition> m_options_definition_up;
1812     std::vector<std::vector<EnumValueStorage>> m_enum_storage;
1813     std::vector<std::vector<OptionEnumValueElement>> m_enum_vector;
1814     std::vector<std::string> m_usage_container;
1815     CommandInterpreter &m_interpreter;
1816     StructuredData::GenericSP m_cmd_obj_sp;
1817     static std::unordered_set<std::string> g_string_storer;
1818   };
1819 
1820 public:
Create(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch,CommandReturnObject & result)1821   static CommandObjectSP Create(CommandInterpreter &interpreter,
1822                 std::string name,
1823                 StructuredData::GenericSP cmd_obj_sp,
1824                 ScriptedCommandSynchronicity synch,
1825                 CommandReturnObject &result) {
1826     CommandObjectSP new_cmd_sp(new CommandObjectScriptingObjectParsed(
1827         interpreter, name, cmd_obj_sp, synch));
1828 
1829     CommandObjectScriptingObjectParsed *parsed_cmd
1830         = static_cast<CommandObjectScriptingObjectParsed *>(new_cmd_sp.get());
1831     // Now check all the failure modes, and report if found.
1832     Status opt_error = parsed_cmd->GetOptionsError();
1833     Status arg_error = parsed_cmd->GetArgsError();
1834 
1835     if (opt_error.Fail())
1836       result.AppendErrorWithFormat("failed to parse option definitions: %s",
1837                                    opt_error.AsCString());
1838     if (arg_error.Fail())
1839       result.AppendErrorWithFormat("%sfailed to parse argument definitions: %s",
1840                                    opt_error.Fail() ? ", also " : "",
1841                                    arg_error.AsCString());
1842 
1843     if (!result.Succeeded())
1844       return {};
1845 
1846     return new_cmd_sp;
1847   }
1848 
CommandObjectScriptingObjectParsed(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch)1849   CommandObjectScriptingObjectParsed(CommandInterpreter &interpreter,
1850                                std::string name,
1851                                StructuredData::GenericSP cmd_obj_sp,
1852                                ScriptedCommandSynchronicity synch)
1853       : CommandObjectParsed(interpreter, name.c_str()),
1854         m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch),
1855         m_options(interpreter, cmd_obj_sp), m_fetched_help_short(false),
1856         m_fetched_help_long(false) {
1857     StreamString stream;
1858     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1859     if (!scripter) {
1860       m_options_error = Status::FromErrorString("No script interpreter");
1861       return;
1862     }
1863 
1864     // Set the flags:
1865     GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1866 
1867     // Now set up the options definitions from the options:
1868     StructuredData::ObjectSP options_object_sp
1869         = scripter->GetOptionsForCommandObject(cmd_obj_sp);
1870     // It's okay not to have an options dict.
1871     if (options_object_sp) {
1872       // The options come as a dictionary of dictionaries.  The key of the
1873       // outer dict is the long option name (since that's required).  The
1874       // value holds all the other option specification bits.
1875       StructuredData::Dictionary *options_dict
1876           = options_object_sp->GetAsDictionary();
1877       // but if it exists, it has to be an array.
1878       if (options_dict) {
1879         m_options_error = m_options.SetOptionsFromArray(*(options_dict));
1880         // If we got an error don't bother with the arguments...
1881         if (m_options_error.Fail())
1882           return;
1883       } else {
1884         m_options_error = Status::FromErrorString("Options array not an array");
1885         return;
1886       }
1887     }
1888     // Then fetch the args.  Since the arguments can have usage masks you need
1889     // an array of arrays.
1890     StructuredData::ObjectSP args_object_sp
1891       = scripter->GetArgumentsForCommandObject(cmd_obj_sp);
1892     if (args_object_sp) {
1893       StructuredData::Array *args_array = args_object_sp->GetAsArray();
1894       if (!args_array) {
1895         m_args_error =
1896             Status::FromErrorString("Argument specification is not an array");
1897         return;
1898       }
1899       size_t counter = 0;
1900 
1901       // This is the Array::ForEach function that handles the
1902       // CommandArgumentEntry arrays one by one:
1903       auto arg_array_adder = [this, &counter] (StructuredData::Object *object)
1904           -> bool {
1905         // This is the Array::ForEach function to add argument entries:
1906         CommandArgumentEntry this_entry;
1907         size_t elem_counter = 0;
1908         auto args_adder = [this, counter, &elem_counter, &this_entry]
1909             (StructuredData::Object *object) -> bool {
1910           // The arguments definition has three fields, the argument type, the
1911           // repeat and the usage mask.
1912           CommandArgumentType arg_type = eArgTypeNone;
1913           ArgumentRepetitionType arg_repetition = eArgRepeatOptional;
1914           uint32_t arg_opt_set_association;
1915 
1916           auto report_error = [this, elem_counter,
1917                                counter](const char *err_txt) -> bool {
1918             m_args_error = Status::FromErrorStringWithFormatv(
1919                 "Element {0} of arguments "
1920                 "list element {1}: %s.",
1921                 elem_counter, counter, err_txt);
1922             return false;
1923           };
1924 
1925           StructuredData::Dictionary *arg_dict = object->GetAsDictionary();
1926           if (!arg_dict) {
1927             report_error("is not a dictionary.");
1928             return false;
1929           }
1930           // Argument Type:
1931           StructuredData::ObjectSP obj_sp
1932               = arg_dict->GetValueForKey("arg_type");
1933           if (obj_sp) {
1934             StructuredData::UnsignedInteger *uint_val
1935                 = obj_sp->GetAsUnsignedInteger();
1936             if (!uint_val) {
1937               report_error("value type must be an unsigned integer");
1938               return false;
1939             }
1940             uint64_t arg_type_int = uint_val->GetValue();
1941             if (arg_type_int >= eArgTypeLastArg) {
1942               report_error("value type beyond ArgumentRepetitionType bounds");
1943               return false;
1944             }
1945             arg_type = (CommandArgumentType) arg_type_int;
1946           }
1947           // Repeat Value:
1948           obj_sp = arg_dict->GetValueForKey("repeat");
1949           std::optional<ArgumentRepetitionType> repeat;
1950           if (obj_sp) {
1951             llvm::StringRef repeat_str = obj_sp->GetStringValue();
1952             if (repeat_str.empty()) {
1953               report_error("repeat value is empty");
1954               return false;
1955             }
1956             repeat = ArgRepetitionFromString(repeat_str);
1957             if (!repeat) {
1958               report_error("invalid repeat value");
1959               return false;
1960             }
1961             arg_repetition = *repeat;
1962           }
1963 
1964           // Usage Mask:
1965           obj_sp = arg_dict->GetValueForKey("groups");
1966           m_args_error = CommandOptions::ParseUsageMaskFromArray(obj_sp,
1967               counter, arg_opt_set_association);
1968           this_entry.emplace_back(arg_type, arg_repetition,
1969               arg_opt_set_association);
1970           elem_counter++;
1971           return true;
1972         };
1973         StructuredData::Array *args_array = object->GetAsArray();
1974         if (!args_array) {
1975           m_args_error =
1976               Status::FromErrorStringWithFormatv("Argument definition element "
1977                                                  "{0} is not an array",
1978                                                  counter);
1979         }
1980 
1981         args_array->ForEach(args_adder);
1982         if (m_args_error.Fail())
1983           return false;
1984         if (this_entry.empty()) {
1985           m_args_error =
1986               Status::FromErrorStringWithFormatv("Argument definition element "
1987                                                  "{0} is empty",
1988                                                  counter);
1989           return false;
1990         }
1991         m_arguments.push_back(this_entry);
1992         counter++;
1993         return true;
1994       }; // end of arg_array_adder
1995       // Here we actually parse the args definition:
1996       args_array->ForEach(arg_array_adder);
1997     }
1998   }
1999 
2000   ~CommandObjectScriptingObjectParsed() override = default;
2001 
GetOptionsError()2002   Status GetOptionsError() { return m_options_error.Clone(); }
GetArgsError()2003   Status GetArgsError() { return m_args_error.Clone(); }
WantsCompletion()2004   bool WantsCompletion() override { return true; }
2005 
2006 private:
PrepareOptionsForCompletion(CompletionRequest & request,OptionElementVector & option_vec)2007   void PrepareOptionsForCompletion(CompletionRequest &request,
2008                                    OptionElementVector &option_vec) {
2009     // First, we have to tell the Scripted side to set the values in its
2010     // option store, then we call into the handle_completion passing in
2011     // an array of the args, the arg index and the cursor position in the arg.
2012     // We want the script side to have a chance to clear its state, so tell
2013     // it argument parsing has started:
2014     Options *options = GetOptions();
2015     // If there are not options, this will be nullptr, and in that case we
2016     // can just skip setting the options on the scripted side:
2017     if (options)
2018       m_options.PrepareOptionsForCompletion(request, option_vec, &m_exe_ctx);
2019   }
2020 
2021 public:
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & option_vec)2022   void HandleArgumentCompletion(CompletionRequest &request,
2023                                 OptionElementVector &option_vec) override {
2024     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
2025 
2026     if (!scripter)
2027       return;
2028 
2029     // Set up the options values on the scripted side:
2030     PrepareOptionsForCompletion(request, option_vec);
2031 
2032     // Now we have to make up the argument list.
2033     // The ParseForCompletion only identifies tokens in the m_parsed_line
2034     // it doesn't remove the options leaving only the args as it does for
2035     // the regular Parse, so we have to filter out the option ones using the
2036     // option_element_vector:
2037 
2038     Options *options = GetOptions();
2039     auto defs = options->GetDefinitions();
2040 
2041     std::unordered_set<size_t> option_slots;
2042     for (const auto &elem : option_vec) {
2043       if (elem.opt_defs_index == -1)
2044         continue;
2045       option_slots.insert(elem.opt_pos);
2046       if (defs[elem.opt_defs_index].option_has_arg)
2047         option_slots.insert(elem.opt_arg_pos);
2048     }
2049 
2050     std::vector<llvm::StringRef> args_vec;
2051     Args &args = request.GetParsedLine();
2052     size_t num_args = args.GetArgumentCount();
2053     size_t cursor_idx = request.GetCursorIndex();
2054     size_t args_elem_pos = cursor_idx;
2055 
2056     for (size_t idx = 0; idx < num_args; idx++) {
2057       if (option_slots.count(idx) == 0)
2058         args_vec.push_back(args[idx].ref());
2059       else if (idx < cursor_idx)
2060         args_elem_pos--;
2061     }
2062     StructuredData::DictionarySP completion_dict_sp =
2063         scripter->HandleArgumentCompletionForScriptedCommand(
2064             m_cmd_obj_sp, args_vec, args_elem_pos, request.GetCursorCharPos());
2065 
2066     if (!completion_dict_sp) {
2067       CommandObject::HandleArgumentCompletion(request, option_vec);
2068       return;
2069     }
2070 
2071     m_options.ProcessCompletionDict(request, completion_dict_sp);
2072   }
2073 
IsRemovable() const2074   bool IsRemovable() const override { return true; }
2075 
GetSynchronicity()2076   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
2077 
GetRepeatCommand(Args & args,uint32_t index)2078   std::optional<std::string> GetRepeatCommand(Args &args,
2079                                               uint32_t index) override {
2080     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
2081     if (!scripter)
2082       return std::nullopt;
2083 
2084     return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
2085   }
2086 
GetHelp()2087   llvm::StringRef GetHelp() override {
2088     if (m_fetched_help_short)
2089       return CommandObjectParsed::GetHelp();
2090     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
2091     if (!scripter)
2092       return CommandObjectParsed::GetHelp();
2093     std::string docstring;
2094     m_fetched_help_short =
2095         scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
2096     if (!docstring.empty())
2097       SetHelp(docstring);
2098 
2099     return CommandObjectParsed::GetHelp();
2100   }
2101 
GetHelpLong()2102   llvm::StringRef GetHelpLong() override {
2103     if (m_fetched_help_long)
2104       return CommandObjectParsed::GetHelpLong();
2105 
2106     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
2107     if (!scripter)
2108       return CommandObjectParsed::GetHelpLong();
2109 
2110     std::string docstring;
2111     m_fetched_help_long =
2112         scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
2113     if (!docstring.empty())
2114       SetHelpLong(docstring);
2115     return CommandObjectParsed::GetHelpLong();
2116   }
2117 
GetOptions()2118   Options *GetOptions() override {
2119     // CommandObjectParsed requires that a command with no options return
2120     // nullptr.
2121     if (m_options.GetNumOptions() == 0)
2122       return nullptr;
2123     return &m_options;
2124   }
2125 
2126 protected:
DoExecute(Args & args,CommandReturnObject & result)2127   void DoExecute(Args &args,
2128                  CommandReturnObject &result) override {
2129     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
2130 
2131     Status error;
2132 
2133     result.SetStatus(eReturnStatusInvalid);
2134 
2135     if (!scripter ||
2136         !scripter->RunScriptBasedParsedCommand(m_cmd_obj_sp, args,
2137                                          m_synchro, result, error, m_exe_ctx)) {
2138       result.AppendError(error.AsCString());
2139     } else {
2140       // Don't change the status if the command already set it...
2141       if (result.GetStatus() == eReturnStatusInvalid) {
2142         if (result.GetOutputString().empty())
2143           result.SetStatus(eReturnStatusSuccessFinishNoResult);
2144         else
2145           result.SetStatus(eReturnStatusSuccessFinishResult);
2146       }
2147     }
2148   }
2149 
2150 private:
2151   StructuredData::GenericSP m_cmd_obj_sp;
2152   ScriptedCommandSynchronicity m_synchro;
2153   CommandOptions m_options;
2154   Status m_options_error;
2155   Status m_args_error;
2156   bool m_fetched_help_short : 1;
2157   bool m_fetched_help_long : 1;
2158 };
2159 
2160 std::unordered_set<std::string>
2161     CommandObjectScriptingObjectParsed::CommandOptions::g_string_storer;
2162 
2163 // CommandObjectCommandsScriptImport
2164 #define LLDB_OPTIONS_script_import
2165 #include "CommandOptions.inc"
2166 
2167 class CommandObjectCommandsScriptImport : public CommandObjectParsed {
2168 public:
CommandObjectCommandsScriptImport(CommandInterpreter & interpreter)2169   CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
2170       : CommandObjectParsed(interpreter, "command script import",
2171                             "Import a scripting module in LLDB.", nullptr) {
2172     AddSimpleArgumentList(eArgTypeFilename, eArgRepeatPlus);
2173   }
2174 
2175   ~CommandObjectCommandsScriptImport() override = default;
2176 
GetOptions()2177   Options *GetOptions() override { return &m_options; }
2178 
2179 protected:
2180   class CommandOptions : public Options {
2181   public:
2182     CommandOptions() = default;
2183 
2184     ~CommandOptions() override = default;
2185 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2186     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2187                           ExecutionContext *execution_context) override {
2188       Status error;
2189       const int short_option = m_getopt_table[option_idx].val;
2190 
2191       switch (short_option) {
2192       case 'r':
2193         // NO-OP
2194         break;
2195       case 'c':
2196         relative_to_command_file = true;
2197         break;
2198       case 's':
2199         silent = true;
2200         break;
2201       default:
2202         llvm_unreachable("Unimplemented option");
2203       }
2204 
2205       return error;
2206     }
2207 
OptionParsingStarting(ExecutionContext * execution_context)2208     void OptionParsingStarting(ExecutionContext *execution_context) override {
2209       relative_to_command_file = false;
2210     }
2211 
GetDefinitions()2212     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2213       return llvm::ArrayRef(g_script_import_options);
2214     }
2215     bool relative_to_command_file = false;
2216     bool silent = false;
2217   };
2218 
DoExecute(Args & command,CommandReturnObject & result)2219   void DoExecute(Args &command, CommandReturnObject &result) override {
2220     if (command.empty()) {
2221       result.AppendError("command script import needs one or more arguments");
2222       return;
2223     }
2224 
2225     FileSpec source_dir = {};
2226     if (m_options.relative_to_command_file) {
2227       source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
2228       if (!source_dir) {
2229         result.AppendError("command script import -c can only be specified "
2230                            "from a command file");
2231         return;
2232       }
2233     }
2234 
2235     for (auto &entry : command.entries()) {
2236       Status error;
2237 
2238       LoadScriptOptions options;
2239       options.SetInitSession(true);
2240       options.SetSilent(m_options.silent);
2241 
2242       // FIXME: this is necessary because CommandObject::CheckRequirements()
2243       // assumes that commands won't ever be recursively invoked, but it's
2244       // actually possible to craft a Python script that does other "command
2245       // script imports" in __lldb_init_module the real fix is to have
2246       // recursive commands possible with a CommandInvocation object separate
2247       // from the CommandObject itself, so that recursive command invocations
2248       // won't stomp on each other (wrt to execution contents, options, and
2249       // more)
2250       m_exe_ctx.Clear();
2251       if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
2252               entry.c_str(), options, error, /*module_sp=*/nullptr,
2253               source_dir)) {
2254         result.SetStatus(eReturnStatusSuccessFinishNoResult);
2255       } else {
2256         result.AppendErrorWithFormat("module importing failed: %s",
2257                                      error.AsCString());
2258       }
2259     }
2260   }
2261 
2262   CommandOptions m_options;
2263 };
2264 
2265 #define LLDB_OPTIONS_script_add
2266 #include "CommandOptions.inc"
2267 
2268 class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
2269                                        public IOHandlerDelegateMultiline {
2270 public:
CommandObjectCommandsScriptAdd(CommandInterpreter & interpreter)2271   CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
2272       : CommandObjectParsed(interpreter, "command script add",
2273                             "Add a scripted function as an LLDB command.",
2274                             "Add a scripted function as an lldb command. "
2275                             "If you provide a single argument, the command "
2276                             "will be added at the root level of the command "
2277                             "hierarchy.  If there are more arguments they "
2278                             "must be a path to a user-added container "
2279                             "command, and the last element will be the new "
2280                             "command name."),
2281         IOHandlerDelegateMultiline("DONE") {
2282     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2283   }
2284 
2285   ~CommandObjectCommandsScriptAdd() override = default;
2286 
GetOptions()2287   Options *GetOptions() override { return &m_options; }
2288 
2289   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2290   HandleArgumentCompletion(CompletionRequest &request,
2291                            OptionElementVector &opt_element_vector) override {
2292     CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
2293                                                       opt_element_vector);
2294   }
2295 
2296 protected:
2297   class CommandOptions : public Options {
2298   public:
2299     CommandOptions() = default;
2300 
2301     ~CommandOptions() override = default;
2302 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2303     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2304                           ExecutionContext *execution_context) override {
2305       Status error;
2306       const int short_option = m_getopt_table[option_idx].val;
2307 
2308       switch (short_option) {
2309       case 'f':
2310         if (!option_arg.empty())
2311           m_funct_name = std::string(option_arg);
2312         break;
2313       case 'c':
2314         if (!option_arg.empty())
2315           m_class_name = std::string(option_arg);
2316         break;
2317       case 'h':
2318         if (!option_arg.empty())
2319           m_short_help = std::string(option_arg);
2320         break;
2321       case 'o':
2322         m_overwrite_lazy = eLazyBoolYes;
2323         break;
2324       case 'p':
2325         m_parsed_command = true;
2326         break;
2327       case 's':
2328         m_synchronicity =
2329             (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
2330                 option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
2331         if (!error.Success())
2332           return Status::FromErrorStringWithFormat(
2333               "unrecognized value for synchronicity '%s'",
2334               option_arg.str().c_str());
2335         break;
2336       case 'C': {
2337         Status error;
2338         OptionDefinition definition = GetDefinitions()[option_idx];
2339         lldb::CompletionType completion_type =
2340             static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum(
2341                 option_arg, definition.enum_values, eNoCompletion, error));
2342         if (!error.Success())
2343           return Status::FromErrorStringWithFormat(
2344               "unrecognized value for command completion type '%s'",
2345               option_arg.str().c_str());
2346         m_completion_type = completion_type;
2347       } break;
2348       default:
2349         llvm_unreachable("Unimplemented option");
2350       }
2351 
2352       return error;
2353     }
2354 
OptionParsingStarting(ExecutionContext * execution_context)2355     void OptionParsingStarting(ExecutionContext *execution_context) override {
2356       m_class_name.clear();
2357       m_funct_name.clear();
2358       m_short_help.clear();
2359       m_completion_type = eNoCompletion;
2360       m_overwrite_lazy = eLazyBoolCalculate;
2361       m_synchronicity = eScriptedCommandSynchronicitySynchronous;
2362       m_parsed_command = false;
2363     }
2364 
GetDefinitions()2365     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2366       return llvm::ArrayRef(g_script_add_options);
2367     }
2368 
2369     // Instance variables to hold the values for command options.
2370 
2371     std::string m_class_name;
2372     std::string m_funct_name;
2373     std::string m_short_help;
2374     LazyBool m_overwrite_lazy = eLazyBoolCalculate;
2375     ScriptedCommandSynchronicity m_synchronicity =
2376         eScriptedCommandSynchronicitySynchronous;
2377     CompletionType m_completion_type = eNoCompletion;
2378     bool m_parsed_command = false;
2379   };
2380 
IOHandlerActivated(IOHandler & io_handler,bool interactive)2381   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
2382     if (interactive) {
2383       if (lldb::LockableStreamFileSP output_sp =
2384               io_handler.GetOutputStreamFileSP()) {
2385         LockedStreamFile locked_stream = output_sp->Lock();
2386         locked_stream.PutCString(g_python_command_instructions);
2387       }
2388     }
2389   }
2390 
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)2391   void IOHandlerInputComplete(IOHandler &io_handler,
2392                               std::string &data) override {
2393     LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
2394 
2395     ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2396     if (interpreter) {
2397       StringList lines;
2398       lines.SplitIntoLines(data);
2399       if (lines.GetSize() > 0) {
2400         std::string funct_name_str;
2401         if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
2402           if (funct_name_str.empty()) {
2403             LockedStreamFile locked_stream = error_sp->Lock();
2404             locked_stream.Printf(
2405                 "error: unable to obtain a function name, didn't "
2406                 "add python command.\n");
2407           } else {
2408             // everything should be fine now, let's add this alias
2409 
2410             CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
2411                 m_interpreter, m_cmd_name, funct_name_str, m_short_help,
2412                 m_synchronicity, m_completion_type));
2413             if (!m_container) {
2414               Status error = m_interpreter.AddUserCommand(
2415                   m_cmd_name, command_obj_sp, m_overwrite);
2416               if (error.Fail()) {
2417                 LockedStreamFile locked_stream = error_sp->Lock();
2418                 locked_stream.Printf(
2419                     "error: unable to add selected command: '%s'",
2420                     error.AsCString());
2421               }
2422             } else {
2423               llvm::Error llvm_error = m_container->LoadUserSubcommand(
2424                   m_cmd_name, command_obj_sp, m_overwrite);
2425               if (llvm_error) {
2426                 LockedStreamFile locked_stream = error_sp->Lock();
2427                 locked_stream.Printf(
2428                     "error: unable to add selected command: '%s'",
2429                     llvm::toString(std::move(llvm_error)).c_str());
2430               }
2431             }
2432           }
2433         } else {
2434           LockedStreamFile locked_stream = error_sp->Lock();
2435           locked_stream.Printf(
2436               "error: unable to create function, didn't add python command\n");
2437         }
2438       } else {
2439         LockedStreamFile locked_stream = error_sp->Lock();
2440         locked_stream.Printf(
2441             "error: empty function, didn't add python command\n");
2442       }
2443     } else {
2444       LockedStreamFile locked_stream = error_sp->Lock();
2445       locked_stream.Printf(
2446           "error: script interpreter missing, didn't add python command\n");
2447     }
2448 
2449     io_handler.SetIsDone(true);
2450   }
2451 
DoExecute(Args & command,CommandReturnObject & result)2452   void DoExecute(Args &command, CommandReturnObject &result) override {
2453     if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
2454       result.AppendError("only scripting language supported for scripted "
2455                          "commands is currently Python");
2456       return;
2457     }
2458 
2459     if (command.GetArgumentCount() == 0) {
2460       result.AppendError("'command script add' requires at least one argument");
2461       return;
2462     }
2463     // Store the options in case we get multi-line input, also figure out the
2464     // default if not user supplied:
2465     switch (m_options.m_overwrite_lazy) {
2466       case eLazyBoolCalculate:
2467         m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite();
2468         break;
2469       case eLazyBoolYes:
2470         m_overwrite = true;
2471         break;
2472       case eLazyBoolNo:
2473         m_overwrite = false;
2474     }
2475 
2476     Status path_error;
2477     m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath(
2478         command, true, path_error);
2479 
2480     if (path_error.Fail()) {
2481       result.AppendErrorWithFormat("error in command path: %s",
2482                                    path_error.AsCString());
2483       return;
2484     }
2485 
2486     if (!m_container) {
2487       // This is getting inserted into the root of the interpreter.
2488       m_cmd_name = std::string(command[0].ref());
2489     } else {
2490       size_t num_args = command.GetArgumentCount();
2491       m_cmd_name = std::string(command[num_args - 1].ref());
2492     }
2493 
2494     m_short_help.assign(m_options.m_short_help);
2495     m_synchronicity = m_options.m_synchronicity;
2496     m_completion_type = m_options.m_completion_type;
2497 
2498     // Handle the case where we prompt for the script code first:
2499     if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) {
2500       m_interpreter.GetPythonCommandsFromIOHandler("     ", // Prompt
2501                                                    *this);  // IOHandlerDelegate
2502       return;
2503     }
2504 
2505     CommandObjectSP new_cmd_sp;
2506     if (m_options.m_class_name.empty()) {
2507       new_cmd_sp.reset(new CommandObjectPythonFunction(
2508           m_interpreter, m_cmd_name, m_options.m_funct_name,
2509           m_options.m_short_help, m_synchronicity, m_completion_type));
2510     } else {
2511       ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2512       if (!interpreter) {
2513         result.AppendError("cannot find ScriptInterpreter");
2514         return;
2515       }
2516 
2517       auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
2518           m_options.m_class_name.c_str());
2519       if (!cmd_obj_sp) {
2520         result.AppendErrorWithFormatv("cannot create helper object for: "
2521                                       "'{0}'", m_options.m_class_name);
2522         return;
2523       }
2524 
2525       if (m_options.m_parsed_command) {
2526         new_cmd_sp = CommandObjectScriptingObjectParsed::Create(m_interpreter,
2527             m_cmd_name, cmd_obj_sp, m_synchronicity, result);
2528         if (!result.Succeeded())
2529           return;
2530       } else
2531         new_cmd_sp.reset(new CommandObjectScriptingObjectRaw(
2532             m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity,
2533             m_completion_type));
2534     }
2535 
2536     // Assume we're going to succeed...
2537     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2538     if (!m_container) {
2539       Status add_error =
2540           m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite);
2541       if (add_error.Fail())
2542         result.AppendErrorWithFormat("cannot add command: %s",
2543                                      add_error.AsCString());
2544     } else {
2545       llvm::Error llvm_error =
2546           m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite);
2547       if (llvm_error)
2548         result.AppendErrorWithFormat(
2549             "cannot add command: %s",
2550             llvm::toString(std::move(llvm_error)).c_str());
2551     }
2552   }
2553 
2554   CommandOptions m_options;
2555   std::string m_cmd_name;
2556   CommandObjectMultiword *m_container = nullptr;
2557   std::string m_short_help;
2558   bool m_overwrite = false;
2559   ScriptedCommandSynchronicity m_synchronicity =
2560       eScriptedCommandSynchronicitySynchronous;
2561   CompletionType m_completion_type = eNoCompletion;
2562 };
2563 
2564 // CommandObjectCommandsScriptList
2565 
2566 class CommandObjectCommandsScriptList : public CommandObjectParsed {
2567 public:
CommandObjectCommandsScriptList(CommandInterpreter & interpreter)2568   CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
2569       : CommandObjectParsed(interpreter, "command script list",
2570                             "List defined top-level scripted commands.",
2571                             nullptr) {}
2572 
2573   ~CommandObjectCommandsScriptList() override = default;
2574 
DoExecute(Args & command,CommandReturnObject & result)2575   void DoExecute(Args &command, CommandReturnObject &result) override {
2576     m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
2577 
2578     result.SetStatus(eReturnStatusSuccessFinishResult);
2579   }
2580 };
2581 
2582 // CommandObjectCommandsScriptClear
2583 
2584 class CommandObjectCommandsScriptClear : public CommandObjectParsed {
2585 public:
CommandObjectCommandsScriptClear(CommandInterpreter & interpreter)2586   CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
2587       : CommandObjectParsed(interpreter, "command script clear",
2588                             "Delete all scripted commands.", nullptr) {}
2589 
2590   ~CommandObjectCommandsScriptClear() override = default;
2591 
2592 protected:
DoExecute(Args & command,CommandReturnObject & result)2593   void DoExecute(Args &command, CommandReturnObject &result) override {
2594     m_interpreter.RemoveAllUser();
2595 
2596     result.SetStatus(eReturnStatusSuccessFinishResult);
2597   }
2598 };
2599 
2600 // CommandObjectCommandsScriptDelete
2601 
2602 class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
2603 public:
CommandObjectCommandsScriptDelete(CommandInterpreter & interpreter)2604   CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
2605       : CommandObjectParsed(
2606             interpreter, "command script delete",
2607             "Delete a scripted command by specifying the path to the command.",
2608             nullptr) {
2609     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2610   }
2611 
2612   ~CommandObjectCommandsScriptDelete() override = default;
2613 
2614   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2615   HandleArgumentCompletion(CompletionRequest &request,
2616                            OptionElementVector &opt_element_vector) override {
2617     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2618         m_interpreter, request, opt_element_vector);
2619   }
2620 
2621 protected:
DoExecute(Args & command,CommandReturnObject & result)2622   void DoExecute(Args &command, CommandReturnObject &result) override {
2623 
2624     llvm::StringRef root_cmd = command[0].ref();
2625     size_t num_args = command.GetArgumentCount();
2626 
2627     if (root_cmd.empty()) {
2628       result.AppendErrorWithFormat("empty root command name");
2629       return;
2630     }
2631     if (!m_interpreter.HasUserCommands() &&
2632         !m_interpreter.HasUserMultiwordCommands()) {
2633       result.AppendErrorWithFormat("can only delete user defined commands, "
2634                                    "but no user defined commands found");
2635       return;
2636     }
2637 
2638     CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd);
2639     if (!cmd_sp) {
2640       result.AppendErrorWithFormat("command '%s' not found.",
2641                                    command[0].c_str());
2642       return;
2643     }
2644     if (!cmd_sp->IsUserCommand()) {
2645       result.AppendErrorWithFormat("command '%s' is not a user command.",
2646                                    command[0].c_str());
2647       return;
2648     }
2649     if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) {
2650       result.AppendErrorWithFormat("command '%s' is a multi-word command.\n "
2651                                    "Delete with \"command container delete\"",
2652                                    command[0].c_str());
2653       return;
2654     }
2655 
2656     if (command.GetArgumentCount() == 1) {
2657       m_interpreter.RemoveUser(root_cmd);
2658       result.SetStatus(eReturnStatusSuccessFinishResult);
2659       return;
2660     }
2661     // We're deleting a command from a multiword command.  Verify the command
2662     // path:
2663     Status error;
2664     CommandObjectMultiword *container =
2665         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2666                                                            error);
2667     if (error.Fail()) {
2668       result.AppendErrorWithFormat("could not resolve command path: %s",
2669                                    error.AsCString());
2670       return;
2671     }
2672     if (!container) {
2673       // This means that command only had a leaf command, so the container is
2674       // the root.  That should have been handled above.
2675       result.AppendErrorWithFormat("could not find a container for '%s'",
2676                                    command[0].c_str());
2677       return;
2678     }
2679     const char *leaf_cmd = command[num_args - 1].c_str();
2680     llvm::Error llvm_error =
2681         container->RemoveUserSubcommand(leaf_cmd,
2682                                         /* multiword not okay */ false);
2683     if (llvm_error) {
2684       result.AppendErrorWithFormat(
2685           "could not delete command '%s': %s", leaf_cmd,
2686           llvm::toString(std::move(llvm_error)).c_str());
2687       return;
2688     }
2689 
2690     Stream &out_stream = result.GetOutputStream();
2691 
2692     out_stream << "Deleted command:";
2693     for (size_t idx = 0; idx < num_args; idx++) {
2694       out_stream << ' ';
2695       out_stream << command[idx].c_str();
2696     }
2697     out_stream << '\n';
2698     result.SetStatus(eReturnStatusSuccessFinishResult);
2699   }
2700 };
2701 
2702 #pragma mark CommandObjectMultiwordCommandsScript
2703 
2704 // CommandObjectMultiwordCommandsScript
2705 
2706 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
2707 public:
CommandObjectMultiwordCommandsScript(CommandInterpreter & interpreter)2708   CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
2709       : CommandObjectMultiword(
2710             interpreter, "command script",
2711             "Commands for managing custom "
2712             "commands implemented by "
2713             "interpreter scripts.",
2714             "command script <subcommand> [<subcommand-options>]") {
2715     LoadSubCommand("add", CommandObjectSP(
2716                               new CommandObjectCommandsScriptAdd(interpreter)));
2717     LoadSubCommand(
2718         "delete",
2719         CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
2720     LoadSubCommand(
2721         "clear",
2722         CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
2723     LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
2724                                interpreter)));
2725     LoadSubCommand(
2726         "import",
2727         CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
2728   }
2729 
2730   ~CommandObjectMultiwordCommandsScript() override = default;
2731 };
2732 
2733 #pragma mark CommandObjectCommandContainer
2734 #define LLDB_OPTIONS_container_add
2735 #include "CommandOptions.inc"
2736 
2737 class CommandObjectCommandsContainerAdd : public CommandObjectParsed {
2738 public:
CommandObjectCommandsContainerAdd(CommandInterpreter & interpreter)2739   CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter)
2740       : CommandObjectParsed(
2741             interpreter, "command container add",
2742             "Add a container command to lldb.  Adding to built-"
2743             "in container commands is not allowed.",
2744             "command container add [[path1]...] container-name") {
2745     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2746   }
2747 
2748   ~CommandObjectCommandsContainerAdd() override = default;
2749 
GetOptions()2750   Options *GetOptions() override { return &m_options; }
2751 
2752   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2753   HandleArgumentCompletion(CompletionRequest &request,
2754                            OptionElementVector &opt_element_vector) override {
2755     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2756         m_interpreter, request, opt_element_vector);
2757   }
2758 
2759 protected:
2760   class CommandOptions : public Options {
2761   public:
2762     CommandOptions() = default;
2763 
2764     ~CommandOptions() override = default;
2765 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2766     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2767                           ExecutionContext *execution_context) override {
2768       Status error;
2769       const int short_option = m_getopt_table[option_idx].val;
2770 
2771       switch (short_option) {
2772       case 'h':
2773         if (!option_arg.empty())
2774           m_short_help = std::string(option_arg);
2775         break;
2776       case 'o':
2777         m_overwrite = true;
2778         break;
2779       case 'H':
2780         if (!option_arg.empty())
2781           m_long_help = std::string(option_arg);
2782         break;
2783       default:
2784         llvm_unreachable("Unimplemented option");
2785       }
2786 
2787       return error;
2788     }
2789 
OptionParsingStarting(ExecutionContext * execution_context)2790     void OptionParsingStarting(ExecutionContext *execution_context) override {
2791       m_short_help.clear();
2792       m_long_help.clear();
2793       m_overwrite = false;
2794     }
2795 
GetDefinitions()2796     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2797       return llvm::ArrayRef(g_container_add_options);
2798     }
2799 
2800     // Instance variables to hold the values for command options.
2801 
2802     std::string m_short_help;
2803     std::string m_long_help;
2804     bool m_overwrite = false;
2805   };
DoExecute(Args & command,CommandReturnObject & result)2806   void DoExecute(Args &command, CommandReturnObject &result) override {
2807     size_t num_args = command.GetArgumentCount();
2808 
2809     if (num_args == 0) {
2810       result.AppendError("no command was specified");
2811       return;
2812     }
2813 
2814     if (num_args == 1) {
2815       // We're adding this as a root command, so use the interpreter.
2816       const char *cmd_name = command.GetArgumentAtIndex(0);
2817       auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
2818           GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
2819           m_options.m_long_help.c_str()));
2820       cmd_sp->GetAsMultiwordCommand()->SetRemovable(true);
2821       Status add_error = GetCommandInterpreter().AddUserCommand(
2822           cmd_name, cmd_sp, m_options.m_overwrite);
2823       if (add_error.Fail()) {
2824         result.AppendErrorWithFormat("error adding command: %s",
2825                                      add_error.AsCString());
2826         return;
2827       }
2828       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2829       return;
2830     }
2831 
2832     // We're adding this to a subcommand, first find the subcommand:
2833     Status path_error;
2834     CommandObjectMultiword *add_to_me =
2835         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2836                                                            path_error);
2837 
2838     if (!add_to_me) {
2839       result.AppendErrorWithFormat("error adding command: %s",
2840                                    path_error.AsCString());
2841       return;
2842     }
2843 
2844     const char *cmd_name = command.GetArgumentAtIndex(num_args - 1);
2845     auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
2846         GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
2847         m_options.m_long_help.c_str()));
2848     llvm::Error llvm_error =
2849         add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite);
2850     if (llvm_error) {
2851       result.AppendErrorWithFormat("error adding subcommand: %s",
2852                                    llvm::toString(std::move(llvm_error)).c_str());
2853       return;
2854     }
2855 
2856     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2857   }
2858 
2859 private:
2860   CommandOptions m_options;
2861 };
2862 
2863 #define LLDB_OPTIONS_multiword_delete
2864 #include "CommandOptions.inc"
2865 class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
2866 public:
CommandObjectCommandsContainerDelete(CommandInterpreter & interpreter)2867   CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter)
2868       : CommandObjectParsed(
2869             interpreter, "command container delete",
2870             "Delete a container command previously added to "
2871             "lldb.",
2872             "command container delete [[path1] ...] container-cmd") {
2873     AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2874   }
2875 
2876   ~CommandObjectCommandsContainerDelete() override = default;
2877 
2878   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2879   HandleArgumentCompletion(CompletionRequest &request,
2880                            OptionElementVector &opt_element_vector) override {
2881     lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2882         m_interpreter, request, opt_element_vector);
2883   }
2884 
2885 protected:
DoExecute(Args & command,CommandReturnObject & result)2886   void DoExecute(Args &command, CommandReturnObject &result) override {
2887     size_t num_args = command.GetArgumentCount();
2888 
2889     if (num_args == 0) {
2890       result.AppendError("No command was specified.");
2891       return;
2892     }
2893 
2894     if (num_args == 1) {
2895       // We're removing a root command, so we need to delete it from the
2896       // interpreter.
2897       const char *cmd_name = command.GetArgumentAtIndex(0);
2898       // Let's do a little more work here so we can do better error reporting.
2899       CommandInterpreter &interp = GetCommandInterpreter();
2900       CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name);
2901       if (!cmd_sp) {
2902         result.AppendErrorWithFormat("container command %s doesn't exist.",
2903                                      cmd_name);
2904         return;
2905       }
2906       if (!cmd_sp->IsUserCommand()) {
2907         result.AppendErrorWithFormat(
2908             "container command %s is not a user command", cmd_name);
2909         return;
2910       }
2911       if (!cmd_sp->GetAsMultiwordCommand()) {
2912         result.AppendErrorWithFormat("command %s is not a container command",
2913                                      cmd_name);
2914         return;
2915       }
2916 
2917       bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name);
2918       if (!did_remove) {
2919         result.AppendErrorWithFormat("error removing command %s.", cmd_name);
2920         return;
2921       }
2922 
2923       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2924       return;
2925     }
2926 
2927     // We're removing a subcommand, first find the subcommand's owner:
2928     Status path_error;
2929     CommandObjectMultiword *container =
2930         GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2931                                                            path_error);
2932 
2933     if (!container) {
2934       result.AppendErrorWithFormat("error removing container command: %s",
2935                                    path_error.AsCString());
2936       return;
2937     }
2938     const char *leaf = command.GetArgumentAtIndex(num_args - 1);
2939     llvm::Error llvm_error =
2940         container->RemoveUserSubcommand(leaf, /* multiword okay */ true);
2941     if (llvm_error) {
2942       result.AppendErrorWithFormat("error removing container command: %s",
2943                                    llvm::toString(std::move(llvm_error)).c_str());
2944       return;
2945     }
2946     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2947   }
2948 };
2949 
2950 class CommandObjectCommandContainer : public CommandObjectMultiword {
2951 public:
CommandObjectCommandContainer(CommandInterpreter & interpreter)2952   CommandObjectCommandContainer(CommandInterpreter &interpreter)
2953       : CommandObjectMultiword(
2954             interpreter, "command container",
2955             "Commands for adding container commands to lldb.  "
2956             "Container commands are containers for other commands.  You can "
2957             "add nested container commands by specifying a command path, "
2958             "but you can't add commands into the built-in command hierarchy.",
2959             "command container <subcommand> [<subcommand-options>]") {
2960     LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd(
2961                               interpreter)));
2962     LoadSubCommand(
2963         "delete",
2964         CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter)));
2965   }
2966 
2967   ~CommandObjectCommandContainer() override = default;
2968 };
2969 
2970 #pragma mark CommandObjectMultiwordCommands
2971 
2972 // CommandObjectMultiwordCommands
2973 
CommandObjectMultiwordCommands(CommandInterpreter & interpreter)2974 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
2975     CommandInterpreter &interpreter)
2976     : CommandObjectMultiword(interpreter, "command",
2977                              "Commands for managing custom LLDB commands.",
2978                              "command <subcommand> [<subcommand-options>]") {
2979   LoadSubCommand("source",
2980                  CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
2981   LoadSubCommand("alias",
2982                  CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
2983   LoadSubCommand("unalias", CommandObjectSP(
2984                                 new CommandObjectCommandsUnalias(interpreter)));
2985   LoadSubCommand("delete",
2986                  CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
2987   LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer(
2988                                   interpreter)));
2989   LoadSubCommand(
2990       "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
2991   LoadSubCommand(
2992       "script",
2993       CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
2994 }
2995 
2996 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
2997