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