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