Coverage Report

Created: 2023-11-11 10:31

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