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(), false)) { 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(), false); 554 if (use_subcommand) 555 tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName(), 556 false); 557 558 args.GetCommandString(args_string); 559 } 560 561 if (m_interpreter.AliasExists(alias_command) || 562 m_interpreter.UserCommandExists(alias_command)) { 563 result.AppendWarningWithFormat( 564 "Overwriting existing definition for '%s'.\n", alias_command.c_str()); 565 } 566 567 if (CommandAlias *alias = m_interpreter.AddAlias( 568 alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp, 569 args_string)) { 570 if (m_command_options.m_help.OptionWasSet()) 571 alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 572 if (m_command_options.m_long_help.OptionWasSet()) 573 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 574 result.SetStatus(eReturnStatusSuccessFinishNoResult); 575 } else { 576 result.AppendError("Unable to create requested alias.\n"); 577 result.SetStatus(eReturnStatusFailed); 578 return false; 579 } 580 581 return result.Succeeded(); 582 } 583 }; 584 585 #pragma mark CommandObjectCommandsUnalias 586 // CommandObjectCommandsUnalias 587 588 class CommandObjectCommandsUnalias : public CommandObjectParsed { 589 public: 590 CommandObjectCommandsUnalias(CommandInterpreter &interpreter) 591 : CommandObjectParsed( 592 interpreter, "command unalias", 593 "Delete one or more custom commands defined by 'command alias'.", 594 nullptr) { 595 CommandArgumentEntry arg; 596 CommandArgumentData alias_arg; 597 598 // Define the first (and only) variant of this arg. 599 alias_arg.arg_type = eArgTypeAliasName; 600 alias_arg.arg_repetition = eArgRepeatPlain; 601 602 // There is only one variant this argument could be; put it into the 603 // argument entry. 604 arg.push_back(alias_arg); 605 606 // Push the data for the first argument into the m_arguments vector. 607 m_arguments.push_back(arg); 608 } 609 610 ~CommandObjectCommandsUnalias() override = default; 611 612 void 613 HandleArgumentCompletion(CompletionRequest &request, 614 OptionElementVector &opt_element_vector) override { 615 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 616 return; 617 618 for (const auto &ent : m_interpreter.GetAliases()) { 619 request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); 620 } 621 } 622 623 protected: 624 bool DoExecute(Args &args, CommandReturnObject &result) override { 625 CommandObject::CommandMap::iterator pos; 626 CommandObject *cmd_obj; 627 628 if (args.empty()) { 629 result.AppendError("must call 'unalias' with a valid alias"); 630 result.SetStatus(eReturnStatusFailed); 631 return false; 632 } 633 634 auto command_name = args[0].ref(); 635 cmd_obj = m_interpreter.GetCommandObject(command_name); 636 if (!cmd_obj) { 637 result.AppendErrorWithFormat( 638 "'%s' is not a known command.\nTry 'help' to see a " 639 "current list of commands.\n", 640 args[0].c_str()); 641 result.SetStatus(eReturnStatusFailed); 642 return false; 643 } 644 645 if (m_interpreter.CommandExists(command_name)) { 646 if (cmd_obj->IsRemovable()) { 647 result.AppendErrorWithFormat( 648 "'%s' is not an alias, it is a debugger command which can be " 649 "removed using the 'command delete' command.\n", 650 args[0].c_str()); 651 } else { 652 result.AppendErrorWithFormat( 653 "'%s' is a permanent debugger command and cannot be removed.\n", 654 args[0].c_str()); 655 } 656 result.SetStatus(eReturnStatusFailed); 657 return false; 658 } 659 660 if (!m_interpreter.RemoveAlias(command_name)) { 661 if (m_interpreter.AliasExists(command_name)) 662 result.AppendErrorWithFormat( 663 "Error occurred while attempting to unalias '%s'.\n", 664 args[0].c_str()); 665 else 666 result.AppendErrorWithFormat("'%s' is not an existing alias.\n", 667 args[0].c_str()); 668 result.SetStatus(eReturnStatusFailed); 669 return false; 670 } 671 672 result.SetStatus(eReturnStatusSuccessFinishNoResult); 673 return result.Succeeded(); 674 } 675 }; 676 677 #pragma mark CommandObjectCommandsDelete 678 // CommandObjectCommandsDelete 679 680 class CommandObjectCommandsDelete : public CommandObjectParsed { 681 public: 682 CommandObjectCommandsDelete(CommandInterpreter &interpreter) 683 : CommandObjectParsed( 684 interpreter, "command delete", 685 "Delete one or more custom commands defined by 'command regex'.", 686 nullptr) { 687 CommandArgumentEntry arg; 688 CommandArgumentData alias_arg; 689 690 // Define the first (and only) variant of this arg. 691 alias_arg.arg_type = eArgTypeCommandName; 692 alias_arg.arg_repetition = eArgRepeatPlain; 693 694 // There is only one variant this argument could be; put it into the 695 // argument entry. 696 arg.push_back(alias_arg); 697 698 // Push the data for the first argument into the m_arguments vector. 699 m_arguments.push_back(arg); 700 } 701 702 ~CommandObjectCommandsDelete() override = default; 703 704 void 705 HandleArgumentCompletion(CompletionRequest &request, 706 OptionElementVector &opt_element_vector) override { 707 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 708 return; 709 710 for (const auto &ent : m_interpreter.GetCommands()) { 711 if (ent.second->IsRemovable()) 712 request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); 713 } 714 } 715 716 protected: 717 bool DoExecute(Args &args, CommandReturnObject &result) override { 718 CommandObject::CommandMap::iterator pos; 719 720 if (args.empty()) { 721 result.AppendErrorWithFormat("must call '%s' with one or more valid user " 722 "defined regular expression command names", 723 GetCommandName().str().c_str()); 724 result.SetStatus(eReturnStatusFailed); 725 return false; 726 } 727 728 auto command_name = args[0].ref(); 729 if (!m_interpreter.CommandExists(command_name)) { 730 StreamString error_msg_stream; 731 const bool generate_upropos = true; 732 const bool generate_type_lookup = false; 733 CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage( 734 &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(), 735 generate_upropos, generate_type_lookup); 736 result.AppendError(error_msg_stream.GetString()); 737 result.SetStatus(eReturnStatusFailed); 738 return false; 739 } 740 741 if (!m_interpreter.RemoveCommand(command_name)) { 742 result.AppendErrorWithFormat( 743 "'%s' is a permanent debugger command and cannot be removed.\n", 744 args[0].c_str()); 745 result.SetStatus(eReturnStatusFailed); 746 return false; 747 } 748 749 result.SetStatus(eReturnStatusSuccessFinishNoResult); 750 return true; 751 } 752 }; 753 754 // CommandObjectCommandsAddRegex 755 756 #define LLDB_OPTIONS_regex 757 #include "CommandOptions.inc" 758 759 #pragma mark CommandObjectCommandsAddRegex 760 761 class CommandObjectCommandsAddRegex : public CommandObjectParsed, 762 public IOHandlerDelegateMultiline { 763 public: 764 CommandObjectCommandsAddRegex(CommandInterpreter &interpreter) 765 : CommandObjectParsed( 766 interpreter, "command regex", 767 "Define a custom command in terms of " 768 "existing commands by matching " 769 "regular expressions.", 770 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 771 IOHandlerDelegateMultiline("", 772 IOHandlerDelegate::Completion::LLDBCommand), 773 m_options() { 774 SetHelpLong( 775 R"( 776 )" 777 "This command allows the user to create powerful regular expression commands \ 778 with substitutions. The regular expressions and substitutions are specified \ 779 using the regular expression substitution format of:" 780 R"( 781 782 s/<regex>/<subst>/ 783 784 )" 785 "<regex> is a regular expression that can use parenthesis to capture regular \ 786 expression input and substitute the captured matches in the output using %1 \ 787 for the first match, %2 for the second, and so on." 788 R"( 789 790 )" 791 "The regular expressions can all be specified on the command line if more than \ 792 one argument is provided. If just the command name is provided on the command \ 793 line, then the regular expressions and substitutions can be entered on separate \ 794 lines, followed by an empty line to terminate the command definition." 795 R"( 796 797 EXAMPLES 798 799 )" 800 "The following example will define a regular expression command named 'f' that \ 801 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ 802 a number follows 'f':" 803 R"( 804 805 (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"); 806 } 807 808 ~CommandObjectCommandsAddRegex() override = default; 809 810 protected: 811 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 812 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 813 if (output_sp && interactive) { 814 output_sp->PutCString("Enter one or more sed substitution commands in " 815 "the form: 's/<regex>/<subst>/'.\nTerminate the " 816 "substitution list with an empty line.\n"); 817 output_sp->Flush(); 818 } 819 } 820 821 void IOHandlerInputComplete(IOHandler &io_handler, 822 std::string &data) override { 823 io_handler.SetIsDone(true); 824 if (m_regex_cmd_up) { 825 StringList lines; 826 if (lines.SplitIntoLines(data)) { 827 bool check_only = false; 828 for (const std::string &line : lines) { 829 Status error = AppendRegexSubstitution(line, check_only); 830 if (error.Fail()) { 831 if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) { 832 StreamSP out_stream = GetDebugger().GetAsyncOutputStream(); 833 out_stream->Printf("error: %s\n", error.AsCString()); 834 } 835 } 836 } 837 } 838 if (m_regex_cmd_up->HasRegexEntries()) { 839 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 840 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 841 } 842 } 843 } 844 845 bool DoExecute(Args &command, CommandReturnObject &result) override { 846 const size_t argc = command.GetArgumentCount(); 847 if (argc == 0) { 848 result.AppendError("usage: 'command regex <command-name> " 849 "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 850 result.SetStatus(eReturnStatusFailed); 851 return false; 852 } 853 854 Status error; 855 auto name = command[0].ref(); 856 m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>( 857 m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0, 858 true); 859 860 if (argc == 1) { 861 Debugger &debugger = GetDebugger(); 862 bool color_prompt = debugger.GetUseColor(); 863 const bool multiple_lines = true; // Get multiple lines 864 IOHandlerSP io_handler_sp(new IOHandlerEditline( 865 debugger, IOHandler::Type::Other, 866 "lldb-regex", // Name of input reader for history 867 llvm::StringRef("> "), // Prompt 868 llvm::StringRef(), // Continuation prompt 869 multiple_lines, color_prompt, 870 0, // Don't show line numbers 871 *this, nullptr)); 872 873 if (io_handler_sp) { 874 debugger.RunIOHandlerAsync(io_handler_sp); 875 result.SetStatus(eReturnStatusSuccessFinishNoResult); 876 } 877 } else { 878 for (auto &entry : command.entries().drop_front()) { 879 bool check_only = false; 880 error = AppendRegexSubstitution(entry.ref(), check_only); 881 if (error.Fail()) 882 break; 883 } 884 885 if (error.Success()) { 886 AddRegexCommandToInterpreter(); 887 } 888 } 889 if (error.Fail()) { 890 result.AppendError(error.AsCString()); 891 result.SetStatus(eReturnStatusFailed); 892 } 893 894 return result.Succeeded(); 895 } 896 897 Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed, 898 bool check_only) { 899 Status error; 900 901 if (!m_regex_cmd_up) { 902 error.SetErrorStringWithFormat( 903 "invalid regular expression command object for: '%.*s'", 904 (int)regex_sed.size(), regex_sed.data()); 905 return error; 906 } 907 908 size_t regex_sed_size = regex_sed.size(); 909 910 if (regex_sed_size <= 1) { 911 error.SetErrorStringWithFormat( 912 "regular expression substitution string is too short: '%.*s'", 913 (int)regex_sed.size(), regex_sed.data()); 914 return error; 915 } 916 917 if (regex_sed[0] != 's') { 918 error.SetErrorStringWithFormat("regular expression substitution string " 919 "doesn't start with 's': '%.*s'", 920 (int)regex_sed.size(), regex_sed.data()); 921 return error; 922 } 923 const size_t first_separator_char_pos = 1; 924 // use the char that follows 's' as the regex separator character so we can 925 // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 926 const char separator_char = regex_sed[first_separator_char_pos]; 927 const size_t second_separator_char_pos = 928 regex_sed.find(separator_char, first_separator_char_pos + 1); 929 930 if (second_separator_char_pos == std::string::npos) { 931 error.SetErrorStringWithFormat( 932 "missing second '%c' separator char after '%.*s' in '%.*s'", 933 separator_char, 934 (int)(regex_sed.size() - first_separator_char_pos - 1), 935 regex_sed.data() + (first_separator_char_pos + 1), 936 (int)regex_sed.size(), regex_sed.data()); 937 return error; 938 } 939 940 const size_t third_separator_char_pos = 941 regex_sed.find(separator_char, second_separator_char_pos + 1); 942 943 if (third_separator_char_pos == std::string::npos) { 944 error.SetErrorStringWithFormat( 945 "missing third '%c' separator char after '%.*s' in '%.*s'", 946 separator_char, 947 (int)(regex_sed.size() - second_separator_char_pos - 1), 948 regex_sed.data() + (second_separator_char_pos + 1), 949 (int)regex_sed.size(), regex_sed.data()); 950 return error; 951 } 952 953 if (third_separator_char_pos != regex_sed_size - 1) { 954 // Make sure that everything that follows the last regex separator char 955 if (regex_sed.find_first_not_of("\t\n\v\f\r ", 956 third_separator_char_pos + 1) != 957 std::string::npos) { 958 error.SetErrorStringWithFormat( 959 "extra data found after the '%.*s' regular expression substitution " 960 "string: '%.*s'", 961 (int)third_separator_char_pos + 1, regex_sed.data(), 962 (int)(regex_sed.size() - third_separator_char_pos - 1), 963 regex_sed.data() + (third_separator_char_pos + 1)); 964 return error; 965 } 966 } else if (first_separator_char_pos + 1 == second_separator_char_pos) { 967 error.SetErrorStringWithFormat( 968 "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 969 separator_char, separator_char, separator_char, (int)regex_sed.size(), 970 regex_sed.data()); 971 return error; 972 } else if (second_separator_char_pos + 1 == third_separator_char_pos) { 973 error.SetErrorStringWithFormat( 974 "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 975 separator_char, separator_char, separator_char, (int)regex_sed.size(), 976 regex_sed.data()); 977 return error; 978 } 979 980 if (!check_only) { 981 std::string regex(std::string(regex_sed.substr( 982 first_separator_char_pos + 1, 983 second_separator_char_pos - first_separator_char_pos - 1))); 984 std::string subst(std::string(regex_sed.substr( 985 second_separator_char_pos + 1, 986 third_separator_char_pos - second_separator_char_pos - 1))); 987 m_regex_cmd_up->AddRegexCommand(regex, subst); 988 } 989 return error; 990 } 991 992 void AddRegexCommandToInterpreter() { 993 if (m_regex_cmd_up) { 994 if (m_regex_cmd_up->HasRegexEntries()) { 995 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 996 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 997 } 998 } 999 } 1000 1001 private: 1002 std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up; 1003 1004 class CommandOptions : public Options { 1005 public: 1006 CommandOptions() : Options() {} 1007 1008 ~CommandOptions() override = default; 1009 1010 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1011 ExecutionContext *execution_context) override { 1012 Status error; 1013 const int short_option = m_getopt_table[option_idx].val; 1014 1015 switch (short_option) { 1016 case 'h': 1017 m_help.assign(std::string(option_arg)); 1018 break; 1019 case 's': 1020 m_syntax.assign(std::string(option_arg)); 1021 break; 1022 default: 1023 llvm_unreachable("Unimplemented option"); 1024 } 1025 1026 return error; 1027 } 1028 1029 void OptionParsingStarting(ExecutionContext *execution_context) override { 1030 m_help.clear(); 1031 m_syntax.clear(); 1032 } 1033 1034 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1035 return llvm::makeArrayRef(g_regex_options); 1036 } 1037 1038 llvm::StringRef GetHelp() { return m_help; } 1039 1040 llvm::StringRef GetSyntax() { return m_syntax; } 1041 1042 protected: 1043 // Instance variables to hold the values for command options. 1044 1045 std::string m_help; 1046 std::string m_syntax; 1047 }; 1048 1049 Options *GetOptions() override { return &m_options; } 1050 1051 CommandOptions m_options; 1052 }; 1053 1054 class CommandObjectPythonFunction : public CommandObjectRaw { 1055 public: 1056 CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name, 1057 std::string funct, std::string help, 1058 ScriptedCommandSynchronicity synch) 1059 : CommandObjectRaw(interpreter, name), m_function_name(funct), 1060 m_synchro(synch), m_fetched_help_long(false) { 1061 if (!help.empty()) 1062 SetHelp(help); 1063 else { 1064 StreamString stream; 1065 stream.Printf("For more information run 'help %s'", name.c_str()); 1066 SetHelp(stream.GetString()); 1067 } 1068 } 1069 1070 ~CommandObjectPythonFunction() override = default; 1071 1072 bool IsRemovable() const override { return true; } 1073 1074 const std::string &GetFunctionName() { return m_function_name; } 1075 1076 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1077 1078 llvm::StringRef GetHelpLong() override { 1079 if (m_fetched_help_long) 1080 return CommandObjectRaw::GetHelpLong(); 1081 1082 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1083 if (!scripter) 1084 return CommandObjectRaw::GetHelpLong(); 1085 1086 std::string docstring; 1087 m_fetched_help_long = 1088 scripter->GetDocumentationForItem(m_function_name.c_str(), docstring); 1089 if (!docstring.empty()) 1090 SetHelpLong(docstring); 1091 return CommandObjectRaw::GetHelpLong(); 1092 } 1093 1094 protected: 1095 bool DoExecute(llvm::StringRef raw_command_line, 1096 CommandReturnObject &result) override { 1097 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1098 1099 Status error; 1100 1101 result.SetStatus(eReturnStatusInvalid); 1102 1103 if (!scripter || !scripter->RunScriptBasedCommand( 1104 m_function_name.c_str(), raw_command_line, m_synchro, 1105 result, error, m_exe_ctx)) { 1106 result.AppendError(error.AsCString()); 1107 result.SetStatus(eReturnStatusFailed); 1108 } else { 1109 // Don't change the status if the command already set it... 1110 if (result.GetStatus() == eReturnStatusInvalid) { 1111 if (result.GetOutputData().empty()) 1112 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1113 else 1114 result.SetStatus(eReturnStatusSuccessFinishResult); 1115 } 1116 } 1117 1118 return result.Succeeded(); 1119 } 1120 1121 private: 1122 std::string m_function_name; 1123 ScriptedCommandSynchronicity m_synchro; 1124 bool m_fetched_help_long; 1125 }; 1126 1127 class CommandObjectScriptingObject : public CommandObjectRaw { 1128 public: 1129 CommandObjectScriptingObject(CommandInterpreter &interpreter, 1130 std::string name, 1131 StructuredData::GenericSP cmd_obj_sp, 1132 ScriptedCommandSynchronicity synch) 1133 : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp), 1134 m_synchro(synch), m_fetched_help_short(false), 1135 m_fetched_help_long(false) { 1136 StreamString stream; 1137 stream.Printf("For more information run 'help %s'", name.c_str()); 1138 SetHelp(stream.GetString()); 1139 if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter()) 1140 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1141 } 1142 1143 ~CommandObjectScriptingObject() override = default; 1144 1145 bool IsRemovable() const override { return true; } 1146 1147 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1148 1149 llvm::StringRef GetHelp() override { 1150 if (m_fetched_help_short) 1151 return CommandObjectRaw::GetHelp(); 1152 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1153 if (!scripter) 1154 return CommandObjectRaw::GetHelp(); 1155 std::string docstring; 1156 m_fetched_help_short = 1157 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1158 if (!docstring.empty()) 1159 SetHelp(docstring); 1160 1161 return CommandObjectRaw::GetHelp(); 1162 } 1163 1164 llvm::StringRef GetHelpLong() override { 1165 if (m_fetched_help_long) 1166 return CommandObjectRaw::GetHelpLong(); 1167 1168 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1169 if (!scripter) 1170 return CommandObjectRaw::GetHelpLong(); 1171 1172 std::string docstring; 1173 m_fetched_help_long = 1174 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1175 if (!docstring.empty()) 1176 SetHelpLong(docstring); 1177 return CommandObjectRaw::GetHelpLong(); 1178 } 1179 1180 protected: 1181 bool DoExecute(llvm::StringRef raw_command_line, 1182 CommandReturnObject &result) override { 1183 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1184 1185 Status error; 1186 1187 result.SetStatus(eReturnStatusInvalid); 1188 1189 if (!scripter || 1190 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1191 m_synchro, result, error, m_exe_ctx)) { 1192 result.AppendError(error.AsCString()); 1193 result.SetStatus(eReturnStatusFailed); 1194 } else { 1195 // Don't change the status if the command already set it... 1196 if (result.GetStatus() == eReturnStatusInvalid) { 1197 if (result.GetOutputData().empty()) 1198 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1199 else 1200 result.SetStatus(eReturnStatusSuccessFinishResult); 1201 } 1202 } 1203 1204 return result.Succeeded(); 1205 } 1206 1207 private: 1208 StructuredData::GenericSP m_cmd_obj_sp; 1209 ScriptedCommandSynchronicity m_synchro; 1210 bool m_fetched_help_short : 1; 1211 bool m_fetched_help_long : 1; 1212 }; 1213 1214 // CommandObjectCommandsScriptImport 1215 #define LLDB_OPTIONS_script_import 1216 #include "CommandOptions.inc" 1217 1218 class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1219 public: 1220 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1221 : CommandObjectParsed(interpreter, "command script import", 1222 "Import a scripting module in LLDB.", nullptr), 1223 m_options() { 1224 CommandArgumentEntry arg1; 1225 CommandArgumentData cmd_arg; 1226 1227 // Define the first (and only) variant of this arg. 1228 cmd_arg.arg_type = eArgTypeFilename; 1229 cmd_arg.arg_repetition = eArgRepeatPlus; 1230 1231 // There is only one variant this argument could be; put it into the 1232 // argument entry. 1233 arg1.push_back(cmd_arg); 1234 1235 // Push the data for the first argument into the m_arguments vector. 1236 m_arguments.push_back(arg1); 1237 } 1238 1239 ~CommandObjectCommandsScriptImport() override = default; 1240 1241 void 1242 HandleArgumentCompletion(CompletionRequest &request, 1243 OptionElementVector &opt_element_vector) override { 1244 CommandCompletions::InvokeCommonCompletionCallbacks( 1245 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 1246 request, nullptr); 1247 } 1248 1249 Options *GetOptions() override { return &m_options; } 1250 1251 protected: 1252 class CommandOptions : public Options { 1253 public: 1254 CommandOptions() : Options() {} 1255 1256 ~CommandOptions() override = default; 1257 1258 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1259 ExecutionContext *execution_context) override { 1260 Status error; 1261 const int short_option = m_getopt_table[option_idx].val; 1262 1263 switch (short_option) { 1264 case 'r': 1265 // NO-OP 1266 break; 1267 case 'c': 1268 relative_to_command_file = true; 1269 break; 1270 default: 1271 llvm_unreachable("Unimplemented option"); 1272 } 1273 1274 return error; 1275 } 1276 1277 void OptionParsingStarting(ExecutionContext *execution_context) override { 1278 relative_to_command_file = false; 1279 } 1280 1281 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1282 return llvm::makeArrayRef(g_script_import_options); 1283 } 1284 bool relative_to_command_file = false; 1285 }; 1286 1287 bool DoExecute(Args &command, CommandReturnObject &result) override { 1288 if (command.empty()) { 1289 result.AppendError("command script import needs one or more arguments"); 1290 result.SetStatus(eReturnStatusFailed); 1291 return false; 1292 } 1293 1294 FileSpec source_dir = {}; 1295 if (m_options.relative_to_command_file) { 1296 source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); 1297 if (!source_dir) { 1298 result.AppendError("command script import -c can only be specified " 1299 "from a command file"); 1300 result.SetStatus(eReturnStatusFailed); 1301 return false; 1302 } 1303 } 1304 1305 for (auto &entry : command.entries()) { 1306 Status error; 1307 1308 const bool init_session = true; 1309 // FIXME: this is necessary because CommandObject::CheckRequirements() 1310 // assumes that commands won't ever be recursively invoked, but it's 1311 // actually possible to craft a Python script that does other "command 1312 // script imports" in __lldb_init_module the real fix is to have 1313 // recursive commands possible with a CommandInvocation object separate 1314 // from the CommandObject itself, so that recursive command invocations 1315 // won't stomp on each other (wrt to execution contents, options, and 1316 // more) 1317 m_exe_ctx.Clear(); 1318 if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( 1319 entry.c_str(), init_session, error, nullptr, source_dir)) { 1320 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1321 } else { 1322 result.AppendErrorWithFormat("module importing failed: %s", 1323 error.AsCString()); 1324 result.SetStatus(eReturnStatusFailed); 1325 } 1326 } 1327 1328 return result.Succeeded(); 1329 } 1330 1331 CommandOptions m_options; 1332 }; 1333 1334 // CommandObjectCommandsScriptAdd 1335 static constexpr OptionEnumValueElement g_script_synchro_type[] = { 1336 { 1337 eScriptedCommandSynchronicitySynchronous, 1338 "synchronous", 1339 "Run synchronous", 1340 }, 1341 { 1342 eScriptedCommandSynchronicityAsynchronous, 1343 "asynchronous", 1344 "Run asynchronous", 1345 }, 1346 { 1347 eScriptedCommandSynchronicityCurrentValue, 1348 "current", 1349 "Do not alter current setting", 1350 }, 1351 }; 1352 1353 static constexpr OptionEnumValues ScriptSynchroType() { 1354 return OptionEnumValues(g_script_synchro_type); 1355 } 1356 1357 #define LLDB_OPTIONS_script_add 1358 #include "CommandOptions.inc" 1359 1360 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1361 public IOHandlerDelegateMultiline { 1362 public: 1363 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1364 : CommandObjectParsed(interpreter, "command script add", 1365 "Add a scripted function as an LLDB command.", 1366 nullptr), 1367 IOHandlerDelegateMultiline("DONE"), m_options() { 1368 CommandArgumentEntry arg1; 1369 CommandArgumentData cmd_arg; 1370 1371 // Define the first (and only) variant of this arg. 1372 cmd_arg.arg_type = eArgTypeCommandName; 1373 cmd_arg.arg_repetition = eArgRepeatPlain; 1374 1375 // There is only one variant this argument could be; put it into the 1376 // argument entry. 1377 arg1.push_back(cmd_arg); 1378 1379 // Push the data for the first argument into the m_arguments vector. 1380 m_arguments.push_back(arg1); 1381 } 1382 1383 ~CommandObjectCommandsScriptAdd() override = default; 1384 1385 Options *GetOptions() override { return &m_options; } 1386 1387 protected: 1388 class CommandOptions : public Options { 1389 public: 1390 CommandOptions() 1391 : Options(), m_class_name(), m_funct_name(), m_short_help(), 1392 m_synchronicity(eScriptedCommandSynchronicitySynchronous) {} 1393 1394 ~CommandOptions() override = default; 1395 1396 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1397 ExecutionContext *execution_context) override { 1398 Status error; 1399 const int short_option = m_getopt_table[option_idx].val; 1400 1401 switch (short_option) { 1402 case 'f': 1403 if (!option_arg.empty()) 1404 m_funct_name = std::string(option_arg); 1405 break; 1406 case 'c': 1407 if (!option_arg.empty()) 1408 m_class_name = std::string(option_arg); 1409 break; 1410 case 'h': 1411 if (!option_arg.empty()) 1412 m_short_help = std::string(option_arg); 1413 break; 1414 case 's': 1415 m_synchronicity = 1416 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1417 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1418 if (!error.Success()) 1419 error.SetErrorStringWithFormat( 1420 "unrecognized value for synchronicity '%s'", 1421 option_arg.str().c_str()); 1422 break; 1423 default: 1424 llvm_unreachable("Unimplemented option"); 1425 } 1426 1427 return error; 1428 } 1429 1430 void OptionParsingStarting(ExecutionContext *execution_context) override { 1431 m_class_name.clear(); 1432 m_funct_name.clear(); 1433 m_short_help.clear(); 1434 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1435 } 1436 1437 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1438 return llvm::makeArrayRef(g_script_add_options); 1439 } 1440 1441 // Instance variables to hold the values for command options. 1442 1443 std::string m_class_name; 1444 std::string m_funct_name; 1445 std::string m_short_help; 1446 ScriptedCommandSynchronicity m_synchronicity; 1447 }; 1448 1449 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 1450 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 1451 if (output_sp && interactive) { 1452 output_sp->PutCString(g_python_command_instructions); 1453 output_sp->Flush(); 1454 } 1455 } 1456 1457 void IOHandlerInputComplete(IOHandler &io_handler, 1458 std::string &data) override { 1459 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); 1460 1461 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1462 if (interpreter) { 1463 1464 StringList lines; 1465 lines.SplitIntoLines(data); 1466 if (lines.GetSize() > 0) { 1467 std::string funct_name_str; 1468 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1469 if (funct_name_str.empty()) { 1470 error_sp->Printf("error: unable to obtain a function name, didn't " 1471 "add python command.\n"); 1472 error_sp->Flush(); 1473 } else { 1474 // everything should be fine now, let's add this alias 1475 1476 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1477 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1478 m_synchronicity)); 1479 1480 if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, 1481 true)) { 1482 error_sp->Printf("error: unable to add selected command, didn't " 1483 "add python command.\n"); 1484 error_sp->Flush(); 1485 } 1486 } 1487 } else { 1488 error_sp->Printf( 1489 "error: unable to create function, didn't add python command.\n"); 1490 error_sp->Flush(); 1491 } 1492 } else { 1493 error_sp->Printf("error: empty function, didn't add python command.\n"); 1494 error_sp->Flush(); 1495 } 1496 } else { 1497 error_sp->Printf( 1498 "error: script interpreter missing, didn't add python command.\n"); 1499 error_sp->Flush(); 1500 } 1501 1502 io_handler.SetIsDone(true); 1503 } 1504 1505 bool DoExecute(Args &command, CommandReturnObject &result) override { 1506 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1507 result.AppendError("only scripting language supported for scripted " 1508 "commands is currently Python"); 1509 result.SetStatus(eReturnStatusFailed); 1510 return false; 1511 } 1512 1513 if (command.GetArgumentCount() != 1) { 1514 result.AppendError("'command script add' requires one argument"); 1515 result.SetStatus(eReturnStatusFailed); 1516 return false; 1517 } 1518 1519 // Store the options in case we get multi-line input 1520 m_cmd_name = std::string(command[0].ref()); 1521 m_short_help.assign(m_options.m_short_help); 1522 m_synchronicity = m_options.m_synchronicity; 1523 1524 if (m_options.m_class_name.empty()) { 1525 if (m_options.m_funct_name.empty()) { 1526 m_interpreter.GetPythonCommandsFromIOHandler( 1527 " ", // Prompt 1528 *this); // IOHandlerDelegate 1529 } else { 1530 CommandObjectSP new_cmd(new CommandObjectPythonFunction( 1531 m_interpreter, m_cmd_name, m_options.m_funct_name, 1532 m_options.m_short_help, m_synchronicity)); 1533 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1534 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1535 } else { 1536 result.AppendError("cannot add command"); 1537 result.SetStatus(eReturnStatusFailed); 1538 } 1539 } 1540 } else { 1541 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1542 if (!interpreter) { 1543 result.AppendError("cannot find ScriptInterpreter"); 1544 result.SetStatus(eReturnStatusFailed); 1545 return false; 1546 } 1547 1548 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1549 m_options.m_class_name.c_str()); 1550 if (!cmd_obj_sp) { 1551 result.AppendError("cannot create helper object"); 1552 result.SetStatus(eReturnStatusFailed); 1553 return false; 1554 } 1555 1556 CommandObjectSP new_cmd(new CommandObjectScriptingObject( 1557 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1558 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1559 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1560 } else { 1561 result.AppendError("cannot add command"); 1562 result.SetStatus(eReturnStatusFailed); 1563 } 1564 } 1565 1566 return result.Succeeded(); 1567 } 1568 1569 CommandOptions m_options; 1570 std::string m_cmd_name; 1571 std::string m_short_help; 1572 ScriptedCommandSynchronicity m_synchronicity; 1573 }; 1574 1575 // CommandObjectCommandsScriptList 1576 1577 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1578 public: 1579 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1580 : CommandObjectParsed(interpreter, "command script list", 1581 "List defined scripted commands.", nullptr) {} 1582 1583 ~CommandObjectCommandsScriptList() override = default; 1584 1585 bool DoExecute(Args &command, CommandReturnObject &result) override { 1586 if (command.GetArgumentCount() != 0) { 1587 result.AppendError("'command script list' doesn't take any arguments"); 1588 result.SetStatus(eReturnStatusFailed); 1589 return false; 1590 } 1591 1592 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1593 1594 result.SetStatus(eReturnStatusSuccessFinishResult); 1595 1596 return true; 1597 } 1598 }; 1599 1600 // CommandObjectCommandsScriptClear 1601 1602 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1603 public: 1604 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1605 : CommandObjectParsed(interpreter, "command script clear", 1606 "Delete all scripted commands.", nullptr) {} 1607 1608 ~CommandObjectCommandsScriptClear() override = default; 1609 1610 protected: 1611 bool DoExecute(Args &command, CommandReturnObject &result) override { 1612 if (command.GetArgumentCount() != 0) { 1613 result.AppendError("'command script clear' doesn't take any arguments"); 1614 result.SetStatus(eReturnStatusFailed); 1615 return false; 1616 } 1617 1618 m_interpreter.RemoveAllUser(); 1619 1620 result.SetStatus(eReturnStatusSuccessFinishResult); 1621 1622 return true; 1623 } 1624 }; 1625 1626 // CommandObjectCommandsScriptDelete 1627 1628 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1629 public: 1630 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1631 : CommandObjectParsed(interpreter, "command script delete", 1632 "Delete a scripted command.", nullptr) { 1633 CommandArgumentEntry arg1; 1634 CommandArgumentData cmd_arg; 1635 1636 // Define the first (and only) variant of this arg. 1637 cmd_arg.arg_type = eArgTypeCommandName; 1638 cmd_arg.arg_repetition = eArgRepeatPlain; 1639 1640 // There is only one variant this argument could be; put it into the 1641 // argument entry. 1642 arg1.push_back(cmd_arg); 1643 1644 // Push the data for the first argument into the m_arguments vector. 1645 m_arguments.push_back(arg1); 1646 } 1647 1648 ~CommandObjectCommandsScriptDelete() override = default; 1649 1650 void 1651 HandleArgumentCompletion(CompletionRequest &request, 1652 OptionElementVector &opt_element_vector) override { 1653 if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) 1654 return; 1655 1656 for (const auto &c : m_interpreter.GetUserCommands()) 1657 request.TryCompleteCurrentArg(c.first, c.second->GetHelp()); 1658 } 1659 1660 protected: 1661 bool DoExecute(Args &command, CommandReturnObject &result) override { 1662 1663 if (command.GetArgumentCount() != 1) { 1664 result.AppendError("'command script delete' requires one argument"); 1665 result.SetStatus(eReturnStatusFailed); 1666 return false; 1667 } 1668 1669 auto cmd_name = command[0].ref(); 1670 1671 if (cmd_name.empty() || !m_interpreter.HasUserCommands() || 1672 !m_interpreter.UserCommandExists(cmd_name)) { 1673 result.AppendErrorWithFormat("command %s not found", command[0].c_str()); 1674 result.SetStatus(eReturnStatusFailed); 1675 return false; 1676 } 1677 1678 m_interpreter.RemoveUser(cmd_name); 1679 result.SetStatus(eReturnStatusSuccessFinishResult); 1680 return true; 1681 } 1682 }; 1683 1684 #pragma mark CommandObjectMultiwordCommandsScript 1685 1686 // CommandObjectMultiwordCommandsScript 1687 1688 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1689 public: 1690 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1691 : CommandObjectMultiword( 1692 interpreter, "command script", 1693 "Commands for managing custom " 1694 "commands implemented by " 1695 "interpreter scripts.", 1696 "command script <subcommand> [<subcommand-options>]") { 1697 LoadSubCommand("add", CommandObjectSP( 1698 new CommandObjectCommandsScriptAdd(interpreter))); 1699 LoadSubCommand( 1700 "delete", 1701 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1702 LoadSubCommand( 1703 "clear", 1704 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1705 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1706 interpreter))); 1707 LoadSubCommand( 1708 "import", 1709 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1710 } 1711 1712 ~CommandObjectMultiwordCommandsScript() override = default; 1713 }; 1714 1715 #pragma mark CommandObjectMultiwordCommands 1716 1717 // CommandObjectMultiwordCommands 1718 1719 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 1720 CommandInterpreter &interpreter) 1721 : CommandObjectMultiword(interpreter, "command", 1722 "Commands for managing custom LLDB commands.", 1723 "command <subcommand> [<subcommand-options>]") { 1724 LoadSubCommand("source", 1725 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 1726 LoadSubCommand("alias", 1727 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 1728 LoadSubCommand("unalias", CommandObjectSP( 1729 new CommandObjectCommandsUnalias(interpreter))); 1730 LoadSubCommand("delete", 1731 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 1732 LoadSubCommand( 1733 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 1734 LoadSubCommand( 1735 "script", 1736 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 1737 } 1738 1739 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 1740