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