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