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