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 bool check_only = false; 970 for (const std::string &line : lines) { 971 Status error = AppendRegexSubstitution(line, check_only); 972 if (error.Fail()) { 973 if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) { 974 StreamSP out_stream = GetDebugger().GetAsyncOutputStream(); 975 out_stream->Printf("error: %s\n", error.AsCString()); 976 } 977 } 978 } 979 } 980 if (m_regex_cmd_up->HasRegexEntries()) { 981 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 982 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 983 } 984 } 985 } 986 987 bool DoExecute(Args &command, CommandReturnObject &result) override { 988 const size_t argc = command.GetArgumentCount(); 989 if (argc == 0) { 990 result.AppendError("usage: 'command regex <command-name> " 991 "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 992 result.SetStatus(eReturnStatusFailed); 993 return false; 994 } 995 996 Status error; 997 auto name = command[0].ref; 998 m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>( 999 m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0, 1000 true); 1001 1002 if (argc == 1) { 1003 Debugger &debugger = GetDebugger(); 1004 bool color_prompt = debugger.GetUseColor(); 1005 const bool multiple_lines = true; // Get multiple lines 1006 IOHandlerSP io_handler_sp(new IOHandlerEditline( 1007 debugger, IOHandler::Type::Other, 1008 "lldb-regex", // Name of input reader for history 1009 llvm::StringRef("> "), // Prompt 1010 llvm::StringRef(), // Continuation prompt 1011 multiple_lines, color_prompt, 1012 0, // Don't show line numbers 1013 *this, nullptr)); 1014 1015 if (io_handler_sp) { 1016 debugger.PushIOHandler(io_handler_sp); 1017 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1018 } 1019 } else { 1020 for (auto &entry : command.entries().drop_front()) { 1021 bool check_only = false; 1022 error = AppendRegexSubstitution(entry.ref, check_only); 1023 if (error.Fail()) 1024 break; 1025 } 1026 1027 if (error.Success()) { 1028 AddRegexCommandToInterpreter(); 1029 } 1030 } 1031 if (error.Fail()) { 1032 result.AppendError(error.AsCString()); 1033 result.SetStatus(eReturnStatusFailed); 1034 } 1035 1036 return result.Succeeded(); 1037 } 1038 1039 Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed, 1040 bool check_only) { 1041 Status error; 1042 1043 if (!m_regex_cmd_up) { 1044 error.SetErrorStringWithFormat( 1045 "invalid regular expression command object for: '%.*s'", 1046 (int)regex_sed.size(), regex_sed.data()); 1047 return error; 1048 } 1049 1050 size_t regex_sed_size = regex_sed.size(); 1051 1052 if (regex_sed_size <= 1) { 1053 error.SetErrorStringWithFormat( 1054 "regular expression substitution string is too short: '%.*s'", 1055 (int)regex_sed.size(), regex_sed.data()); 1056 return error; 1057 } 1058 1059 if (regex_sed[0] != 's') { 1060 error.SetErrorStringWithFormat("regular expression substitution string " 1061 "doesn't start with 's': '%.*s'", 1062 (int)regex_sed.size(), regex_sed.data()); 1063 return error; 1064 } 1065 const size_t first_separator_char_pos = 1; 1066 // use the char that follows 's' as the regex separator character so we can 1067 // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 1068 const char separator_char = regex_sed[first_separator_char_pos]; 1069 const size_t second_separator_char_pos = 1070 regex_sed.find(separator_char, first_separator_char_pos + 1); 1071 1072 if (second_separator_char_pos == std::string::npos) { 1073 error.SetErrorStringWithFormat( 1074 "missing second '%c' separator char after '%.*s' in '%.*s'", 1075 separator_char, 1076 (int)(regex_sed.size() - first_separator_char_pos - 1), 1077 regex_sed.data() + (first_separator_char_pos + 1), 1078 (int)regex_sed.size(), regex_sed.data()); 1079 return error; 1080 } 1081 1082 const size_t third_separator_char_pos = 1083 regex_sed.find(separator_char, second_separator_char_pos + 1); 1084 1085 if (third_separator_char_pos == std::string::npos) { 1086 error.SetErrorStringWithFormat( 1087 "missing third '%c' separator char after '%.*s' in '%.*s'", 1088 separator_char, 1089 (int)(regex_sed.size() - second_separator_char_pos - 1), 1090 regex_sed.data() + (second_separator_char_pos + 1), 1091 (int)regex_sed.size(), regex_sed.data()); 1092 return error; 1093 } 1094 1095 if (third_separator_char_pos != regex_sed_size - 1) { 1096 // Make sure that everything that follows the last regex separator char 1097 if (regex_sed.find_first_not_of("\t\n\v\f\r ", 1098 third_separator_char_pos + 1) != 1099 std::string::npos) { 1100 error.SetErrorStringWithFormat( 1101 "extra data found after the '%.*s' regular expression substitution " 1102 "string: '%.*s'", 1103 (int)third_separator_char_pos + 1, regex_sed.data(), 1104 (int)(regex_sed.size() - third_separator_char_pos - 1), 1105 regex_sed.data() + (third_separator_char_pos + 1)); 1106 return error; 1107 } 1108 } else if (first_separator_char_pos + 1 == second_separator_char_pos) { 1109 error.SetErrorStringWithFormat( 1110 "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 1111 separator_char, separator_char, separator_char, (int)regex_sed.size(), 1112 regex_sed.data()); 1113 return error; 1114 } else if (second_separator_char_pos + 1 == third_separator_char_pos) { 1115 error.SetErrorStringWithFormat( 1116 "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 1117 separator_char, separator_char, separator_char, (int)regex_sed.size(), 1118 regex_sed.data()); 1119 return error; 1120 } 1121 1122 if (!check_only) { 1123 std::string regex(regex_sed.substr(first_separator_char_pos + 1, 1124 second_separator_char_pos - 1125 first_separator_char_pos - 1)); 1126 std::string subst(regex_sed.substr(second_separator_char_pos + 1, 1127 third_separator_char_pos - 1128 second_separator_char_pos - 1)); 1129 m_regex_cmd_up->AddRegexCommand(regex.c_str(), subst.c_str()); 1130 } 1131 return error; 1132 } 1133 1134 void AddRegexCommandToInterpreter() { 1135 if (m_regex_cmd_up) { 1136 if (m_regex_cmd_up->HasRegexEntries()) { 1137 CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 1138 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 1139 } 1140 } 1141 } 1142 1143 private: 1144 std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up; 1145 1146 class CommandOptions : public Options { 1147 public: 1148 CommandOptions() : Options() {} 1149 1150 ~CommandOptions() override = default; 1151 1152 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1153 ExecutionContext *execution_context) override { 1154 Status error; 1155 const int short_option = m_getopt_table[option_idx].val; 1156 1157 switch (short_option) { 1158 case 'h': 1159 m_help.assign(option_arg); 1160 break; 1161 case 's': 1162 m_syntax.assign(option_arg); 1163 break; 1164 default: 1165 error.SetErrorStringWithFormat("unrecognized option '%c'", 1166 short_option); 1167 break; 1168 } 1169 1170 return error; 1171 } 1172 1173 void OptionParsingStarting(ExecutionContext *execution_context) override { 1174 m_help.clear(); 1175 m_syntax.clear(); 1176 } 1177 1178 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1179 return llvm::makeArrayRef(g_regex_options); 1180 } 1181 1182 // TODO: Convert these functions to return StringRefs. 1183 const char *GetHelp() { 1184 return (m_help.empty() ? nullptr : m_help.c_str()); 1185 } 1186 1187 const char *GetSyntax() { 1188 return (m_syntax.empty() ? nullptr : m_syntax.c_str()); 1189 } 1190 1191 protected: 1192 // Instance variables to hold the values for command options. 1193 1194 std::string m_help; 1195 std::string m_syntax; 1196 }; 1197 1198 Options *GetOptions() override { return &m_options; } 1199 1200 CommandOptions m_options; 1201 }; 1202 1203 class CommandObjectPythonFunction : public CommandObjectRaw { 1204 public: 1205 CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name, 1206 std::string funct, std::string help, 1207 ScriptedCommandSynchronicity synch) 1208 : CommandObjectRaw(interpreter, name), 1209 m_function_name(funct), m_synchro(synch), m_fetched_help_long(false) { 1210 if (!help.empty()) 1211 SetHelp(help); 1212 else { 1213 StreamString stream; 1214 stream.Printf("For more information run 'help %s'", name.c_str()); 1215 SetHelp(stream.GetString()); 1216 } 1217 } 1218 1219 ~CommandObjectPythonFunction() override = default; 1220 1221 bool IsRemovable() const override { return true; } 1222 1223 const std::string &GetFunctionName() { return m_function_name; } 1224 1225 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1226 1227 llvm::StringRef GetHelpLong() override { 1228 if (m_fetched_help_long) 1229 return CommandObjectRaw::GetHelpLong(); 1230 1231 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1232 if (!scripter) 1233 return CommandObjectRaw::GetHelpLong(); 1234 1235 std::string docstring; 1236 m_fetched_help_long = 1237 scripter->GetDocumentationForItem(m_function_name.c_str(), docstring); 1238 if (!docstring.empty()) 1239 SetHelpLong(docstring); 1240 return CommandObjectRaw::GetHelpLong(); 1241 } 1242 1243 protected: 1244 bool DoExecute(llvm::StringRef raw_command_line, 1245 CommandReturnObject &result) override { 1246 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1247 1248 Status error; 1249 1250 result.SetStatus(eReturnStatusInvalid); 1251 1252 if (!scripter || 1253 !scripter->RunScriptBasedCommand(m_function_name.c_str(), 1254 raw_command_line, m_synchro, result, 1255 error, m_exe_ctx)) { 1256 result.AppendError(error.AsCString()); 1257 result.SetStatus(eReturnStatusFailed); 1258 } else { 1259 // Don't change the status if the command already set it... 1260 if (result.GetStatus() == eReturnStatusInvalid) { 1261 if (result.GetOutputData().empty()) 1262 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1263 else 1264 result.SetStatus(eReturnStatusSuccessFinishResult); 1265 } 1266 } 1267 1268 return result.Succeeded(); 1269 } 1270 1271 private: 1272 std::string m_function_name; 1273 ScriptedCommandSynchronicity m_synchro; 1274 bool m_fetched_help_long; 1275 }; 1276 1277 class CommandObjectScriptingObject : public CommandObjectRaw { 1278 public: 1279 CommandObjectScriptingObject(CommandInterpreter &interpreter, 1280 std::string name, 1281 StructuredData::GenericSP cmd_obj_sp, 1282 ScriptedCommandSynchronicity synch) 1283 : CommandObjectRaw(interpreter, name), 1284 m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch), m_fetched_help_short(false), 1285 m_fetched_help_long(false) { 1286 StreamString stream; 1287 stream.Printf("For more information run 'help %s'", name.c_str()); 1288 SetHelp(stream.GetString()); 1289 if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter()) 1290 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1291 } 1292 1293 ~CommandObjectScriptingObject() override = default; 1294 1295 bool IsRemovable() const override { return true; } 1296 1297 ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1298 1299 llvm::StringRef GetHelp() override { 1300 if (m_fetched_help_short) 1301 return CommandObjectRaw::GetHelp(); 1302 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1303 if (!scripter) 1304 return CommandObjectRaw::GetHelp(); 1305 std::string docstring; 1306 m_fetched_help_short = 1307 scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1308 if (!docstring.empty()) 1309 SetHelp(docstring); 1310 1311 return CommandObjectRaw::GetHelp(); 1312 } 1313 1314 llvm::StringRef GetHelpLong() override { 1315 if (m_fetched_help_long) 1316 return CommandObjectRaw::GetHelpLong(); 1317 1318 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1319 if (!scripter) 1320 return CommandObjectRaw::GetHelpLong(); 1321 1322 std::string docstring; 1323 m_fetched_help_long = 1324 scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1325 if (!docstring.empty()) 1326 SetHelpLong(docstring); 1327 return CommandObjectRaw::GetHelpLong(); 1328 } 1329 1330 protected: 1331 bool DoExecute(llvm::StringRef raw_command_line, 1332 CommandReturnObject &result) override { 1333 ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1334 1335 Status error; 1336 1337 result.SetStatus(eReturnStatusInvalid); 1338 1339 if (!scripter || 1340 !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1341 m_synchro, result, error, m_exe_ctx)) { 1342 result.AppendError(error.AsCString()); 1343 result.SetStatus(eReturnStatusFailed); 1344 } else { 1345 // Don't change the status if the command already set it... 1346 if (result.GetStatus() == eReturnStatusInvalid) { 1347 if (result.GetOutputData().empty()) 1348 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1349 else 1350 result.SetStatus(eReturnStatusSuccessFinishResult); 1351 } 1352 } 1353 1354 return result.Succeeded(); 1355 } 1356 1357 private: 1358 StructuredData::GenericSP m_cmd_obj_sp; 1359 ScriptedCommandSynchronicity m_synchro; 1360 bool m_fetched_help_short : 1; 1361 bool m_fetched_help_long : 1; 1362 }; 1363 1364 // CommandObjectCommandsScriptImport 1365 #define LLDB_OPTIONS_script_import 1366 #include "CommandOptions.inc" 1367 1368 class CommandObjectCommandsScriptImport : public CommandObjectParsed { 1369 public: 1370 CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1371 : CommandObjectParsed(interpreter, "command script import", 1372 "Import a scripting module in LLDB.", nullptr), 1373 m_options() { 1374 CommandArgumentEntry arg1; 1375 CommandArgumentData cmd_arg; 1376 1377 // Define the first (and only) variant of this arg. 1378 cmd_arg.arg_type = eArgTypeFilename; 1379 cmd_arg.arg_repetition = eArgRepeatPlus; 1380 1381 // There is only one variant this argument could be; put it into the 1382 // argument entry. 1383 arg1.push_back(cmd_arg); 1384 1385 // Push the data for the first argument into the m_arguments vector. 1386 m_arguments.push_back(arg1); 1387 } 1388 1389 ~CommandObjectCommandsScriptImport() override = default; 1390 1391 int HandleArgumentCompletion( 1392 CompletionRequest &request, 1393 OptionElementVector &opt_element_vector) override { 1394 CommandCompletions::InvokeCommonCompletionCallbacks( 1395 GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 1396 request, nullptr); 1397 return request.GetNumberOfMatches(); 1398 } 1399 1400 Options *GetOptions() override { return &m_options; } 1401 1402 protected: 1403 class CommandOptions : public Options { 1404 public: 1405 CommandOptions() : Options() {} 1406 1407 ~CommandOptions() override = default; 1408 1409 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1410 ExecutionContext *execution_context) override { 1411 Status error; 1412 const int short_option = m_getopt_table[option_idx].val; 1413 1414 switch (short_option) { 1415 case 'r': 1416 m_allow_reload = true; 1417 break; 1418 default: 1419 error.SetErrorStringWithFormat("unrecognized option '%c'", 1420 short_option); 1421 break; 1422 } 1423 1424 return error; 1425 } 1426 1427 void OptionParsingStarting(ExecutionContext *execution_context) override { 1428 m_allow_reload = true; 1429 } 1430 1431 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1432 return llvm::makeArrayRef(g_script_import_options); 1433 } 1434 1435 // Instance variables to hold the values for command options. 1436 1437 bool m_allow_reload; 1438 }; 1439 1440 bool DoExecute(Args &command, CommandReturnObject &result) override { 1441 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1442 result.AppendError("only scripting language supported for module " 1443 "importing is currently Python"); 1444 result.SetStatus(eReturnStatusFailed); 1445 return false; 1446 } 1447 1448 if (command.empty()) { 1449 result.AppendError("command script import needs one or more arguments"); 1450 result.SetStatus(eReturnStatusFailed); 1451 return false; 1452 } 1453 1454 for (auto &entry : command.entries()) { 1455 Status error; 1456 1457 const bool init_session = true; 1458 // FIXME: this is necessary because CommandObject::CheckRequirements() 1459 // assumes that commands won't ever be recursively invoked, but it's 1460 // actually possible to craft a Python script that does other "command 1461 // script imports" in __lldb_init_module the real fix is to have 1462 // recursive commands possible with a CommandInvocation object separate 1463 // from the CommandObject itself, so that recursive command invocations 1464 // won't stomp on each other (wrt to execution contents, options, and 1465 // more) 1466 m_exe_ctx.Clear(); 1467 if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( 1468 entry.c_str(), m_options.m_allow_reload, init_session, error)) { 1469 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1470 } else { 1471 result.AppendErrorWithFormat("module importing failed: %s", 1472 error.AsCString()); 1473 result.SetStatus(eReturnStatusFailed); 1474 } 1475 } 1476 1477 return result.Succeeded(); 1478 } 1479 1480 CommandOptions m_options; 1481 }; 1482 1483 // CommandObjectCommandsScriptAdd 1484 static constexpr OptionEnumValueElement g_script_synchro_type[] = { 1485 { 1486 eScriptedCommandSynchronicitySynchronous, 1487 "synchronous", 1488 "Run synchronous", 1489 }, 1490 { 1491 eScriptedCommandSynchronicityAsynchronous, 1492 "asynchronous", 1493 "Run asynchronous", 1494 }, 1495 { 1496 eScriptedCommandSynchronicityCurrentValue, 1497 "current", 1498 "Do not alter current setting", 1499 }, 1500 }; 1501 1502 static constexpr OptionEnumValues ScriptSynchroType() { 1503 return OptionEnumValues(g_script_synchro_type); 1504 } 1505 1506 #define LLDB_OPTIONS_script_add 1507 #include "CommandOptions.inc" 1508 1509 class CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1510 public IOHandlerDelegateMultiline { 1511 public: 1512 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1513 : CommandObjectParsed(interpreter, "command script add", 1514 "Add a scripted function as an LLDB command.", 1515 nullptr), 1516 IOHandlerDelegateMultiline("DONE"), m_options() { 1517 CommandArgumentEntry arg1; 1518 CommandArgumentData cmd_arg; 1519 1520 // Define the first (and only) variant of this arg. 1521 cmd_arg.arg_type = eArgTypeCommandName; 1522 cmd_arg.arg_repetition = eArgRepeatPlain; 1523 1524 // There is only one variant this argument could be; put it into the 1525 // argument entry. 1526 arg1.push_back(cmd_arg); 1527 1528 // Push the data for the first argument into the m_arguments vector. 1529 m_arguments.push_back(arg1); 1530 } 1531 1532 ~CommandObjectCommandsScriptAdd() override = default; 1533 1534 Options *GetOptions() override { return &m_options; } 1535 1536 protected: 1537 class CommandOptions : public Options { 1538 public: 1539 CommandOptions() 1540 : Options(), m_class_name(), m_funct_name(), m_short_help(), 1541 m_synchronicity(eScriptedCommandSynchronicitySynchronous) {} 1542 1543 ~CommandOptions() override = default; 1544 1545 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1546 ExecutionContext *execution_context) override { 1547 Status error; 1548 const int short_option = m_getopt_table[option_idx].val; 1549 1550 switch (short_option) { 1551 case 'f': 1552 if (!option_arg.empty()) 1553 m_funct_name = option_arg; 1554 break; 1555 case 'c': 1556 if (!option_arg.empty()) 1557 m_class_name = option_arg; 1558 break; 1559 case 'h': 1560 if (!option_arg.empty()) 1561 m_short_help = option_arg; 1562 break; 1563 case 's': 1564 m_synchronicity = 1565 (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1566 option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1567 if (!error.Success()) 1568 error.SetErrorStringWithFormat( 1569 "unrecognized value for synchronicity '%s'", 1570 option_arg.str().c_str()); 1571 break; 1572 default: 1573 error.SetErrorStringWithFormat("unrecognized option '%c'", 1574 short_option); 1575 break; 1576 } 1577 1578 return error; 1579 } 1580 1581 void OptionParsingStarting(ExecutionContext *execution_context) override { 1582 m_class_name.clear(); 1583 m_funct_name.clear(); 1584 m_short_help.clear(); 1585 m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1586 } 1587 1588 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1589 return llvm::makeArrayRef(g_script_add_options); 1590 } 1591 1592 // Instance variables to hold the values for command options. 1593 1594 std::string m_class_name; 1595 std::string m_funct_name; 1596 std::string m_short_help; 1597 ScriptedCommandSynchronicity m_synchronicity; 1598 }; 1599 1600 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 1601 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 1602 if (output_sp && interactive) { 1603 output_sp->PutCString(g_python_command_instructions); 1604 output_sp->Flush(); 1605 } 1606 } 1607 1608 void IOHandlerInputComplete(IOHandler &io_handler, 1609 std::string &data) override { 1610 StreamFileSP error_sp = io_handler.GetErrorStreamFile(); 1611 1612 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1613 if (interpreter) { 1614 1615 StringList lines; 1616 lines.SplitIntoLines(data); 1617 if (lines.GetSize() > 0) { 1618 std::string funct_name_str; 1619 if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1620 if (funct_name_str.empty()) { 1621 error_sp->Printf("error: unable to obtain a function name, didn't " 1622 "add python command.\n"); 1623 error_sp->Flush(); 1624 } else { 1625 // everything should be fine now, let's add this alias 1626 1627 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1628 m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1629 m_synchronicity)); 1630 1631 if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, 1632 true)) { 1633 error_sp->Printf("error: unable to add selected command, didn't " 1634 "add python command.\n"); 1635 error_sp->Flush(); 1636 } 1637 } 1638 } else { 1639 error_sp->Printf( 1640 "error: unable to create function, didn't add python command.\n"); 1641 error_sp->Flush(); 1642 } 1643 } else { 1644 error_sp->Printf("error: empty function, didn't add python command.\n"); 1645 error_sp->Flush(); 1646 } 1647 } else { 1648 error_sp->Printf( 1649 "error: script interpreter missing, didn't add python command.\n"); 1650 error_sp->Flush(); 1651 } 1652 1653 io_handler.SetIsDone(true); 1654 } 1655 1656 protected: 1657 bool DoExecute(Args &command, CommandReturnObject &result) override { 1658 if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1659 result.AppendError("only scripting language supported for scripted " 1660 "commands is currently Python"); 1661 result.SetStatus(eReturnStatusFailed); 1662 return false; 1663 } 1664 1665 if (command.GetArgumentCount() != 1) { 1666 result.AppendError("'command script add' requires one argument"); 1667 result.SetStatus(eReturnStatusFailed); 1668 return false; 1669 } 1670 1671 // Store the options in case we get multi-line input 1672 m_cmd_name = command[0].ref; 1673 m_short_help.assign(m_options.m_short_help); 1674 m_synchronicity = m_options.m_synchronicity; 1675 1676 if (m_options.m_class_name.empty()) { 1677 if (m_options.m_funct_name.empty()) { 1678 m_interpreter.GetPythonCommandsFromIOHandler( 1679 " ", // Prompt 1680 *this, // IOHandlerDelegate 1681 true, // Run IOHandler in async mode 1682 nullptr); // Baton for the "io_handler" that will be passed back 1683 // into our IOHandlerDelegate functions 1684 } else { 1685 CommandObjectSP new_cmd(new CommandObjectPythonFunction( 1686 m_interpreter, m_cmd_name, m_options.m_funct_name, 1687 m_options.m_short_help, m_synchronicity)); 1688 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1689 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1690 } else { 1691 result.AppendError("cannot add command"); 1692 result.SetStatus(eReturnStatusFailed); 1693 } 1694 } 1695 } else { 1696 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1697 if (!interpreter) { 1698 result.AppendError("cannot find ScriptInterpreter"); 1699 result.SetStatus(eReturnStatusFailed); 1700 return false; 1701 } 1702 1703 auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1704 m_options.m_class_name.c_str()); 1705 if (!cmd_obj_sp) { 1706 result.AppendError("cannot create helper object"); 1707 result.SetStatus(eReturnStatusFailed); 1708 return false; 1709 } 1710 1711 CommandObjectSP new_cmd(new CommandObjectScriptingObject( 1712 m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1713 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1714 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1715 } else { 1716 result.AppendError("cannot add command"); 1717 result.SetStatus(eReturnStatusFailed); 1718 } 1719 } 1720 1721 return result.Succeeded(); 1722 } 1723 1724 CommandOptions m_options; 1725 std::string m_cmd_name; 1726 std::string m_short_help; 1727 ScriptedCommandSynchronicity m_synchronicity; 1728 }; 1729 1730 // CommandObjectCommandsScriptList 1731 1732 class CommandObjectCommandsScriptList : public CommandObjectParsed { 1733 public: 1734 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1735 : CommandObjectParsed(interpreter, "command script list", 1736 "List defined scripted commands.", nullptr) {} 1737 1738 ~CommandObjectCommandsScriptList() override = default; 1739 1740 bool DoExecute(Args &command, CommandReturnObject &result) override { 1741 m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1742 1743 result.SetStatus(eReturnStatusSuccessFinishResult); 1744 1745 return true; 1746 } 1747 }; 1748 1749 // CommandObjectCommandsScriptClear 1750 1751 class CommandObjectCommandsScriptClear : public CommandObjectParsed { 1752 public: 1753 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1754 : CommandObjectParsed(interpreter, "command script clear", 1755 "Delete all scripted commands.", nullptr) {} 1756 1757 ~CommandObjectCommandsScriptClear() override = default; 1758 1759 protected: 1760 bool DoExecute(Args &command, CommandReturnObject &result) override { 1761 m_interpreter.RemoveAllUser(); 1762 1763 result.SetStatus(eReturnStatusSuccessFinishResult); 1764 1765 return true; 1766 } 1767 }; 1768 1769 // CommandObjectCommandsScriptDelete 1770 1771 class CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1772 public: 1773 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1774 : CommandObjectParsed(interpreter, "command script delete", 1775 "Delete a scripted command.", nullptr) { 1776 CommandArgumentEntry arg1; 1777 CommandArgumentData cmd_arg; 1778 1779 // Define the first (and only) variant of this arg. 1780 cmd_arg.arg_type = eArgTypeCommandName; 1781 cmd_arg.arg_repetition = eArgRepeatPlain; 1782 1783 // There is only one variant this argument could be; put it into the 1784 // argument entry. 1785 arg1.push_back(cmd_arg); 1786 1787 // Push the data for the first argument into the m_arguments vector. 1788 m_arguments.push_back(arg1); 1789 } 1790 1791 ~CommandObjectCommandsScriptDelete() override = default; 1792 1793 protected: 1794 bool DoExecute(Args &command, CommandReturnObject &result) override { 1795 1796 if (command.GetArgumentCount() != 1) { 1797 result.AppendError("'command script delete' requires one argument"); 1798 result.SetStatus(eReturnStatusFailed); 1799 return false; 1800 } 1801 1802 auto cmd_name = command[0].ref; 1803 1804 if (cmd_name.empty() || !m_interpreter.HasUserCommands() || 1805 !m_interpreter.UserCommandExists(cmd_name)) { 1806 result.AppendErrorWithFormat("command %s not found", command[0].c_str()); 1807 result.SetStatus(eReturnStatusFailed); 1808 return false; 1809 } 1810 1811 m_interpreter.RemoveUser(cmd_name); 1812 result.SetStatus(eReturnStatusSuccessFinishResult); 1813 return true; 1814 } 1815 }; 1816 1817 #pragma mark CommandObjectMultiwordCommandsScript 1818 1819 // CommandObjectMultiwordCommandsScript 1820 1821 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1822 public: 1823 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1824 : CommandObjectMultiword( 1825 interpreter, "command script", "Commands for managing custom " 1826 "commands implemented by " 1827 "interpreter scripts.", 1828 "command script <subcommand> [<subcommand-options>]") { 1829 LoadSubCommand("add", CommandObjectSP( 1830 new CommandObjectCommandsScriptAdd(interpreter))); 1831 LoadSubCommand( 1832 "delete", 1833 CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1834 LoadSubCommand( 1835 "clear", 1836 CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1837 LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1838 interpreter))); 1839 LoadSubCommand( 1840 "import", 1841 CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1842 } 1843 1844 ~CommandObjectMultiwordCommandsScript() override = default; 1845 }; 1846 1847 #pragma mark CommandObjectMultiwordCommands 1848 1849 // CommandObjectMultiwordCommands 1850 1851 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 1852 CommandInterpreter &interpreter) 1853 : CommandObjectMultiword(interpreter, "command", 1854 "Commands for managing custom LLDB commands.", 1855 "command <subcommand> [<subcommand-options>]") { 1856 LoadSubCommand("source", 1857 CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 1858 LoadSubCommand("alias", 1859 CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 1860 LoadSubCommand("unalias", CommandObjectSP( 1861 new CommandObjectCommandsUnalias(interpreter))); 1862 LoadSubCommand("delete", 1863 CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 1864 LoadSubCommand( 1865 "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 1866 LoadSubCommand("history", CommandObjectSP( 1867 new CommandObjectCommandsHistory(interpreter))); 1868 LoadSubCommand( 1869 "script", 1870 CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 1871 } 1872 1873 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 1874