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