1 //===-- CommandObjectCommands.cpp -----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "CommandObjectCommands.h"
10 #include "CommandObjectHelp.h"
11 #include "CommandObjectRegexCommand.h"
12 #include "lldb/Core/Debugger.h"
13 #include "lldb/Core/IOHandler.h"
14 #include "lldb/Interpreter/CommandHistory.h"
15 #include "lldb/Interpreter/CommandInterpreter.h"
16 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17 #include "lldb/Interpreter/CommandReturnObject.h"
18 #include "lldb/Interpreter/OptionArgParser.h"
19 #include "lldb/Interpreter/OptionValueBoolean.h"
20 #include "lldb/Interpreter/OptionValueString.h"
21 #include "lldb/Interpreter/OptionValueUInt64.h"
22 #include "lldb/Interpreter/Options.h"
23 #include "lldb/Interpreter/ScriptInterpreter.h"
24 #include "lldb/Utility/Args.h"
25 #include "lldb/Utility/StringList.h"
26 #include "llvm/ADT/StringRef.h"
27 #include <optional>
28
29 using namespace lldb;
30 using namespace lldb_private;
31
32 // CommandObjectCommandsSource
33
34 #define LLDB_OPTIONS_source
35 #include "CommandOptions.inc"
36
37 class CommandObjectCommandsSource : public CommandObjectParsed {
38 public:
CommandObjectCommandsSource(CommandInterpreter & interpreter)39 CommandObjectCommandsSource(CommandInterpreter &interpreter)
40 : CommandObjectParsed(
41 interpreter, "command source",
42 "Read and execute LLDB commands from the file <filename>.",
43 nullptr) {
44 CommandArgumentEntry arg;
45 CommandArgumentData file_arg;
46
47 // Define the first (and only) variant of this arg.
48 file_arg.arg_type = eArgTypeFilename;
49 file_arg.arg_repetition = eArgRepeatPlain;
50
51 // There is only one variant this argument could be; put it into the
52 // argument entry.
53 arg.push_back(file_arg);
54
55 // Push the data for the first argument into the m_arguments vector.
56 m_arguments.push_back(arg);
57 }
58
59 ~CommandObjectCommandsSource() override = default;
60
GetRepeatCommand(Args & current_command_args,uint32_t index)61 std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,
62 uint32_t index) override {
63 return std::string("");
64 }
65
66 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)67 HandleArgumentCompletion(CompletionRequest &request,
68 OptionElementVector &opt_element_vector) override {
69 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
70 GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);
71 }
72
GetOptions()73 Options *GetOptions() override { return &m_options; }
74
75 protected:
76 class CommandOptions : public Options {
77 public:
CommandOptions()78 CommandOptions()
79 : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true),
80 m_cmd_relative_to_command_file(false) {}
81
82 ~CommandOptions() override = default;
83
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)84 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
85 ExecutionContext *execution_context) override {
86 Status error;
87 const int short_option = m_getopt_table[option_idx].val;
88
89 switch (short_option) {
90 case 'e':
91 error = m_stop_on_error.SetValueFromString(option_arg);
92 break;
93
94 case 'c':
95 error = m_stop_on_continue.SetValueFromString(option_arg);
96 break;
97
98 case 'C':
99 m_cmd_relative_to_command_file = true;
100 break;
101
102 case 's':
103 error = m_silent_run.SetValueFromString(option_arg);
104 break;
105
106 default:
107 llvm_unreachable("Unimplemented option");
108 }
109
110 return error;
111 }
112
OptionParsingStarting(ExecutionContext * execution_context)113 void OptionParsingStarting(ExecutionContext *execution_context) override {
114 m_stop_on_error.Clear();
115 m_silent_run.Clear();
116 m_stop_on_continue.Clear();
117 m_cmd_relative_to_command_file.Clear();
118 }
119
GetDefinitions()120 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
121 return llvm::ArrayRef(g_source_options);
122 }
123
124 // Instance variables to hold the values for command options.
125
126 OptionValueBoolean m_stop_on_error;
127 OptionValueBoolean m_silent_run;
128 OptionValueBoolean m_stop_on_continue;
129 OptionValueBoolean m_cmd_relative_to_command_file;
130 };
131
DoExecute(Args & command,CommandReturnObject & result)132 void DoExecute(Args &command, CommandReturnObject &result) override {
133 if (command.GetArgumentCount() != 1) {
134 result.AppendErrorWithFormat(
135 "'%s' takes exactly one executable filename argument.\n",
136 GetCommandName().str().c_str());
137 return;
138 }
139
140 FileSpec source_dir = {};
141 if (m_options.m_cmd_relative_to_command_file) {
142 source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
143 if (!source_dir) {
144 result.AppendError("command source -C can only be specified "
145 "from a command file");
146 result.SetStatus(eReturnStatusFailed);
147 return;
148 }
149 }
150
151 FileSpec cmd_file(command[0].ref());
152 if (source_dir) {
153 // Prepend the source_dir to the cmd_file path:
154 if (!cmd_file.IsRelative()) {
155 result.AppendError("command source -C can only be used "
156 "with a relative path.");
157 result.SetStatus(eReturnStatusFailed);
158 return;
159 }
160 cmd_file.MakeAbsolute(source_dir);
161 }
162
163 FileSystem::Instance().Resolve(cmd_file);
164
165 CommandInterpreterRunOptions options;
166 // If any options were set, then use them
167 if (m_options.m_stop_on_error.OptionWasSet() ||
168 m_options.m_silent_run.OptionWasSet() ||
169 m_options.m_stop_on_continue.OptionWasSet()) {
170 if (m_options.m_stop_on_continue.OptionWasSet())
171 options.SetStopOnContinue(
172 m_options.m_stop_on_continue.GetCurrentValue());
173
174 if (m_options.m_stop_on_error.OptionWasSet())
175 options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
176
177 // Individual silent setting is override for global command echo settings.
178 if (m_options.m_silent_run.GetCurrentValue()) {
179 options.SetSilent(true);
180 } else {
181 options.SetPrintResults(true);
182 options.SetPrintErrors(true);
183 options.SetEchoCommands(m_interpreter.GetEchoCommands());
184 options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
185 }
186 }
187
188 m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
189 }
190
191 CommandOptions m_options;
192 };
193
194 #pragma mark CommandObjectCommandsAlias
195 // CommandObjectCommandsAlias
196
197 #define LLDB_OPTIONS_alias
198 #include "CommandOptions.inc"
199
200 static const char *g_python_command_instructions =
201 "Enter your Python command(s). Type 'DONE' to end.\n"
202 "You must define a Python function with this signature:\n"
203 "def my_command_impl(debugger, args, exe_ctx, result, internal_dict):\n";
204
205 class CommandObjectCommandsAlias : public CommandObjectRaw {
206 protected:
207 class CommandOptions : public OptionGroup {
208 public:
209 CommandOptions() = default;
210
211 ~CommandOptions() override = default;
212
GetDefinitions()213 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
214 return llvm::ArrayRef(g_alias_options);
215 }
216
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)217 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
218 ExecutionContext *execution_context) override {
219 Status error;
220
221 const int short_option = GetDefinitions()[option_idx].short_option;
222 std::string option_str(option_value);
223
224 switch (short_option) {
225 case 'h':
226 m_help.SetCurrentValue(option_str);
227 m_help.SetOptionWasSet();
228 break;
229
230 case 'H':
231 m_long_help.SetCurrentValue(option_str);
232 m_long_help.SetOptionWasSet();
233 break;
234
235 default:
236 llvm_unreachable("Unimplemented option");
237 }
238
239 return error;
240 }
241
OptionParsingStarting(ExecutionContext * execution_context)242 void OptionParsingStarting(ExecutionContext *execution_context) override {
243 m_help.Clear();
244 m_long_help.Clear();
245 }
246
247 OptionValueString m_help;
248 OptionValueString m_long_help;
249 };
250
251 OptionGroupOptions m_option_group;
252 CommandOptions m_command_options;
253
254 public:
GetOptions()255 Options *GetOptions() override { return &m_option_group; }
256
CommandObjectCommandsAlias(CommandInterpreter & interpreter)257 CommandObjectCommandsAlias(CommandInterpreter &interpreter)
258 : CommandObjectRaw(
259 interpreter, "command alias",
260 "Define a custom command in terms of an existing command.") {
261 m_option_group.Append(&m_command_options);
262 m_option_group.Finalize();
263
264 SetHelpLong(
265 "'alias' allows the user to create a short-cut or abbreviation for long \
266 commands, multi-word commands, and commands that take particular options. \
267 Below are some simple examples of how one might use the 'alias' command:"
268 R"(
269
270 (lldb) command alias sc script
271
272 Creates the abbreviation 'sc' for the 'script' command.
273
274 (lldb) command alias bp breakpoint
275
276 )"
277 " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \
278 breakpoint commands are two-word commands, the user would still need to \
279 enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
280 R"(
281
282 (lldb) command alias bpl breakpoint list
283
284 Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
285
286 )"
287 "An alias can include some options for the command, with the values either \
288 filled in at the time the alias is created, or specified as positional \
289 arguments, to be filled in when the alias is invoked. The following example \
290 shows how to create aliases with options:"
291 R"(
292
293 (lldb) command alias bfl breakpoint set -f %1 -l %2
294
295 )"
296 " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
297 options already part of the alias. So if the user wants to set a breakpoint \
298 by file and line without explicitly having to use the -f and -l options, the \
299 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \
300 for the actual arguments that will be passed when the alias command is used. \
301 The number in the placeholder refers to the position/order the actual value \
302 occupies when the alias is used. All the occurrences of '%1' in the alias \
303 will be replaced with the first argument, all the occurrences of '%2' in the \
304 alias will be replaced with the second argument, and so on. This also allows \
305 actual arguments to be used multiple times within an alias (see 'process \
306 launch' example below)."
307 R"(
308
309 )"
310 "Note: the positional arguments must substitute as whole words in the resultant \
311 command, so you can't at present do something like this to append the file extension \
312 \".cpp\":"
313 R"(
314
315 (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
316
317 )"
318 "For more complex aliasing, use the \"command regex\" command instead. In the \
319 'bfl' case above, the actual file value will be filled in with the first argument \
320 following 'bfl' and the actual line number value will be filled in with the second \
321 argument. The user would use this alias as follows:"
322 R"(
323
324 (lldb) command alias bfl breakpoint set -f %1 -l %2
325 (lldb) bfl my-file.c 137
326
327 This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
328
329 Another example:
330
331 (lldb) command alias pltty process launch -s -o %1 -e %1
332 (lldb) pltty /dev/tty0
333
334 Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
335
336 )"
337 "If the user always wanted to pass the same value to a particular option, the \
338 alias could be defined with that value directly in the alias as a constant, \
339 rather than using a positional placeholder:"
340 R"(
341
342 (lldb) command alias bl3 breakpoint set -f %1 -l 3
343
344 Always sets a breakpoint on line 3 of whatever file is indicated.)");
345
346 CommandArgumentEntry arg1;
347 CommandArgumentEntry arg2;
348 CommandArgumentEntry arg3;
349 CommandArgumentData alias_arg;
350 CommandArgumentData cmd_arg;
351 CommandArgumentData options_arg;
352
353 // Define the first (and only) variant of this arg.
354 alias_arg.arg_type = eArgTypeAliasName;
355 alias_arg.arg_repetition = eArgRepeatPlain;
356
357 // There is only one variant this argument could be; put it into the
358 // argument entry.
359 arg1.push_back(alias_arg);
360
361 // Define the first (and only) variant of this arg.
362 cmd_arg.arg_type = eArgTypeCommandName;
363 cmd_arg.arg_repetition = eArgRepeatPlain;
364
365 // There is only one variant this argument could be; put it into the
366 // argument entry.
367 arg2.push_back(cmd_arg);
368
369 // Define the first (and only) variant of this arg.
370 options_arg.arg_type = eArgTypeAliasOptions;
371 options_arg.arg_repetition = eArgRepeatOptional;
372
373 // There is only one variant this argument could be; put it into the
374 // argument entry.
375 arg3.push_back(options_arg);
376
377 // Push the data for the first argument into the m_arguments vector.
378 m_arguments.push_back(arg1);
379 m_arguments.push_back(arg2);
380 m_arguments.push_back(arg3);
381 }
382
383 ~CommandObjectCommandsAlias() override = default;
384
385 protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)386 void DoExecute(llvm::StringRef raw_command_line,
387 CommandReturnObject &result) override {
388 if (raw_command_line.empty()) {
389 result.AppendError("'command alias' requires at least two arguments");
390 return;
391 }
392
393 ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
394 m_option_group.NotifyOptionParsingStarting(&exe_ctx);
395
396 OptionsWithRaw args_with_suffix(raw_command_line);
397
398 if (args_with_suffix.HasArgs())
399 if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result,
400 m_option_group, exe_ctx))
401 return;
402
403 llvm::StringRef raw_command_string = args_with_suffix.GetRawPart();
404 Args args(raw_command_string);
405
406 if (args.GetArgumentCount() < 2) {
407 result.AppendError("'command alias' requires at least two arguments");
408 return;
409 }
410
411 // Get the alias command.
412
413 auto alias_command = args[0].ref();
414 if (alias_command.starts_with("-")) {
415 result.AppendError("aliases starting with a dash are not supported");
416 if (alias_command == "--help" || alias_command == "--long-help") {
417 result.AppendWarning("if trying to pass options to 'command alias' add "
418 "a -- at the end of the options");
419 }
420 return;
421 }
422
423 // Strip the new alias name off 'raw_command_string' (leave it on args,
424 // which gets passed to 'Execute', which does the stripping itself.
425 size_t pos = raw_command_string.find(alias_command);
426 if (pos == 0) {
427 raw_command_string = raw_command_string.substr(alias_command.size());
428 pos = raw_command_string.find_first_not_of(' ');
429 if ((pos != std::string::npos) && (pos > 0))
430 raw_command_string = raw_command_string.substr(pos);
431 } else {
432 result.AppendError("Error parsing command string. No alias created.");
433 return;
434 }
435
436 // Verify that the command is alias-able.
437 if (m_interpreter.CommandExists(alias_command)) {
438 result.AppendErrorWithFormat(
439 "'%s' is a permanent debugger command and cannot be redefined.\n",
440 args[0].c_str());
441 return;
442 }
443
444 if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
445 result.AppendErrorWithFormat(
446 "'%s' is a user container command and cannot be overwritten.\n"
447 "Delete it first with 'command container delete'\n",
448 args[0].c_str());
449 return;
450 }
451
452 // Get CommandObject that is being aliased. The command name is read from
453 // the front of raw_command_string. raw_command_string is returned with the
454 // name of the command object stripped off the front.
455 llvm::StringRef original_raw_command_string = raw_command_string;
456 CommandObject *cmd_obj =
457 m_interpreter.GetCommandObjectForCommand(raw_command_string);
458
459 if (!cmd_obj) {
460 result.AppendErrorWithFormat("invalid command given to 'command alias'. "
461 "'%s' does not begin with a valid command."
462 " No alias created.",
463 original_raw_command_string.str().c_str());
464 } else if (!cmd_obj->WantsRawCommandString()) {
465 // Note that args was initialized with the original command, and has not
466 // been updated to this point. Therefore can we pass it to the version of
467 // Execute that does not need/expect raw input in the alias.
468 HandleAliasingNormalCommand(args, result);
469 } else {
470 HandleAliasingRawCommand(alias_command, raw_command_string, *cmd_obj,
471 result);
472 }
473 }
474
HandleAliasingRawCommand(llvm::StringRef alias_command,llvm::StringRef raw_command_string,CommandObject & cmd_obj,CommandReturnObject & result)475 bool HandleAliasingRawCommand(llvm::StringRef alias_command,
476 llvm::StringRef raw_command_string,
477 CommandObject &cmd_obj,
478 CommandReturnObject &result) {
479 // Verify & handle any options/arguments passed to the alias command
480
481 OptionArgVectorSP option_arg_vector_sp =
482 OptionArgVectorSP(new OptionArgVector);
483
484 const bool include_aliases = true;
485 // Look up the command using command's name first. This is to resolve
486 // aliases when you are making nested aliases. But if you don't find
487 // it that way, then it wasn't an alias and we can just use the object
488 // we were passed in.
489 CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact(
490 cmd_obj.GetCommandName(), include_aliases);
491 if (!cmd_obj_sp)
492 cmd_obj_sp = cmd_obj.shared_from_this();
493
494 if (m_interpreter.AliasExists(alias_command) ||
495 m_interpreter.UserCommandExists(alias_command)) {
496 result.AppendWarningWithFormat(
497 "Overwriting existing definition for '%s'.\n",
498 alias_command.str().c_str());
499 }
500 if (CommandAlias *alias = m_interpreter.AddAlias(
501 alias_command, cmd_obj_sp, raw_command_string)) {
502 if (m_command_options.m_help.OptionWasSet())
503 alias->SetHelp(m_command_options.m_help.GetCurrentValue());
504 if (m_command_options.m_long_help.OptionWasSet())
505 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
506 result.SetStatus(eReturnStatusSuccessFinishNoResult);
507 } else {
508 result.AppendError("Unable to create requested alias.\n");
509 }
510 return result.Succeeded();
511 }
512
HandleAliasingNormalCommand(Args & args,CommandReturnObject & result)513 bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
514 size_t argc = args.GetArgumentCount();
515
516 if (argc < 2) {
517 result.AppendError("'command alias' requires at least two arguments");
518 return false;
519 }
520
521 // Save these in std::strings since we're going to shift them off.
522 const std::string alias_command(std::string(args[0].ref()));
523 const std::string actual_command(std::string(args[1].ref()));
524
525 args.Shift(); // Shift the alias command word off the argument vector.
526 args.Shift(); // Shift the old command word off the argument vector.
527
528 // Verify that the command is alias'able, and get the appropriate command
529 // object.
530
531 if (m_interpreter.CommandExists(alias_command)) {
532 result.AppendErrorWithFormat(
533 "'%s' is a permanent debugger command and cannot be redefined.\n",
534 alias_command.c_str());
535 return false;
536 }
537
538 if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
539 result.AppendErrorWithFormat(
540 "'%s' is user container command and cannot be overwritten.\n"
541 "Delete it first with 'command container delete'",
542 alias_command.c_str());
543 return false;
544 }
545
546 CommandObjectSP command_obj_sp(
547 m_interpreter.GetCommandSPExact(actual_command, true));
548 CommandObjectSP subcommand_obj_sp;
549 bool use_subcommand = false;
550 if (!command_obj_sp) {
551 result.AppendErrorWithFormat("'%s' is not an existing command.\n",
552 actual_command.c_str());
553 return false;
554 }
555 CommandObject *cmd_obj = command_obj_sp.get();
556 CommandObject *sub_cmd_obj = nullptr;
557 OptionArgVectorSP option_arg_vector_sp =
558 OptionArgVectorSP(new OptionArgVector);
559
560 while (cmd_obj->IsMultiwordObject() && !args.empty()) {
561 auto sub_command = args[0].ref();
562 assert(!sub_command.empty());
563 subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
564 if (!subcommand_obj_sp) {
565 result.AppendErrorWithFormat(
566 "'%s' is not a valid sub-command of '%s'. "
567 "Unable to create alias.\n",
568 args[0].c_str(), actual_command.c_str());
569 return false;
570 }
571
572 sub_cmd_obj = subcommand_obj_sp.get();
573 use_subcommand = true;
574 args.Shift(); // Shift the sub_command word off the argument vector.
575 cmd_obj = sub_cmd_obj;
576 }
577
578 // Verify & handle any options/arguments passed to the alias command
579
580 std::string args_string;
581
582 if (!args.empty()) {
583 CommandObjectSP tmp_sp =
584 m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName());
585 if (use_subcommand)
586 tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName());
587
588 args.GetCommandString(args_string);
589 }
590
591 if (m_interpreter.AliasExists(alias_command) ||
592 m_interpreter.UserCommandExists(alias_command)) {
593 result.AppendWarningWithFormat(
594 "Overwriting existing definition for '%s'.\n", alias_command.c_str());
595 }
596
597 if (CommandAlias *alias = m_interpreter.AddAlias(
598 alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
599 args_string)) {
600 if (m_command_options.m_help.OptionWasSet())
601 alias->SetHelp(m_command_options.m_help.GetCurrentValue());
602 if (m_command_options.m_long_help.OptionWasSet())
603 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
604 result.SetStatus(eReturnStatusSuccessFinishNoResult);
605 } else {
606 result.AppendError("Unable to create requested alias.\n");
607 return false;
608 }
609
610 return result.Succeeded();
611 }
612 };
613
614 #pragma mark CommandObjectCommandsUnalias
615 // CommandObjectCommandsUnalias
616
617 class CommandObjectCommandsUnalias : public CommandObjectParsed {
618 public:
CommandObjectCommandsUnalias(CommandInterpreter & interpreter)619 CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
620 : CommandObjectParsed(
621 interpreter, "command unalias",
622 "Delete one or more custom commands defined by 'command alias'.",
623 nullptr) {
624 CommandArgumentEntry arg;
625 CommandArgumentData alias_arg;
626
627 // Define the first (and only) variant of this arg.
628 alias_arg.arg_type = eArgTypeAliasName;
629 alias_arg.arg_repetition = eArgRepeatPlain;
630
631 // There is only one variant this argument could be; put it into the
632 // argument entry.
633 arg.push_back(alias_arg);
634
635 // Push the data for the first argument into the m_arguments vector.
636 m_arguments.push_back(arg);
637 }
638
639 ~CommandObjectCommandsUnalias() override = default;
640
641 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)642 HandleArgumentCompletion(CompletionRequest &request,
643 OptionElementVector &opt_element_vector) override {
644 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
645 return;
646
647 for (const auto &ent : m_interpreter.GetAliases()) {
648 request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
649 }
650 }
651
652 protected:
DoExecute(Args & args,CommandReturnObject & result)653 void DoExecute(Args &args, CommandReturnObject &result) override {
654 CommandObject::CommandMap::iterator pos;
655 CommandObject *cmd_obj;
656
657 if (args.empty()) {
658 result.AppendError("must call 'unalias' with a valid alias");
659 return;
660 }
661
662 auto command_name = args[0].ref();
663 cmd_obj = m_interpreter.GetCommandObject(command_name);
664 if (!cmd_obj) {
665 result.AppendErrorWithFormat(
666 "'%s' is not a known command.\nTry 'help' to see a "
667 "current list of commands.\n",
668 args[0].c_str());
669 return;
670 }
671
672 if (m_interpreter.CommandExists(command_name)) {
673 if (cmd_obj->IsRemovable()) {
674 result.AppendErrorWithFormat(
675 "'%s' is not an alias, it is a debugger command which can be "
676 "removed using the 'command delete' command.\n",
677 args[0].c_str());
678 } else {
679 result.AppendErrorWithFormat(
680 "'%s' is a permanent debugger command and cannot be removed.\n",
681 args[0].c_str());
682 }
683 return;
684 }
685
686 if (!m_interpreter.RemoveAlias(command_name)) {
687 if (m_interpreter.AliasExists(command_name))
688 result.AppendErrorWithFormat(
689 "Error occurred while attempting to unalias '%s'.\n",
690 args[0].c_str());
691 else
692 result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
693 args[0].c_str());
694 return;
695 }
696
697 result.SetStatus(eReturnStatusSuccessFinishNoResult);
698 }
699 };
700
701 #pragma mark CommandObjectCommandsDelete
702 // CommandObjectCommandsDelete
703
704 class CommandObjectCommandsDelete : public CommandObjectParsed {
705 public:
CommandObjectCommandsDelete(CommandInterpreter & interpreter)706 CommandObjectCommandsDelete(CommandInterpreter &interpreter)
707 : CommandObjectParsed(
708 interpreter, "command delete",
709 "Delete one or more custom commands defined by 'command regex'.",
710 nullptr) {
711 CommandArgumentEntry arg;
712 CommandArgumentData alias_arg;
713
714 // Define the first (and only) variant of this arg.
715 alias_arg.arg_type = eArgTypeCommandName;
716 alias_arg.arg_repetition = eArgRepeatPlain;
717
718 // There is only one variant this argument could be; put it into the
719 // argument entry.
720 arg.push_back(alias_arg);
721
722 // Push the data for the first argument into the m_arguments vector.
723 m_arguments.push_back(arg);
724 }
725
726 ~CommandObjectCommandsDelete() override = default;
727
728 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)729 HandleArgumentCompletion(CompletionRequest &request,
730 OptionElementVector &opt_element_vector) override {
731 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
732 return;
733
734 for (const auto &ent : m_interpreter.GetCommands()) {
735 if (ent.second->IsRemovable())
736 request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
737 }
738 }
739
740 protected:
DoExecute(Args & args,CommandReturnObject & result)741 void DoExecute(Args &args, CommandReturnObject &result) override {
742 CommandObject::CommandMap::iterator pos;
743
744 if (args.empty()) {
745 result.AppendErrorWithFormat("must call '%s' with one or more valid user "
746 "defined regular expression command names",
747 GetCommandName().str().c_str());
748 return;
749 }
750
751 auto command_name = args[0].ref();
752 if (!m_interpreter.CommandExists(command_name)) {
753 StreamString error_msg_stream;
754 const bool generate_upropos = true;
755 const bool generate_type_lookup = false;
756 CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
757 &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
758 generate_upropos, generate_type_lookup);
759 result.AppendError(error_msg_stream.GetString());
760 return;
761 }
762
763 if (!m_interpreter.RemoveCommand(command_name)) {
764 result.AppendErrorWithFormat(
765 "'%s' is a permanent debugger command and cannot be removed.\n",
766 args[0].c_str());
767 return;
768 }
769
770 result.SetStatus(eReturnStatusSuccessFinishNoResult);
771 }
772 };
773
774 // CommandObjectCommandsAddRegex
775
776 #define LLDB_OPTIONS_regex
777 #include "CommandOptions.inc"
778
779 #pragma mark CommandObjectCommandsAddRegex
780
781 class CommandObjectCommandsAddRegex : public CommandObjectParsed,
782 public IOHandlerDelegateMultiline {
783 public:
CommandObjectCommandsAddRegex(CommandInterpreter & interpreter)784 CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
785 : CommandObjectParsed(
786 interpreter, "command regex",
787 "Define a custom command in terms of "
788 "existing commands by matching "
789 "regular expressions.",
790 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
791 IOHandlerDelegateMultiline("",
792 IOHandlerDelegate::Completion::LLDBCommand) {
793 SetHelpLong(
794 R"(
795 )"
796 "This command allows the user to create powerful regular expression commands \
797 with substitutions. The regular expressions and substitutions are specified \
798 using the regular expression substitution format of:"
799 R"(
800
801 s/<regex>/<subst>/
802
803 )"
804 "<regex> is a regular expression that can use parenthesis to capture regular \
805 expression input and substitute the captured matches in the output using %1 \
806 for the first match, %2 for the second, and so on."
807 R"(
808
809 )"
810 "The regular expressions can all be specified on the command line if more than \
811 one argument is provided. If just the command name is provided on the command \
812 line, then the regular expressions and substitutions can be entered on separate \
813 lines, followed by an empty line to terminate the command definition."
814 R"(
815
816 EXAMPLES
817
818 )"
819 "The following example will define a regular expression command named 'f' that \
820 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
821 a number follows 'f':"
822 R"(
823
824 (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
825 CommandArgumentData thread_arg{eArgTypeSEDStylePair, eArgRepeatOptional};
826 m_arguments.push_back({thread_arg});
827 }
828
829 ~CommandObjectCommandsAddRegex() override = default;
830
831 protected:
IOHandlerActivated(IOHandler & io_handler,bool interactive)832 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
833 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
834 if (output_sp && interactive) {
835 output_sp->PutCString("Enter one or more sed substitution commands in "
836 "the form: 's/<regex>/<subst>/'.\nTerminate the "
837 "substitution list with an empty line.\n");
838 output_sp->Flush();
839 }
840 }
841
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)842 void IOHandlerInputComplete(IOHandler &io_handler,
843 std::string &data) override {
844 io_handler.SetIsDone(true);
845 if (m_regex_cmd_up) {
846 StringList lines;
847 if (lines.SplitIntoLines(data)) {
848 bool check_only = false;
849 for (const std::string &line : lines) {
850 Status error = AppendRegexSubstitution(line, check_only);
851 if (error.Fail()) {
852 if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) {
853 StreamSP out_stream = GetDebugger().GetAsyncOutputStream();
854 out_stream->Printf("error: %s\n", error.AsCString());
855 }
856 }
857 }
858 }
859 if (m_regex_cmd_up->HasRegexEntries()) {
860 CommandObjectSP cmd_sp(m_regex_cmd_up.release());
861 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
862 }
863 }
864 }
865
DoExecute(Args & command,CommandReturnObject & result)866 void DoExecute(Args &command, CommandReturnObject &result) override {
867 const size_t argc = command.GetArgumentCount();
868 if (argc == 0) {
869 result.AppendError("usage: 'command regex <command-name> "
870 "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
871 return;
872 }
873
874 Status error;
875 auto name = command[0].ref();
876 m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
877 m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 0,
878 true);
879
880 if (argc == 1) {
881 Debugger &debugger = GetDebugger();
882 bool color_prompt = debugger.GetUseColor();
883 const bool multiple_lines = true; // Get multiple lines
884 IOHandlerSP io_handler_sp(new IOHandlerEditline(
885 debugger, IOHandler::Type::Other,
886 "lldb-regex", // Name of input reader for history
887 llvm::StringRef("> "), // Prompt
888 llvm::StringRef(), // Continuation prompt
889 multiple_lines, color_prompt,
890 0, // Don't show line numbers
891 *this));
892
893 if (io_handler_sp) {
894 debugger.RunIOHandlerAsync(io_handler_sp);
895 result.SetStatus(eReturnStatusSuccessFinishNoResult);
896 }
897 } else {
898 for (auto &entry : command.entries().drop_front()) {
899 bool check_only = false;
900 error = AppendRegexSubstitution(entry.ref(), check_only);
901 if (error.Fail())
902 break;
903 }
904
905 if (error.Success()) {
906 AddRegexCommandToInterpreter();
907 }
908 }
909 if (error.Fail()) {
910 result.AppendError(error.AsCString());
911 }
912 }
913
AppendRegexSubstitution(const llvm::StringRef & regex_sed,bool check_only)914 Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed,
915 bool check_only) {
916 Status error;
917
918 if (!m_regex_cmd_up) {
919 error.SetErrorStringWithFormat(
920 "invalid regular expression command object for: '%.*s'",
921 (int)regex_sed.size(), regex_sed.data());
922 return error;
923 }
924
925 size_t regex_sed_size = regex_sed.size();
926
927 if (regex_sed_size <= 1) {
928 error.SetErrorStringWithFormat(
929 "regular expression substitution string is too short: '%.*s'",
930 (int)regex_sed.size(), regex_sed.data());
931 return error;
932 }
933
934 if (regex_sed[0] != 's') {
935 error.SetErrorStringWithFormat("regular expression substitution string "
936 "doesn't start with 's': '%.*s'",
937 (int)regex_sed.size(), regex_sed.data());
938 return error;
939 }
940 const size_t first_separator_char_pos = 1;
941 // use the char that follows 's' as the regex separator character so we can
942 // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
943 const char separator_char = regex_sed[first_separator_char_pos];
944 const size_t second_separator_char_pos =
945 regex_sed.find(separator_char, first_separator_char_pos + 1);
946
947 if (second_separator_char_pos == std::string::npos) {
948 error.SetErrorStringWithFormat(
949 "missing second '%c' separator char after '%.*s' in '%.*s'",
950 separator_char,
951 (int)(regex_sed.size() - first_separator_char_pos - 1),
952 regex_sed.data() + (first_separator_char_pos + 1),
953 (int)regex_sed.size(), regex_sed.data());
954 return error;
955 }
956
957 const size_t third_separator_char_pos =
958 regex_sed.find(separator_char, second_separator_char_pos + 1);
959
960 if (third_separator_char_pos == std::string::npos) {
961 error.SetErrorStringWithFormat(
962 "missing third '%c' separator char after '%.*s' in '%.*s'",
963 separator_char,
964 (int)(regex_sed.size() - second_separator_char_pos - 1),
965 regex_sed.data() + (second_separator_char_pos + 1),
966 (int)regex_sed.size(), regex_sed.data());
967 return error;
968 }
969
970 if (third_separator_char_pos != regex_sed_size - 1) {
971 // Make sure that everything that follows the last regex separator char
972 if (regex_sed.find_first_not_of("\t\n\v\f\r ",
973 third_separator_char_pos + 1) !=
974 std::string::npos) {
975 error.SetErrorStringWithFormat(
976 "extra data found after the '%.*s' regular expression substitution "
977 "string: '%.*s'",
978 (int)third_separator_char_pos + 1, regex_sed.data(),
979 (int)(regex_sed.size() - third_separator_char_pos - 1),
980 regex_sed.data() + (third_separator_char_pos + 1));
981 return error;
982 }
983 } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
984 error.SetErrorStringWithFormat(
985 "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
986 separator_char, separator_char, separator_char, (int)regex_sed.size(),
987 regex_sed.data());
988 return error;
989 } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
990 error.SetErrorStringWithFormat(
991 "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
992 separator_char, separator_char, separator_char, (int)regex_sed.size(),
993 regex_sed.data());
994 return error;
995 }
996
997 if (!check_only) {
998 std::string regex(std::string(regex_sed.substr(
999 first_separator_char_pos + 1,
1000 second_separator_char_pos - first_separator_char_pos - 1)));
1001 std::string subst(std::string(regex_sed.substr(
1002 second_separator_char_pos + 1,
1003 third_separator_char_pos - second_separator_char_pos - 1)));
1004 m_regex_cmd_up->AddRegexCommand(regex, subst);
1005 }
1006 return error;
1007 }
1008
AddRegexCommandToInterpreter()1009 void AddRegexCommandToInterpreter() {
1010 if (m_regex_cmd_up) {
1011 if (m_regex_cmd_up->HasRegexEntries()) {
1012 CommandObjectSP cmd_sp(m_regex_cmd_up.release());
1013 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
1014 }
1015 }
1016 }
1017
1018 private:
1019 std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
1020
1021 class CommandOptions : public Options {
1022 public:
1023 CommandOptions() = default;
1024
1025 ~CommandOptions() override = default;
1026
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1027 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1028 ExecutionContext *execution_context) override {
1029 Status error;
1030 const int short_option = m_getopt_table[option_idx].val;
1031
1032 switch (short_option) {
1033 case 'h':
1034 m_help.assign(std::string(option_arg));
1035 break;
1036 case 's':
1037 m_syntax.assign(std::string(option_arg));
1038 break;
1039 default:
1040 llvm_unreachable("Unimplemented option");
1041 }
1042
1043 return error;
1044 }
1045
OptionParsingStarting(ExecutionContext * execution_context)1046 void OptionParsingStarting(ExecutionContext *execution_context) override {
1047 m_help.clear();
1048 m_syntax.clear();
1049 }
1050
GetDefinitions()1051 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1052 return llvm::ArrayRef(g_regex_options);
1053 }
1054
GetHelp()1055 llvm::StringRef GetHelp() { return m_help; }
1056
GetSyntax()1057 llvm::StringRef GetSyntax() { return m_syntax; }
1058
1059 protected:
1060 // Instance variables to hold the values for command options.
1061
1062 std::string m_help;
1063 std::string m_syntax;
1064 };
1065
GetOptions()1066 Options *GetOptions() override { return &m_options; }
1067
1068 CommandOptions m_options;
1069 };
1070
1071 class CommandObjectPythonFunction : public CommandObjectRaw {
1072 public:
CommandObjectPythonFunction(CommandInterpreter & interpreter,std::string name,std::string funct,std::string help,ScriptedCommandSynchronicity synch,CompletionType completion_type)1073 CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
1074 std::string funct, std::string help,
1075 ScriptedCommandSynchronicity synch,
1076 CompletionType completion_type)
1077 : CommandObjectRaw(interpreter, name), m_function_name(funct),
1078 m_synchro(synch), m_completion_type(completion_type) {
1079 if (!help.empty())
1080 SetHelp(help);
1081 else {
1082 StreamString stream;
1083 stream.Printf("For more information run 'help %s'", name.c_str());
1084 SetHelp(stream.GetString());
1085 }
1086 }
1087
1088 ~CommandObjectPythonFunction() override = default;
1089
IsRemovable() const1090 bool IsRemovable() const override { return true; }
1091
GetFunctionName()1092 const std::string &GetFunctionName() { return m_function_name; }
1093
GetSynchronicity()1094 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1095
GetHelpLong()1096 llvm::StringRef GetHelpLong() override {
1097 if (m_fetched_help_long)
1098 return CommandObjectRaw::GetHelpLong();
1099
1100 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1101 if (!scripter)
1102 return CommandObjectRaw::GetHelpLong();
1103
1104 std::string docstring;
1105 m_fetched_help_long =
1106 scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
1107 if (!docstring.empty())
1108 SetHelpLong(docstring);
1109 return CommandObjectRaw::GetHelpLong();
1110 }
1111
1112 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1113 HandleArgumentCompletion(CompletionRequest &request,
1114 OptionElementVector &opt_element_vector) override {
1115 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1116 GetCommandInterpreter(), m_completion_type, request, nullptr);
1117 }
1118
WantsCompletion()1119 bool WantsCompletion() override { return true; }
1120
1121 protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1122 void DoExecute(llvm::StringRef raw_command_line,
1123 CommandReturnObject &result) override {
1124 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1125
1126 Status error;
1127
1128 result.SetStatus(eReturnStatusInvalid);
1129
1130 if (!scripter || !scripter->RunScriptBasedCommand(
1131 m_function_name.c_str(), raw_command_line, m_synchro,
1132 result, error, m_exe_ctx)) {
1133 result.AppendError(error.AsCString());
1134 } else {
1135 // Don't change the status if the command already set it...
1136 if (result.GetStatus() == eReturnStatusInvalid) {
1137 if (result.GetOutputData().empty())
1138 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1139 else
1140 result.SetStatus(eReturnStatusSuccessFinishResult);
1141 }
1142 }
1143 }
1144
1145 private:
1146 std::string m_function_name;
1147 ScriptedCommandSynchronicity m_synchro;
1148 bool m_fetched_help_long = false;
1149 CompletionType m_completion_type = eNoCompletion;
1150 };
1151
1152 class CommandObjectScriptingObject : public CommandObjectRaw {
1153 public:
CommandObjectScriptingObject(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch,CompletionType completion_type)1154 CommandObjectScriptingObject(CommandInterpreter &interpreter,
1155 std::string name,
1156 StructuredData::GenericSP cmd_obj_sp,
1157 ScriptedCommandSynchronicity synch,
1158 CompletionType completion_type)
1159 : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1160 m_synchro(synch), m_fetched_help_short(false),
1161 m_fetched_help_long(false), m_completion_type(completion_type) {
1162 StreamString stream;
1163 stream.Printf("For more information run 'help %s'", name.c_str());
1164 SetHelp(stream.GetString());
1165 if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
1166 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1167 }
1168
1169 ~CommandObjectScriptingObject() override = default;
1170
1171 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1172 HandleArgumentCompletion(CompletionRequest &request,
1173 OptionElementVector &opt_element_vector) override {
1174 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1175 GetCommandInterpreter(), m_completion_type, request, nullptr);
1176 }
1177
WantsCompletion()1178 bool WantsCompletion() override { return true; }
1179
IsRemovable() const1180 bool IsRemovable() const override { return true; }
1181
GetSynchronicity()1182 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1183
GetHelp()1184 llvm::StringRef GetHelp() override {
1185 if (m_fetched_help_short)
1186 return CommandObjectRaw::GetHelp();
1187 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1188 if (!scripter)
1189 return CommandObjectRaw::GetHelp();
1190 std::string docstring;
1191 m_fetched_help_short =
1192 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1193 if (!docstring.empty())
1194 SetHelp(docstring);
1195
1196 return CommandObjectRaw::GetHelp();
1197 }
1198
GetHelpLong()1199 llvm::StringRef GetHelpLong() override {
1200 if (m_fetched_help_long)
1201 return CommandObjectRaw::GetHelpLong();
1202
1203 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1204 if (!scripter)
1205 return CommandObjectRaw::GetHelpLong();
1206
1207 std::string docstring;
1208 m_fetched_help_long =
1209 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1210 if (!docstring.empty())
1211 SetHelpLong(docstring);
1212 return CommandObjectRaw::GetHelpLong();
1213 }
1214
1215 protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1216 void DoExecute(llvm::StringRef raw_command_line,
1217 CommandReturnObject &result) override {
1218 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1219
1220 Status error;
1221
1222 result.SetStatus(eReturnStatusInvalid);
1223
1224 if (!scripter ||
1225 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
1226 m_synchro, result, error, m_exe_ctx)) {
1227 result.AppendError(error.AsCString());
1228 } else {
1229 // Don't change the status if the command already set it...
1230 if (result.GetStatus() == eReturnStatusInvalid) {
1231 if (result.GetOutputData().empty())
1232 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1233 else
1234 result.SetStatus(eReturnStatusSuccessFinishResult);
1235 }
1236 }
1237 }
1238
1239 private:
1240 StructuredData::GenericSP m_cmd_obj_sp;
1241 ScriptedCommandSynchronicity m_synchro;
1242 bool m_fetched_help_short : 1;
1243 bool m_fetched_help_long : 1;
1244 CompletionType m_completion_type = eNoCompletion;
1245 };
1246
1247 // CommandObjectCommandsScriptImport
1248 #define LLDB_OPTIONS_script_import
1249 #include "CommandOptions.inc"
1250
1251 class CommandObjectCommandsScriptImport : public CommandObjectParsed {
1252 public:
CommandObjectCommandsScriptImport(CommandInterpreter & interpreter)1253 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
1254 : CommandObjectParsed(interpreter, "command script import",
1255 "Import a scripting module in LLDB.", nullptr) {
1256 CommandArgumentEntry arg1;
1257 CommandArgumentData cmd_arg;
1258
1259 // Define the first (and only) variant of this arg.
1260 cmd_arg.arg_type = eArgTypeFilename;
1261 cmd_arg.arg_repetition = eArgRepeatPlus;
1262
1263 // There is only one variant this argument could be; put it into the
1264 // argument entry.
1265 arg1.push_back(cmd_arg);
1266
1267 // Push the data for the first argument into the m_arguments vector.
1268 m_arguments.push_back(arg1);
1269 }
1270
1271 ~CommandObjectCommandsScriptImport() override = default;
1272
1273 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1274 HandleArgumentCompletion(CompletionRequest &request,
1275 OptionElementVector &opt_element_vector) override {
1276 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1277 GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);
1278 }
1279
GetOptions()1280 Options *GetOptions() override { return &m_options; }
1281
1282 protected:
1283 class CommandOptions : public Options {
1284 public:
1285 CommandOptions() = default;
1286
1287 ~CommandOptions() override = default;
1288
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1289 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1290 ExecutionContext *execution_context) override {
1291 Status error;
1292 const int short_option = m_getopt_table[option_idx].val;
1293
1294 switch (short_option) {
1295 case 'r':
1296 // NO-OP
1297 break;
1298 case 'c':
1299 relative_to_command_file = true;
1300 break;
1301 case 's':
1302 silent = true;
1303 break;
1304 default:
1305 llvm_unreachable("Unimplemented option");
1306 }
1307
1308 return error;
1309 }
1310
OptionParsingStarting(ExecutionContext * execution_context)1311 void OptionParsingStarting(ExecutionContext *execution_context) override {
1312 relative_to_command_file = false;
1313 }
1314
GetDefinitions()1315 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1316 return llvm::ArrayRef(g_script_import_options);
1317 }
1318 bool relative_to_command_file = false;
1319 bool silent = false;
1320 };
1321
DoExecute(Args & command,CommandReturnObject & result)1322 void DoExecute(Args &command, CommandReturnObject &result) override {
1323 if (command.empty()) {
1324 result.AppendError("command script import needs one or more arguments");
1325 return;
1326 }
1327
1328 FileSpec source_dir = {};
1329 if (m_options.relative_to_command_file) {
1330 source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
1331 if (!source_dir) {
1332 result.AppendError("command script import -c can only be specified "
1333 "from a command file");
1334 return;
1335 }
1336 }
1337
1338 for (auto &entry : command.entries()) {
1339 Status error;
1340
1341 LoadScriptOptions options;
1342 options.SetInitSession(true);
1343 options.SetSilent(m_options.silent);
1344
1345 // FIXME: this is necessary because CommandObject::CheckRequirements()
1346 // assumes that commands won't ever be recursively invoked, but it's
1347 // actually possible to craft a Python script that does other "command
1348 // script imports" in __lldb_init_module the real fix is to have
1349 // recursive commands possible with a CommandInvocation object separate
1350 // from the CommandObject itself, so that recursive command invocations
1351 // won't stomp on each other (wrt to execution contents, options, and
1352 // more)
1353 m_exe_ctx.Clear();
1354 if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
1355 entry.c_str(), options, error, /*module_sp=*/nullptr,
1356 source_dir)) {
1357 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1358 } else {
1359 result.AppendErrorWithFormat("module importing failed: %s",
1360 error.AsCString());
1361 }
1362 }
1363 }
1364
1365 CommandOptions m_options;
1366 };
1367
1368 #define LLDB_OPTIONS_script_add
1369 #include "CommandOptions.inc"
1370
1371 class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
1372 public IOHandlerDelegateMultiline {
1373 public:
CommandObjectCommandsScriptAdd(CommandInterpreter & interpreter)1374 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
1375 : CommandObjectParsed(interpreter, "command script add",
1376 "Add a scripted function as an LLDB command.",
1377 "Add a scripted function as an lldb command. "
1378 "If you provide a single argument, the command "
1379 "will be added at the root level of the command "
1380 "hierarchy. If there are more arguments they "
1381 "must be a path to a user-added container "
1382 "command, and the last element will be the new "
1383 "command name."),
1384 IOHandlerDelegateMultiline("DONE") {
1385 CommandArgumentEntry arg1;
1386 CommandArgumentData cmd_arg;
1387
1388 // This is one or more command names, which form the path to the command
1389 // you want to add.
1390 cmd_arg.arg_type = eArgTypeCommand;
1391 cmd_arg.arg_repetition = eArgRepeatPlus;
1392
1393 // There is only one variant this argument could be; put it into the
1394 // argument entry.
1395 arg1.push_back(cmd_arg);
1396
1397 // Push the data for the first argument into the m_arguments vector.
1398 m_arguments.push_back(arg1);
1399 }
1400
1401 ~CommandObjectCommandsScriptAdd() override = default;
1402
GetOptions()1403 Options *GetOptions() override { return &m_options; }
1404
1405 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1406 HandleArgumentCompletion(CompletionRequest &request,
1407 OptionElementVector &opt_element_vector) override {
1408 CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1409 opt_element_vector);
1410 }
1411
1412 protected:
1413 class CommandOptions : public Options {
1414 public:
1415 CommandOptions() = default;
1416
1417 ~CommandOptions() override = default;
1418
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1419 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1420 ExecutionContext *execution_context) override {
1421 Status error;
1422 const int short_option = m_getopt_table[option_idx].val;
1423
1424 switch (short_option) {
1425 case 'f':
1426 if (!option_arg.empty())
1427 m_funct_name = std::string(option_arg);
1428 break;
1429 case 'c':
1430 if (!option_arg.empty())
1431 m_class_name = std::string(option_arg);
1432 break;
1433 case 'h':
1434 if (!option_arg.empty())
1435 m_short_help = std::string(option_arg);
1436 break;
1437 case 'o':
1438 m_overwrite_lazy = eLazyBoolYes;
1439 break;
1440 case 's':
1441 m_synchronicity =
1442 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
1443 option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
1444 if (!error.Success())
1445 error.SetErrorStringWithFormat(
1446 "unrecognized value for synchronicity '%s'",
1447 option_arg.str().c_str());
1448 break;
1449 case 'C': {
1450 Status error;
1451 OptionDefinition definition = GetDefinitions()[option_idx];
1452 lldb::CompletionType completion_type =
1453 static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum(
1454 option_arg, definition.enum_values, eNoCompletion, error));
1455 if (!error.Success())
1456 error.SetErrorStringWithFormat(
1457 "unrecognized value for command completion type '%s'",
1458 option_arg.str().c_str());
1459 m_completion_type = completion_type;
1460 } break;
1461 default:
1462 llvm_unreachable("Unimplemented option");
1463 }
1464
1465 return error;
1466 }
1467
OptionParsingStarting(ExecutionContext * execution_context)1468 void OptionParsingStarting(ExecutionContext *execution_context) override {
1469 m_class_name.clear();
1470 m_funct_name.clear();
1471 m_short_help.clear();
1472 m_completion_type = eNoCompletion;
1473 m_overwrite_lazy = eLazyBoolCalculate;
1474 m_synchronicity = eScriptedCommandSynchronicitySynchronous;
1475 }
1476
GetDefinitions()1477 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1478 return llvm::ArrayRef(g_script_add_options);
1479 }
1480
1481 // Instance variables to hold the values for command options.
1482
1483 std::string m_class_name;
1484 std::string m_funct_name;
1485 std::string m_short_help;
1486 LazyBool m_overwrite_lazy = eLazyBoolCalculate;
1487 ScriptedCommandSynchronicity m_synchronicity =
1488 eScriptedCommandSynchronicitySynchronous;
1489 CompletionType m_completion_type = eNoCompletion;
1490 };
1491
IOHandlerActivated(IOHandler & io_handler,bool interactive)1492 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
1493 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
1494 if (output_sp && interactive) {
1495 output_sp->PutCString(g_python_command_instructions);
1496 output_sp->Flush();
1497 }
1498 }
1499
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)1500 void IOHandlerInputComplete(IOHandler &io_handler,
1501 std::string &data) override {
1502 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
1503
1504 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1505 if (interpreter) {
1506 StringList lines;
1507 lines.SplitIntoLines(data);
1508 if (lines.GetSize() > 0) {
1509 std::string funct_name_str;
1510 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
1511 if (funct_name_str.empty()) {
1512 error_sp->Printf("error: unable to obtain a function name, didn't "
1513 "add python command.\n");
1514 error_sp->Flush();
1515 } else {
1516 // everything should be fine now, let's add this alias
1517
1518 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
1519 m_interpreter, m_cmd_name, funct_name_str, m_short_help,
1520 m_synchronicity, m_completion_type));
1521 if (!m_container) {
1522 Status error = m_interpreter.AddUserCommand(
1523 m_cmd_name, command_obj_sp, m_overwrite);
1524 if (error.Fail()) {
1525 error_sp->Printf("error: unable to add selected command: '%s'",
1526 error.AsCString());
1527 error_sp->Flush();
1528 }
1529 } else {
1530 llvm::Error llvm_error = m_container->LoadUserSubcommand(
1531 m_cmd_name, command_obj_sp, m_overwrite);
1532 if (llvm_error) {
1533 error_sp->Printf("error: unable to add selected command: '%s'",
1534 llvm::toString(std::move(llvm_error)).c_str());
1535 error_sp->Flush();
1536 }
1537 }
1538 }
1539 } else {
1540 error_sp->Printf(
1541 "error: unable to create function, didn't add python command\n");
1542 error_sp->Flush();
1543 }
1544 } else {
1545 error_sp->Printf("error: empty function, didn't add python command\n");
1546 error_sp->Flush();
1547 }
1548 } else {
1549 error_sp->Printf(
1550 "error: script interpreter missing, didn't add python command\n");
1551 error_sp->Flush();
1552 }
1553
1554 io_handler.SetIsDone(true);
1555 }
1556
DoExecute(Args & command,CommandReturnObject & result)1557 void DoExecute(Args &command, CommandReturnObject &result) override {
1558 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
1559 result.AppendError("only scripting language supported for scripted "
1560 "commands is currently Python");
1561 return;
1562 }
1563
1564 if (command.GetArgumentCount() == 0) {
1565 result.AppendError("'command script add' requires at least one argument");
1566 return;
1567 }
1568 // Store the options in case we get multi-line input, also figure out the
1569 // default if not user supplied:
1570 switch (m_options.m_overwrite_lazy) {
1571 case eLazyBoolCalculate:
1572 m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite();
1573 break;
1574 case eLazyBoolYes:
1575 m_overwrite = true;
1576 break;
1577 case eLazyBoolNo:
1578 m_overwrite = false;
1579 }
1580
1581 Status path_error;
1582 m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath(
1583 command, true, path_error);
1584
1585 if (path_error.Fail()) {
1586 result.AppendErrorWithFormat("error in command path: %s",
1587 path_error.AsCString());
1588 return;
1589 }
1590
1591 if (!m_container) {
1592 // This is getting inserted into the root of the interpreter.
1593 m_cmd_name = std::string(command[0].ref());
1594 } else {
1595 size_t num_args = command.GetArgumentCount();
1596 m_cmd_name = std::string(command[num_args - 1].ref());
1597 }
1598
1599 m_short_help.assign(m_options.m_short_help);
1600 m_synchronicity = m_options.m_synchronicity;
1601 m_completion_type = m_options.m_completion_type;
1602
1603 // Handle the case where we prompt for the script code first:
1604 if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) {
1605 m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt
1606 *this); // IOHandlerDelegate
1607 return;
1608 }
1609
1610 CommandObjectSP new_cmd_sp;
1611 if (m_options.m_class_name.empty()) {
1612 new_cmd_sp.reset(new CommandObjectPythonFunction(
1613 m_interpreter, m_cmd_name, m_options.m_funct_name,
1614 m_options.m_short_help, m_synchronicity, m_completion_type));
1615 } else {
1616 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1617 if (!interpreter) {
1618 result.AppendError("cannot find ScriptInterpreter");
1619 return;
1620 }
1621
1622 auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
1623 m_options.m_class_name.c_str());
1624 if (!cmd_obj_sp) {
1625 result.AppendErrorWithFormatv("cannot create helper object for: "
1626 "'{0}'", m_options.m_class_name);
1627 return;
1628 }
1629
1630 new_cmd_sp.reset(new CommandObjectScriptingObject(
1631 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity,
1632 m_completion_type));
1633 }
1634
1635 // Assume we're going to succeed...
1636 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1637 if (!m_container) {
1638 Status add_error =
1639 m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite);
1640 if (add_error.Fail())
1641 result.AppendErrorWithFormat("cannot add command: %s",
1642 add_error.AsCString());
1643 } else {
1644 llvm::Error llvm_error =
1645 m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite);
1646 if (llvm_error)
1647 result.AppendErrorWithFormat("cannot add command: %s",
1648 llvm::toString(std::move(llvm_error)).c_str());
1649 }
1650 }
1651
1652 CommandOptions m_options;
1653 std::string m_cmd_name;
1654 CommandObjectMultiword *m_container = nullptr;
1655 std::string m_short_help;
1656 bool m_overwrite = false;
1657 ScriptedCommandSynchronicity m_synchronicity =
1658 eScriptedCommandSynchronicitySynchronous;
1659 CompletionType m_completion_type = eNoCompletion;
1660 };
1661
1662 // CommandObjectCommandsScriptList
1663
1664 class CommandObjectCommandsScriptList : public CommandObjectParsed {
1665 public:
CommandObjectCommandsScriptList(CommandInterpreter & interpreter)1666 CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
1667 : CommandObjectParsed(interpreter, "command script list",
1668 "List defined top-level scripted commands.",
1669 nullptr) {}
1670
1671 ~CommandObjectCommandsScriptList() override = default;
1672
DoExecute(Args & command,CommandReturnObject & result)1673 void DoExecute(Args &command, CommandReturnObject &result) override {
1674 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
1675
1676 result.SetStatus(eReturnStatusSuccessFinishResult);
1677 }
1678 };
1679
1680 // CommandObjectCommandsScriptClear
1681
1682 class CommandObjectCommandsScriptClear : public CommandObjectParsed {
1683 public:
CommandObjectCommandsScriptClear(CommandInterpreter & interpreter)1684 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
1685 : CommandObjectParsed(interpreter, "command script clear",
1686 "Delete all scripted commands.", nullptr) {}
1687
1688 ~CommandObjectCommandsScriptClear() override = default;
1689
1690 protected:
DoExecute(Args & command,CommandReturnObject & result)1691 void DoExecute(Args &command, CommandReturnObject &result) override {
1692 m_interpreter.RemoveAllUser();
1693
1694 result.SetStatus(eReturnStatusSuccessFinishResult);
1695 }
1696 };
1697
1698 // CommandObjectCommandsScriptDelete
1699
1700 class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
1701 public:
CommandObjectCommandsScriptDelete(CommandInterpreter & interpreter)1702 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
1703 : CommandObjectParsed(
1704 interpreter, "command script delete",
1705 "Delete a scripted command by specifying the path to the command.",
1706 nullptr) {
1707 CommandArgumentEntry arg1;
1708 CommandArgumentData cmd_arg;
1709
1710 // This is a list of command names forming the path to the command
1711 // to be deleted.
1712 cmd_arg.arg_type = eArgTypeCommand;
1713 cmd_arg.arg_repetition = eArgRepeatPlus;
1714
1715 // There is only one variant this argument could be; put it into the
1716 // argument entry.
1717 arg1.push_back(cmd_arg);
1718
1719 // Push the data for the first argument into the m_arguments vector.
1720 m_arguments.push_back(arg1);
1721 }
1722
1723 ~CommandObjectCommandsScriptDelete() override = default;
1724
1725 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1726 HandleArgumentCompletion(CompletionRequest &request,
1727 OptionElementVector &opt_element_vector) override {
1728 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
1729 m_interpreter, request, opt_element_vector);
1730 }
1731
1732 protected:
DoExecute(Args & command,CommandReturnObject & result)1733 void DoExecute(Args &command, CommandReturnObject &result) override {
1734
1735 llvm::StringRef root_cmd = command[0].ref();
1736 size_t num_args = command.GetArgumentCount();
1737
1738 if (root_cmd.empty()) {
1739 result.AppendErrorWithFormat("empty root command name");
1740 return;
1741 }
1742 if (!m_interpreter.HasUserCommands() &&
1743 !m_interpreter.HasUserMultiwordCommands()) {
1744 result.AppendErrorWithFormat("can only delete user defined commands, "
1745 "but no user defined commands found");
1746 return;
1747 }
1748
1749 CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd);
1750 if (!cmd_sp) {
1751 result.AppendErrorWithFormat("command '%s' not found.",
1752 command[0].c_str());
1753 return;
1754 }
1755 if (!cmd_sp->IsUserCommand()) {
1756 result.AppendErrorWithFormat("command '%s' is not a user command.",
1757 command[0].c_str());
1758 return;
1759 }
1760 if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) {
1761 result.AppendErrorWithFormat("command '%s' is a multi-word command.\n "
1762 "Delete with \"command container delete\"",
1763 command[0].c_str());
1764 return;
1765 }
1766
1767 if (command.GetArgumentCount() == 1) {
1768 m_interpreter.RemoveUser(root_cmd);
1769 result.SetStatus(eReturnStatusSuccessFinishResult);
1770 return;
1771 }
1772 // We're deleting a command from a multiword command. Verify the command
1773 // path:
1774 Status error;
1775 CommandObjectMultiword *container =
1776 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
1777 error);
1778 if (error.Fail()) {
1779 result.AppendErrorWithFormat("could not resolve command path: %s",
1780 error.AsCString());
1781 return;
1782 }
1783 if (!container) {
1784 // This means that command only had a leaf command, so the container is
1785 // the root. That should have been handled above.
1786 result.AppendErrorWithFormat("could not find a container for '%s'",
1787 command[0].c_str());
1788 return;
1789 }
1790 const char *leaf_cmd = command[num_args - 1].c_str();
1791 llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd,
1792 /* multiword not okay */ false);
1793 if (llvm_error) {
1794 result.AppendErrorWithFormat("could not delete command '%s': %s",
1795 leaf_cmd,
1796 llvm::toString(std::move(llvm_error)).c_str());
1797 return;
1798 }
1799
1800 Stream &out_stream = result.GetOutputStream();
1801
1802 out_stream << "Deleted command:";
1803 for (size_t idx = 0; idx < num_args; idx++) {
1804 out_stream << ' ';
1805 out_stream << command[idx].c_str();
1806 }
1807 out_stream << '\n';
1808 result.SetStatus(eReturnStatusSuccessFinishResult);
1809 }
1810 };
1811
1812 #pragma mark CommandObjectMultiwordCommandsScript
1813
1814 // CommandObjectMultiwordCommandsScript
1815
1816 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
1817 public:
CommandObjectMultiwordCommandsScript(CommandInterpreter & interpreter)1818 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
1819 : CommandObjectMultiword(
1820 interpreter, "command script",
1821 "Commands for managing custom "
1822 "commands implemented by "
1823 "interpreter scripts.",
1824 "command script <subcommand> [<subcommand-options>]") {
1825 LoadSubCommand("add", CommandObjectSP(
1826 new CommandObjectCommandsScriptAdd(interpreter)));
1827 LoadSubCommand(
1828 "delete",
1829 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
1830 LoadSubCommand(
1831 "clear",
1832 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
1833 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
1834 interpreter)));
1835 LoadSubCommand(
1836 "import",
1837 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
1838 }
1839
1840 ~CommandObjectMultiwordCommandsScript() override = default;
1841 };
1842
1843 #pragma mark CommandObjectCommandContainer
1844 #define LLDB_OPTIONS_container_add
1845 #include "CommandOptions.inc"
1846
1847 class CommandObjectCommandsContainerAdd : public CommandObjectParsed {
1848 public:
CommandObjectCommandsContainerAdd(CommandInterpreter & interpreter)1849 CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter)
1850 : CommandObjectParsed(
1851 interpreter, "command container add",
1852 "Add a container command to lldb. Adding to built-"
1853 "in container commands is not allowed.",
1854 "command container add [[path1]...] container-name") {
1855 CommandArgumentEntry arg1;
1856 CommandArgumentData cmd_arg;
1857
1858 // This is one or more command names, which form the path to the command
1859 // you want to add.
1860 cmd_arg.arg_type = eArgTypeCommand;
1861 cmd_arg.arg_repetition = eArgRepeatPlus;
1862
1863 // There is only one variant this argument could be; put it into the
1864 // argument entry.
1865 arg1.push_back(cmd_arg);
1866
1867 // Push the data for the first argument into the m_arguments vector.
1868 m_arguments.push_back(arg1);
1869 }
1870
1871 ~CommandObjectCommandsContainerAdd() override = default;
1872
GetOptions()1873 Options *GetOptions() override { return &m_options; }
1874
1875 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1876 HandleArgumentCompletion(CompletionRequest &request,
1877 OptionElementVector &opt_element_vector) override {
1878 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
1879 m_interpreter, request, opt_element_vector);
1880 }
1881
1882 protected:
1883 class CommandOptions : public Options {
1884 public:
1885 CommandOptions() = default;
1886
1887 ~CommandOptions() override = default;
1888
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1889 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1890 ExecutionContext *execution_context) override {
1891 Status error;
1892 const int short_option = m_getopt_table[option_idx].val;
1893
1894 switch (short_option) {
1895 case 'h':
1896 if (!option_arg.empty())
1897 m_short_help = std::string(option_arg);
1898 break;
1899 case 'o':
1900 m_overwrite = true;
1901 break;
1902 case 'H':
1903 if (!option_arg.empty())
1904 m_long_help = std::string(option_arg);
1905 break;
1906 default:
1907 llvm_unreachable("Unimplemented option");
1908 }
1909
1910 return error;
1911 }
1912
OptionParsingStarting(ExecutionContext * execution_context)1913 void OptionParsingStarting(ExecutionContext *execution_context) override {
1914 m_short_help.clear();
1915 m_long_help.clear();
1916 m_overwrite = false;
1917 }
1918
GetDefinitions()1919 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1920 return llvm::ArrayRef(g_container_add_options);
1921 }
1922
1923 // Instance variables to hold the values for command options.
1924
1925 std::string m_short_help;
1926 std::string m_long_help;
1927 bool m_overwrite = false;
1928 };
DoExecute(Args & command,CommandReturnObject & result)1929 void DoExecute(Args &command, CommandReturnObject &result) override {
1930 size_t num_args = command.GetArgumentCount();
1931
1932 if (num_args == 0) {
1933 result.AppendError("no command was specified");
1934 return;
1935 }
1936
1937 if (num_args == 1) {
1938 // We're adding this as a root command, so use the interpreter.
1939 const char *cmd_name = command.GetArgumentAtIndex(0);
1940 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
1941 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
1942 m_options.m_long_help.c_str()));
1943 cmd_sp->GetAsMultiwordCommand()->SetRemovable(true);
1944 Status add_error = GetCommandInterpreter().AddUserCommand(
1945 cmd_name, cmd_sp, m_options.m_overwrite);
1946 if (add_error.Fail()) {
1947 result.AppendErrorWithFormat("error adding command: %s",
1948 add_error.AsCString());
1949 return;
1950 }
1951 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1952 return;
1953 }
1954
1955 // We're adding this to a subcommand, first find the subcommand:
1956 Status path_error;
1957 CommandObjectMultiword *add_to_me =
1958 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
1959 path_error);
1960
1961 if (!add_to_me) {
1962 result.AppendErrorWithFormat("error adding command: %s",
1963 path_error.AsCString());
1964 return;
1965 }
1966
1967 const char *cmd_name = command.GetArgumentAtIndex(num_args - 1);
1968 auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
1969 GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
1970 m_options.m_long_help.c_str()));
1971 llvm::Error llvm_error =
1972 add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite);
1973 if (llvm_error) {
1974 result.AppendErrorWithFormat("error adding subcommand: %s",
1975 llvm::toString(std::move(llvm_error)).c_str());
1976 return;
1977 }
1978
1979 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1980 }
1981
1982 private:
1983 CommandOptions m_options;
1984 };
1985
1986 #define LLDB_OPTIONS_multiword_delete
1987 #include "CommandOptions.inc"
1988 class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
1989 public:
CommandObjectCommandsContainerDelete(CommandInterpreter & interpreter)1990 CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter)
1991 : CommandObjectParsed(
1992 interpreter, "command container delete",
1993 "Delete a container command previously added to "
1994 "lldb.",
1995 "command container delete [[path1] ...] container-cmd") {
1996 CommandArgumentEntry arg1;
1997 CommandArgumentData cmd_arg;
1998
1999 // This is one or more command names, which form the path to the command
2000 // you want to add.
2001 cmd_arg.arg_type = eArgTypeCommand;
2002 cmd_arg.arg_repetition = eArgRepeatPlus;
2003
2004 // There is only one variant this argument could be; put it into the
2005 // argument entry.
2006 arg1.push_back(cmd_arg);
2007
2008 // Push the data for the first argument into the m_arguments vector.
2009 m_arguments.push_back(arg1);
2010 }
2011
2012 ~CommandObjectCommandsContainerDelete() override = default;
2013
2014 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2015 HandleArgumentCompletion(CompletionRequest &request,
2016 OptionElementVector &opt_element_vector) override {
2017 lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2018 m_interpreter, request, opt_element_vector);
2019 }
2020
2021 protected:
DoExecute(Args & command,CommandReturnObject & result)2022 void DoExecute(Args &command, CommandReturnObject &result) override {
2023 size_t num_args = command.GetArgumentCount();
2024
2025 if (num_args == 0) {
2026 result.AppendError("No command was specified.");
2027 return;
2028 }
2029
2030 if (num_args == 1) {
2031 // We're removing a root command, so we need to delete it from the
2032 // interpreter.
2033 const char *cmd_name = command.GetArgumentAtIndex(0);
2034 // Let's do a little more work here so we can do better error reporting.
2035 CommandInterpreter &interp = GetCommandInterpreter();
2036 CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name);
2037 if (!cmd_sp) {
2038 result.AppendErrorWithFormat("container command %s doesn't exist.",
2039 cmd_name);
2040 return;
2041 }
2042 if (!cmd_sp->IsUserCommand()) {
2043 result.AppendErrorWithFormat(
2044 "container command %s is not a user command", cmd_name);
2045 return;
2046 }
2047 if (!cmd_sp->GetAsMultiwordCommand()) {
2048 result.AppendErrorWithFormat("command %s is not a container command",
2049 cmd_name);
2050 return;
2051 }
2052
2053 bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name);
2054 if (!did_remove) {
2055 result.AppendErrorWithFormat("error removing command %s.", cmd_name);
2056 return;
2057 }
2058
2059 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2060 return;
2061 }
2062
2063 // We're removing a subcommand, first find the subcommand's owner:
2064 Status path_error;
2065 CommandObjectMultiword *container =
2066 GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2067 path_error);
2068
2069 if (!container) {
2070 result.AppendErrorWithFormat("error removing container command: %s",
2071 path_error.AsCString());
2072 return;
2073 }
2074 const char *leaf = command.GetArgumentAtIndex(num_args - 1);
2075 llvm::Error llvm_error =
2076 container->RemoveUserSubcommand(leaf, /* multiword okay */ true);
2077 if (llvm_error) {
2078 result.AppendErrorWithFormat("error removing container command: %s",
2079 llvm::toString(std::move(llvm_error)).c_str());
2080 return;
2081 }
2082 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2083 }
2084 };
2085
2086 class CommandObjectCommandContainer : public CommandObjectMultiword {
2087 public:
CommandObjectCommandContainer(CommandInterpreter & interpreter)2088 CommandObjectCommandContainer(CommandInterpreter &interpreter)
2089 : CommandObjectMultiword(
2090 interpreter, "command container",
2091 "Commands for adding container commands to lldb. "
2092 "Container commands are containers for other commands. You can "
2093 "add nested container commands by specifying a command path, "
2094 "but you can't add commands into the built-in command hierarchy.",
2095 "command container <subcommand> [<subcommand-options>]") {
2096 LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd(
2097 interpreter)));
2098 LoadSubCommand(
2099 "delete",
2100 CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter)));
2101 }
2102
2103 ~CommandObjectCommandContainer() override = default;
2104 };
2105
2106 #pragma mark CommandObjectMultiwordCommands
2107
2108 // CommandObjectMultiwordCommands
2109
CommandObjectMultiwordCommands(CommandInterpreter & interpreter)2110 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
2111 CommandInterpreter &interpreter)
2112 : CommandObjectMultiword(interpreter, "command",
2113 "Commands for managing custom LLDB commands.",
2114 "command <subcommand> [<subcommand-options>]") {
2115 LoadSubCommand("source",
2116 CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
2117 LoadSubCommand("alias",
2118 CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
2119 LoadSubCommand("unalias", CommandObjectSP(
2120 new CommandObjectCommandsUnalias(interpreter)));
2121 LoadSubCommand("delete",
2122 CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
2123 LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer(
2124 interpreter)));
2125 LoadSubCommand(
2126 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
2127 LoadSubCommand(
2128 "script",
2129 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
2130 }
2131
2132 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
2133