CommandObjectCommands.cpp 72.7 KB
Newer Older
1
//===-- CommandObjectCommands.cpp -----------------------------------------===//
2
//
3
4
5
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// 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"
Enrico Granata's avatar
Enrico Granata committed
14
#include "lldb/Interpreter/CommandHistory.h"
15
16
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
17
#include "lldb/Interpreter/OptionArgParser.h"
Enrico Granata's avatar
Enrico Granata committed
18
#include "lldb/Interpreter/OptionValueBoolean.h"
19
#include "lldb/Interpreter/OptionValueString.h"
Enrico Granata's avatar
Enrico Granata committed
20
#include "lldb/Interpreter/OptionValueUInt64.h"
21
#include "lldb/Interpreter/Options.h"
22
#include "lldb/Interpreter/ScriptInterpreter.h"
23
#include "lldb/Utility/Args.h"
24
#include "lldb/Utility/StringList.h"
25
#include "llvm/ADT/StringRef.h"
26
27
28
29

using namespace lldb;
using namespace lldb_private;

30
31
// CommandObjectCommandsSource

32
33
#define LLDB_OPTIONS_source
#include "CommandOptions.inc"
34

35
class CommandObjectCommandsSource : public CommandObjectParsed {
36
public:
37
38
39
40
  CommandObjectCommandsSource(CommandInterpreter &interpreter)
      : CommandObjectParsed(
            interpreter, "command source",
            "Read and execute LLDB commands from the file <filename>.",
41
            nullptr) {
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    CommandArgumentEntry arg;
    CommandArgumentData file_arg;

    // Define the first (and only) variant of this arg.
    file_arg.arg_type = eArgTypeFilename;
    file_arg.arg_repetition = eArgRepeatPlain;

    // There is only one variant this argument could be; put it into the
    // argument entry.
    arg.push_back(file_arg);

    // Push the data for the first argument into the m_arguments vector.
    m_arguments.push_back(arg);
  }

  ~CommandObjectCommandsSource() override = default;

  const char *GetRepeatCommand(Args &current_command_args,
                               uint32_t index) override {
    return "";
  }

64
65
66
  void
  HandleArgumentCompletion(CompletionRequest &request,
                           OptionElementVector &opt_element_vector) override {
67
68
    CommandCompletions::InvokeCommonCompletionCallbacks(
        GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
69
        request, nullptr);
70
71
72
  }

  Options *GetOptions() override { return &m_options; }
73

74
75
76
77
protected:
  class CommandOptions : public Options {
  public:
    CommandOptions()
78
79
        : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true),
          m_cmd_relative_to_command_file(false) {}
80
81
82

    ~CommandOptions() override = default;

Zachary Turner's avatar
Zachary Turner committed
83
84
85
    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
                          ExecutionContext *execution_context) override {
      Status error;
86
87
88
89
      const int short_option = m_getopt_table[option_idx].val;

      switch (short_option) {
      case 'e':
90
        error = m_stop_on_error.SetValueFromString(option_arg);
91
92
93
        break;

      case 'c':
94
        error = m_stop_on_continue.SetValueFromString(option_arg);
95
96
        break;

97
98
99
100
      case 'C':
        m_cmd_relative_to_command_file = true;
        break;

101
      case 's':
102
        error = m_silent_run.SetValueFromString(option_arg);
103
104
105
        break;

      default:
106
        llvm_unreachable("Unimplemented option");
107
108
109
      }

      return error;
110
111
    }

112
113
114
115
    void OptionParsingStarting(ExecutionContext *execution_context) override {
      m_stop_on_error.Clear();
      m_silent_run.Clear();
      m_stop_on_continue.Clear();
116
      m_cmd_relative_to_command_file.Clear();
117
118
    }

119
    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
120
      return llvm::makeArrayRef(g_source_options);
121
    }
122
123
124
125
126
127

    // Instance variables to hold the values for command options.

    OptionValueBoolean m_stop_on_error;
    OptionValueBoolean m_silent_run;
    OptionValueBoolean m_stop_on_continue;
128
    OptionValueBoolean m_cmd_relative_to_command_file;
129
130
131
  };

  bool DoExecute(Args &command, CommandReturnObject &result) override {
132
    if (command.GetArgumentCount() != 1) {
133
134
      result.AppendErrorWithFormat(
          "'%s' takes exactly one executable filename argument.\n",
135
          GetCommandName().str().c_str());
136
137
138
      return false;
    }

139
140
141
142
143
144
145
146
147
148
149
    FileSpec source_dir = {};
    if (m_options.m_cmd_relative_to_command_file) {
      source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
      if (!source_dir) {
        result.AppendError("command source -C can only be specified "
                           "from a command file");
        result.SetStatus(eReturnStatusFailed);
        return false;
      }
    }

150
    FileSpec cmd_file(command[0].ref());
151
152
153
154
155
156
157
158
159
160
161
    if (source_dir) {
      // Prepend the source_dir to the cmd_file path:
      if (!cmd_file.IsRelative()) {
        result.AppendError("command source -C can only be used "
                           "with a relative path.");
        result.SetStatus(eReturnStatusFailed);
        return false;
      }
      cmd_file.MakeAbsolute(source_dir);
    }

162
    FileSystem::Instance().Resolve(cmd_file);
163

164
    CommandInterpreterRunOptions options;
165
166
167
168
    // If any options were set, then use them
    if (m_options.m_stop_on_error.OptionWasSet() ||
        m_options.m_silent_run.OptionWasSet() ||
        m_options.m_stop_on_continue.OptionWasSet()) {
169
170
171
172
173
174
      if (m_options.m_stop_on_continue.OptionWasSet())
        options.SetStopOnContinue(
            m_options.m_stop_on_continue.GetCurrentValue());

      if (m_options.m_stop_on_error.OptionWasSet())
        options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
175
176
177
178
179
180

      // Individual silent setting is override for global command echo settings.
      if (m_options.m_silent_run.GetCurrentValue()) {
        options.SetSilent(true);
      } else {
        options.SetPrintResults(true);
181
        options.SetPrintErrors(true);
182
183
184
        options.SetEchoCommands(m_interpreter.GetEchoCommands());
        options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
      }
185
    }
186
187

    m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
188
189
    return result.Succeeded();
  }
190

191
  CommandOptions m_options;
192
193
194
195
196
};

#pragma mark CommandObjectCommandsAlias
// CommandObjectCommandsAlias

197
198
#define LLDB_OPTIONS_alias
#include "CommandOptions.inc"
199

200
201
202
203
static const char *g_python_command_instructions =
    "Enter your Python command(s). Type 'DONE' to end.\n"
    "You must define a Python function with this signature:\n"
    "def my_command_impl(debugger, args, result, internal_dict):\n";
Enrico Granata's avatar
Enrico Granata committed
204

205
class CommandObjectCommandsAlias : public CommandObjectRaw {
206
protected:
207
208
  class CommandOptions : public OptionGroup {
  public:
209
    CommandOptions() {}
210
211
212

    ~CommandOptions() override = default;

213
    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
214
      return llvm::makeArrayRef(g_alias_options);
215
    }
216

Zachary Turner's avatar
Zachary Turner committed
217
218
219
    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
                          ExecutionContext *execution_context) override {
      Status error;
220

221
      const int short_option = GetDefinitions()[option_idx].short_option;
222
      std::string option_str(option_value);
223
224
225

      switch (short_option) {
      case 'h':
226
        m_help.SetCurrentValue(option_str);
227
228
229
230
        m_help.SetOptionWasSet();
        break;

      case 'H':
231
        m_long_help.SetCurrentValue(option_str);
232
233
234
235
        m_long_help.SetOptionWasSet();
        break;

      default:
236
        llvm_unreachable("Unimplemented option");
237
238
239
      }

      return error;
240
241
    }

242
243
244
245
246
247
248
249
    void OptionParsingStarting(ExecutionContext *execution_context) override {
      m_help.Clear();
      m_long_help.Clear();
    }

    OptionValueString m_help;
    OptionValueString m_long_help;
  };
250

251
252
253
254
255
256
257
258
259
  OptionGroupOptions m_option_group;
  CommandOptions m_command_options;

public:
  Options *GetOptions() override { return &m_option_group; }

  CommandObjectCommandsAlias(CommandInterpreter &interpreter)
      : CommandObjectRaw(
            interpreter, "command alias",
260
            "Define a custom command in terms of an existing command.") {
261
262
263
264
265
    m_option_group.Append(&m_command_options);
    m_option_group.Finalize();

    SetHelpLong(
        "'alias' allows the user to create a short-cut or abbreviation for long \
266
commands, multi-word commands, and commands that take particular options.  \
267
268
Below are some simple examples of how one might use the 'alias' command:"
        R"(
269
270
271
272
273
274
275

(lldb) command alias sc script

    Creates the abbreviation 'sc' for the 'script' command.

(lldb) command alias bp breakpoint

276
277
)"
        "    Creates the abbreviation 'bp' for the 'breakpoint' command.  Since \
278
breakpoint commands are two-word commands, the user would still need to \
279
280
enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
        R"(
281
282
283
284
285

(lldb) command alias bpl breakpoint list

    Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.

286
287
)"
        "An alias can include some options for the command, with the values either \
288
289
filled in at the time the alias is created, or specified as positional \
arguments, to be filled in when the alias is invoked.  The following example \
290
291
shows how to create aliases with options:"
        R"(
292
293
294

(lldb) command alias bfl breakpoint set -f %1 -l %2

295
296
)"
        "    Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
297
298
299
300
301
302
303
304
305
options already part of the alias.  So if the user wants to set a breakpoint \
by file and line without explicitly having to use the -f and -l options, the \
user can now use 'bfl' instead.  The '%1' and '%2' are positional placeholders \
for the actual arguments that will be passed when the alias command is used.  \
The number in the placeholder refers to the position/order the actual value \
occupies when the alias is used.  All the occurrences of '%1' in the alias \
will be replaced with the first argument, all the occurrences of '%2' in the \
alias will be replaced with the second argument, and so on.  This also allows \
actual arguments to be used multiple times within an alias (see 'process \
306
307
launch' example below)."
        R"(
308

309
310
)"
        "Note: the positional arguments must substitute as whole words in the resultant \
311
command, so you can't at present do something like this to append the file extension \
312
313
\".cpp\":"
        R"(
314
315
316

(lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2

317
318
)"
        "For more complex aliasing, use the \"command regex\" command instead.  In the \
319
320
'bfl' case above, the actual file value will be filled in with the first argument \
following 'bfl' and the actual line number value will be filled in with the second \
321
322
argument.  The user would use this alias as follows:"
        R"(
323
324
325
326
327
328
329
330
331
332
333
334
335

(lldb) command alias bfl breakpoint set -f %1 -l %2
(lldb) bfl my-file.c 137

This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.

Another example:

(lldb) command alias pltty process launch -s -o %1 -e %1
(lldb) pltty /dev/tty0

    Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'

336
337
)"
        "If the user always wanted to pass the same value to a particular option, the \
338
alias could be defined with that value directly in the alias as a constant, \
339
340
rather than using a positional placeholder:"
        R"(
341
342
343

(lldb) command alias bl3 breakpoint set -f %1 -l 3

344
345
346
347
348
349
350
351
352
353
354
355
    Always sets a breakpoint on line 3 of whatever file is indicated.)");

    CommandArgumentEntry arg1;
    CommandArgumentEntry arg2;
    CommandArgumentEntry arg3;
    CommandArgumentData alias_arg;
    CommandArgumentData cmd_arg;
    CommandArgumentData options_arg;

    // Define the first (and only) variant of this arg.
    alias_arg.arg_type = eArgTypeAliasName;
    alias_arg.arg_repetition = eArgRepeatPlain;
356

357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
    // There is only one variant this argument could be; put it into the
    // argument entry.
    arg1.push_back(alias_arg);

    // Define the first (and only) variant of this arg.
    cmd_arg.arg_type = eArgTypeCommandName;
    cmd_arg.arg_repetition = eArgRepeatPlain;

    // There is only one variant this argument could be; put it into the
    // argument entry.
    arg2.push_back(cmd_arg);

    // Define the first (and only) variant of this arg.
    options_arg.arg_type = eArgTypeAliasOptions;
    options_arg.arg_repetition = eArgRepeatOptional;

    // There is only one variant this argument could be; put it into the
    // argument entry.
    arg3.push_back(options_arg);

    // Push the data for the first argument into the m_arguments vector.
    m_arguments.push_back(arg1);
    m_arguments.push_back(arg2);
    m_arguments.push_back(arg3);
  }

  ~CommandObjectCommandsAlias() override = default;
384

385
protected:
386
  bool DoExecute(llvm::StringRef raw_command_line,
387
                 CommandReturnObject &result) override {
388
    if (raw_command_line.empty()) {
389
390
391
      result.AppendError("'command alias' requires at least two arguments");
      return false;
    }
392

393
394
395
    ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
    m_option_group.NotifyOptionParsingStarting(&exe_ctx);

396
    OptionsWithRaw args_with_suffix(raw_command_line);
397

398
399
400
401
    if (args_with_suffix.HasArgs())
      if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result,
                                 m_option_group, exe_ctx))
        return false;
402

403
    llvm::StringRef raw_command_string = args_with_suffix.GetRawPart();
404
    Args args(raw_command_string);
405

406
    if (args.GetArgumentCount() < 2) {
407
408
      result.AppendError("'command alias' requires at least two arguments");
      return false;
Caroline Tice's avatar
   
Caroline Tice committed
409
    }
410

411
412
    // Get the alias command.

413
    auto alias_command = args[0].ref();
414
    if (alias_command.startswith("-")) {
415
416
417
418
419
420
421
422
423
      result.AppendError("aliases starting with a dash are not supported");
      if (alias_command == "--help" || alias_command == "--long-help") {
        result.AppendWarning("if trying to pass options to 'command alias' add "
                             "a -- at the end of the options");
      }
      return false;
    }

    // Strip the new alias name off 'raw_command_string'  (leave it on args,
Adrian Prantl's avatar
Adrian Prantl committed
424
    // which gets passed to 'Execute', which does the stripping itself.
425
426
427
428
429
430
431
432
433
434
435
436
    size_t pos = raw_command_string.find(alias_command);
    if (pos == 0) {
      raw_command_string = raw_command_string.substr(alias_command.size());
      pos = raw_command_string.find_first_not_of(' ');
      if ((pos != std::string::npos) && (pos > 0))
        raw_command_string = raw_command_string.substr(pos);
    } else {
      result.AppendError("Error parsing command string.  No alias created.");
      return false;
    }

    // Verify that the command is alias-able.
437
    if (m_interpreter.CommandExists(alias_command)) {
438
439
      result.AppendErrorWithFormat(
          "'%s' is a permanent debugger command and cannot be redefined.\n",
440
          args[0].c_str());
441
442
      return false;
    }
443

444
445
446
447
448
449
450
451
    if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
      result.AppendErrorWithFormat(
          "'%s' is a user container command and cannot be overwritten.\n"
          "Delete it first with 'command container delete'\n",
          args[0].c_str());
      return false;
    }

452
    // Get CommandObject that is being aliased. The command name is read from
453
454
455
    // the front of raw_command_string. raw_command_string is returned with the
    // name of the command object stripped off the front.
    llvm::StringRef original_raw_command_string = raw_command_string;
456
457
458
459
460
461
462
    CommandObject *cmd_obj =
        m_interpreter.GetCommandObjectForCommand(raw_command_string);

    if (!cmd_obj) {
      result.AppendErrorWithFormat("invalid command given to 'command alias'. "
                                   "'%s' does not begin with a valid command."
                                   "  No alias created.",
463
                                   original_raw_command_string.str().c_str());
464
465
466
      return false;
    } else if (!cmd_obj->WantsRawCommandString()) {
      // Note that args was initialized with the original command, and has not
Adrian Prantl's avatar
Adrian Prantl committed
467
468
      // been updated to this point. Therefore can we pass it to the version of
      // Execute that does not need/expect raw input in the alias.
469
470
471
472
473
474
475
476
      return HandleAliasingNormalCommand(args, result);
    } else {
      return HandleAliasingRawCommand(alias_command, raw_command_string,
                                      *cmd_obj, result);
    }
    return result.Succeeded();
  }

477
478
  bool HandleAliasingRawCommand(llvm::StringRef alias_command,
                                llvm::StringRef raw_command_string,
479
480
481
482
483
484
485
                                CommandObject &cmd_obj,
                                CommandReturnObject &result) {
    // Verify & handle any options/arguments passed to the alias command

    OptionArgVectorSP option_arg_vector_sp =
        OptionArgVectorSP(new OptionArgVector);

486
487
488
    const bool include_aliases = true;
    if (CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact(
            cmd_obj.GetCommandName(), include_aliases)) {
489
490
      if (m_interpreter.AliasExists(alias_command) ||
          m_interpreter.UserCommandExists(alias_command)) {
491
492
        result.AppendWarningWithFormat(
            "Overwriting existing definition for '%s'.\n",
493
            alias_command.str().c_str());
494
495
      }
      if (CommandAlias *alias = m_interpreter.AddAlias(
496
              alias_command, cmd_obj_sp, raw_command_string)) {
497
498
499
500
501
502
503
504
505
506
507
508
        if (m_command_options.m_help.OptionWasSet())
          alias->SetHelp(m_command_options.m_help.GetCurrentValue());
        if (m_command_options.m_long_help.OptionWasSet())
          alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
        result.SetStatus(eReturnStatusSuccessFinishNoResult);
      } else {
        result.AppendError("Unable to create requested alias.\n");
      }

    } else {
      result.AppendError("Unable to create requested alias.\n");
    }
509

510
511
    return result.Succeeded();
  }
512

513
514
  bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
    size_t argc = args.GetArgumentCount();
515

516
517
518
519
    if (argc < 2) {
      result.AppendError("'command alias' requires at least two arguments");
      return false;
    }
520

521
    // Save these in std::strings since we're going to shift them off.
522
523
    const std::string alias_command(std::string(args[0].ref()));
    const std::string actual_command(std::string(args[1].ref()));
524
525
526
527
528
529
530

    args.Shift(); // Shift the alias command word off the argument vector.
    args.Shift(); // Shift the old command word off the argument vector.

    // Verify that the command is alias'able, and get the appropriate command
    // object.

531
    if (m_interpreter.CommandExists(alias_command)) {
532
533
534
      result.AppendErrorWithFormat(
          "'%s' is a permanent debugger command and cannot be redefined.\n",
          alias_command.c_str());
535
536
537
      return false;
    }

538
539
540
541
542
543
544
545
    if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
      result.AppendErrorWithFormat(
          "'%s' is user container command and cannot be overwritten.\n"
          "Delete it first with 'command container delete'",
          alias_command.c_str());
      return false;
    }

546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
    CommandObjectSP command_obj_sp(
        m_interpreter.GetCommandSPExact(actual_command, true));
    CommandObjectSP subcommand_obj_sp;
    bool use_subcommand = false;
    if (!command_obj_sp) {
      result.AppendErrorWithFormat("'%s' is not an existing command.\n",
                                   actual_command.c_str());
      return false;
    }
    CommandObject *cmd_obj = command_obj_sp.get();
    CommandObject *sub_cmd_obj = nullptr;
    OptionArgVectorSP option_arg_vector_sp =
        OptionArgVectorSP(new OptionArgVector);

    while (cmd_obj->IsMultiwordObject() && !args.empty()) {
561
      auto sub_command = args[0].ref();
562
563
564
565
566
567
568
569
570
      assert(!sub_command.empty());
      subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
      if (!subcommand_obj_sp) {
        result.AppendErrorWithFormat(
            "'%s' is not a valid sub-command of '%s'.  "
            "Unable to create alias.\n",
            args[0].c_str(), actual_command.c_str());
        return false;
      }
571

572
573
574
575
576
      sub_cmd_obj = subcommand_obj_sp.get();
      use_subcommand = true;
      args.Shift(); // Shift the sub_command word off the argument vector.
      cmd_obj = sub_cmd_obj;
    }
577

578
    // Verify & handle any options/arguments passed to the alias command
579

580
    std::string args_string;
581

582
583
    if (!args.empty()) {
      CommandObjectSP tmp_sp =
584
          m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName());
585
      if (use_subcommand)
586
        tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName());
587

588
589
      args.GetCommandString(args_string);
    }
590

591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
    if (m_interpreter.AliasExists(alias_command) ||
        m_interpreter.UserCommandExists(alias_command)) {
      result.AppendWarningWithFormat(
          "Overwriting existing definition for '%s'.\n", alias_command.c_str());
    }

    if (CommandAlias *alias = m_interpreter.AddAlias(
            alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
            args_string)) {
      if (m_command_options.m_help.OptionWasSet())
        alias->SetHelp(m_command_options.m_help.GetCurrentValue());
      if (m_command_options.m_long_help.OptionWasSet())
        alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
      result.SetStatus(eReturnStatusSuccessFinishNoResult);
    } else {
      result.AppendError("Unable to create requested alias.\n");
      return false;
608
    }
609
610
611

    return result.Succeeded();
  }
612
613
614
615
616
};

#pragma mark CommandObjectCommandsUnalias
// CommandObjectCommandsUnalias

617
class CommandObjectCommandsUnalias : public CommandObjectParsed {
618
public:
619
620
621
622
623
624
625
  CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
      : CommandObjectParsed(
            interpreter, "command unalias",
            "Delete one or more custom commands defined by 'command alias'.",
            nullptr) {
    CommandArgumentEntry arg;
    CommandArgumentData alias_arg;
626

627
628
629
630
631
632
633
634
635
636
637
638
639
    // Define the first (and only) variant of this arg.
    alias_arg.arg_type = eArgTypeAliasName;
    alias_arg.arg_repetition = eArgRepeatPlain;

    // There is only one variant this argument could be; put it into the
    // argument entry.
    arg.push_back(alias_arg);

    // Push the data for the first argument into the m_arguments vector.
    m_arguments.push_back(arg);
  }

  ~CommandObjectCommandsUnalias() override = default;
640

641
642
643
644
645
646
647
648
649
650
651
  void
  HandleArgumentCompletion(CompletionRequest &request,
                           OptionElementVector &opt_element_vector) override {
    if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
      return;

    for (const auto &ent : m_interpreter.GetAliases()) {
      request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
    }
  }

652
protected:
653
654
655
656
  bool DoExecute(Args &args, CommandReturnObject &result) override {
    CommandObject::CommandMap::iterator pos;
    CommandObject *cmd_obj;

657
658
659
660
661
    if (args.empty()) {
      result.AppendError("must call 'unalias' with a valid alias");
      return false;
    }

662
    auto command_name = args[0].ref();
663
    cmd_obj = m_interpreter.GetCommandObject(command_name);
664
    if (!cmd_obj) {
665
666
667
      result.AppendErrorWithFormat(
          "'%s' is not a known command.\nTry 'help' to see a "
          "current list of commands.\n",
668
          args[0].c_str());
669
      return false;
670
    }
671

672
673
674
675
676
    if (m_interpreter.CommandExists(command_name)) {
      if (cmd_obj->IsRemovable()) {
        result.AppendErrorWithFormat(
            "'%s' is not an alias, it is a debugger command which can be "
            "removed using the 'command delete' command.\n",
677
            args[0].c_str());
678
679
680
      } else {
        result.AppendErrorWithFormat(
            "'%s' is a permanent debugger command and cannot be removed.\n",
681
            args[0].c_str());
682
683
684
685
686
687
688
      }
      return false;
    }

    if (!m_interpreter.RemoveAlias(command_name)) {
      if (m_interpreter.AliasExists(command_name))
        result.AppendErrorWithFormat(
689
690
            "Error occurred while attempting to unalias '%s'.\n",
            args[0].c_str());
691
692
      else
        result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
693
                                     args[0].c_str());
694
695
696
697
      return false;
    }

    result.SetStatus(eReturnStatusSuccessFinishNoResult);
698
699
    return result.Succeeded();
  }
700
701
};

702
703
704
#pragma mark CommandObjectCommandsDelete
// CommandObjectCommandsDelete

705
class CommandObjectCommandsDelete : public CommandObjectParsed {
706
public:
707
708
709
710
711
712
713
  CommandObjectCommandsDelete(CommandInterpreter &interpreter)
      : CommandObjectParsed(
            interpreter, "command delete",
            "Delete one or more custom commands defined by 'command regex'.",
            nullptr) {
    CommandArgumentEntry arg;
    CommandArgumentData alias_arg;
714

715
716
717
    // Define the first (and only) variant of this arg.
    alias_arg.arg_type = eArgTypeCommandName;
    alias_arg.arg_repetition = eArgRepeatPlain;
718

719
720
721
    // There is only one variant this argument could be; put it into the
    // argument entry.
    arg.push_back(alias_arg);
722

723
724
725
    // Push the data for the first argument into the m_arguments vector.
    m_arguments.push_back(arg);
  }
726

727
  ~CommandObjectCommandsDelete() override = default;
728

729
730
731
732
733
734
735
736
737
738
739
740
  void
  HandleArgumentCompletion(CompletionRequest &request,
                           OptionElementVector &opt_element_vector) override {
    if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
      return;

    for (const auto &ent : m_interpreter.GetCommands()) {
      if (ent.second->IsRemovable())
        request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
    }
  }

741
protected:
742
743
744
  bool DoExecute(Args &args, CommandReturnObject &result) override {
    CommandObject::CommandMap::iterator pos;

745
746
747
    if (args.empty()) {
      result.AppendErrorWithFormat("must call '%s' with one or more valid user "
                                   "defined regular expression command names",
748
                                   GetCommandName().str().c_str());
749
      return false;
750
751
    }

752
    auto command_name = args[0].ref();
753
    if (!m_interpreter.CommandExists(command_name)) {
754
      StreamString error_msg_stream;
755
      const bool generate_upropos = true;
756
757
      const bool generate_type_lookup = false;
      CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
758
          &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
759
          generate_upropos, generate_type_lookup);
760
      result.AppendError(error_msg_stream.GetString());
761
      return false;
762
    }
763

764
765
766
    if (!m_interpreter.RemoveCommand(command_name)) {
      result.AppendErrorWithFormat(
          "'%s' is a permanent debugger command and cannot be removed.\n",
767
          args[0].c_str());
768
769
770
771
772
      return false;
    }

    result.SetStatus(eReturnStatusSuccessFinishNoResult);
    return true;
773
  }
774
775
};

776
// CommandObjectCommandsAddRegex
777

778
779
#define LLDB_OPTIONS_regex
#include "CommandOptions.inc"
780

781
#pragma mark CommandObjectCommandsAddRegex
782

783
784
class CommandObjectCommandsAddRegex : public CommandObjectParsed,
                                      public IOHandlerDelegateMultiline {
785
public:
786
787
  CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
      : CommandObjectParsed(
788
789
790
791
            interpreter, "command regex",
            "Define a custom command in terms of "
            "existing commands by matching "
            "regular expressions.",
792
793
            "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
        IOHandlerDelegateMultiline("",
794
                                   IOHandlerDelegate::Completion::LLDBCommand) {
795
796
797
798
    SetHelpLong(
        R"(
)"
        "This command allows the user to create powerful regular expression commands \
799
with substitutions. The regular expressions and substitutions are specified \
800
801
using the regular expression substitution format of:"
        R"(
802
803
804

    s/<regex>/<subst>/

805
806
)"
        "<regex> is a regular expression that can use parenthesis to capture regular \
807
expression input and substitute the captured matches in the output using %1 \
808
809
for the first match, %2 for the second, and so on."
        R"(
810

811
812
)"
        "The regular expressions can all be specified on the command line if more than \
813
814
one argument is provided. If just the command name is provided on the command \
line, then the regular expressions and substitutions can be entered on separate \
815
816
lines, followed by an empty line to terminate the command definition."
        R"(
817
818
819

EXAMPLES

820
821
)"
        "The following example will define a regular expression command named 'f' that \
822
will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
823
824
a number follows 'f':"
        R"(
825

826
827
    (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
  }
828

829
  ~CommandObjectCommandsAddRegex() override = default;
830

831
protected:
832
  void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
833
    StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
834
835
    if (output_sp && interactive) {
      output_sp->PutCString("Enter one or more sed substitution commands in "
836
837
838
                            "the form: 's/<regex>/<subst>/'.\nTerminate the "
                            "substitution list with an empty line.\n");
      output_sp->Flush();
839
    }
840
841
842
843
844
  }

  void IOHandlerInputComplete(IOHandler &io_handler,
                              std::string &data) override {
    io_handler.SetIsDone(true);
845
    if (m_regex_cmd_up) {
846
847
848
      StringList lines;
      if (lines.SplitIntoLines(data)) {
        bool check_only = false;
849
850
        for (const std::string &line : lines) {
          Status error = AppendRegexSubstitution(line, check_only);
851
          if (error.Fail()) {
852
853
            if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) {
              StreamSP out_stream = GetDebugger().GetAsyncOutputStream();
854
              out_stream->Printf("error: %s\n", error.AsCString());
855
            }
856
          }
857
        }
858
      }
859
860
      if (m_regex_cmd_up->HasRegexEntries()) {
        CommandObjectSP cmd_sp(m_regex_cmd_up.release());
861
862
863
864
865
866
867
868
869
870
        m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
      }
    }
  }

  bool DoExecute(Args &command, CommandReturnObject &result) override {
    const size_t argc = command.GetArgumentCount();
    if (argc == 0) {
      result.AppendError("usage: 'command regex <command-name> "
                         "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
871
872
      return false;
    }
873

Zachary Turner's avatar
Zachary Turner committed
874
    Status error;
875
    auto name = command[0].ref();
876
    m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
877
878
        m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0,
        true);
879
880

    if (argc == 1) {
881
      Debugger &debugger = GetDebugger();
882
883
884
885
886
887
888
889
890
      bool color_prompt = debugger.GetUseColor();
      const bool multiple_lines = true; // Get multiple lines
      IOHandlerSP io_handler_sp(new IOHandlerEditline(
          debugger, IOHandler::Type::Other,
          "lldb-regex",          // Name of input reader for history
          llvm::StringRef("> "), // Prompt
          llvm::StringRef(),     // Continuation prompt
          multiple_lines, color_prompt,
          0, // Don't show line numbers
891
          *this, nullptr));
892
893

      if (io_handler_sp) {
894
        debugger.RunIOHandlerAsync(io_handler_sp);
895
        result.SetStatus(eReturnStatusSuccessFinishNoResult);
896
      }
897
    } else {
898
      for (auto &entry : command.entries().drop_front()) {
899
        bool check_only = false;
900
        error = AppendRegexSubstitution(entry.ref(), check_only);
901
902
903
904
905
906
        if (error.Fail())
          break;
      }

      if (error.Success()) {
        AddRegexCommandToInterpreter();
907
      }
908
    }
909
910
911
    if (error.Fail()) {
      result.AppendError(error.AsCString());
    }
912

913
914
915
    return result.Succeeded();
  }

Zachary Turner's avatar
Zachary Turner committed
916
917
918
  Status AppendRegexSubstitution(const llvm::StringRef &regex_sed,
                                 bool check_only) {
    Status error;
919

920
    if (!m_regex_cmd_up) {
921
922
923
924
      error.SetErrorStringWithFormat(
          "invalid regular expression command object for: '%.*s'",
          (int)regex_sed.size(), regex_sed.data());
      return error;
925
    }
926

927
    size_t regex_sed_size = regex_sed.size();
928

929
930
931
932
933
934
    if (regex_sed_size <= 1) {
      error.SetErrorStringWithFormat(
          "regular expression substitution string is too short: '%.*s'",
          (int)regex_sed.size(), regex_sed.data());
      return error;
    }
935

936
937
938
939
940
941
942
    if (regex_sed[0] != 's') {
      error.SetErrorStringWithFormat("regular expression substitution string "
                                     "doesn't start with 's': '%.*s'",
                                     (int)regex_sed.size(), regex_sed.data());
      return error;
    }
    const size_t first_separator_char_pos = 1;
Adrian Prantl's avatar
Adrian Prantl committed
943
944
    // use the char that follows 's' as the regex separator character so we can
    // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
945
946
947
948
949
950
951
952
953
954
955
956
957
    const char separator_char = regex_sed[first_separator_char_pos];
    const size_t second_separator_char_pos =
        regex_sed.find(separator_char, first_separator_char_pos + 1);

    if (second_separator_char_pos == std::string::npos) {
      error.SetErrorStringWithFormat(
          "missing second '%c' separator char after '%.*s' in '%.*s'",
          separator_char,
          (int)(regex_sed.size() - first_separator_char_pos - 1),
          regex_sed.data() + (first_separator_char_pos + 1),
          (int)regex_sed.size(), regex_sed.data());
      return error;
    }
958

959
960
961
962
963
964
965
966
967
968
969
970
971
972
    const size_t third_separator_char_pos =
        regex_sed.find(separator_char, second_separator_char_pos + 1);

    if (third_separator_char_pos == std::string::npos) {
      error.SetErrorStringWithFormat(
          "missing third '%c' separator char after '%.*s' in '%.*s'",
          separator_char,
          (int)(regex_sed.size() - second_separator_char_pos - 1),
          regex_sed.data() + (second_separator_char_pos + 1),
          (int)regex_sed.size(), regex_sed.data());
      return error;
    }

    if (third_separator_char_pos != regex_sed_size - 1) {
Adrian Prantl's avatar
Adrian Prantl committed
973
      // Make sure that everything that follows the last regex separator char
974
975
976
977
978
979
980
981
982
      if (regex_sed.find_first_not_of("\t\n\v\f\r ",
                                      third_separator_char_pos + 1) !=
          std::string::npos) {
        error.SetErrorStringWithFormat(
            "extra data found after the '%.*s' regular expression substitution "
            "string: '%.*s'",
            (int)third_separator_char_pos + 1, regex_sed.data(),
            (int)(regex_sed.size() - third_separator_char_pos - 1),
            regex_sed.data() + (third_separator_char_pos + 1));
983
        return error;
984
985
986
987
988
989
990
991
992
993
994
995
996
      }
    } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
      error.SetErrorStringWithFormat(
          "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
          separator_char, separator_char, separator_char, (int)regex_sed.size(),
          regex_sed.data());
      return error;
    } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
      error.SetErrorStringWithFormat(
          "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
          separator_char, separator_char, separator_char, (int)regex_sed.size(),
          regex_sed.data());
      return error;
997
    }
998
999

    if (!check_only) {
1000
1001
1002
1003
1004
1005
      std::string regex(std::string(regex_sed.substr(
          first_separator_char_pos + 1,
          second_separator_char_pos - first_separator_char_pos - 1)));
      std::string subst(std::string(regex_sed.substr(
          second_separator_char_pos + 1,
          third_separator_char_pos - second_separator_char_pos - 1)));
1006
      m_regex_cmd_up->AddRegexCommand(regex, subst);
1007
1008
1009
1010
1011
    }
    return error;
  }

  void AddRegexCommandToInterpreter() {
1012
1013
1014
    if (m_regex_cmd_up) {
      if (m_regex_cmd_up->HasRegexEntries()) {
        CommandObjectSP cmd_sp(m_regex_cmd_up.release());
1015
1016
        m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
      }
1017
    }
1018
  }
1019
1020

private:
1021
  std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
1022
1023
1024

  class CommandOptions : public Options {
  public:
1025
    CommandOptions() {}
1026
1027
1028

    ~CommandOptions() override = default;

Zachary Turner's avatar
Zachary Turner committed
1029
1030
1031
    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
                          ExecutionContext *execution_context) override {
      Status error;
1032
1033
1034
1035
      const int short_option = m_getopt_table[option_idx].val;

      switch (short_option) {
      case 'h':
1036
        m_help.assign(std::string(option_arg));
1037
1038
        break;
      case 's':
1039
        m_syntax.assign(std::string(option_arg));
1040
1041
        break;
      default:
1042
        llvm_unreachable("Unimplemented option");