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