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