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