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