Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp
39587 views
1
//===-- CommandObjectCommands.cpp -----------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "CommandObjectCommands.h"
10
#include "CommandObjectHelp.h"
11
#include "CommandObjectRegexCommand.h"
12
#include "lldb/Core/Debugger.h"
13
#include "lldb/Core/IOHandler.h"
14
#include "lldb/Interpreter/CommandHistory.h"
15
#include "lldb/Interpreter/CommandInterpreter.h"
16
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
17
#include "lldb/Interpreter/CommandReturnObject.h"
18
#include "lldb/Interpreter/OptionArgParser.h"
19
#include "lldb/Interpreter/OptionValueBoolean.h"
20
#include "lldb/Interpreter/OptionValueString.h"
21
#include "lldb/Interpreter/OptionValueUInt64.h"
22
#include "lldb/Interpreter/Options.h"
23
#include "lldb/Interpreter/ScriptInterpreter.h"
24
#include "lldb/Utility/Args.h"
25
#include "lldb/Utility/StringList.h"
26
#include "llvm/ADT/StringRef.h"
27
#include <optional>
28
29
using namespace lldb;
30
using namespace lldb_private;
31
32
// CommandObjectCommandsSource
33
34
#define LLDB_OPTIONS_source
35
#include "CommandOptions.inc"
36
37
class CommandObjectCommandsSource : public CommandObjectParsed {
38
public:
39
CommandObjectCommandsSource(CommandInterpreter &interpreter)
40
: CommandObjectParsed(
41
interpreter, "command source",
42
"Read and execute LLDB commands from the file <filename>.",
43
nullptr) {
44
AddSimpleArgumentList(eArgTypeFilename);
45
}
46
47
~CommandObjectCommandsSource() override = default;
48
49
std::optional<std::string> GetRepeatCommand(Args &current_command_args,
50
uint32_t index) override {
51
return std::string("");
52
}
53
54
Options *GetOptions() override { return &m_options; }
55
56
protected:
57
class CommandOptions : public Options {
58
public:
59
CommandOptions()
60
: m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true),
61
m_cmd_relative_to_command_file(false) {}
62
63
~CommandOptions() override = default;
64
65
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
66
ExecutionContext *execution_context) override {
67
Status error;
68
const int short_option = m_getopt_table[option_idx].val;
69
70
switch (short_option) {
71
case 'e':
72
error = m_stop_on_error.SetValueFromString(option_arg);
73
break;
74
75
case 'c':
76
error = m_stop_on_continue.SetValueFromString(option_arg);
77
break;
78
79
case 'C':
80
m_cmd_relative_to_command_file = true;
81
break;
82
83
case 's':
84
error = m_silent_run.SetValueFromString(option_arg);
85
break;
86
87
default:
88
llvm_unreachable("Unimplemented option");
89
}
90
91
return error;
92
}
93
94
void OptionParsingStarting(ExecutionContext *execution_context) override {
95
m_stop_on_error.Clear();
96
m_silent_run.Clear();
97
m_stop_on_continue.Clear();
98
m_cmd_relative_to_command_file.Clear();
99
}
100
101
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
102
return llvm::ArrayRef(g_source_options);
103
}
104
105
// Instance variables to hold the values for command options.
106
107
OptionValueBoolean m_stop_on_error;
108
OptionValueBoolean m_silent_run;
109
OptionValueBoolean m_stop_on_continue;
110
OptionValueBoolean m_cmd_relative_to_command_file;
111
};
112
113
void DoExecute(Args &command, CommandReturnObject &result) override {
114
if (command.GetArgumentCount() != 1) {
115
result.AppendErrorWithFormat(
116
"'%s' takes exactly one executable filename argument.\n",
117
GetCommandName().str().c_str());
118
return;
119
}
120
121
FileSpec source_dir = {};
122
if (m_options.m_cmd_relative_to_command_file) {
123
source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
124
if (!source_dir) {
125
result.AppendError("command source -C can only be specified "
126
"from a command file");
127
result.SetStatus(eReturnStatusFailed);
128
return;
129
}
130
}
131
132
FileSpec cmd_file(command[0].ref());
133
if (source_dir) {
134
// Prepend the source_dir to the cmd_file path:
135
if (!cmd_file.IsRelative()) {
136
result.AppendError("command source -C can only be used "
137
"with a relative path.");
138
result.SetStatus(eReturnStatusFailed);
139
return;
140
}
141
cmd_file.MakeAbsolute(source_dir);
142
}
143
144
FileSystem::Instance().Resolve(cmd_file);
145
146
CommandInterpreterRunOptions options;
147
// If any options were set, then use them
148
if (m_options.m_stop_on_error.OptionWasSet() ||
149
m_options.m_silent_run.OptionWasSet() ||
150
m_options.m_stop_on_continue.OptionWasSet()) {
151
if (m_options.m_stop_on_continue.OptionWasSet())
152
options.SetStopOnContinue(
153
m_options.m_stop_on_continue.GetCurrentValue());
154
155
if (m_options.m_stop_on_error.OptionWasSet())
156
options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
157
158
// Individual silent setting is override for global command echo settings.
159
if (m_options.m_silent_run.GetCurrentValue()) {
160
options.SetSilent(true);
161
} else {
162
options.SetPrintResults(true);
163
options.SetPrintErrors(true);
164
options.SetEchoCommands(m_interpreter.GetEchoCommands());
165
options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
166
}
167
}
168
169
m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
170
}
171
172
CommandOptions m_options;
173
};
174
175
#pragma mark CommandObjectCommandsAlias
176
// CommandObjectCommandsAlias
177
178
#define LLDB_OPTIONS_alias
179
#include "CommandOptions.inc"
180
181
static const char *g_python_command_instructions =
182
"Enter your Python command(s). Type 'DONE' to end.\n"
183
"You must define a Python function with this signature:\n"
184
"def my_command_impl(debugger, args, exe_ctx, result, internal_dict):\n";
185
186
class CommandObjectCommandsAlias : public CommandObjectRaw {
187
protected:
188
class CommandOptions : public OptionGroup {
189
public:
190
CommandOptions() = default;
191
192
~CommandOptions() override = default;
193
194
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
195
return llvm::ArrayRef(g_alias_options);
196
}
197
198
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
199
ExecutionContext *execution_context) override {
200
Status error;
201
202
const int short_option = GetDefinitions()[option_idx].short_option;
203
std::string option_str(option_value);
204
205
switch (short_option) {
206
case 'h':
207
m_help.SetCurrentValue(option_str);
208
m_help.SetOptionWasSet();
209
break;
210
211
case 'H':
212
m_long_help.SetCurrentValue(option_str);
213
m_long_help.SetOptionWasSet();
214
break;
215
216
default:
217
llvm_unreachable("Unimplemented option");
218
}
219
220
return error;
221
}
222
223
void OptionParsingStarting(ExecutionContext *execution_context) override {
224
m_help.Clear();
225
m_long_help.Clear();
226
}
227
228
OptionValueString m_help;
229
OptionValueString m_long_help;
230
};
231
232
OptionGroupOptions m_option_group;
233
CommandOptions m_command_options;
234
235
public:
236
Options *GetOptions() override { return &m_option_group; }
237
238
CommandObjectCommandsAlias(CommandInterpreter &interpreter)
239
: CommandObjectRaw(
240
interpreter, "command alias",
241
"Define a custom command in terms of an existing command.") {
242
m_option_group.Append(&m_command_options);
243
m_option_group.Finalize();
244
245
SetHelpLong(
246
"'alias' allows the user to create a short-cut or abbreviation for long \
247
commands, multi-word commands, and commands that take particular options. \
248
Below are some simple examples of how one might use the 'alias' command:"
249
R"(
250
251
(lldb) command alias sc script
252
253
Creates the abbreviation 'sc' for the 'script' command.
254
255
(lldb) command alias bp breakpoint
256
257
)"
258
" Creates the abbreviation 'bp' for the 'breakpoint' command. Since \
259
breakpoint commands are two-word commands, the user would still need to \
260
enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
261
R"(
262
263
(lldb) command alias bpl breakpoint list
264
265
Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
266
267
)"
268
"An alias can include some options for the command, with the values either \
269
filled in at the time the alias is created, or specified as positional \
270
arguments, to be filled in when the alias is invoked. The following example \
271
shows how to create aliases with options:"
272
R"(
273
274
(lldb) command alias bfl breakpoint set -f %1 -l %2
275
276
)"
277
" Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
278
options already part of the alias. So if the user wants to set a breakpoint \
279
by file and line without explicitly having to use the -f and -l options, the \
280
user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \
281
for the actual arguments that will be passed when the alias command is used. \
282
The number in the placeholder refers to the position/order the actual value \
283
occupies when the alias is used. All the occurrences of '%1' in the alias \
284
will be replaced with the first argument, all the occurrences of '%2' in the \
285
alias will be replaced with the second argument, and so on. This also allows \
286
actual arguments to be used multiple times within an alias (see 'process \
287
launch' example below)."
288
R"(
289
290
)"
291
"Note: the positional arguments must substitute as whole words in the resultant \
292
command, so you can't at present do something like this to append the file extension \
293
\".cpp\":"
294
R"(
295
296
(lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
297
298
)"
299
"For more complex aliasing, use the \"command regex\" command instead. In the \
300
'bfl' case above, the actual file value will be filled in with the first argument \
301
following 'bfl' and the actual line number value will be filled in with the second \
302
argument. The user would use this alias as follows:"
303
R"(
304
305
(lldb) command alias bfl breakpoint set -f %1 -l %2
306
(lldb) bfl my-file.c 137
307
308
This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
309
310
Another example:
311
312
(lldb) command alias pltty process launch -s -o %1 -e %1
313
(lldb) pltty /dev/tty0
314
315
Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
316
317
)"
318
"If the user always wanted to pass the same value to a particular option, the \
319
alias could be defined with that value directly in the alias as a constant, \
320
rather than using a positional placeholder:"
321
R"(
322
323
(lldb) command alias bl3 breakpoint set -f %1 -l 3
324
325
Always sets a breakpoint on line 3 of whatever file is indicated.)");
326
327
CommandArgumentEntry arg1;
328
CommandArgumentEntry arg2;
329
CommandArgumentEntry arg3;
330
CommandArgumentData alias_arg;
331
CommandArgumentData cmd_arg;
332
CommandArgumentData options_arg;
333
334
// Define the first (and only) variant of this arg.
335
alias_arg.arg_type = eArgTypeAliasName;
336
alias_arg.arg_repetition = eArgRepeatPlain;
337
338
// There is only one variant this argument could be; put it into the
339
// argument entry.
340
arg1.push_back(alias_arg);
341
342
// Define the first (and only) variant of this arg.
343
cmd_arg.arg_type = eArgTypeCommandName;
344
cmd_arg.arg_repetition = eArgRepeatPlain;
345
346
// There is only one variant this argument could be; put it into the
347
// argument entry.
348
arg2.push_back(cmd_arg);
349
350
// Define the first (and only) variant of this arg.
351
options_arg.arg_type = eArgTypeAliasOptions;
352
options_arg.arg_repetition = eArgRepeatOptional;
353
354
// There is only one variant this argument could be; put it into the
355
// argument entry.
356
arg3.push_back(options_arg);
357
358
// Push the data for the first argument into the m_arguments vector.
359
m_arguments.push_back(arg1);
360
m_arguments.push_back(arg2);
361
m_arguments.push_back(arg3);
362
}
363
364
~CommandObjectCommandsAlias() override = default;
365
366
protected:
367
void DoExecute(llvm::StringRef raw_command_line,
368
CommandReturnObject &result) override {
369
if (raw_command_line.empty()) {
370
result.AppendError("'command alias' requires at least two arguments");
371
return;
372
}
373
374
ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
375
m_option_group.NotifyOptionParsingStarting(&exe_ctx);
376
377
OptionsWithRaw args_with_suffix(raw_command_line);
378
379
if (args_with_suffix.HasArgs())
380
if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result,
381
m_option_group, exe_ctx))
382
return;
383
384
llvm::StringRef raw_command_string = args_with_suffix.GetRawPart();
385
Args args(raw_command_string);
386
387
if (args.GetArgumentCount() < 2) {
388
result.AppendError("'command alias' requires at least two arguments");
389
return;
390
}
391
392
// Get the alias command.
393
394
auto alias_command = args[0].ref();
395
if (alias_command.starts_with("-")) {
396
result.AppendError("aliases starting with a dash are not supported");
397
if (alias_command == "--help" || alias_command == "--long-help") {
398
result.AppendWarning("if trying to pass options to 'command alias' add "
399
"a -- at the end of the options");
400
}
401
return;
402
}
403
404
// Strip the new alias name off 'raw_command_string' (leave it on args,
405
// which gets passed to 'Execute', which does the stripping itself.
406
size_t pos = raw_command_string.find(alias_command);
407
if (pos == 0) {
408
raw_command_string = raw_command_string.substr(alias_command.size());
409
pos = raw_command_string.find_first_not_of(' ');
410
if ((pos != std::string::npos) && (pos > 0))
411
raw_command_string = raw_command_string.substr(pos);
412
} else {
413
result.AppendError("Error parsing command string. No alias created.");
414
return;
415
}
416
417
// Verify that the command is alias-able.
418
if (m_interpreter.CommandExists(alias_command)) {
419
result.AppendErrorWithFormat(
420
"'%s' is a permanent debugger command and cannot be redefined.\n",
421
args[0].c_str());
422
return;
423
}
424
425
if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
426
result.AppendErrorWithFormat(
427
"'%s' is a user container command and cannot be overwritten.\n"
428
"Delete it first with 'command container delete'\n",
429
args[0].c_str());
430
return;
431
}
432
433
// Get CommandObject that is being aliased. The command name is read from
434
// the front of raw_command_string. raw_command_string is returned with the
435
// name of the command object stripped off the front.
436
llvm::StringRef original_raw_command_string = raw_command_string;
437
CommandObject *cmd_obj =
438
m_interpreter.GetCommandObjectForCommand(raw_command_string);
439
440
if (!cmd_obj) {
441
result.AppendErrorWithFormat("invalid command given to 'command alias'. "
442
"'%s' does not begin with a valid command."
443
" No alias created.",
444
original_raw_command_string.str().c_str());
445
} else if (!cmd_obj->WantsRawCommandString()) {
446
// Note that args was initialized with the original command, and has not
447
// been updated to this point. Therefore can we pass it to the version of
448
// Execute that does not need/expect raw input in the alias.
449
HandleAliasingNormalCommand(args, result);
450
} else {
451
HandleAliasingRawCommand(alias_command, raw_command_string, *cmd_obj,
452
result);
453
}
454
}
455
456
bool HandleAliasingRawCommand(llvm::StringRef alias_command,
457
llvm::StringRef raw_command_string,
458
CommandObject &cmd_obj,
459
CommandReturnObject &result) {
460
// Verify & handle any options/arguments passed to the alias command
461
462
OptionArgVectorSP option_arg_vector_sp =
463
OptionArgVectorSP(new OptionArgVector);
464
465
const bool include_aliases = true;
466
// Look up the command using command's name first. This is to resolve
467
// aliases when you are making nested aliases. But if you don't find
468
// it that way, then it wasn't an alias and we can just use the object
469
// we were passed in.
470
CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact(
471
cmd_obj.GetCommandName(), include_aliases);
472
if (!cmd_obj_sp)
473
cmd_obj_sp = cmd_obj.shared_from_this();
474
475
if (m_interpreter.AliasExists(alias_command) ||
476
m_interpreter.UserCommandExists(alias_command)) {
477
result.AppendWarningWithFormat(
478
"Overwriting existing definition for '%s'.\n",
479
alias_command.str().c_str());
480
}
481
if (CommandAlias *alias = m_interpreter.AddAlias(
482
alias_command, cmd_obj_sp, raw_command_string)) {
483
if (m_command_options.m_help.OptionWasSet())
484
alias->SetHelp(m_command_options.m_help.GetCurrentValue());
485
if (m_command_options.m_long_help.OptionWasSet())
486
alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
487
result.SetStatus(eReturnStatusSuccessFinishNoResult);
488
} else {
489
result.AppendError("Unable to create requested alias.\n");
490
}
491
return result.Succeeded();
492
}
493
494
bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
495
size_t argc = args.GetArgumentCount();
496
497
if (argc < 2) {
498
result.AppendError("'command alias' requires at least two arguments");
499
return false;
500
}
501
502
// Save these in std::strings since we're going to shift them off.
503
const std::string alias_command(std::string(args[0].ref()));
504
const std::string actual_command(std::string(args[1].ref()));
505
506
args.Shift(); // Shift the alias command word off the argument vector.
507
args.Shift(); // Shift the old command word off the argument vector.
508
509
// Verify that the command is alias'able, and get the appropriate command
510
// object.
511
512
if (m_interpreter.CommandExists(alias_command)) {
513
result.AppendErrorWithFormat(
514
"'%s' is a permanent debugger command and cannot be redefined.\n",
515
alias_command.c_str());
516
return false;
517
}
518
519
if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
520
result.AppendErrorWithFormat(
521
"'%s' is user container command and cannot be overwritten.\n"
522
"Delete it first with 'command container delete'",
523
alias_command.c_str());
524
return false;
525
}
526
527
CommandObjectSP command_obj_sp(
528
m_interpreter.GetCommandSPExact(actual_command, true));
529
CommandObjectSP subcommand_obj_sp;
530
bool use_subcommand = false;
531
if (!command_obj_sp) {
532
result.AppendErrorWithFormat("'%s' is not an existing command.\n",
533
actual_command.c_str());
534
return false;
535
}
536
CommandObject *cmd_obj = command_obj_sp.get();
537
CommandObject *sub_cmd_obj = nullptr;
538
OptionArgVectorSP option_arg_vector_sp =
539
OptionArgVectorSP(new OptionArgVector);
540
541
while (cmd_obj->IsMultiwordObject() && !args.empty()) {
542
auto sub_command = args[0].ref();
543
assert(!sub_command.empty());
544
subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
545
if (!subcommand_obj_sp) {
546
result.AppendErrorWithFormat(
547
"'%s' is not a valid sub-command of '%s'. "
548
"Unable to create alias.\n",
549
args[0].c_str(), actual_command.c_str());
550
return false;
551
}
552
553
sub_cmd_obj = subcommand_obj_sp.get();
554
use_subcommand = true;
555
args.Shift(); // Shift the sub_command word off the argument vector.
556
cmd_obj = sub_cmd_obj;
557
}
558
559
// Verify & handle any options/arguments passed to the alias command
560
561
std::string args_string;
562
563
if (!args.empty()) {
564
CommandObjectSP tmp_sp =
565
m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName());
566
if (use_subcommand)
567
tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName());
568
569
args.GetCommandString(args_string);
570
}
571
572
if (m_interpreter.AliasExists(alias_command) ||
573
m_interpreter.UserCommandExists(alias_command)) {
574
result.AppendWarningWithFormat(
575
"Overwriting existing definition for '%s'.\n", alias_command.c_str());
576
}
577
578
if (CommandAlias *alias = m_interpreter.AddAlias(
579
alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
580
args_string)) {
581
if (m_command_options.m_help.OptionWasSet())
582
alias->SetHelp(m_command_options.m_help.GetCurrentValue());
583
if (m_command_options.m_long_help.OptionWasSet())
584
alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
585
result.SetStatus(eReturnStatusSuccessFinishNoResult);
586
} else {
587
result.AppendError("Unable to create requested alias.\n");
588
return false;
589
}
590
591
return result.Succeeded();
592
}
593
};
594
595
#pragma mark CommandObjectCommandsUnalias
596
// CommandObjectCommandsUnalias
597
598
class CommandObjectCommandsUnalias : public CommandObjectParsed {
599
public:
600
CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
601
: CommandObjectParsed(
602
interpreter, "command unalias",
603
"Delete one or more custom commands defined by 'command alias'.",
604
nullptr) {
605
AddSimpleArgumentList(eArgTypeAliasName);
606
}
607
608
~CommandObjectCommandsUnalias() override = default;
609
610
void
611
HandleArgumentCompletion(CompletionRequest &request,
612
OptionElementVector &opt_element_vector) override {
613
if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
614
return;
615
616
for (const auto &ent : m_interpreter.GetAliases()) {
617
request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
618
}
619
}
620
621
protected:
622
void DoExecute(Args &args, CommandReturnObject &result) override {
623
CommandObject::CommandMap::iterator pos;
624
CommandObject *cmd_obj;
625
626
if (args.empty()) {
627
result.AppendError("must call 'unalias' with a valid alias");
628
return;
629
}
630
631
auto command_name = args[0].ref();
632
cmd_obj = m_interpreter.GetCommandObject(command_name);
633
if (!cmd_obj) {
634
result.AppendErrorWithFormat(
635
"'%s' is not a known command.\nTry 'help' to see a "
636
"current list of commands.\n",
637
args[0].c_str());
638
return;
639
}
640
641
if (m_interpreter.CommandExists(command_name)) {
642
if (cmd_obj->IsRemovable()) {
643
result.AppendErrorWithFormat(
644
"'%s' is not an alias, it is a debugger command which can be "
645
"removed using the 'command delete' command.\n",
646
args[0].c_str());
647
} else {
648
result.AppendErrorWithFormat(
649
"'%s' is a permanent debugger command and cannot be removed.\n",
650
args[0].c_str());
651
}
652
return;
653
}
654
655
if (!m_interpreter.RemoveAlias(command_name)) {
656
if (m_interpreter.AliasExists(command_name))
657
result.AppendErrorWithFormat(
658
"Error occurred while attempting to unalias '%s'.\n",
659
args[0].c_str());
660
else
661
result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
662
args[0].c_str());
663
return;
664
}
665
666
result.SetStatus(eReturnStatusSuccessFinishNoResult);
667
}
668
};
669
670
#pragma mark CommandObjectCommandsDelete
671
// CommandObjectCommandsDelete
672
673
class CommandObjectCommandsDelete : public CommandObjectParsed {
674
public:
675
CommandObjectCommandsDelete(CommandInterpreter &interpreter)
676
: CommandObjectParsed(
677
interpreter, "command delete",
678
"Delete one or more custom commands defined by 'command regex'.",
679
nullptr) {
680
AddSimpleArgumentList(eArgTypeCommandName);
681
}
682
683
~CommandObjectCommandsDelete() override = default;
684
685
void
686
HandleArgumentCompletion(CompletionRequest &request,
687
OptionElementVector &opt_element_vector) override {
688
if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
689
return;
690
691
for (const auto &ent : m_interpreter.GetCommands()) {
692
if (ent.second->IsRemovable())
693
request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
694
}
695
}
696
697
protected:
698
void DoExecute(Args &args, CommandReturnObject &result) override {
699
CommandObject::CommandMap::iterator pos;
700
701
if (args.empty()) {
702
result.AppendErrorWithFormat("must call '%s' with one or more valid user "
703
"defined regular expression command names",
704
GetCommandName().str().c_str());
705
return;
706
}
707
708
auto command_name = args[0].ref();
709
if (!m_interpreter.CommandExists(command_name)) {
710
StreamString error_msg_stream;
711
const bool generate_upropos = true;
712
const bool generate_type_lookup = false;
713
CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
714
&error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
715
generate_upropos, generate_type_lookup);
716
result.AppendError(error_msg_stream.GetString());
717
return;
718
}
719
720
if (!m_interpreter.RemoveCommand(command_name)) {
721
result.AppendErrorWithFormat(
722
"'%s' is a permanent debugger command and cannot be removed.\n",
723
args[0].c_str());
724
return;
725
}
726
727
result.SetStatus(eReturnStatusSuccessFinishNoResult);
728
}
729
};
730
731
// CommandObjectCommandsAddRegex
732
733
#define LLDB_OPTIONS_regex
734
#include "CommandOptions.inc"
735
736
#pragma mark CommandObjectCommandsAddRegex
737
738
class CommandObjectCommandsAddRegex : public CommandObjectParsed,
739
public IOHandlerDelegateMultiline {
740
public:
741
CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
742
: CommandObjectParsed(
743
interpreter, "command regex",
744
"Define a custom command in terms of "
745
"existing commands by matching "
746
"regular expressions.",
747
"command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
748
IOHandlerDelegateMultiline("",
749
IOHandlerDelegate::Completion::LLDBCommand) {
750
SetHelpLong(
751
R"(
752
)"
753
"This command allows the user to create powerful regular expression commands \
754
with substitutions. The regular expressions and substitutions are specified \
755
using the regular expression substitution format of:"
756
R"(
757
758
s/<regex>/<subst>/
759
760
)"
761
"<regex> is a regular expression that can use parenthesis to capture regular \
762
expression input and substitute the captured matches in the output using %1 \
763
for the first match, %2 for the second, and so on."
764
R"(
765
766
)"
767
"The regular expressions can all be specified on the command line if more than \
768
one argument is provided. If just the command name is provided on the command \
769
line, then the regular expressions and substitutions can be entered on separate \
770
lines, followed by an empty line to terminate the command definition."
771
R"(
772
773
EXAMPLES
774
775
)"
776
"The following example will define a regular expression command named 'f' that \
777
will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
778
a number follows 'f':"
779
R"(
780
781
(lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
782
AddSimpleArgumentList(eArgTypeSEDStylePair, eArgRepeatOptional);
783
}
784
785
~CommandObjectCommandsAddRegex() override = default;
786
787
protected:
788
void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
789
StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
790
if (output_sp && interactive) {
791
output_sp->PutCString("Enter one or more sed substitution commands in "
792
"the form: 's/<regex>/<subst>/'.\nTerminate the "
793
"substitution list with an empty line.\n");
794
output_sp->Flush();
795
}
796
}
797
798
void IOHandlerInputComplete(IOHandler &io_handler,
799
std::string &data) override {
800
io_handler.SetIsDone(true);
801
if (m_regex_cmd_up) {
802
StringList lines;
803
if (lines.SplitIntoLines(data)) {
804
bool check_only = false;
805
for (const std::string &line : lines) {
806
Status error = AppendRegexSubstitution(line, check_only);
807
if (error.Fail()) {
808
if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) {
809
StreamSP out_stream = GetDebugger().GetAsyncOutputStream();
810
out_stream->Printf("error: %s\n", error.AsCString());
811
}
812
}
813
}
814
}
815
if (m_regex_cmd_up->HasRegexEntries()) {
816
CommandObjectSP cmd_sp(m_regex_cmd_up.release());
817
m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
818
}
819
}
820
}
821
822
void DoExecute(Args &command, CommandReturnObject &result) override {
823
const size_t argc = command.GetArgumentCount();
824
if (argc == 0) {
825
result.AppendError("usage: 'command regex <command-name> "
826
"[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
827
return;
828
}
829
830
Status error;
831
auto name = command[0].ref();
832
m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
833
m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 0,
834
true);
835
836
if (argc == 1) {
837
Debugger &debugger = GetDebugger();
838
bool color_prompt = debugger.GetUseColor();
839
const bool multiple_lines = true; // Get multiple lines
840
IOHandlerSP io_handler_sp(new IOHandlerEditline(
841
debugger, IOHandler::Type::Other,
842
"lldb-regex", // Name of input reader for history
843
llvm::StringRef("> "), // Prompt
844
llvm::StringRef(), // Continuation prompt
845
multiple_lines, color_prompt,
846
0, // Don't show line numbers
847
*this));
848
849
if (io_handler_sp) {
850
debugger.RunIOHandlerAsync(io_handler_sp);
851
result.SetStatus(eReturnStatusSuccessFinishNoResult);
852
}
853
} else {
854
for (auto &entry : command.entries().drop_front()) {
855
bool check_only = false;
856
error = AppendRegexSubstitution(entry.ref(), check_only);
857
if (error.Fail())
858
break;
859
}
860
861
if (error.Success()) {
862
AddRegexCommandToInterpreter();
863
}
864
}
865
if (error.Fail()) {
866
result.AppendError(error.AsCString());
867
}
868
}
869
870
Status AppendRegexSubstitution(const llvm::StringRef &regex_sed,
871
bool check_only) {
872
Status error;
873
874
if (!m_regex_cmd_up) {
875
error.SetErrorStringWithFormat(
876
"invalid regular expression command object for: '%.*s'",
877
(int)regex_sed.size(), regex_sed.data());
878
return error;
879
}
880
881
size_t regex_sed_size = regex_sed.size();
882
883
if (regex_sed_size <= 1) {
884
error.SetErrorStringWithFormat(
885
"regular expression substitution string is too short: '%.*s'",
886
(int)regex_sed.size(), regex_sed.data());
887
return error;
888
}
889
890
if (regex_sed[0] != 's') {
891
error.SetErrorStringWithFormat("regular expression substitution string "
892
"doesn't start with 's': '%.*s'",
893
(int)regex_sed.size(), regex_sed.data());
894
return error;
895
}
896
const size_t first_separator_char_pos = 1;
897
// use the char that follows 's' as the regex separator character so we can
898
// have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
899
const char separator_char = regex_sed[first_separator_char_pos];
900
const size_t second_separator_char_pos =
901
regex_sed.find(separator_char, first_separator_char_pos + 1);
902
903
if (second_separator_char_pos == std::string::npos) {
904
error.SetErrorStringWithFormat(
905
"missing second '%c' separator char after '%.*s' in '%.*s'",
906
separator_char,
907
(int)(regex_sed.size() - first_separator_char_pos - 1),
908
regex_sed.data() + (first_separator_char_pos + 1),
909
(int)regex_sed.size(), regex_sed.data());
910
return error;
911
}
912
913
const size_t third_separator_char_pos =
914
regex_sed.find(separator_char, second_separator_char_pos + 1);
915
916
if (third_separator_char_pos == std::string::npos) {
917
error.SetErrorStringWithFormat(
918
"missing third '%c' separator char after '%.*s' in '%.*s'",
919
separator_char,
920
(int)(regex_sed.size() - second_separator_char_pos - 1),
921
regex_sed.data() + (second_separator_char_pos + 1),
922
(int)regex_sed.size(), regex_sed.data());
923
return error;
924
}
925
926
if (third_separator_char_pos != regex_sed_size - 1) {
927
// Make sure that everything that follows the last regex separator char
928
if (regex_sed.find_first_not_of("\t\n\v\f\r ",
929
third_separator_char_pos + 1) !=
930
std::string::npos) {
931
error.SetErrorStringWithFormat(
932
"extra data found after the '%.*s' regular expression substitution "
933
"string: '%.*s'",
934
(int)third_separator_char_pos + 1, regex_sed.data(),
935
(int)(regex_sed.size() - third_separator_char_pos - 1),
936
regex_sed.data() + (third_separator_char_pos + 1));
937
return error;
938
}
939
} else if (first_separator_char_pos + 1 == second_separator_char_pos) {
940
error.SetErrorStringWithFormat(
941
"<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
942
separator_char, separator_char, separator_char, (int)regex_sed.size(),
943
regex_sed.data());
944
return error;
945
} else if (second_separator_char_pos + 1 == third_separator_char_pos) {
946
error.SetErrorStringWithFormat(
947
"<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
948
separator_char, separator_char, separator_char, (int)regex_sed.size(),
949
regex_sed.data());
950
return error;
951
}
952
953
if (!check_only) {
954
std::string regex(std::string(regex_sed.substr(
955
first_separator_char_pos + 1,
956
second_separator_char_pos - first_separator_char_pos - 1)));
957
std::string subst(std::string(regex_sed.substr(
958
second_separator_char_pos + 1,
959
third_separator_char_pos - second_separator_char_pos - 1)));
960
m_regex_cmd_up->AddRegexCommand(regex, subst);
961
}
962
return error;
963
}
964
965
void AddRegexCommandToInterpreter() {
966
if (m_regex_cmd_up) {
967
if (m_regex_cmd_up->HasRegexEntries()) {
968
CommandObjectSP cmd_sp(m_regex_cmd_up.release());
969
m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
970
}
971
}
972
}
973
974
private:
975
std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
976
977
class CommandOptions : public Options {
978
public:
979
CommandOptions() = default;
980
981
~CommandOptions() override = default;
982
983
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
984
ExecutionContext *execution_context) override {
985
Status error;
986
const int short_option = m_getopt_table[option_idx].val;
987
988
switch (short_option) {
989
case 'h':
990
m_help.assign(std::string(option_arg));
991
break;
992
case 's':
993
m_syntax.assign(std::string(option_arg));
994
break;
995
default:
996
llvm_unreachable("Unimplemented option");
997
}
998
999
return error;
1000
}
1001
1002
void OptionParsingStarting(ExecutionContext *execution_context) override {
1003
m_help.clear();
1004
m_syntax.clear();
1005
}
1006
1007
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1008
return llvm::ArrayRef(g_regex_options);
1009
}
1010
1011
llvm::StringRef GetHelp() { return m_help; }
1012
1013
llvm::StringRef GetSyntax() { return m_syntax; }
1014
1015
protected:
1016
// Instance variables to hold the values for command options.
1017
1018
std::string m_help;
1019
std::string m_syntax;
1020
};
1021
1022
Options *GetOptions() override { return &m_options; }
1023
1024
CommandOptions m_options;
1025
};
1026
1027
class CommandObjectPythonFunction : public CommandObjectRaw {
1028
public:
1029
CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
1030
std::string funct, std::string help,
1031
ScriptedCommandSynchronicity synch,
1032
CompletionType completion_type)
1033
: CommandObjectRaw(interpreter, name), m_function_name(funct),
1034
m_synchro(synch), m_completion_type(completion_type) {
1035
if (!help.empty())
1036
SetHelp(help);
1037
else {
1038
StreamString stream;
1039
stream.Printf("For more information run 'help %s'", name.c_str());
1040
SetHelp(stream.GetString());
1041
}
1042
}
1043
1044
~CommandObjectPythonFunction() override = default;
1045
1046
bool IsRemovable() const override { return true; }
1047
1048
const std::string &GetFunctionName() { return m_function_name; }
1049
1050
ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1051
1052
llvm::StringRef GetHelpLong() override {
1053
if (m_fetched_help_long)
1054
return CommandObjectRaw::GetHelpLong();
1055
1056
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1057
if (!scripter)
1058
return CommandObjectRaw::GetHelpLong();
1059
1060
std::string docstring;
1061
m_fetched_help_long =
1062
scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
1063
if (!docstring.empty())
1064
SetHelpLong(docstring);
1065
return CommandObjectRaw::GetHelpLong();
1066
}
1067
1068
void
1069
HandleArgumentCompletion(CompletionRequest &request,
1070
OptionElementVector &opt_element_vector) override {
1071
lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1072
GetCommandInterpreter(), m_completion_type, request, nullptr);
1073
}
1074
1075
bool WantsCompletion() override { return true; }
1076
1077
protected:
1078
void DoExecute(llvm::StringRef raw_command_line,
1079
CommandReturnObject &result) override {
1080
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1081
1082
m_interpreter.IncreaseCommandUsage(*this);
1083
1084
Status error;
1085
1086
result.SetStatus(eReturnStatusInvalid);
1087
1088
if (!scripter || !scripter->RunScriptBasedCommand(
1089
m_function_name.c_str(), raw_command_line, m_synchro,
1090
result, error, m_exe_ctx)) {
1091
result.AppendError(error.AsCString());
1092
} else {
1093
// Don't change the status if the command already set it...
1094
if (result.GetStatus() == eReturnStatusInvalid) {
1095
if (result.GetOutputData().empty())
1096
result.SetStatus(eReturnStatusSuccessFinishNoResult);
1097
else
1098
result.SetStatus(eReturnStatusSuccessFinishResult);
1099
}
1100
}
1101
}
1102
1103
private:
1104
std::string m_function_name;
1105
ScriptedCommandSynchronicity m_synchro;
1106
bool m_fetched_help_long = false;
1107
CompletionType m_completion_type = eNoCompletion;
1108
};
1109
1110
/// This class implements a "raw" scripted command. lldb does no parsing of the
1111
/// command line, instead passing the line unaltered (except for backtick
1112
/// substitution).
1113
class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
1114
public:
1115
CommandObjectScriptingObjectRaw(CommandInterpreter &interpreter,
1116
std::string name,
1117
StructuredData::GenericSP cmd_obj_sp,
1118
ScriptedCommandSynchronicity synch,
1119
CompletionType completion_type)
1120
: CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1121
m_synchro(synch), m_fetched_help_short(false),
1122
m_fetched_help_long(false), m_completion_type(completion_type) {
1123
StreamString stream;
1124
stream.Printf("For more information run 'help %s'", name.c_str());
1125
SetHelp(stream.GetString());
1126
if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
1127
GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1128
}
1129
1130
~CommandObjectScriptingObjectRaw() override = default;
1131
1132
void
1133
HandleArgumentCompletion(CompletionRequest &request,
1134
OptionElementVector &opt_element_vector) override {
1135
lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1136
GetCommandInterpreter(), m_completion_type, request, nullptr);
1137
}
1138
1139
bool WantsCompletion() override { return true; }
1140
1141
bool IsRemovable() const override { return true; }
1142
1143
ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1144
1145
std::optional<std::string> GetRepeatCommand(Args &args,
1146
uint32_t index) override {
1147
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1148
if (!scripter)
1149
return std::nullopt;
1150
1151
return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
1152
}
1153
1154
llvm::StringRef GetHelp() override {
1155
if (m_fetched_help_short)
1156
return CommandObjectRaw::GetHelp();
1157
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1158
if (!scripter)
1159
return CommandObjectRaw::GetHelp();
1160
std::string docstring;
1161
m_fetched_help_short =
1162
scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1163
if (!docstring.empty())
1164
SetHelp(docstring);
1165
1166
return CommandObjectRaw::GetHelp();
1167
}
1168
1169
llvm::StringRef GetHelpLong() override {
1170
if (m_fetched_help_long)
1171
return CommandObjectRaw::GetHelpLong();
1172
1173
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1174
if (!scripter)
1175
return CommandObjectRaw::GetHelpLong();
1176
1177
std::string docstring;
1178
m_fetched_help_long =
1179
scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1180
if (!docstring.empty())
1181
SetHelpLong(docstring);
1182
return CommandObjectRaw::GetHelpLong();
1183
}
1184
1185
protected:
1186
void DoExecute(llvm::StringRef raw_command_line,
1187
CommandReturnObject &result) override {
1188
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1189
1190
Status error;
1191
1192
result.SetStatus(eReturnStatusInvalid);
1193
1194
if (!scripter ||
1195
!scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
1196
m_synchro, result, error, m_exe_ctx)) {
1197
result.AppendError(error.AsCString());
1198
} else {
1199
// Don't change the status if the command already set it...
1200
if (result.GetStatus() == eReturnStatusInvalid) {
1201
if (result.GetOutputData().empty())
1202
result.SetStatus(eReturnStatusSuccessFinishNoResult);
1203
else
1204
result.SetStatus(eReturnStatusSuccessFinishResult);
1205
}
1206
}
1207
}
1208
1209
private:
1210
StructuredData::GenericSP m_cmd_obj_sp;
1211
ScriptedCommandSynchronicity m_synchro;
1212
bool m_fetched_help_short : 1;
1213
bool m_fetched_help_long : 1;
1214
CompletionType m_completion_type = eNoCompletion;
1215
};
1216
1217
1218
/// This command implements a lldb parsed scripted command. The command
1219
/// provides a definition of the options and arguments, and a option value
1220
/// setting callback, and then the command's execution function gets passed
1221
/// just the parsed arguments.
1222
/// Note, implementing a command in Python using these base interfaces is a bit
1223
/// of a pain, but it is much easier to export this low level interface, and
1224
/// then make it nicer on the Python side, than to try to do that in a
1225
/// script language neutral way.
1226
/// So I've also added a base class in Python that provides a table-driven
1227
/// way of defining the options and arguments, which automatically fills the
1228
/// option values, making them available as properties in Python.
1229
///
1230
class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
1231
private:
1232
class CommandOptions : public Options {
1233
public:
1234
CommandOptions(CommandInterpreter &interpreter,
1235
StructuredData::GenericSP cmd_obj_sp) : m_interpreter(interpreter),
1236
m_cmd_obj_sp(cmd_obj_sp) {}
1237
1238
~CommandOptions() override = default;
1239
1240
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1241
ExecutionContext *execution_context) override {
1242
Status error;
1243
ScriptInterpreter *scripter =
1244
m_interpreter.GetDebugger().GetScriptInterpreter();
1245
if (!scripter) {
1246
error.SetErrorString("No script interpreter for SetOptionValue.");
1247
return error;
1248
}
1249
if (!m_cmd_obj_sp) {
1250
error.SetErrorString("SetOptionValue called with empty cmd_obj.");
1251
return error;
1252
}
1253
if (!m_options_definition_up) {
1254
error.SetErrorString("SetOptionValue called before options definitions "
1255
"were created.");
1256
return error;
1257
}
1258
// Pass the long option, since you aren't actually required to have a
1259
// short_option, and for those options the index or short option character
1260
// aren't meaningful on the python side.
1261
const char * long_option =
1262
m_options_definition_up.get()[option_idx].long_option;
1263
bool success = scripter->SetOptionValueForCommandObject(m_cmd_obj_sp,
1264
execution_context, long_option, option_arg);
1265
if (!success)
1266
error.SetErrorStringWithFormatv("Error setting option: {0} to {1}",
1267
long_option, option_arg);
1268
return error;
1269
}
1270
1271
void OptionParsingStarting(ExecutionContext *execution_context) override {
1272
ScriptInterpreter *scripter =
1273
m_interpreter.GetDebugger().GetScriptInterpreter();
1274
if (!scripter || !m_cmd_obj_sp)
1275
return;
1276
1277
scripter->OptionParsingStartedForCommandObject(m_cmd_obj_sp);
1278
}
1279
1280
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1281
if (!m_options_definition_up)
1282
return {};
1283
return llvm::ArrayRef(m_options_definition_up.get(), m_num_options);
1284
}
1285
1286
static Status ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp,
1287
size_t counter, uint32_t &usage_mask) {
1288
// If the usage entry is not provided, we use LLDB_OPT_SET_ALL.
1289
// If the usage mask is a UINT, the option belongs to that group.
1290
// If the usage mask is a vector of UINT's, the option belongs to all the
1291
// groups listed.
1292
// If a subelement of the vector is a vector of two ints, then the option
1293
// belongs to the inclusive range from the first to the second element.
1294
Status error;
1295
if (!obj_sp) {
1296
usage_mask = LLDB_OPT_SET_ALL;
1297
return error;
1298
}
1299
1300
usage_mask = 0;
1301
1302
StructuredData::UnsignedInteger *uint_val =
1303
obj_sp->GetAsUnsignedInteger();
1304
if (uint_val) {
1305
// If this is an integer, then this specifies a single group:
1306
uint32_t value = uint_val->GetValue();
1307
if (value == 0) {
1308
error.SetErrorStringWithFormatv(
1309
"0 is not a valid group for option {0}", counter);
1310
return error;
1311
}
1312
usage_mask = (1 << (value - 1));
1313
return error;
1314
}
1315
// Otherwise it has to be an array:
1316
StructuredData::Array *array_val = obj_sp->GetAsArray();
1317
if (!array_val) {
1318
error.SetErrorStringWithFormatv(
1319
"required field is not a array for option {0}", counter);
1320
return error;
1321
}
1322
// This is the array ForEach for accumulating a group usage mask from
1323
// an array of string descriptions of groups.
1324
auto groups_accumulator
1325
= [counter, &usage_mask, &error]
1326
(StructuredData::Object *obj) -> bool {
1327
StructuredData::UnsignedInteger *int_val = obj->GetAsUnsignedInteger();
1328
if (int_val) {
1329
uint32_t value = int_val->GetValue();
1330
if (value == 0) {
1331
error.SetErrorStringWithFormatv(
1332
"0 is not a valid group for element {0}", counter);
1333
return false;
1334
}
1335
usage_mask |= (1 << (value - 1));
1336
return true;
1337
}
1338
StructuredData::Array *arr_val = obj->GetAsArray();
1339
if (!arr_val) {
1340
error.SetErrorStringWithFormatv(
1341
"Group element not an int or array of integers for element {0}",
1342
counter);
1343
return false;
1344
}
1345
size_t num_range_elem = arr_val->GetSize();
1346
if (num_range_elem != 2) {
1347
error.SetErrorStringWithFormatv(
1348
"Subranges of a group not a start and a stop for element {0}",
1349
counter);
1350
return false;
1351
}
1352
int_val = arr_val->GetItemAtIndex(0)->GetAsUnsignedInteger();
1353
if (!int_val) {
1354
error.SetErrorStringWithFormatv("Start element of a subrange of a "
1355
"group not unsigned int for element {0}", counter);
1356
return false;
1357
}
1358
uint32_t start = int_val->GetValue();
1359
int_val = arr_val->GetItemAtIndex(1)->GetAsUnsignedInteger();
1360
if (!int_val) {
1361
error.SetErrorStringWithFormatv("End element of a subrange of a group"
1362
" not unsigned int for element {0}", counter);
1363
return false;
1364
}
1365
uint32_t end = int_val->GetValue();
1366
if (start == 0 || end == 0 || start > end) {
1367
error.SetErrorStringWithFormatv("Invalid subrange of a group: {0} - "
1368
"{1} for element {2}", start, end, counter);
1369
return false;
1370
}
1371
for (uint32_t i = start; i <= end; i++) {
1372
usage_mask |= (1 << (i - 1));
1373
}
1374
return true;
1375
};
1376
array_val->ForEach(groups_accumulator);
1377
return error;
1378
}
1379
1380
1381
Status SetOptionsFromArray(StructuredData::Dictionary &options) {
1382
Status error;
1383
m_num_options = options.GetSize();
1384
m_options_definition_up.reset(new OptionDefinition[m_num_options]);
1385
// We need to hand out pointers to contents of these vectors; we reserve
1386
// as much as we'll need up front so they don't get freed on resize...
1387
m_usage_container.resize(m_num_options);
1388
m_enum_storage.resize(m_num_options);
1389
m_enum_vector.resize(m_num_options);
1390
1391
size_t counter = 0;
1392
size_t short_opt_counter = 0;
1393
// This is the Array::ForEach function for adding option elements:
1394
auto add_element = [this, &error, &counter, &short_opt_counter]
1395
(llvm::StringRef long_option, StructuredData::Object *object) -> bool {
1396
StructuredData::Dictionary *opt_dict = object->GetAsDictionary();
1397
if (!opt_dict) {
1398
error.SetErrorString("Value in options dictionary is not a dictionary");
1399
return false;
1400
}
1401
OptionDefinition &option_def = m_options_definition_up.get()[counter];
1402
1403
// We aren't exposing the validator yet, set it to null
1404
option_def.validator = nullptr;
1405
// We don't require usage masks, so set it to one group by default:
1406
option_def.usage_mask = 1;
1407
1408
// Now set the fields of the OptionDefinition Array from the dictionary:
1409
//
1410
// Note that I don't check for unknown fields in the option dictionaries
1411
// so a scriptor can add extra elements that are helpful when they go to
1412
// do "set_option_value"
1413
1414
// Usage Mask:
1415
StructuredData::ObjectSP obj_sp = opt_dict->GetValueForKey("groups");
1416
if (obj_sp) {
1417
error = ParseUsageMaskFromArray(obj_sp, counter,
1418
option_def.usage_mask);
1419
if (error.Fail())
1420
return false;
1421
}
1422
1423
// Required:
1424
option_def.required = false;
1425
obj_sp = opt_dict->GetValueForKey("required");
1426
if (obj_sp) {
1427
StructuredData::Boolean *boolean_val = obj_sp->GetAsBoolean();
1428
if (!boolean_val) {
1429
error.SetErrorStringWithFormatv("'required' field is not a boolean "
1430
"for option {0}", counter);
1431
return false;
1432
}
1433
option_def.required = boolean_val->GetValue();
1434
}
1435
1436
// Short Option:
1437
int short_option;
1438
obj_sp = opt_dict->GetValueForKey("short_option");
1439
if (obj_sp) {
1440
// The value is a string, so pull the
1441
llvm::StringRef short_str = obj_sp->GetStringValue();
1442
if (short_str.empty()) {
1443
error.SetErrorStringWithFormatv("short_option field empty for "
1444
"option {0}", counter);
1445
return false;
1446
} else if (short_str.size() != 1) {
1447
error.SetErrorStringWithFormatv("short_option field has extra "
1448
"characters for option {0}", counter);
1449
return false;
1450
}
1451
short_option = (int) short_str[0];
1452
} else {
1453
// If the short option is not provided, then we need a unique value
1454
// less than the lowest printable ASCII character.
1455
short_option = short_opt_counter++;
1456
}
1457
option_def.short_option = short_option;
1458
1459
// Long Option is the key from the outer dict:
1460
if (long_option.empty()) {
1461
error.SetErrorStringWithFormatv("empty long_option for option {0}",
1462
counter);
1463
return false;
1464
}
1465
auto inserted = g_string_storer.insert(long_option.str());
1466
option_def.long_option = ((*(inserted.first)).data());
1467
1468
// Value Type:
1469
obj_sp = opt_dict->GetValueForKey("value_type");
1470
if (obj_sp) {
1471
StructuredData::UnsignedInteger *uint_val
1472
= obj_sp->GetAsUnsignedInteger();
1473
if (!uint_val) {
1474
error.SetErrorStringWithFormatv("Value type must be an unsigned "
1475
"integer");
1476
return false;
1477
}
1478
uint64_t val_type = uint_val->GetValue();
1479
if (val_type >= eArgTypeLastArg) {
1480
error.SetErrorStringWithFormatv("Value type {0} beyond the "
1481
"CommandArgumentType bounds", val_type);
1482
return false;
1483
}
1484
option_def.argument_type = (CommandArgumentType) val_type;
1485
option_def.option_has_arg = true;
1486
} else {
1487
option_def.argument_type = eArgTypeNone;
1488
option_def.option_has_arg = false;
1489
}
1490
1491
// Completion Type:
1492
obj_sp = opt_dict->GetValueForKey("completion_type");
1493
if (obj_sp) {
1494
StructuredData::UnsignedInteger *uint_val = obj_sp->GetAsUnsignedInteger();
1495
if (!uint_val) {
1496
error.SetErrorStringWithFormatv("Completion type must be an "
1497
"unsigned integer for option {0}", counter);
1498
return false;
1499
}
1500
uint64_t completion_type = uint_val->GetValue();
1501
if (completion_type > eCustomCompletion) {
1502
error.SetErrorStringWithFormatv("Completion type for option {0} "
1503
"beyond the CompletionType bounds", completion_type);
1504
return false;
1505
}
1506
option_def.completion_type = (CommandArgumentType) completion_type;
1507
} else
1508
option_def.completion_type = eNoCompletion;
1509
1510
// Usage Text:
1511
std::string usage_text;
1512
obj_sp = opt_dict->GetValueForKey("help");
1513
if (!obj_sp) {
1514
error.SetErrorStringWithFormatv("required usage missing from option "
1515
"{0}", counter);
1516
return false;
1517
}
1518
llvm::StringRef usage_stref;
1519
usage_stref = obj_sp->GetStringValue();
1520
if (usage_stref.empty()) {
1521
error.SetErrorStringWithFormatv("empty usage text for option {0}",
1522
counter);
1523
return false;
1524
}
1525
m_usage_container[counter] = usage_stref.str().c_str();
1526
option_def.usage_text = m_usage_container[counter].data();
1527
1528
// Enum Values:
1529
1530
obj_sp = opt_dict->GetValueForKey("enum_values");
1531
if (obj_sp) {
1532
StructuredData::Array *array = obj_sp->GetAsArray();
1533
if (!array) {
1534
error.SetErrorStringWithFormatv("enum values must be an array for "
1535
"option {0}", counter);
1536
return false;
1537
}
1538
size_t num_elem = array->GetSize();
1539
size_t enum_ctr = 0;
1540
m_enum_storage[counter] = std::vector<EnumValueStorage>(num_elem);
1541
std::vector<EnumValueStorage> &curr_elem = m_enum_storage[counter];
1542
1543
// This is the Array::ForEach function for adding enum elements:
1544
// Since there are only two fields to specify the enum, use a simple
1545
// two element array with value first, usage second.
1546
// counter is only used for reporting so I pass it by value here.
1547
auto add_enum = [&enum_ctr, &curr_elem, counter, &error]
1548
(StructuredData::Object *object) -> bool {
1549
StructuredData::Array *enum_arr = object->GetAsArray();
1550
if (!enum_arr) {
1551
error.SetErrorStringWithFormatv("Enum values for option {0} not "
1552
"an array", counter);
1553
return false;
1554
}
1555
size_t num_enum_elements = enum_arr->GetSize();
1556
if (num_enum_elements != 2) {
1557
error.SetErrorStringWithFormatv("Wrong number of elements: {0} "
1558
"for enum {1} in option {2}",
1559
num_enum_elements, enum_ctr, counter);
1560
return false;
1561
}
1562
// Enum Value:
1563
StructuredData::ObjectSP obj_sp = enum_arr->GetItemAtIndex(0);
1564
llvm::StringRef val_stref = obj_sp->GetStringValue();
1565
std::string value_cstr_str = val_stref.str().c_str();
1566
1567
// Enum Usage:
1568
obj_sp = enum_arr->GetItemAtIndex(1);
1569
if (!obj_sp) {
1570
error.SetErrorStringWithFormatv("No usage for enum {0} in option "
1571
"{1}", enum_ctr, counter);
1572
return false;
1573
}
1574
llvm::StringRef usage_stref = obj_sp->GetStringValue();
1575
std::string usage_cstr_str = usage_stref.str().c_str();
1576
curr_elem[enum_ctr] = EnumValueStorage(value_cstr_str,
1577
usage_cstr_str, enum_ctr);
1578
1579
enum_ctr++;
1580
return true;
1581
}; // end of add_enum
1582
1583
array->ForEach(add_enum);
1584
if (!error.Success())
1585
return false;
1586
// We have to have a vector of elements to set in the options, make
1587
// that here:
1588
for (auto &elem : curr_elem)
1589
m_enum_vector[counter].emplace_back(elem.element);
1590
1591
option_def.enum_values = llvm::ArrayRef(m_enum_vector[counter]);
1592
}
1593
counter++;
1594
return true;
1595
}; // end of add_element
1596
1597
options.ForEach(add_element);
1598
return error;
1599
}
1600
1601
size_t GetNumOptions() { return m_num_options; }
1602
1603
private:
1604
struct EnumValueStorage {
1605
EnumValueStorage() {
1606
element.string_value = "value not set";
1607
element.usage = "usage not set";
1608
element.value = 0;
1609
}
1610
1611
EnumValueStorage(std::string in_str_val, std::string in_usage,
1612
size_t in_value) : value(std::move(in_str_val)), usage(std::move(in_usage)) {
1613
SetElement(in_value);
1614
}
1615
1616
EnumValueStorage(const EnumValueStorage &in) : value(in.value),
1617
usage(in.usage) {
1618
SetElement(in.element.value);
1619
}
1620
1621
EnumValueStorage &operator=(const EnumValueStorage &in) {
1622
value = in.value;
1623
usage = in.usage;
1624
SetElement(in.element.value);
1625
return *this;
1626
}
1627
1628
void SetElement(size_t in_value) {
1629
element.value = in_value;
1630
element.string_value = value.data();
1631
element.usage = usage.data();
1632
}
1633
1634
std::string value;
1635
std::string usage;
1636
OptionEnumValueElement element;
1637
};
1638
// We have to provide char * values for the long option, usage and enum
1639
// values, that's what the option definitions hold.
1640
// The long option strings are quite likely to be reused in other added
1641
// commands, so those are stored in a global set: g_string_storer.
1642
// But the usages are much less likely to be reused, so those are stored in
1643
// a vector in the command instance. It gets resized to the correct size
1644
// and then filled with null-terminated strings in the std::string, so the
1645
// are valid C-strings that won't move around.
1646
// The enum values and descriptions are treated similarly - these aren't
1647
// all that common so it's not worth the effort to dedup them.
1648
size_t m_num_options = 0;
1649
std::unique_ptr<OptionDefinition> m_options_definition_up;
1650
std::vector<std::vector<EnumValueStorage>> m_enum_storage;
1651
std::vector<std::vector<OptionEnumValueElement>> m_enum_vector;
1652
std::vector<std::string> m_usage_container;
1653
CommandInterpreter &m_interpreter;
1654
StructuredData::GenericSP m_cmd_obj_sp;
1655
static std::unordered_set<std::string> g_string_storer;
1656
};
1657
1658
public:
1659
static CommandObjectSP Create(CommandInterpreter &interpreter,
1660
std::string name,
1661
StructuredData::GenericSP cmd_obj_sp,
1662
ScriptedCommandSynchronicity synch,
1663
CommandReturnObject &result) {
1664
CommandObjectSP new_cmd_sp(new CommandObjectScriptingObjectParsed(
1665
interpreter, name, cmd_obj_sp, synch));
1666
1667
CommandObjectScriptingObjectParsed *parsed_cmd
1668
= static_cast<CommandObjectScriptingObjectParsed *>(new_cmd_sp.get());
1669
// Now check all the failure modes, and report if found.
1670
Status opt_error = parsed_cmd->GetOptionsError();
1671
Status arg_error = parsed_cmd->GetArgsError();
1672
1673
if (opt_error.Fail())
1674
result.AppendErrorWithFormat("failed to parse option definitions: %s",
1675
opt_error.AsCString());
1676
if (arg_error.Fail())
1677
result.AppendErrorWithFormat("%sfailed to parse argument definitions: %s",
1678
opt_error.Fail() ? ", also " : "",
1679
arg_error.AsCString());
1680
1681
if (!result.Succeeded())
1682
return {};
1683
1684
return new_cmd_sp;
1685
}
1686
1687
CommandObjectScriptingObjectParsed(CommandInterpreter &interpreter,
1688
std::string name,
1689
StructuredData::GenericSP cmd_obj_sp,
1690
ScriptedCommandSynchronicity synch)
1691
: CommandObjectParsed(interpreter, name.c_str()),
1692
m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch),
1693
m_options(interpreter, cmd_obj_sp), m_fetched_help_short(false),
1694
m_fetched_help_long(false) {
1695
StreamString stream;
1696
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1697
if (!scripter) {
1698
m_options_error.SetErrorString("No script interpreter");
1699
return;
1700
}
1701
1702
// Set the flags:
1703
GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1704
1705
// Now set up the options definitions from the options:
1706
StructuredData::ObjectSP options_object_sp
1707
= scripter->GetOptionsForCommandObject(cmd_obj_sp);
1708
// It's okay not to have an options dict.
1709
if (options_object_sp) {
1710
// The options come as a dictionary of dictionaries. The key of the
1711
// outer dict is the long option name (since that's required). The
1712
// value holds all the other option specification bits.
1713
StructuredData::Dictionary *options_dict
1714
= options_object_sp->GetAsDictionary();
1715
// but if it exists, it has to be an array.
1716
if (options_dict) {
1717
m_options_error = m_options.SetOptionsFromArray(*(options_dict));
1718
// If we got an error don't bother with the arguments...
1719
if (m_options_error.Fail())
1720
return;
1721
} else {
1722
m_options_error.SetErrorString("Options array not an array");
1723
return;
1724
}
1725
}
1726
// Then fetch the args. Since the arguments can have usage masks you need
1727
// an array of arrays.
1728
StructuredData::ObjectSP args_object_sp
1729
= scripter->GetArgumentsForCommandObject(cmd_obj_sp);
1730
if (args_object_sp) {
1731
StructuredData::Array *args_array = args_object_sp->GetAsArray();
1732
if (!args_array) {
1733
m_args_error.SetErrorString("Argument specification is not an array");
1734
return;
1735
}
1736
size_t counter = 0;
1737
1738
// This is the Array::ForEach function that handles the
1739
// CommandArgumentEntry arrays one by one:
1740
auto arg_array_adder = [this, &counter] (StructuredData::Object *object)
1741
-> bool {
1742
// This is the Array::ForEach function to add argument entries:
1743
CommandArgumentEntry this_entry;
1744
size_t elem_counter = 0;
1745
auto args_adder = [this, counter, &elem_counter, &this_entry]
1746
(StructuredData::Object *object) -> bool {
1747
// The arguments definition has three fields, the argument type, the
1748
// repeat and the usage mask.
1749
CommandArgumentType arg_type = eArgTypeNone;
1750
ArgumentRepetitionType arg_repetition = eArgRepeatOptional;
1751
uint32_t arg_opt_set_association;
1752
1753
auto report_error = [this, elem_counter, counter]
1754
(const char *err_txt) -> bool {
1755
m_args_error.SetErrorStringWithFormatv("Element {0} of arguments "
1756
"list element {1}: %s.", elem_counter, counter, err_txt);
1757
return false;
1758
};
1759
1760
StructuredData::Dictionary *arg_dict = object->GetAsDictionary();
1761
if (!arg_dict) {
1762
report_error("is not a dictionary.");
1763
return false;
1764
}
1765
// Argument Type:
1766
StructuredData::ObjectSP obj_sp
1767
= arg_dict->GetValueForKey("arg_type");
1768
if (obj_sp) {
1769
StructuredData::UnsignedInteger *uint_val
1770
= obj_sp->GetAsUnsignedInteger();
1771
if (!uint_val) {
1772
report_error("value type must be an unsigned integer");
1773
return false;
1774
}
1775
uint64_t arg_type_int = uint_val->GetValue();
1776
if (arg_type_int >= eArgTypeLastArg) {
1777
report_error("value type beyond ArgumentRepetitionType bounds");
1778
return false;
1779
}
1780
arg_type = (CommandArgumentType) arg_type_int;
1781
}
1782
// Repeat Value:
1783
obj_sp = arg_dict->GetValueForKey("repeat");
1784
std::optional<ArgumentRepetitionType> repeat;
1785
if (obj_sp) {
1786
llvm::StringRef repeat_str = obj_sp->GetStringValue();
1787
if (repeat_str.empty()) {
1788
report_error("repeat value is empty");
1789
return false;
1790
}
1791
repeat = ArgRepetitionFromString(repeat_str);
1792
if (!repeat) {
1793
report_error("invalid repeat value");
1794
return false;
1795
}
1796
arg_repetition = *repeat;
1797
}
1798
1799
// Usage Mask:
1800
obj_sp = arg_dict->GetValueForKey("groups");
1801
m_args_error = CommandOptions::ParseUsageMaskFromArray(obj_sp,
1802
counter, arg_opt_set_association);
1803
this_entry.emplace_back(arg_type, arg_repetition,
1804
arg_opt_set_association);
1805
elem_counter++;
1806
return true;
1807
};
1808
StructuredData::Array *args_array = object->GetAsArray();
1809
if (!args_array) {
1810
m_args_error.SetErrorStringWithFormatv("Argument definition element "
1811
"{0} is not an array", counter);
1812
}
1813
1814
args_array->ForEach(args_adder);
1815
if (m_args_error.Fail())
1816
return false;
1817
if (this_entry.empty()) {
1818
m_args_error.SetErrorStringWithFormatv("Argument definition element "
1819
"{0} is empty", counter);
1820
return false;
1821
}
1822
m_arguments.push_back(this_entry);
1823
counter++;
1824
return true;
1825
}; // end of arg_array_adder
1826
// Here we actually parse the args definition:
1827
args_array->ForEach(arg_array_adder);
1828
}
1829
}
1830
1831
~CommandObjectScriptingObjectParsed() override = default;
1832
1833
Status GetOptionsError() { return m_options_error; }
1834
Status GetArgsError() { return m_args_error; }
1835
bool WantsCompletion() override { return true; }
1836
1837
bool IsRemovable() const override { return true; }
1838
1839
ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1840
1841
std::optional<std::string> GetRepeatCommand(Args &args,
1842
uint32_t index) override {
1843
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1844
if (!scripter)
1845
return std::nullopt;
1846
1847
return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
1848
}
1849
1850
llvm::StringRef GetHelp() override {
1851
if (m_fetched_help_short)
1852
return CommandObjectParsed::GetHelp();
1853
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1854
if (!scripter)
1855
return CommandObjectParsed::GetHelp();
1856
std::string docstring;
1857
m_fetched_help_short =
1858
scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1859
if (!docstring.empty())
1860
SetHelp(docstring);
1861
1862
return CommandObjectParsed::GetHelp();
1863
}
1864
1865
llvm::StringRef GetHelpLong() override {
1866
if (m_fetched_help_long)
1867
return CommandObjectParsed::GetHelpLong();
1868
1869
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1870
if (!scripter)
1871
return CommandObjectParsed::GetHelpLong();
1872
1873
std::string docstring;
1874
m_fetched_help_long =
1875
scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1876
if (!docstring.empty())
1877
SetHelpLong(docstring);
1878
return CommandObjectParsed::GetHelpLong();
1879
}
1880
1881
Options *GetOptions() override {
1882
// CommandObjectParsed requires that a command with no options return
1883
// nullptr.
1884
if (m_options.GetNumOptions() == 0)
1885
return nullptr;
1886
return &m_options;
1887
}
1888
1889
protected:
1890
void DoExecute(Args &args,
1891
CommandReturnObject &result) override {
1892
ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
1893
1894
Status error;
1895
1896
result.SetStatus(eReturnStatusInvalid);
1897
1898
if (!scripter ||
1899
!scripter->RunScriptBasedParsedCommand(m_cmd_obj_sp, args,
1900
m_synchro, result, error, m_exe_ctx)) {
1901
result.AppendError(error.AsCString());
1902
} else {
1903
// Don't change the status if the command already set it...
1904
if (result.GetStatus() == eReturnStatusInvalid) {
1905
if (result.GetOutputData().empty())
1906
result.SetStatus(eReturnStatusSuccessFinishNoResult);
1907
else
1908
result.SetStatus(eReturnStatusSuccessFinishResult);
1909
}
1910
}
1911
}
1912
1913
private:
1914
StructuredData::GenericSP m_cmd_obj_sp;
1915
ScriptedCommandSynchronicity m_synchro;
1916
CommandOptions m_options;
1917
Status m_options_error;
1918
Status m_args_error;
1919
bool m_fetched_help_short : 1;
1920
bool m_fetched_help_long : 1;
1921
};
1922
1923
std::unordered_set<std::string>
1924
CommandObjectScriptingObjectParsed::CommandOptions::g_string_storer;
1925
1926
// CommandObjectCommandsScriptImport
1927
#define LLDB_OPTIONS_script_import
1928
#include "CommandOptions.inc"
1929
1930
class CommandObjectCommandsScriptImport : public CommandObjectParsed {
1931
public:
1932
CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
1933
: CommandObjectParsed(interpreter, "command script import",
1934
"Import a scripting module in LLDB.", nullptr) {
1935
AddSimpleArgumentList(eArgTypeFilename, eArgRepeatPlus);
1936
}
1937
1938
~CommandObjectCommandsScriptImport() override = default;
1939
1940
Options *GetOptions() override { return &m_options; }
1941
1942
protected:
1943
class CommandOptions : public Options {
1944
public:
1945
CommandOptions() = default;
1946
1947
~CommandOptions() override = default;
1948
1949
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1950
ExecutionContext *execution_context) override {
1951
Status error;
1952
const int short_option = m_getopt_table[option_idx].val;
1953
1954
switch (short_option) {
1955
case 'r':
1956
// NO-OP
1957
break;
1958
case 'c':
1959
relative_to_command_file = true;
1960
break;
1961
case 's':
1962
silent = true;
1963
break;
1964
default:
1965
llvm_unreachable("Unimplemented option");
1966
}
1967
1968
return error;
1969
}
1970
1971
void OptionParsingStarting(ExecutionContext *execution_context) override {
1972
relative_to_command_file = false;
1973
}
1974
1975
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1976
return llvm::ArrayRef(g_script_import_options);
1977
}
1978
bool relative_to_command_file = false;
1979
bool silent = false;
1980
};
1981
1982
void DoExecute(Args &command, CommandReturnObject &result) override {
1983
if (command.empty()) {
1984
result.AppendError("command script import needs one or more arguments");
1985
return;
1986
}
1987
1988
FileSpec source_dir = {};
1989
if (m_options.relative_to_command_file) {
1990
source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
1991
if (!source_dir) {
1992
result.AppendError("command script import -c can only be specified "
1993
"from a command file");
1994
return;
1995
}
1996
}
1997
1998
for (auto &entry : command.entries()) {
1999
Status error;
2000
2001
LoadScriptOptions options;
2002
options.SetInitSession(true);
2003
options.SetSilent(m_options.silent);
2004
2005
// FIXME: this is necessary because CommandObject::CheckRequirements()
2006
// assumes that commands won't ever be recursively invoked, but it's
2007
// actually possible to craft a Python script that does other "command
2008
// script imports" in __lldb_init_module the real fix is to have
2009
// recursive commands possible with a CommandInvocation object separate
2010
// from the CommandObject itself, so that recursive command invocations
2011
// won't stomp on each other (wrt to execution contents, options, and
2012
// more)
2013
m_exe_ctx.Clear();
2014
if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
2015
entry.c_str(), options, error, /*module_sp=*/nullptr,
2016
source_dir)) {
2017
result.SetStatus(eReturnStatusSuccessFinishNoResult);
2018
} else {
2019
result.AppendErrorWithFormat("module importing failed: %s",
2020
error.AsCString());
2021
}
2022
}
2023
}
2024
2025
CommandOptions m_options;
2026
};
2027
2028
#define LLDB_OPTIONS_script_add
2029
#include "CommandOptions.inc"
2030
2031
class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
2032
public IOHandlerDelegateMultiline {
2033
public:
2034
CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
2035
: CommandObjectParsed(interpreter, "command script add",
2036
"Add a scripted function as an LLDB command.",
2037
"Add a scripted function as an lldb command. "
2038
"If you provide a single argument, the command "
2039
"will be added at the root level of the command "
2040
"hierarchy. If there are more arguments they "
2041
"must be a path to a user-added container "
2042
"command, and the last element will be the new "
2043
"command name."),
2044
IOHandlerDelegateMultiline("DONE") {
2045
AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2046
}
2047
2048
~CommandObjectCommandsScriptAdd() override = default;
2049
2050
Options *GetOptions() override { return &m_options; }
2051
2052
void
2053
HandleArgumentCompletion(CompletionRequest &request,
2054
OptionElementVector &opt_element_vector) override {
2055
CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
2056
opt_element_vector);
2057
}
2058
2059
protected:
2060
class CommandOptions : public Options {
2061
public:
2062
CommandOptions() = default;
2063
2064
~CommandOptions() override = default;
2065
2066
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2067
ExecutionContext *execution_context) override {
2068
Status error;
2069
const int short_option = m_getopt_table[option_idx].val;
2070
2071
switch (short_option) {
2072
case 'f':
2073
if (!option_arg.empty())
2074
m_funct_name = std::string(option_arg);
2075
break;
2076
case 'c':
2077
if (!option_arg.empty())
2078
m_class_name = std::string(option_arg);
2079
break;
2080
case 'h':
2081
if (!option_arg.empty())
2082
m_short_help = std::string(option_arg);
2083
break;
2084
case 'o':
2085
m_overwrite_lazy = eLazyBoolYes;
2086
break;
2087
case 'p':
2088
m_parsed_command = true;
2089
break;
2090
case 's':
2091
m_synchronicity =
2092
(ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
2093
option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
2094
if (!error.Success())
2095
error.SetErrorStringWithFormat(
2096
"unrecognized value for synchronicity '%s'",
2097
option_arg.str().c_str());
2098
break;
2099
case 'C': {
2100
Status error;
2101
OptionDefinition definition = GetDefinitions()[option_idx];
2102
lldb::CompletionType completion_type =
2103
static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum(
2104
option_arg, definition.enum_values, eNoCompletion, error));
2105
if (!error.Success())
2106
error.SetErrorStringWithFormat(
2107
"unrecognized value for command completion type '%s'",
2108
option_arg.str().c_str());
2109
m_completion_type = completion_type;
2110
} break;
2111
default:
2112
llvm_unreachable("Unimplemented option");
2113
}
2114
2115
return error;
2116
}
2117
2118
void OptionParsingStarting(ExecutionContext *execution_context) override {
2119
m_class_name.clear();
2120
m_funct_name.clear();
2121
m_short_help.clear();
2122
m_completion_type = eNoCompletion;
2123
m_overwrite_lazy = eLazyBoolCalculate;
2124
m_synchronicity = eScriptedCommandSynchronicitySynchronous;
2125
m_parsed_command = false;
2126
}
2127
2128
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2129
return llvm::ArrayRef(g_script_add_options);
2130
}
2131
2132
// Instance variables to hold the values for command options.
2133
2134
std::string m_class_name;
2135
std::string m_funct_name;
2136
std::string m_short_help;
2137
LazyBool m_overwrite_lazy = eLazyBoolCalculate;
2138
ScriptedCommandSynchronicity m_synchronicity =
2139
eScriptedCommandSynchronicitySynchronous;
2140
CompletionType m_completion_type = eNoCompletion;
2141
bool m_parsed_command = false;
2142
};
2143
2144
void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
2145
StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
2146
if (output_sp && interactive) {
2147
output_sp->PutCString(g_python_command_instructions);
2148
output_sp->Flush();
2149
}
2150
}
2151
2152
void IOHandlerInputComplete(IOHandler &io_handler,
2153
std::string &data) override {
2154
StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
2155
2156
ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2157
if (interpreter) {
2158
StringList lines;
2159
lines.SplitIntoLines(data);
2160
if (lines.GetSize() > 0) {
2161
std::string funct_name_str;
2162
if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
2163
if (funct_name_str.empty()) {
2164
error_sp->Printf("error: unable to obtain a function name, didn't "
2165
"add python command.\n");
2166
error_sp->Flush();
2167
} else {
2168
// everything should be fine now, let's add this alias
2169
2170
CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
2171
m_interpreter, m_cmd_name, funct_name_str, m_short_help,
2172
m_synchronicity, m_completion_type));
2173
if (!m_container) {
2174
Status error = m_interpreter.AddUserCommand(
2175
m_cmd_name, command_obj_sp, m_overwrite);
2176
if (error.Fail()) {
2177
error_sp->Printf("error: unable to add selected command: '%s'",
2178
error.AsCString());
2179
error_sp->Flush();
2180
}
2181
} else {
2182
llvm::Error llvm_error = m_container->LoadUserSubcommand(
2183
m_cmd_name, command_obj_sp, m_overwrite);
2184
if (llvm_error) {
2185
error_sp->Printf("error: unable to add selected command: '%s'",
2186
llvm::toString(std::move(llvm_error)).c_str());
2187
error_sp->Flush();
2188
}
2189
}
2190
}
2191
} else {
2192
error_sp->Printf(
2193
"error: unable to create function, didn't add python command\n");
2194
error_sp->Flush();
2195
}
2196
} else {
2197
error_sp->Printf("error: empty function, didn't add python command\n");
2198
error_sp->Flush();
2199
}
2200
} else {
2201
error_sp->Printf(
2202
"error: script interpreter missing, didn't add python command\n");
2203
error_sp->Flush();
2204
}
2205
2206
io_handler.SetIsDone(true);
2207
}
2208
2209
void DoExecute(Args &command, CommandReturnObject &result) override {
2210
if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
2211
result.AppendError("only scripting language supported for scripted "
2212
"commands is currently Python");
2213
return;
2214
}
2215
2216
if (command.GetArgumentCount() == 0) {
2217
result.AppendError("'command script add' requires at least one argument");
2218
return;
2219
}
2220
// Store the options in case we get multi-line input, also figure out the
2221
// default if not user supplied:
2222
switch (m_options.m_overwrite_lazy) {
2223
case eLazyBoolCalculate:
2224
m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite();
2225
break;
2226
case eLazyBoolYes:
2227
m_overwrite = true;
2228
break;
2229
case eLazyBoolNo:
2230
m_overwrite = false;
2231
}
2232
2233
Status path_error;
2234
m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath(
2235
command, true, path_error);
2236
2237
if (path_error.Fail()) {
2238
result.AppendErrorWithFormat("error in command path: %s",
2239
path_error.AsCString());
2240
return;
2241
}
2242
2243
if (!m_container) {
2244
// This is getting inserted into the root of the interpreter.
2245
m_cmd_name = std::string(command[0].ref());
2246
} else {
2247
size_t num_args = command.GetArgumentCount();
2248
m_cmd_name = std::string(command[num_args - 1].ref());
2249
}
2250
2251
m_short_help.assign(m_options.m_short_help);
2252
m_synchronicity = m_options.m_synchronicity;
2253
m_completion_type = m_options.m_completion_type;
2254
2255
// Handle the case where we prompt for the script code first:
2256
if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) {
2257
m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt
2258
*this); // IOHandlerDelegate
2259
return;
2260
}
2261
2262
CommandObjectSP new_cmd_sp;
2263
if (m_options.m_class_name.empty()) {
2264
new_cmd_sp.reset(new CommandObjectPythonFunction(
2265
m_interpreter, m_cmd_name, m_options.m_funct_name,
2266
m_options.m_short_help, m_synchronicity, m_completion_type));
2267
} else {
2268
ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2269
if (!interpreter) {
2270
result.AppendError("cannot find ScriptInterpreter");
2271
return;
2272
}
2273
2274
auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
2275
m_options.m_class_name.c_str());
2276
if (!cmd_obj_sp) {
2277
result.AppendErrorWithFormatv("cannot create helper object for: "
2278
"'{0}'", m_options.m_class_name);
2279
return;
2280
}
2281
2282
if (m_options.m_parsed_command) {
2283
new_cmd_sp = CommandObjectScriptingObjectParsed::Create(m_interpreter,
2284
m_cmd_name, cmd_obj_sp, m_synchronicity, result);
2285
if (!result.Succeeded())
2286
return;
2287
} else
2288
new_cmd_sp.reset(new CommandObjectScriptingObjectRaw(
2289
m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity,
2290
m_completion_type));
2291
}
2292
2293
// Assume we're going to succeed...
2294
result.SetStatus(eReturnStatusSuccessFinishNoResult);
2295
if (!m_container) {
2296
Status add_error =
2297
m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite);
2298
if (add_error.Fail())
2299
result.AppendErrorWithFormat("cannot add command: %s",
2300
add_error.AsCString());
2301
} else {
2302
llvm::Error llvm_error =
2303
m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite);
2304
if (llvm_error)
2305
result.AppendErrorWithFormat(
2306
"cannot add command: %s",
2307
llvm::toString(std::move(llvm_error)).c_str());
2308
}
2309
}
2310
2311
CommandOptions m_options;
2312
std::string m_cmd_name;
2313
CommandObjectMultiword *m_container = nullptr;
2314
std::string m_short_help;
2315
bool m_overwrite = false;
2316
ScriptedCommandSynchronicity m_synchronicity =
2317
eScriptedCommandSynchronicitySynchronous;
2318
CompletionType m_completion_type = eNoCompletion;
2319
};
2320
2321
// CommandObjectCommandsScriptList
2322
2323
class CommandObjectCommandsScriptList : public CommandObjectParsed {
2324
public:
2325
CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
2326
: CommandObjectParsed(interpreter, "command script list",
2327
"List defined top-level scripted commands.",
2328
nullptr) {}
2329
2330
~CommandObjectCommandsScriptList() override = default;
2331
2332
void DoExecute(Args &command, CommandReturnObject &result) override {
2333
m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
2334
2335
result.SetStatus(eReturnStatusSuccessFinishResult);
2336
}
2337
};
2338
2339
// CommandObjectCommandsScriptClear
2340
2341
class CommandObjectCommandsScriptClear : public CommandObjectParsed {
2342
public:
2343
CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
2344
: CommandObjectParsed(interpreter, "command script clear",
2345
"Delete all scripted commands.", nullptr) {}
2346
2347
~CommandObjectCommandsScriptClear() override = default;
2348
2349
protected:
2350
void DoExecute(Args &command, CommandReturnObject &result) override {
2351
m_interpreter.RemoveAllUser();
2352
2353
result.SetStatus(eReturnStatusSuccessFinishResult);
2354
}
2355
};
2356
2357
// CommandObjectCommandsScriptDelete
2358
2359
class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
2360
public:
2361
CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
2362
: CommandObjectParsed(
2363
interpreter, "command script delete",
2364
"Delete a scripted command by specifying the path to the command.",
2365
nullptr) {
2366
AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2367
}
2368
2369
~CommandObjectCommandsScriptDelete() override = default;
2370
2371
void
2372
HandleArgumentCompletion(CompletionRequest &request,
2373
OptionElementVector &opt_element_vector) override {
2374
lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2375
m_interpreter, request, opt_element_vector);
2376
}
2377
2378
protected:
2379
void DoExecute(Args &command, CommandReturnObject &result) override {
2380
2381
llvm::StringRef root_cmd = command[0].ref();
2382
size_t num_args = command.GetArgumentCount();
2383
2384
if (root_cmd.empty()) {
2385
result.AppendErrorWithFormat("empty root command name");
2386
return;
2387
}
2388
if (!m_interpreter.HasUserCommands() &&
2389
!m_interpreter.HasUserMultiwordCommands()) {
2390
result.AppendErrorWithFormat("can only delete user defined commands, "
2391
"but no user defined commands found");
2392
return;
2393
}
2394
2395
CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd);
2396
if (!cmd_sp) {
2397
result.AppendErrorWithFormat("command '%s' not found.",
2398
command[0].c_str());
2399
return;
2400
}
2401
if (!cmd_sp->IsUserCommand()) {
2402
result.AppendErrorWithFormat("command '%s' is not a user command.",
2403
command[0].c_str());
2404
return;
2405
}
2406
if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) {
2407
result.AppendErrorWithFormat("command '%s' is a multi-word command.\n "
2408
"Delete with \"command container delete\"",
2409
command[0].c_str());
2410
return;
2411
}
2412
2413
if (command.GetArgumentCount() == 1) {
2414
m_interpreter.RemoveUser(root_cmd);
2415
result.SetStatus(eReturnStatusSuccessFinishResult);
2416
return;
2417
}
2418
// We're deleting a command from a multiword command. Verify the command
2419
// path:
2420
Status error;
2421
CommandObjectMultiword *container =
2422
GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2423
error);
2424
if (error.Fail()) {
2425
result.AppendErrorWithFormat("could not resolve command path: %s",
2426
error.AsCString());
2427
return;
2428
}
2429
if (!container) {
2430
// This means that command only had a leaf command, so the container is
2431
// the root. That should have been handled above.
2432
result.AppendErrorWithFormat("could not find a container for '%s'",
2433
command[0].c_str());
2434
return;
2435
}
2436
const char *leaf_cmd = command[num_args - 1].c_str();
2437
llvm::Error llvm_error =
2438
container->RemoveUserSubcommand(leaf_cmd,
2439
/* multiword not okay */ false);
2440
if (llvm_error) {
2441
result.AppendErrorWithFormat(
2442
"could not delete command '%s': %s", leaf_cmd,
2443
llvm::toString(std::move(llvm_error)).c_str());
2444
return;
2445
}
2446
2447
Stream &out_stream = result.GetOutputStream();
2448
2449
out_stream << "Deleted command:";
2450
for (size_t idx = 0; idx < num_args; idx++) {
2451
out_stream << ' ';
2452
out_stream << command[idx].c_str();
2453
}
2454
out_stream << '\n';
2455
result.SetStatus(eReturnStatusSuccessFinishResult);
2456
}
2457
};
2458
2459
#pragma mark CommandObjectMultiwordCommandsScript
2460
2461
// CommandObjectMultiwordCommandsScript
2462
2463
class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
2464
public:
2465
CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
2466
: CommandObjectMultiword(
2467
interpreter, "command script",
2468
"Commands for managing custom "
2469
"commands implemented by "
2470
"interpreter scripts.",
2471
"command script <subcommand> [<subcommand-options>]") {
2472
LoadSubCommand("add", CommandObjectSP(
2473
new CommandObjectCommandsScriptAdd(interpreter)));
2474
LoadSubCommand(
2475
"delete",
2476
CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
2477
LoadSubCommand(
2478
"clear",
2479
CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
2480
LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
2481
interpreter)));
2482
LoadSubCommand(
2483
"import",
2484
CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
2485
}
2486
2487
~CommandObjectMultiwordCommandsScript() override = default;
2488
};
2489
2490
#pragma mark CommandObjectCommandContainer
2491
#define LLDB_OPTIONS_container_add
2492
#include "CommandOptions.inc"
2493
2494
class CommandObjectCommandsContainerAdd : public CommandObjectParsed {
2495
public:
2496
CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter)
2497
: CommandObjectParsed(
2498
interpreter, "command container add",
2499
"Add a container command to lldb. Adding to built-"
2500
"in container commands is not allowed.",
2501
"command container add [[path1]...] container-name") {
2502
AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2503
}
2504
2505
~CommandObjectCommandsContainerAdd() override = default;
2506
2507
Options *GetOptions() override { return &m_options; }
2508
2509
void
2510
HandleArgumentCompletion(CompletionRequest &request,
2511
OptionElementVector &opt_element_vector) override {
2512
lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2513
m_interpreter, request, opt_element_vector);
2514
}
2515
2516
protected:
2517
class CommandOptions : public Options {
2518
public:
2519
CommandOptions() = default;
2520
2521
~CommandOptions() override = default;
2522
2523
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2524
ExecutionContext *execution_context) override {
2525
Status error;
2526
const int short_option = m_getopt_table[option_idx].val;
2527
2528
switch (short_option) {
2529
case 'h':
2530
if (!option_arg.empty())
2531
m_short_help = std::string(option_arg);
2532
break;
2533
case 'o':
2534
m_overwrite = true;
2535
break;
2536
case 'H':
2537
if (!option_arg.empty())
2538
m_long_help = std::string(option_arg);
2539
break;
2540
default:
2541
llvm_unreachable("Unimplemented option");
2542
}
2543
2544
return error;
2545
}
2546
2547
void OptionParsingStarting(ExecutionContext *execution_context) override {
2548
m_short_help.clear();
2549
m_long_help.clear();
2550
m_overwrite = false;
2551
}
2552
2553
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2554
return llvm::ArrayRef(g_container_add_options);
2555
}
2556
2557
// Instance variables to hold the values for command options.
2558
2559
std::string m_short_help;
2560
std::string m_long_help;
2561
bool m_overwrite = false;
2562
};
2563
void DoExecute(Args &command, CommandReturnObject &result) override {
2564
size_t num_args = command.GetArgumentCount();
2565
2566
if (num_args == 0) {
2567
result.AppendError("no command was specified");
2568
return;
2569
}
2570
2571
if (num_args == 1) {
2572
// We're adding this as a root command, so use the interpreter.
2573
const char *cmd_name = command.GetArgumentAtIndex(0);
2574
auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
2575
GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
2576
m_options.m_long_help.c_str()));
2577
cmd_sp->GetAsMultiwordCommand()->SetRemovable(true);
2578
Status add_error = GetCommandInterpreter().AddUserCommand(
2579
cmd_name, cmd_sp, m_options.m_overwrite);
2580
if (add_error.Fail()) {
2581
result.AppendErrorWithFormat("error adding command: %s",
2582
add_error.AsCString());
2583
return;
2584
}
2585
result.SetStatus(eReturnStatusSuccessFinishNoResult);
2586
return;
2587
}
2588
2589
// We're adding this to a subcommand, first find the subcommand:
2590
Status path_error;
2591
CommandObjectMultiword *add_to_me =
2592
GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2593
path_error);
2594
2595
if (!add_to_me) {
2596
result.AppendErrorWithFormat("error adding command: %s",
2597
path_error.AsCString());
2598
return;
2599
}
2600
2601
const char *cmd_name = command.GetArgumentAtIndex(num_args - 1);
2602
auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
2603
GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
2604
m_options.m_long_help.c_str()));
2605
llvm::Error llvm_error =
2606
add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite);
2607
if (llvm_error) {
2608
result.AppendErrorWithFormat("error adding subcommand: %s",
2609
llvm::toString(std::move(llvm_error)).c_str());
2610
return;
2611
}
2612
2613
result.SetStatus(eReturnStatusSuccessFinishNoResult);
2614
}
2615
2616
private:
2617
CommandOptions m_options;
2618
};
2619
2620
#define LLDB_OPTIONS_multiword_delete
2621
#include "CommandOptions.inc"
2622
class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
2623
public:
2624
CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter)
2625
: CommandObjectParsed(
2626
interpreter, "command container delete",
2627
"Delete a container command previously added to "
2628
"lldb.",
2629
"command container delete [[path1] ...] container-cmd") {
2630
AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus);
2631
}
2632
2633
~CommandObjectCommandsContainerDelete() override = default;
2634
2635
void
2636
HandleArgumentCompletion(CompletionRequest &request,
2637
OptionElementVector &opt_element_vector) override {
2638
lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2639
m_interpreter, request, opt_element_vector);
2640
}
2641
2642
protected:
2643
void DoExecute(Args &command, CommandReturnObject &result) override {
2644
size_t num_args = command.GetArgumentCount();
2645
2646
if (num_args == 0) {
2647
result.AppendError("No command was specified.");
2648
return;
2649
}
2650
2651
if (num_args == 1) {
2652
// We're removing a root command, so we need to delete it from the
2653
// interpreter.
2654
const char *cmd_name = command.GetArgumentAtIndex(0);
2655
// Let's do a little more work here so we can do better error reporting.
2656
CommandInterpreter &interp = GetCommandInterpreter();
2657
CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name);
2658
if (!cmd_sp) {
2659
result.AppendErrorWithFormat("container command %s doesn't exist.",
2660
cmd_name);
2661
return;
2662
}
2663
if (!cmd_sp->IsUserCommand()) {
2664
result.AppendErrorWithFormat(
2665
"container command %s is not a user command", cmd_name);
2666
return;
2667
}
2668
if (!cmd_sp->GetAsMultiwordCommand()) {
2669
result.AppendErrorWithFormat("command %s is not a container command",
2670
cmd_name);
2671
return;
2672
}
2673
2674
bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name);
2675
if (!did_remove) {
2676
result.AppendErrorWithFormat("error removing command %s.", cmd_name);
2677
return;
2678
}
2679
2680
result.SetStatus(eReturnStatusSuccessFinishNoResult);
2681
return;
2682
}
2683
2684
// We're removing a subcommand, first find the subcommand's owner:
2685
Status path_error;
2686
CommandObjectMultiword *container =
2687
GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2688
path_error);
2689
2690
if (!container) {
2691
result.AppendErrorWithFormat("error removing container command: %s",
2692
path_error.AsCString());
2693
return;
2694
}
2695
const char *leaf = command.GetArgumentAtIndex(num_args - 1);
2696
llvm::Error llvm_error =
2697
container->RemoveUserSubcommand(leaf, /* multiword okay */ true);
2698
if (llvm_error) {
2699
result.AppendErrorWithFormat("error removing container command: %s",
2700
llvm::toString(std::move(llvm_error)).c_str());
2701
return;
2702
}
2703
result.SetStatus(eReturnStatusSuccessFinishNoResult);
2704
}
2705
};
2706
2707
class CommandObjectCommandContainer : public CommandObjectMultiword {
2708
public:
2709
CommandObjectCommandContainer(CommandInterpreter &interpreter)
2710
: CommandObjectMultiword(
2711
interpreter, "command container",
2712
"Commands for adding container commands to lldb. "
2713
"Container commands are containers for other commands. You can "
2714
"add nested container commands by specifying a command path, "
2715
"but you can't add commands into the built-in command hierarchy.",
2716
"command container <subcommand> [<subcommand-options>]") {
2717
LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd(
2718
interpreter)));
2719
LoadSubCommand(
2720
"delete",
2721
CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter)));
2722
}
2723
2724
~CommandObjectCommandContainer() override = default;
2725
};
2726
2727
#pragma mark CommandObjectMultiwordCommands
2728
2729
// CommandObjectMultiwordCommands
2730
2731
CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
2732
CommandInterpreter &interpreter)
2733
: CommandObjectMultiword(interpreter, "command",
2734
"Commands for managing custom LLDB commands.",
2735
"command <subcommand> [<subcommand-options>]") {
2736
LoadSubCommand("source",
2737
CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
2738
LoadSubCommand("alias",
2739
CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
2740
LoadSubCommand("unalias", CommandObjectSP(
2741
new CommandObjectCommandsUnalias(interpreter)));
2742
LoadSubCommand("delete",
2743
CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
2744
LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer(
2745
interpreter)));
2746
LoadSubCommand(
2747
"regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
2748
LoadSubCommand(
2749
"script",
2750
CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
2751
}
2752
2753
CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
2754
2755