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