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