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