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

source code of lldb/source/Commands/CommandObjectCommands.cpp