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