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