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 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1300 1301 llvm::StringRef GetHelp() override { 1302 if (m_fetched_help_short) 1303 return CommandObjectRaw::GetHelp(); 1304 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1305 if (!scripter) 1306 return CommandObjectRaw::GetHelp(); 1307 std::string docstring; 1308 m_fetched_help_short = 1309 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1310 if (!docstring.empty()) 1311 SetHelp(docstring); 1312 1313 return CommandObjectRaw::GetHelp(); 1314 } 1315 1316 llvm::StringRef GetHelpLong() override { 1317 if (m_fetched_help_long) 1318 return CommandObjectRaw::GetHelpLong(); 1319 1320 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1321 if (!scripter) 1322 return CommandObjectRaw::GetHelpLong(); 1323 1324 std::string docstring; 1325 m_fetched_help_long = 1326 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1327 if (!docstring.empty()) 1328 SetHelpLong(docstring); 1329 return CommandObjectRaw::GetHelpLong(); 1330 } 1331 1332 protected: 1333 bool DoExecute(llvm::StringRef raw_command_line, 1334 CommandReturnObject &result) override { 1335 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1336 1337 Status error; 1338 1339 result.SetStatus(eReturnStatusInvalid); 1340 1341 if (!scripter || 1342 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1343 m_synchro, result, error, m_exe_ctx)) { 1344 result.AppendError(error.AsCString()); 1345 result.SetStatus(eReturnStatusFailed); 1346 } else { 1347 // Don't change the status if the command already set it... 1348 if (result.GetStatus() == eReturnStatusInvalid) { 1349 if (result.GetOutputData().empty()) 1350 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1351 else 1352 result.SetStatus(eReturnStatusSuccessFinishResult); 1353 } 1354 } 1355 1356 return result.Succeeded(); 1357 } 1358 1359 private: 1360 StructuredData::GenericSP m_cmd_obj_sp; 1361 ScriptedCommandSynchronicity m_synchro; 1362 bool m_fetched_help_short : 1; 1363 bool m_fetched_help_long : 1; 1364 }; 1365 1366 // CommandObjectCommandsScriptImport 1367 #define LLDB_OPTIONS_script_import 1368 #include "CommandOptions.inc" 1369 1370 class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1371 public: 1372 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1373 : CommandObjectParsed(interpreter, "command script import", 1374 "Import a scripting module in LLDB.", nullptr), 1375 m_options() { 1376 CommandArgumentEntry arg1; 1377 CommandArgumentData cmd_arg; 1378 1379 // Define the first (and only) variant of this arg. 1380 cmd_arg.arg_type = eArgTypeFilename; 1381 cmd_arg.arg_repetition = eArgRepeatPlus; 1382 1383 // There is only one variant this argument could be; put it into the 1384 // argument entry. 1385 arg1.push_back(cmd_arg); 1386 1387 // Push the data for the first argument into the m_arguments vector. 1388 m_arguments.push_back(arg1); 1389 } 1390 1391 ~CommandObjectCommandsScriptImport() override = default; 1392 1393 int HandleArgumentCompletion( 1394 CompletionRequest &request, 1395 OptionElementVector &opt_element_vector) override { 1396 CommandCompletions::InvokeCommonCompletionCallbacks( 1397 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 1398 request, nullptr); 1399 return request.GetNumberOfMatches(); 1400 } 1401 1402 Options *GetOptions() override { return &m_options; } 1403 1404 protected: 1405 class CommandOptions : public Options { 1406 public: 1407 CommandOptions() : Options() {} 1408 1409 ~CommandOptions() override = default; 1410 1411 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1412 ExecutionContext *execution_context) override { 1413 Status error; 1414 const int short_option = m_getopt_table[option_idx].val; 1415 1416 switch (short_option) { 1417 case 'r': 1418 m_allow_reload = true; 1419 break; 1420 default: 1421 error.SetErrorStringWithFormat("unrecognized option '%c'", 1422 short_option); 1423 break; 1424 } 1425 1426 return error; 1427 } 1428 1429 void OptionParsingStarting(ExecutionContext *execution_context) override { 1430 m_allow_reload = true; 1431 } 1432 1433 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1434 return llvm::makeArrayRef(g_script_import_options); 1435 } 1436 1437 // Instance variables to hold the values for command options. 1438 1439 bool m_allow_reload; 1440 }; 1441 1442 bool DoExecute(Args &command, CommandReturnObject &result) override { 1443 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1444 result.AppendError("only scripting language supported for module " 1445 "importing is currently Python"); 1446 result.SetStatus(eReturnStatusFailed); 1447 return false; 1448 } 1449 1450 if (command.empty()) { 1451 result.AppendError("command script import needs one or more arguments"); 1452 result.SetStatus(eReturnStatusFailed); 1453 return false; 1454 } 1455 1456 for (auto &entry : command.entries()) { 1457 Status error; 1458 1459 const bool init_session = true; 1460 // FIXME: this is necessary because CommandObject::CheckRequirements() 1461 // assumes that commands won't ever be recursively invoked, but it's 1462 // actually possible to craft a Python script that does other "command 1463 // script imports" in __lldb_init_module the real fix is to have 1464 // recursive commands possible with a CommandInvocation object separate 1465 // from the CommandObject itself, so that recursive command invocations 1466 // won't stomp on each other (wrt to execution contents, options, and 1467 // more) 1468 m_exe_ctx.Clear(); 1469 if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( 1470 entry.c_str(), m_options.m_allow_reload, init_session, error)) { 1471 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1472 } else { 1473 result.AppendErrorWithFormat("module importing failed: %s", 1474 error.AsCString()); 1475 result.SetStatus(eReturnStatusFailed); 1476 } 1477 } 1478 1479 return result.Succeeded(); 1480 } 1481 1482 CommandOptions m_options; 1483 }; 1484 1485 // CommandObjectCommandsScriptAdd 1486 static constexpr OptionEnumValueElement g_script_synchro_type[] = { 1487 { 1488 eScriptedCommandSynchronicitySynchronous, 1489 "synchronous", 1490 "Run synchronous", 1491 }, 1492 { 1493 eScriptedCommandSynchronicityAsynchronous, 1494 "asynchronous", 1495 "Run asynchronous", 1496 }, 1497 { 1498 eScriptedCommandSynchronicityCurrentValue, 1499 "current", 1500 "Do not alter current setting", 1501 }, 1502 }; 1503 1504 static constexpr OptionEnumValues ScriptSynchroType() { 1505 return OptionEnumValues(g_script_synchro_type); 1506 } 1507 1508 #define LLDB_OPTIONS_script_add 1509 #include "CommandOptions.inc" 1510 1511 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1512 public IOHandlerDelegateMultiline { 1513 public: 1514 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1515 : CommandObjectParsed(interpreter, "command script add", 1516 "Add a scripted function as an LLDB command.", 1517 nullptr), 1518 IOHandlerDelegateMultiline("DONE"), m_options() { 1519 CommandArgumentEntry arg1; 1520 CommandArgumentData cmd_arg; 1521 1522 // Define the first (and only) variant of this arg. 1523 cmd_arg.arg_type = eArgTypeCommandName; 1524 cmd_arg.arg_repetition = eArgRepeatPlain; 1525 1526 // There is only one variant this argument could be; put it into the 1527 // argument entry. 1528 arg1.push_back(cmd_arg); 1529 1530 // Push the data for the first argument into the m_arguments vector. 1531 m_arguments.push_back(arg1); 1532 } 1533 1534 ~CommandObjectCommandsScriptAdd() override = default; 1535 1536 Options *GetOptions() override { return &m_options; } 1537 1538 protected: 1539 class CommandOptions : public Options { 1540 public: 1541 CommandOptions() 1542 : Options(), m_class_name(), m_funct_name(), m_short_help(), 1543 m_synchronicity(eScriptedCommandSynchronicitySynchronous) {} 1544 1545 ~CommandOptions() override = default; 1546 1547 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1548 ExecutionContext *execution_context) override { 1549 Status error; 1550 const int short_option = m_getopt_table[option_idx].val; 1551 1552 switch (short_option) { 1553 case 'f': 1554 if (!option_arg.empty()) 1555 m_funct_name = option_arg; 1556 break; 1557 case 'c': 1558 if (!option_arg.empty()) 1559 m_class_name = option_arg; 1560 break; 1561 case 'h': 1562 if (!option_arg.empty()) 1563 m_short_help = option_arg; 1564 break; 1565 case 's': 1566 m_synchronicity = 1567 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1568 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1569 if (!error.Success()) 1570 error.SetErrorStringWithFormat( 1571 "unrecognized value for synchronicity '%s'", 1572 option_arg.str().c_str()); 1573 break; 1574 default: 1575 error.SetErrorStringWithFormat("unrecognized option '%c'", 1576 short_option); 1577 break; 1578 } 1579 1580 return error; 1581 } 1582 1583 void OptionParsingStarting(ExecutionContext *execution_context) override { 1584 m_class_name.clear(); 1585 m_funct_name.clear(); 1586 m_short_help.clear(); 1587 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1588 } 1589 1590 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1591 return llvm::makeArrayRef(g_script_add_options); 1592 } 1593 1594 // Instance variables to hold the values for command options. 1595 1596 std::string m_class_name; 1597 std::string m_funct_name; 1598 std::string m_short_help; 1599 ScriptedCommandSynchronicity m_synchronicity; 1600 }; 1601 1602 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 1603 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 1604 if (output_sp && interactive) { 1605 output_sp->PutCString(g_python_command_instructions); 1606 output_sp->Flush(); 1607 } 1608 } 1609 1610 void IOHandlerInputComplete(IOHandler &io_handler, 1611 std::string &data) override { 1612 StreamFileSP error_sp = io_handler.GetErrorStreamFile(); 1613 1614 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1615 if (interpreter) { 1616 1617 StringList lines; 1618 lines.SplitIntoLines(data); 1619 if (lines.GetSize() > 0) { 1620 std::string funct_name_str; 1621 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1622 if (funct_name_str.empty()) { 1623 error_sp->Printf("error: unable to obtain a function name, didn't " 1624 "add python command.\n"); 1625 error_sp->Flush(); 1626 } else { 1627 // everything should be fine now, let's add this alias 1628 1629 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1630 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1631 m_synchronicity)); 1632 1633 if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, 1634 true)) { 1635 error_sp->Printf("error: unable to add selected command, didn't " 1636 "add python command.\n"); 1637 error_sp->Flush(); 1638 } 1639 } 1640 } else { 1641 error_sp->Printf( 1642 "error: unable to create function, didn't add python command.\n"); 1643 error_sp->Flush(); 1644 } 1645 } else { 1646 error_sp->Printf("error: empty function, didn't add python command.\n"); 1647 error_sp->Flush(); 1648 } 1649 } else { 1650 error_sp->Printf( 1651 "error: script interpreter missing, didn't add python command.\n"); 1652 error_sp->Flush(); 1653 } 1654 1655 io_handler.SetIsDone(true); 1656 } 1657 1658 protected: 1659 bool DoExecute(Args &command, CommandReturnObject &result) override { 1660 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1661 result.AppendError("only scripting language supported for scripted " 1662 "commands is currently Python"); 1663 result.SetStatus(eReturnStatusFailed); 1664 return false; 1665 } 1666 1667 if (command.GetArgumentCount() != 1) { 1668 result.AppendError("'command script add' requires one argument"); 1669 result.SetStatus(eReturnStatusFailed); 1670 return false; 1671 } 1672 1673 // Store the options in case we get multi-line input 1674 m_cmd_name = command[0].ref; 1675 m_short_help.assign(m_options.m_short_help); 1676 m_synchronicity = m_options.m_synchronicity; 1677 1678 if (m_options.m_class_name.empty()) { 1679 if (m_options.m_funct_name.empty()) { 1680 m_interpreter.GetPythonCommandsFromIOHandler( 1681 " ", // Prompt 1682 *this, // IOHandlerDelegate 1683 true, // Run IOHandler in async mode 1684 nullptr); // Baton for the "io_handler" that will be passed back 1685 // into our IOHandlerDelegate functions 1686 } else { 1687 CommandObjectSP new_cmd(new CommandObjectPythonFunction( 1688 m_interpreter, m_cmd_name, m_options.m_funct_name, 1689 m_options.m_short_help, m_synchronicity)); 1690 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1691 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1692 } else { 1693 result.AppendError("cannot add command"); 1694 result.SetStatus(eReturnStatusFailed); 1695 } 1696 } 1697 } else { 1698 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1699 if (!interpreter) { 1700 result.AppendError("cannot find ScriptInterpreter"); 1701 result.SetStatus(eReturnStatusFailed); 1702 return false; 1703 } 1704 1705 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1706 m_options.m_class_name.c_str()); 1707 if (!cmd_obj_sp) { 1708 result.AppendError("cannot create helper object"); 1709 result.SetStatus(eReturnStatusFailed); 1710 return false; 1711 } 1712 1713 CommandObjectSP new_cmd(new CommandObjectScriptingObject( 1714 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1715 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1716 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1717 } else { 1718 result.AppendError("cannot add command"); 1719 result.SetStatus(eReturnStatusFailed); 1720 } 1721 } 1722 1723 return result.Succeeded(); 1724 } 1725 1726 CommandOptions m_options; 1727 std::string m_cmd_name; 1728 std::string m_short_help; 1729 ScriptedCommandSynchronicity m_synchronicity; 1730 }; 1731 1732 // CommandObjectCommandsScriptList 1733 1734 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1735 public: 1736 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1737 : CommandObjectParsed(interpreter, "command script list", 1738 "List defined scripted commands.", nullptr) {} 1739 1740 ~CommandObjectCommandsScriptList() override = default; 1741 1742 bool DoExecute(Args &command, CommandReturnObject &result) override { 1743 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1744 1745 result.SetStatus(eReturnStatusSuccessFinishResult); 1746 1747 return true; 1748 } 1749 }; 1750 1751 // CommandObjectCommandsScriptClear 1752 1753 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1754 public: 1755 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1756 : CommandObjectParsed(interpreter, "command script clear", 1757 "Delete all scripted commands.", nullptr) {} 1758 1759 ~CommandObjectCommandsScriptClear() override = default; 1760 1761 protected: 1762 bool DoExecute(Args &command, CommandReturnObject &result) override { 1763 m_interpreter.RemoveAllUser(); 1764 1765 result.SetStatus(eReturnStatusSuccessFinishResult); 1766 1767 return true; 1768 } 1769 }; 1770 1771 // CommandObjectCommandsScriptDelete 1772 1773 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1774 public: 1775 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1776 : CommandObjectParsed(interpreter, "command script delete", 1777 "Delete a scripted command.", nullptr) { 1778 CommandArgumentEntry arg1; 1779 CommandArgumentData cmd_arg; 1780 1781 // Define the first (and only) variant of this arg. 1782 cmd_arg.arg_type = eArgTypeCommandName; 1783 cmd_arg.arg_repetition = eArgRepeatPlain; 1784 1785 // There is only one variant this argument could be; put it into the 1786 // argument entry. 1787 arg1.push_back(cmd_arg); 1788 1789 // Push the data for the first argument into the m_arguments vector. 1790 m_arguments.push_back(arg1); 1791 } 1792 1793 ~CommandObjectCommandsScriptDelete() override = default; 1794 1795 protected: 1796 bool DoExecute(Args &command, CommandReturnObject &result) override { 1797 1798 if (command.GetArgumentCount() != 1) { 1799 result.AppendError("'command script delete' requires one argument"); 1800 result.SetStatus(eReturnStatusFailed); 1801 return false; 1802 } 1803 1804 auto cmd_name = command[0].ref; 1805 1806 if (cmd_name.empty() || !m_interpreter.HasUserCommands() || 1807 !m_interpreter.UserCommandExists(cmd_name)) { 1808 result.AppendErrorWithFormat("command %s not found", command[0].c_str()); 1809 result.SetStatus(eReturnStatusFailed); 1810 return false; 1811 } 1812 1813 m_interpreter.RemoveUser(cmd_name); 1814 result.SetStatus(eReturnStatusSuccessFinishResult); 1815 return true; 1816 } 1817 }; 1818 1819 #pragma mark CommandObjectMultiwordCommandsScript 1820 1821 // CommandObjectMultiwordCommandsScript 1822 1823 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1824 public: 1825 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1826 : CommandObjectMultiword( 1827 interpreter, "command script", "Commands for managing custom " 1828 "commands implemented by " 1829 "interpreter scripts.", 1830 "command script <subcommand> [<subcommand-options>]") { 1831 LoadSubCommand("add", CommandObjectSP( 1832 new CommandObjectCommandsScriptAdd(interpreter))); 1833 LoadSubCommand( 1834 "delete", 1835 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1836 LoadSubCommand( 1837 "clear", 1838 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1839 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1840 interpreter))); 1841 LoadSubCommand( 1842 "import", 1843 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1844 } 1845 1846 ~CommandObjectMultiwordCommandsScript() override = default; 1847 }; 1848 1849 #pragma mark CommandObjectMultiwordCommands 1850 1851 // CommandObjectMultiwordCommands 1852 1853 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 1854 CommandInterpreter &interpreter) 1855 : CommandObjectMultiword(interpreter, "command", 1856 "Commands for managing custom LLDB commands.", 1857 "command <subcommand> [<subcommand-options>]") { 1858 LoadSubCommand("source", 1859 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 1860 LoadSubCommand("alias", 1861 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 1862 LoadSubCommand("unalias", CommandObjectSP( 1863 new CommandObjectCommandsUnalias(interpreter))); 1864 LoadSubCommand("delete", 1865 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 1866 LoadSubCommand( 1867 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 1868 LoadSubCommand("history", CommandObjectSP( 1869 new CommandObjectCommandsHistory(interpreter))); 1870 LoadSubCommand( 1871 "script", 1872 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 1873 } 1874 1875 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 1876