1 //===-- CommandObjectSource.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 #include "CommandObjectCommands.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 #include "llvm/ADT/StringRef.h" 16 17 // Project includes 18 #include "lldb/Core/Debugger.h" 19 #include "lldb/Core/InputReader.h" 20 #include "lldb/Interpreter/Args.h" 21 #include "lldb/Interpreter/CommandInterpreter.h" 22 #include "lldb/Interpreter/CommandObjectRegexCommand.h" 23 #include "lldb/Interpreter/CommandReturnObject.h" 24 #include "lldb/Interpreter/Options.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 //------------------------------------------------------------------------- 30 // CommandObjectCommandsSource 31 //------------------------------------------------------------------------- 32 33 class CommandObjectCommandsHistory : public CommandObject 34 { 35 private: 36 37 class CommandOptions : public Options 38 { 39 public: 40 41 CommandOptions (CommandInterpreter &interpreter) : 42 Options (interpreter) 43 { 44 } 45 46 virtual 47 ~CommandOptions (){} 48 49 virtual Error 50 SetOptionValue (uint32_t option_idx, const char *option_arg) 51 { 52 Error error; 53 char short_option = (char) m_getopt_table[option_idx].val; 54 bool success; 55 56 switch (short_option) 57 { 58 case 'c': 59 m_end_idx = Args::StringToUInt32(option_arg, UINT_MAX, 0, &success); 60 if (!success) 61 error.SetErrorStringWithFormat("Invalid value for count: %s.\n", option_arg); 62 if (m_end_idx != 0) 63 m_end_idx--; 64 m_start_idx = 0; 65 break; 66 case 'e': 67 m_end_idx = Args::StringToUInt32(option_arg, 0, 0, &success); 68 if (!success) 69 error.SetErrorStringWithFormat("Invalid value for end index: %s.\n", option_arg); 70 break; 71 case 's': 72 m_start_idx = Args::StringToUInt32(option_arg, 0, 0, &success); 73 if (!success) 74 error.SetErrorStringWithFormat("Invalid value for start index: %s.\n", option_arg); 75 break; 76 default: 77 error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); 78 break; 79 } 80 81 return error; 82 } 83 84 void 85 OptionParsingStarting () 86 { 87 m_start_idx = 0; 88 m_end_idx = UINT_MAX; 89 } 90 91 const OptionDefinition* 92 GetDefinitions () 93 { 94 return g_option_table; 95 } 96 97 // Options table: Required for subclasses of Options. 98 99 static OptionDefinition g_option_table[]; 100 101 // Instance variables to hold the values for command options. 102 103 uint32_t m_start_idx; 104 uint32_t m_end_idx; 105 }; 106 107 CommandOptions m_options; 108 109 virtual Options * 110 GetOptions () 111 { 112 return &m_options; 113 } 114 115 public: 116 CommandObjectCommandsHistory(CommandInterpreter &interpreter) : 117 CommandObject (interpreter, 118 "command history", 119 "Dump the history of commands in this session.", 120 NULL), 121 m_options (interpreter) 122 { 123 } 124 125 ~CommandObjectCommandsHistory () 126 { 127 } 128 129 bool 130 Execute 131 ( 132 Args& args, 133 CommandReturnObject &result 134 ) 135 { 136 137 m_interpreter.DumpHistory (result.GetOutputStream(), 138 m_options.m_start_idx, 139 m_options.m_end_idx); 140 return result.Succeeded(); 141 142 } 143 }; 144 145 OptionDefinition 146 CommandObjectCommandsHistory::CommandOptions::g_option_table[] = 147 { 148 { LLDB_OPT_SET_1, false, "count", 'c', required_argument, NULL, 0, eArgTypeUnsignedInteger, "How many history commands to print."}, 149 { LLDB_OPT_SET_1, false, "start-index", 's', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands."}, 150 { LLDB_OPT_SET_1, false, "end-index", 'e', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands."}, 151 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 152 }; 153 154 155 //------------------------------------------------------------------------- 156 // CommandObjectCommandsSource 157 //------------------------------------------------------------------------- 158 159 class CommandObjectCommandsSource : public CommandObject 160 { 161 private: 162 163 class CommandOptions : public Options 164 { 165 public: 166 167 CommandOptions (CommandInterpreter &interpreter) : 168 Options (interpreter) 169 { 170 } 171 172 virtual 173 ~CommandOptions (){} 174 175 virtual Error 176 SetOptionValue (uint32_t option_idx, const char *option_arg) 177 { 178 Error error; 179 char short_option = (char) m_getopt_table[option_idx].val; 180 bool success; 181 182 switch (short_option) 183 { 184 case 'e': 185 m_stop_on_error = Args::StringToBoolean(option_arg, true, &success); 186 if (!success) 187 error.SetErrorStringWithFormat("Invalid value for stop-on-error: %s.\n", option_arg); 188 break; 189 case 'c': 190 m_stop_on_continue = Args::StringToBoolean(option_arg, true, &success); 191 if (!success) 192 error.SetErrorStringWithFormat("Invalid value for stop-on-continue: %s.\n", option_arg); 193 break; 194 default: 195 error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); 196 break; 197 } 198 199 return error; 200 } 201 202 void 203 OptionParsingStarting () 204 { 205 m_stop_on_error = true; 206 m_stop_on_continue = true; 207 } 208 209 const OptionDefinition* 210 GetDefinitions () 211 { 212 return g_option_table; 213 } 214 215 // Options table: Required for subclasses of Options. 216 217 static OptionDefinition g_option_table[]; 218 219 // Instance variables to hold the values for command options. 220 221 bool m_stop_on_error; 222 bool m_stop_on_continue; 223 }; 224 225 CommandOptions m_options; 226 227 virtual Options * 228 GetOptions () 229 { 230 return &m_options; 231 } 232 233 public: 234 CommandObjectCommandsSource(CommandInterpreter &interpreter) : 235 CommandObject (interpreter, 236 "command source", 237 "Read in debugger commands from the file <filename> and execute them.", 238 NULL), 239 m_options (interpreter) 240 { 241 CommandArgumentEntry arg; 242 CommandArgumentData file_arg; 243 244 // Define the first (and only) variant of this arg. 245 file_arg.arg_type = eArgTypeFilename; 246 file_arg.arg_repetition = eArgRepeatPlain; 247 248 // There is only one variant this argument could be; put it into the argument entry. 249 arg.push_back (file_arg); 250 251 // Push the data for the first argument into the m_arguments vector. 252 m_arguments.push_back (arg); 253 } 254 255 ~CommandObjectCommandsSource () 256 { 257 } 258 259 bool 260 Execute 261 ( 262 Args& args, 263 CommandReturnObject &result 264 ) 265 { 266 const int argc = args.GetArgumentCount(); 267 if (argc == 1) 268 { 269 const char *filename = args.GetArgumentAtIndex(0); 270 271 result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename); 272 273 FileSpec cmd_file (filename, true); 274 ExecutionContext *exe_ctx = NULL; // Just use the default context. 275 bool echo_commands = true; 276 bool print_results = true; 277 278 m_interpreter.HandleCommandsFromFile (cmd_file, 279 exe_ctx, 280 m_options.m_stop_on_continue, 281 m_options.m_stop_on_error, 282 echo_commands, 283 print_results, 284 result); 285 } 286 else 287 { 288 result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName()); 289 result.SetStatus (eReturnStatusFailed); 290 } 291 return result.Succeeded(); 292 293 } 294 }; 295 296 OptionDefinition 297 CommandObjectCommandsSource::CommandOptions::g_option_table[] = 298 { 299 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on error."}, 300 { LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on continue."}, 301 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 302 }; 303 304 #pragma mark CommandObjectCommandsAlias 305 //------------------------------------------------------------------------- 306 // CommandObjectCommandsAlias 307 //------------------------------------------------------------------------- 308 309 class CommandObjectCommandsAlias : public CommandObject 310 { 311 public: 312 CommandObjectCommandsAlias (CommandInterpreter &interpreter) : 313 CommandObject (interpreter, 314 "command alias", 315 "Allow users to define their own debugger command abbreviations.", 316 NULL) 317 { 318 SetHelpLong( 319 "'alias' allows the user to create a short-cut or abbreviation for long \n\ 320 commands, multi-word commands, and commands that take particular options. \n\ 321 Below are some simple examples of how one might use the 'alias' command: \n\ 322 \n 'commands alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\ 323 // command. \n\ 324 'commands alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\ 325 // command. Since breakpoint commands are two-word \n\ 326 // commands, the user will still need to enter the \n\ 327 // second word after 'bp', e.g. 'bp enable' or \n\ 328 // 'bp delete'. \n\ 329 'commands alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\ 330 // two-word command 'breakpoint list'. \n\ 331 \nAn alias can include some options for the command, with the values either \n\ 332 filled in at the time the alias is created, or specified as positional \n\ 333 arguments, to be filled in when the alias is invoked. The following example \n\ 334 shows how to create aliases with options: \n\ 335 \n\ 336 'commands alias bfl breakpoint set -f %1 -l %2' \n\ 337 \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\ 338 options already part of the alias. So if the user wants to set a breakpoint \n\ 339 by file and line without explicitly having to use the -f and -l options, the \n\ 340 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\ 341 for the actual arguments that will be passed when the alias command is used. \n\ 342 The number in the placeholder refers to the position/order the actual value \n\ 343 occupies when the alias is used. So all the occurrences of '%1' in the alias \n\ 344 will be replaced with the first argument, all the occurrences of '%2' in the \n\ 345 alias will be replaced with the second argument, and so on. This also allows \n\ 346 actual arguments to be used multiple times within an alias (see 'process \n\ 347 launch' example below). So in the 'bfl' case, the actual file value will be \n\ 348 filled in with the first argument following 'bfl' and the actual line number \n\ 349 value will be filled in with the second argument. The user would use this \n\ 350 alias as follows: \n\ 351 \n (lldb) commands alias bfl breakpoint set -f %1 -l %2 \n\ 352 <... some time later ...> \n\ 353 (lldb) bfl my-file.c 137 \n\ 354 \nThis would be the same as if the user had entered \n\ 355 'breakpoint set -f my-file.c -l 137'. \n\ 356 \nAnother example: \n\ 357 \n (lldb) commands alias pltty process launch -s -o %1 -e %1 \n\ 358 (lldb) pltty /dev/tty0 \n\ 359 // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\ 360 \nIf the user always wanted to pass the same value to a particular option, the \n\ 361 alias could be defined with that value directly in the alias as a constant, \n\ 362 rather than using a positional placeholder: \n\ 363 \n commands alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\ 364 // 3 of whatever file is indicated. \n"); 365 366 CommandArgumentEntry arg1; 367 CommandArgumentEntry arg2; 368 CommandArgumentEntry arg3; 369 CommandArgumentData alias_arg; 370 CommandArgumentData cmd_arg; 371 CommandArgumentData options_arg; 372 373 // Define the first (and only) variant of this arg. 374 alias_arg.arg_type = eArgTypeAliasName; 375 alias_arg.arg_repetition = eArgRepeatPlain; 376 377 // There is only one variant this argument could be; put it into the argument entry. 378 arg1.push_back (alias_arg); 379 380 // Define the first (and only) variant of this arg. 381 cmd_arg.arg_type = eArgTypeCommandName; 382 cmd_arg.arg_repetition = eArgRepeatPlain; 383 384 // There is only one variant this argument could be; put it into the argument entry. 385 arg2.push_back (cmd_arg); 386 387 // Define the first (and only) variant of this arg. 388 options_arg.arg_type = eArgTypeAliasOptions; 389 options_arg.arg_repetition = eArgRepeatOptional; 390 391 // There is only one variant this argument could be; put it into the argument entry. 392 arg3.push_back (options_arg); 393 394 // Push the data for the first argument into the m_arguments vector. 395 m_arguments.push_back (arg1); 396 m_arguments.push_back (arg2); 397 m_arguments.push_back (arg3); 398 } 399 400 ~CommandObjectCommandsAlias () 401 { 402 } 403 404 bool 405 WantsRawCommandString () 406 { 407 return true; 408 } 409 410 bool 411 ExecuteRawCommandString (const char *raw_command_line, CommandReturnObject &result) 412 { 413 Args args (raw_command_line); 414 std::string raw_command_string (raw_command_line); 415 416 size_t argc = args.GetArgumentCount(); 417 418 if (argc < 2) 419 { 420 result.AppendError ("'alias' requires at least two arguments"); 421 result.SetStatus (eReturnStatusFailed); 422 return false; 423 } 424 425 // Get the alias command. 426 427 const std::string alias_command = args.GetArgumentAtIndex (0); 428 429 // Strip the new alias name off 'raw_command_string' (leave it on args, which gets passed to 'Execute', which 430 // does the stripping itself. 431 size_t pos = raw_command_string.find (alias_command); 432 if (pos == 0) 433 { 434 raw_command_string = raw_command_string.substr (alias_command.size()); 435 pos = raw_command_string.find_first_not_of (' '); 436 if ((pos != std::string::npos) && (pos > 0)) 437 raw_command_string = raw_command_string.substr (pos); 438 } 439 else 440 { 441 result.AppendError ("Error parsing command string. No alias created."); 442 result.SetStatus (eReturnStatusFailed); 443 return false; 444 } 445 446 447 // Verify that the command is alias-able. 448 if (m_interpreter.CommandExists (alias_command.c_str())) 449 { 450 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", 451 alias_command.c_str()); 452 result.SetStatus (eReturnStatusFailed); 453 return false; 454 } 455 456 // Get CommandObject that is being aliased. The command name is read from the front of raw_command_string. 457 // raw_command_string is returned with the name of the command object stripped off the front. 458 CommandObject *cmd_obj = m_interpreter.GetCommandObjectForCommand (raw_command_string); 459 460 if (!cmd_obj) 461 { 462 result.AppendErrorWithFormat ("Invalid command given to 'alias'. '%s' does not begin with a valid command." 463 " No alias created.", raw_command_string.c_str()); 464 result.SetStatus (eReturnStatusFailed); 465 return false; 466 } 467 else if (!cmd_obj->WantsRawCommandString ()) 468 { 469 // Note that args was initialized with the original command, and has not been updated to this point. 470 // Therefore can we pass it to the version of Execute that does not need/expect raw input in the alias. 471 return Execute (args, result); 472 } 473 else 474 { 475 // Verify & handle any options/arguments passed to the alias command 476 477 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); 478 OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); 479 480 CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false); 481 482 if (!m_interpreter.ProcessAliasOptionsArgs (cmd_obj_sp, raw_command_string.c_str(), option_arg_vector_sp)) 483 { 484 result.AppendError ("Unable to create requested alias.\n"); 485 result.SetStatus (eReturnStatusFailed); 486 return false; 487 } 488 489 // Create the alias 490 if (m_interpreter.AliasExists (alias_command.c_str()) 491 || m_interpreter.UserCommandExists (alias_command.c_str())) 492 { 493 OptionArgVectorSP temp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str())); 494 if (temp_option_arg_sp.get()) 495 { 496 if (option_arg_vector->size() == 0) 497 m_interpreter.RemoveAliasOptions (alias_command.c_str()); 498 } 499 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", 500 alias_command.c_str()); 501 } 502 503 if (cmd_obj_sp) 504 { 505 m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp); 506 if (option_arg_vector->size() > 0) 507 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp); 508 result.SetStatus (eReturnStatusSuccessFinishNoResult); 509 } 510 else 511 { 512 result.AppendError ("Unable to create requested alias.\n"); 513 result.SetStatus (eReturnStatusFailed); 514 } 515 } 516 return result.Succeeded(); 517 } 518 519 bool 520 Execute 521 ( 522 Args& args, 523 CommandReturnObject &result 524 ) 525 { 526 size_t argc = args.GetArgumentCount(); 527 528 if (argc < 2) 529 { 530 result.AppendError ("'alias' requires at least two arguments"); 531 result.SetStatus (eReturnStatusFailed); 532 return false; 533 } 534 535 const std::string alias_command = args.GetArgumentAtIndex(0); 536 const std::string actual_command = args.GetArgumentAtIndex(1); 537 538 args.Shift(); // Shift the alias command word off the argument vector. 539 args.Shift(); // Shift the old command word off the argument vector. 540 541 // Verify that the command is alias'able, and get the appropriate command object. 542 543 if (m_interpreter.CommandExists (alias_command.c_str())) 544 { 545 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", 546 alias_command.c_str()); 547 result.SetStatus (eReturnStatusFailed); 548 } 549 else 550 { 551 CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true)); 552 CommandObjectSP subcommand_obj_sp; 553 bool use_subcommand = false; 554 if (command_obj_sp.get()) 555 { 556 CommandObject *cmd_obj = command_obj_sp.get(); 557 CommandObject *sub_cmd_obj = NULL; 558 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); 559 OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); 560 561 while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0) 562 { 563 if (argc >= 3) 564 { 565 const std::string sub_command = args.GetArgumentAtIndex(0); 566 assert (sub_command.length() != 0); 567 subcommand_obj_sp = 568 (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str())); 569 if (subcommand_obj_sp.get()) 570 { 571 sub_cmd_obj = subcommand_obj_sp.get(); 572 use_subcommand = true; 573 args.Shift(); // Shift the sub_command word off the argument vector. 574 cmd_obj = sub_cmd_obj; 575 } 576 else 577 { 578 result.AppendErrorWithFormat("'%s' is not a valid sub-command of '%s'. " 579 "Unable to create alias.\n", 580 sub_command.c_str(), actual_command.c_str()); 581 result.SetStatus (eReturnStatusFailed); 582 return false; 583 } 584 } 585 } 586 587 // Verify & handle any options/arguments passed to the alias command 588 589 if (args.GetArgumentCount () > 0) 590 { 591 CommandObjectSP tmp_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false); 592 if (use_subcommand) 593 tmp_sp = m_interpreter.GetCommandSPExact (sub_cmd_obj->GetCommandName(), false); 594 595 std::string args_string; 596 args.GetCommandString (args_string); 597 598 if (!m_interpreter.ProcessAliasOptionsArgs (tmp_sp, args_string.c_str(), option_arg_vector_sp)) 599 { 600 result.AppendError ("Unable to create requested alias.\n"); 601 result.SetStatus (eReturnStatusFailed); 602 return false; 603 } 604 } 605 606 // Create the alias. 607 608 if (m_interpreter.AliasExists (alias_command.c_str()) 609 || m_interpreter.UserCommandExists (alias_command.c_str())) 610 { 611 OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str())); 612 if (tmp_option_arg_sp.get()) 613 { 614 if (option_arg_vector->size() == 0) 615 m_interpreter.RemoveAliasOptions (alias_command.c_str()); 616 } 617 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", 618 alias_command.c_str()); 619 } 620 621 if (use_subcommand) 622 m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp); 623 else 624 m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp); 625 if (option_arg_vector->size() > 0) 626 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp); 627 result.SetStatus (eReturnStatusSuccessFinishNoResult); 628 } 629 else 630 { 631 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str()); 632 result.SetStatus (eReturnStatusFailed); 633 return false; 634 } 635 } 636 637 return result.Succeeded(); 638 } 639 }; 640 641 #pragma mark CommandObjectCommandsUnalias 642 //------------------------------------------------------------------------- 643 // CommandObjectCommandsUnalias 644 //------------------------------------------------------------------------- 645 646 class CommandObjectCommandsUnalias : public CommandObject 647 { 648 public: 649 CommandObjectCommandsUnalias (CommandInterpreter &interpreter) : 650 CommandObject (interpreter, 651 "command unalias", 652 "Allow the user to remove/delete a user-defined command abbreviation.", 653 NULL) 654 { 655 CommandArgumentEntry arg; 656 CommandArgumentData alias_arg; 657 658 // Define the first (and only) variant of this arg. 659 alias_arg.arg_type = eArgTypeAliasName; 660 alias_arg.arg_repetition = eArgRepeatPlain; 661 662 // There is only one variant this argument could be; put it into the argument entry. 663 arg.push_back (alias_arg); 664 665 // Push the data for the first argument into the m_arguments vector. 666 m_arguments.push_back (arg); 667 } 668 669 ~CommandObjectCommandsUnalias() 670 { 671 } 672 673 674 bool 675 Execute 676 ( 677 Args& args, 678 CommandReturnObject &result 679 ) 680 { 681 CommandObject::CommandMap::iterator pos; 682 CommandObject *cmd_obj; 683 684 if (args.GetArgumentCount() != 0) 685 { 686 const char *command_name = args.GetArgumentAtIndex(0); 687 cmd_obj = m_interpreter.GetCommandObject(command_name); 688 if (cmd_obj) 689 { 690 if (m_interpreter.CommandExists (command_name)) 691 { 692 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", 693 command_name); 694 result.SetStatus (eReturnStatusFailed); 695 } 696 else 697 { 698 699 if (m_interpreter.RemoveAlias (command_name) == false) 700 { 701 if (m_interpreter.AliasExists (command_name)) 702 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n", 703 command_name); 704 else 705 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name); 706 result.SetStatus (eReturnStatusFailed); 707 } 708 else 709 result.SetStatus (eReturnStatusSuccessFinishNoResult); 710 } 711 } 712 else 713 { 714 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a " 715 "current list of commands.\n", 716 command_name); 717 result.SetStatus (eReturnStatusFailed); 718 } 719 } 720 else 721 { 722 result.AppendError ("must call 'unalias' with a valid alias"); 723 result.SetStatus (eReturnStatusFailed); 724 } 725 726 return result.Succeeded(); 727 } 728 }; 729 730 #pragma mark CommandObjectCommandsAddRegex 731 //------------------------------------------------------------------------- 732 // CommandObjectCommandsAddRegex 733 //------------------------------------------------------------------------- 734 735 class CommandObjectCommandsAddRegex : public CommandObject 736 { 737 public: 738 CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) : 739 CommandObject (interpreter, 740 "command regex", 741 "Allow the user to create a regular expression command.", 742 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 743 m_options (interpreter) 744 { 745 SetHelpLong( 746 "This command allows the user to create powerful regular expression commands\n" 747 "with substitutions. The regular expressions and substitutions are specified\n" 748 "using the regular exression substitution format of:\n" 749 "\n" 750 " s/<regex>/<subst>/\n" 751 "\n" 752 "<regex> is a regular expression that can use parenthesis to capture regular\n" 753 "expression input and substitute the captured matches in the output using %1\n" 754 "for the first match, %2 for the second, and so on.\n" 755 "\n" 756 "The regular expressions can all be specified on the command line if more than\n" 757 "one argument is provided. If just the command name is provided on the command\n" 758 "line, then the regular expressions and substitutions can be entered on separate\n" 759 " lines, followed by an empty line to terminate the command definition.\n" 760 "\n" 761 "EXAMPLES\n" 762 "\n" 763 "The following example with define a regular expression command named 'f' that\n" 764 "will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if\n" 765 "a number follows 'f':\n" 766 "(lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/'\n" 767 ); 768 } 769 770 ~CommandObjectCommandsAddRegex() 771 { 772 } 773 774 775 bool 776 Execute (Args& args, CommandReturnObject &result) 777 { 778 const size_t argc = args.GetArgumentCount(); 779 if (argc == 0) 780 { 781 result.AppendError ("usage: 'commands regex <command-name> [s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 782 result.SetStatus (eReturnStatusFailed); 783 } 784 else 785 { 786 Error error; 787 const char *name = args.GetArgumentAtIndex(0); 788 m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter, 789 name, 790 m_options.GetHelp (), 791 m_options.GetSyntax (), 792 10)); 793 794 if (argc == 1) 795 { 796 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); 797 if (reader_sp) 798 { 799 error =reader_sp->Initialize (CommandObjectCommandsAddRegex::InputReaderCallback, 800 this, // baton 801 eInputReaderGranularityLine, // token size, to pass to callback function 802 NULL, // end token 803 "> ", // prompt 804 true); // echo input 805 if (error.Success()) 806 { 807 m_interpreter.GetDebugger().PushInputReader (reader_sp); 808 result.SetStatus (eReturnStatusSuccessFinishNoResult); 809 return true; 810 } 811 } 812 } 813 else 814 { 815 for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx) 816 { 817 llvm::StringRef arg_strref (args.GetArgumentAtIndex(arg_idx)); 818 error = AppendRegexSubstitution (arg_strref); 819 if (error.Fail()) 820 break; 821 } 822 823 if (error.Success()) 824 { 825 AddRegexCommandToInterpreter(); 826 } 827 } 828 if (error.Fail()) 829 { 830 result.AppendError (error.AsCString()); 831 result.SetStatus (eReturnStatusFailed); 832 } 833 } 834 835 return result.Succeeded(); 836 } 837 838 Error 839 AppendRegexSubstitution (const llvm::StringRef ®ex_sed) 840 { 841 Error error; 842 843 if (m_regex_cmd_ap.get() == NULL) 844 { 845 error.SetErrorStringWithFormat("invalid regular expression command object for: '%.*s'", 846 (int)regex_sed.size(), 847 regex_sed.data()); 848 return error; 849 } 850 851 size_t regex_sed_size = regex_sed.size(); 852 853 if (regex_sed_size <= 1) 854 { 855 error.SetErrorStringWithFormat("regular expression substitution string is too short: '%.*s'", 856 (int)regex_sed.size(), 857 regex_sed.data()); 858 return error; 859 } 860 861 if (regex_sed[0] != 's') 862 { 863 error.SetErrorStringWithFormat("regular expression substitution string doesn't start with 's': '%.*s'", 864 (int)regex_sed.size(), 865 regex_sed.data()); 866 return error; 867 } 868 const size_t first_separator_char_pos = 1; 869 // use the char that follows 's' as the regex separator character 870 // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 871 const char separator_char = regex_sed[first_separator_char_pos]; 872 const size_t second_separator_char_pos = regex_sed.find (separator_char, first_separator_char_pos + 1); 873 874 if (second_separator_char_pos == std::string::npos) 875 { 876 error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s'", 877 separator_char, 878 (int)(regex_sed.size() - first_separator_char_pos - 1), 879 regex_sed.data() + (first_separator_char_pos + 1)); 880 return error; 881 } 882 883 const size_t third_separator_char_pos = regex_sed.find (separator_char, second_separator_char_pos + 1); 884 885 if (third_separator_char_pos == std::string::npos) 886 { 887 error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s'", 888 separator_char, 889 (int)(regex_sed.size() - second_separator_char_pos - 1), 890 regex_sed.data() + (second_separator_char_pos + 1)); 891 return error; 892 } 893 894 if (third_separator_char_pos != regex_sed_size - 1) 895 { 896 // Make sure that everything that follows the last regex 897 // separator char 898 if (regex_sed.find_first_not_of("\t\n\v\f\r ", third_separator_char_pos + 1) != std::string::npos) 899 { 900 error.SetErrorStringWithFormat("extra data found after the '%.*s' regular expression substitution string: '%.*s'", 901 (int)third_separator_char_pos + 1, 902 regex_sed.data(), 903 (int)(regex_sed.size() - third_separator_char_pos - 1), 904 regex_sed.data() + (third_separator_char_pos + 1)); 905 return error; 906 } 907 908 } 909 else if (first_separator_char_pos + 1 == second_separator_char_pos) 910 { 911 error.SetErrorStringWithFormat("<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 912 separator_char, 913 separator_char, 914 separator_char, 915 (int)regex_sed.size(), 916 regex_sed.data()); 917 return error; 918 } 919 else if (second_separator_char_pos + 1 == third_separator_char_pos) 920 { 921 error.SetErrorStringWithFormat("<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 922 separator_char, 923 separator_char, 924 separator_char, 925 (int)regex_sed.size(), 926 regex_sed.data()); 927 return error; 928 } 929 std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1)); 930 std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1)); 931 m_regex_cmd_ap->AddRegexCommand (regex.c_str(), 932 subst.c_str()); 933 return error; 934 } 935 936 void 937 AddRegexCommandToInterpreter() 938 { 939 if (m_regex_cmd_ap.get()) 940 { 941 if (m_regex_cmd_ap->HasRegexEntries()) 942 { 943 CommandObjectSP cmd_sp (m_regex_cmd_ap.release()); 944 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 945 } 946 } 947 } 948 949 void 950 InputReaderDidCancel() 951 { 952 m_regex_cmd_ap.reset(); 953 } 954 955 static size_t 956 InputReaderCallback (void *baton, 957 InputReader &reader, 958 lldb::InputReaderAction notification, 959 const char *bytes, 960 size_t bytes_len); 961 private: 962 std::auto_ptr<CommandObjectRegexCommand> m_regex_cmd_ap; 963 964 class CommandOptions : public Options 965 { 966 public: 967 968 CommandOptions (CommandInterpreter &interpreter) : 969 Options (interpreter) 970 { 971 } 972 973 virtual 974 ~CommandOptions (){} 975 976 virtual Error 977 SetOptionValue (uint32_t option_idx, const char *option_arg) 978 { 979 Error error; 980 char short_option = (char) m_getopt_table[option_idx].val; 981 982 switch (short_option) 983 { 984 case 'h': 985 m_help.assign (option_arg); 986 break; 987 case 's': 988 m_syntax.assign (option_arg); 989 break; 990 991 default: 992 error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); 993 break; 994 } 995 996 return error; 997 } 998 999 void 1000 OptionParsingStarting () 1001 { 1002 m_help.clear(); 1003 m_syntax.clear(); 1004 } 1005 1006 const OptionDefinition* 1007 GetDefinitions () 1008 { 1009 return g_option_table; 1010 } 1011 1012 // Options table: Required for subclasses of Options. 1013 1014 static OptionDefinition g_option_table[]; 1015 1016 const char * 1017 GetHelp () 1018 { 1019 if (m_help.empty()) 1020 return NULL; 1021 return m_help.c_str(); 1022 } 1023 const char * 1024 GetSyntax () 1025 { 1026 if (m_syntax.empty()) 1027 return NULL; 1028 return m_syntax.c_str(); 1029 } 1030 // Instance variables to hold the values for command options. 1031 protected: 1032 std::string m_help; 1033 std::string m_syntax; 1034 }; 1035 1036 CommandOptions m_options; 1037 1038 virtual Options * 1039 GetOptions () 1040 { 1041 return &m_options; 1042 } 1043 1044 }; 1045 1046 size_t 1047 CommandObjectCommandsAddRegex::InputReaderCallback (void *baton, 1048 InputReader &reader, 1049 lldb::InputReaderAction notification, 1050 const char *bytes, 1051 size_t bytes_len) 1052 { 1053 CommandObjectCommandsAddRegex *add_regex_cmd = (CommandObjectCommandsAddRegex *) baton; 1054 bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); 1055 1056 switch (notification) 1057 { 1058 case eInputReaderActivate: 1059 if (!batch_mode) 1060 { 1061 StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream (); 1062 out_stream->Printf("%s\n", "Enter regular expressions in the form 's/<regex>/<subst>/' and terminate with an empty line:"); 1063 out_stream->Flush(); 1064 } 1065 break; 1066 case eInputReaderReactivate: 1067 break; 1068 1069 case eInputReaderDeactivate: 1070 break; 1071 1072 case eInputReaderAsynchronousOutputWritten: 1073 break; 1074 1075 case eInputReaderGotToken: 1076 while (bytes_len > 0 && (bytes[bytes_len-1] == '\r' || bytes[bytes_len-1] == '\n')) 1077 --bytes_len; 1078 if (bytes_len == 0) 1079 reader.SetIsDone(true); 1080 else if (bytes) 1081 { 1082 llvm::StringRef bytes_strref (bytes, bytes_len); 1083 Error error (add_regex_cmd->AppendRegexSubstitution (bytes_strref)); 1084 if (error.Fail()) 1085 { 1086 if (!batch_mode) 1087 { 1088 StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); 1089 out_stream->Printf("error: %s\n", error.AsCString()); 1090 out_stream->Flush(); 1091 } 1092 add_regex_cmd->InputReaderDidCancel (); 1093 reader.SetIsDone (true); 1094 } 1095 } 1096 break; 1097 1098 case eInputReaderInterrupt: 1099 { 1100 reader.SetIsDone (true); 1101 if (!batch_mode) 1102 { 1103 StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); 1104 out_stream->PutCString("Regular expression command creations was cancelled.\n"); 1105 out_stream->Flush(); 1106 } 1107 add_regex_cmd->InputReaderDidCancel (); 1108 } 1109 break; 1110 1111 case eInputReaderEndOfFile: 1112 reader.SetIsDone (true); 1113 break; 1114 1115 case eInputReaderDone: 1116 add_regex_cmd->AddRegexCommandToInterpreter(); 1117 break; 1118 } 1119 1120 return bytes_len; 1121 } 1122 1123 1124 OptionDefinition 1125 CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] = 1126 { 1127 { LLDB_OPT_SET_1, false, "help" , 'h', required_argument, NULL, 0, eArgTypeNone, "The help text to display for this command."}, 1128 { LLDB_OPT_SET_1, false, "syntax", 's', required_argument, NULL, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."}, 1129 { 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL } 1130 }; 1131 1132 1133 #pragma mark CommandObjectMultiwordCommands 1134 1135 //------------------------------------------------------------------------- 1136 // CommandObjectMultiwordCommands 1137 //------------------------------------------------------------------------- 1138 1139 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) : 1140 CommandObjectMultiword (interpreter, 1141 "command", 1142 "A set of commands for managing or customizing the debugger commands.", 1143 "command <subcommand> [<subcommand-options>]") 1144 { 1145 LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter))); 1146 LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter))); 1147 LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter))); 1148 LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter))); 1149 LoadSubCommand ("history", CommandObjectSP (new CommandObjectCommandsHistory (interpreter))); 1150 } 1151 1152 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands () 1153 { 1154 } 1155 1156