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