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