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