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