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 {eScriptedCommandSynchronicitySynchronous, "synchronous", 1490 "Run synchronous"}, 1491 {eScriptedCommandSynchronicityAsynchronous, "asynchronous", 1492 "Run asynchronous"}, 1493 {eScriptedCommandSynchronicityCurrentValue, "current", 1494 "Do not alter current setting"} }; 1495 1496 static constexpr OptionEnumValues ScriptSynchroType() { 1497 return OptionEnumValues(g_script_synchro_type); 1498 } 1499 1500 #define LLDB_OPTIONS_script_add 1501 #include "CommandOptions.inc" 1502 1503 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1504 public IOHandlerDelegateMultiline { 1505 public: 1506 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1507 : CommandObjectParsed(interpreter, "command script add", 1508 "Add a scripted function as an LLDB command.", 1509 nullptr), 1510 IOHandlerDelegateMultiline("DONE"), m_options() { 1511 CommandArgumentEntry arg1; 1512 CommandArgumentData cmd_arg; 1513 1514 // Define the first (and only) variant of this arg. 1515 cmd_arg.arg_type = eArgTypeCommandName; 1516 cmd_arg.arg_repetition = eArgRepeatPlain; 1517 1518 // There is only one variant this argument could be; put it into the 1519 // argument entry. 1520 arg1.push_back(cmd_arg); 1521 1522 // Push the data for the first argument into the m_arguments vector. 1523 m_arguments.push_back(arg1); 1524 } 1525 1526 ~CommandObjectCommandsScriptAdd() override = default; 1527 1528 Options *GetOptions() override { return &m_options; } 1529 1530 protected: 1531 class CommandOptions : public Options { 1532 public: 1533 CommandOptions() 1534 : Options(), m_class_name(), m_funct_name(), m_short_help(), 1535 m_synchronicity(eScriptedCommandSynchronicitySynchronous) {} 1536 1537 ~CommandOptions() override = default; 1538 1539 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1540 ExecutionContext *execution_context) override { 1541 Status error; 1542 const int short_option = m_getopt_table[option_idx].val; 1543 1544 switch (short_option) { 1545 case 'f': 1546 if (!option_arg.empty()) 1547 m_funct_name = option_arg; 1548 break; 1549 case 'c': 1550 if (!option_arg.empty()) 1551 m_class_name = option_arg; 1552 break; 1553 case 'h': 1554 if (!option_arg.empty()) 1555 m_short_help = option_arg; 1556 break; 1557 case 's': 1558 m_synchronicity = 1559 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1560 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1561 if (!error.Success()) 1562 error.SetErrorStringWithFormat( 1563 "unrecognized value for synchronicity '%s'", 1564 option_arg.str().c_str()); 1565 break; 1566 default: 1567 error.SetErrorStringWithFormat("unrecognized option '%c'", 1568 short_option); 1569 break; 1570 } 1571 1572 return error; 1573 } 1574 1575 void OptionParsingStarting(ExecutionContext *execution_context) override { 1576 m_class_name.clear(); 1577 m_funct_name.clear(); 1578 m_short_help.clear(); 1579 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1580 } 1581 1582 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1583 return llvm::makeArrayRef(g_script_add_options); 1584 } 1585 1586 // Instance variables to hold the values for command options. 1587 1588 std::string m_class_name; 1589 std::string m_funct_name; 1590 std::string m_short_help; 1591 ScriptedCommandSynchronicity m_synchronicity; 1592 }; 1593 1594 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 1595 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 1596 if (output_sp && interactive) { 1597 output_sp->PutCString(g_python_command_instructions); 1598 output_sp->Flush(); 1599 } 1600 } 1601 1602 void IOHandlerInputComplete(IOHandler &io_handler, 1603 std::string &data) override { 1604 StreamFileSP error_sp = io_handler.GetErrorStreamFile(); 1605 1606 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1607 if (interpreter) { 1608 1609 StringList lines; 1610 lines.SplitIntoLines(data); 1611 if (lines.GetSize() > 0) { 1612 std::string funct_name_str; 1613 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1614 if (funct_name_str.empty()) { 1615 error_sp->Printf("error: unable to obtain a function name, didn't " 1616 "add python command.\n"); 1617 error_sp->Flush(); 1618 } else { 1619 // everything should be fine now, let's add this alias 1620 1621 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1622 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1623 m_synchronicity)); 1624 1625 if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, 1626 true)) { 1627 error_sp->Printf("error: unable to add selected command, didn't " 1628 "add python command.\n"); 1629 error_sp->Flush(); 1630 } 1631 } 1632 } else { 1633 error_sp->Printf( 1634 "error: unable to create function, didn't add python command.\n"); 1635 error_sp->Flush(); 1636 } 1637 } else { 1638 error_sp->Printf("error: empty function, didn't add python command.\n"); 1639 error_sp->Flush(); 1640 } 1641 } else { 1642 error_sp->Printf( 1643 "error: script interpreter missing, didn't add python command.\n"); 1644 error_sp->Flush(); 1645 } 1646 1647 io_handler.SetIsDone(true); 1648 } 1649 1650 protected: 1651 bool DoExecute(Args &command, CommandReturnObject &result) override { 1652 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1653 result.AppendError("only scripting language supported for scripted " 1654 "commands is currently Python"); 1655 result.SetStatus(eReturnStatusFailed); 1656 return false; 1657 } 1658 1659 if (command.GetArgumentCount() != 1) { 1660 result.AppendError("'command script add' requires one argument"); 1661 result.SetStatus(eReturnStatusFailed); 1662 return false; 1663 } 1664 1665 // Store the options in case we get multi-line input 1666 m_cmd_name = command[0].ref; 1667 m_short_help.assign(m_options.m_short_help); 1668 m_synchronicity = m_options.m_synchronicity; 1669 1670 if (m_options.m_class_name.empty()) { 1671 if (m_options.m_funct_name.empty()) { 1672 m_interpreter.GetPythonCommandsFromIOHandler( 1673 " ", // Prompt 1674 *this, // IOHandlerDelegate 1675 true, // Run IOHandler in async mode 1676 nullptr); // Baton for the "io_handler" that will be passed back 1677 // into our IOHandlerDelegate functions 1678 } else { 1679 CommandObjectSP new_cmd(new CommandObjectPythonFunction( 1680 m_interpreter, m_cmd_name, m_options.m_funct_name, 1681 m_options.m_short_help, m_synchronicity)); 1682 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1683 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1684 } else { 1685 result.AppendError("cannot add command"); 1686 result.SetStatus(eReturnStatusFailed); 1687 } 1688 } 1689 } else { 1690 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1691 if (!interpreter) { 1692 result.AppendError("cannot find ScriptInterpreter"); 1693 result.SetStatus(eReturnStatusFailed); 1694 return false; 1695 } 1696 1697 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1698 m_options.m_class_name.c_str()); 1699 if (!cmd_obj_sp) { 1700 result.AppendError("cannot create helper object"); 1701 result.SetStatus(eReturnStatusFailed); 1702 return false; 1703 } 1704 1705 CommandObjectSP new_cmd(new CommandObjectScriptingObject( 1706 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1707 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1708 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1709 } else { 1710 result.AppendError("cannot add command"); 1711 result.SetStatus(eReturnStatusFailed); 1712 } 1713 } 1714 1715 return result.Succeeded(); 1716 } 1717 1718 CommandOptions m_options; 1719 std::string m_cmd_name; 1720 std::string m_short_help; 1721 ScriptedCommandSynchronicity m_synchronicity; 1722 }; 1723 1724 // CommandObjectCommandsScriptList 1725 1726 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1727 public: 1728 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1729 : CommandObjectParsed(interpreter, "command script list", 1730 "List defined scripted commands.", nullptr) {} 1731 1732 ~CommandObjectCommandsScriptList() override = default; 1733 1734 bool DoExecute(Args &command, CommandReturnObject &result) override { 1735 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1736 1737 result.SetStatus(eReturnStatusSuccessFinishResult); 1738 1739 return true; 1740 } 1741 }; 1742 1743 // CommandObjectCommandsScriptClear 1744 1745 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1746 public: 1747 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1748 : CommandObjectParsed(interpreter, "command script clear", 1749 "Delete all scripted commands.", nullptr) {} 1750 1751 ~CommandObjectCommandsScriptClear() override = default; 1752 1753 protected: 1754 bool DoExecute(Args &command, CommandReturnObject &result) override { 1755 m_interpreter.RemoveAllUser(); 1756 1757 result.SetStatus(eReturnStatusSuccessFinishResult); 1758 1759 return true; 1760 } 1761 }; 1762 1763 // CommandObjectCommandsScriptDelete 1764 1765 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1766 public: 1767 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1768 : CommandObjectParsed(interpreter, "command script delete", 1769 "Delete a scripted command.", nullptr) { 1770 CommandArgumentEntry arg1; 1771 CommandArgumentData cmd_arg; 1772 1773 // Define the first (and only) variant of this arg. 1774 cmd_arg.arg_type = eArgTypeCommandName; 1775 cmd_arg.arg_repetition = eArgRepeatPlain; 1776 1777 // There is only one variant this argument could be; put it into the 1778 // argument entry. 1779 arg1.push_back(cmd_arg); 1780 1781 // Push the data for the first argument into the m_arguments vector. 1782 m_arguments.push_back(arg1); 1783 } 1784 1785 ~CommandObjectCommandsScriptDelete() override = default; 1786 1787 protected: 1788 bool DoExecute(Args &command, CommandReturnObject &result) override { 1789 1790 if (command.GetArgumentCount() != 1) { 1791 result.AppendError("'command script delete' requires one argument"); 1792 result.SetStatus(eReturnStatusFailed); 1793 return false; 1794 } 1795 1796 auto cmd_name = command[0].ref; 1797 1798 if (cmd_name.empty() || !m_interpreter.HasUserCommands() || 1799 !m_interpreter.UserCommandExists(cmd_name)) { 1800 result.AppendErrorWithFormat("command %s not found", command[0].c_str()); 1801 result.SetStatus(eReturnStatusFailed); 1802 return false; 1803 } 1804 1805 m_interpreter.RemoveUser(cmd_name); 1806 result.SetStatus(eReturnStatusSuccessFinishResult); 1807 return true; 1808 } 1809 }; 1810 1811 #pragma mark CommandObjectMultiwordCommandsScript 1812 1813 // CommandObjectMultiwordCommandsScript 1814 1815 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1816 public: 1817 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1818 : CommandObjectMultiword( 1819 interpreter, "command script", "Commands for managing custom " 1820 "commands implemented by " 1821 "interpreter scripts.", 1822 "command script <subcommand> [<subcommand-options>]") { 1823 LoadSubCommand("add", CommandObjectSP( 1824 new CommandObjectCommandsScriptAdd(interpreter))); 1825 LoadSubCommand( 1826 "delete", 1827 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1828 LoadSubCommand( 1829 "clear", 1830 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1831 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1832 interpreter))); 1833 LoadSubCommand( 1834 "import", 1835 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1836 } 1837 1838 ~CommandObjectMultiwordCommandsScript() override = default; 1839 }; 1840 1841 #pragma mark CommandObjectMultiwordCommands 1842 1843 // CommandObjectMultiwordCommands 1844 1845 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 1846 CommandInterpreter &interpreter) 1847 : CommandObjectMultiword(interpreter, "command", 1848 "Commands for managing custom LLDB commands.", 1849 "command <subcommand> [<subcommand-options>]") { 1850 LoadSubCommand("source", 1851 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 1852 LoadSubCommand("alias", 1853 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 1854 LoadSubCommand("unalias", CommandObjectSP( 1855 new CommandObjectCommandsUnalias(interpreter))); 1856 LoadSubCommand("delete", 1857 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 1858 LoadSubCommand( 1859 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 1860 LoadSubCommand("history", CommandObjectSP( 1861 new CommandObjectCommandsHistory(interpreter))); 1862 LoadSubCommand( 1863 "script", 1864 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 1865 } 1866 1867 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 1868