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 // Project includes 16 #include "lldb/Interpreter/Args.h" 17 #include "lldb/Core/Debugger.h" 18 #include "lldb/Interpreter/CommandInterpreter.h" 19 #include "lldb/Interpreter/CommandReturnObject.h" 20 #include "lldb/Interpreter/Options.h" 21 22 using namespace lldb; 23 using namespace lldb_private; 24 25 //------------------------------------------------------------------------- 26 // CommandObjectCommandsSource 27 //------------------------------------------------------------------------- 28 29 class CommandObjectCommandsSource : public CommandObject 30 { 31 private: 32 33 class CommandOptions : public Options 34 { 35 public: 36 37 CommandOptions (CommandInterpreter &interpreter) : 38 Options (interpreter) 39 { 40 } 41 42 virtual 43 ~CommandOptions (){} 44 45 virtual Error 46 SetOptionValue (uint32_t option_idx, const char *option_arg) 47 { 48 Error error; 49 char short_option = (char) m_getopt_table[option_idx].val; 50 bool success; 51 52 switch (short_option) 53 { 54 case 'e': 55 m_stop_on_error = Args::StringToBoolean(option_arg, true, &success); 56 if (!success) 57 error.SetErrorStringWithFormat("Invalid value for stop-on-error: %s.\n", option_arg); 58 break; 59 case 'c': 60 m_stop_on_continue = Args::StringToBoolean(option_arg, true, &success); 61 if (!success) 62 error.SetErrorStringWithFormat("Invalid value for stop-on-continue: %s.\n", option_arg); 63 break; 64 default: 65 error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); 66 break; 67 } 68 69 return error; 70 } 71 72 void 73 OptionParsingStarting () 74 { 75 m_stop_on_error = true; 76 m_stop_on_continue = true; 77 } 78 79 const OptionDefinition* 80 GetDefinitions () 81 { 82 return g_option_table; 83 } 84 85 // Options table: Required for subclasses of Options. 86 87 static OptionDefinition g_option_table[]; 88 89 // Instance variables to hold the values for command options. 90 91 bool m_stop_on_error; 92 bool m_stop_on_continue; 93 }; 94 95 // Options table: Required for subclasses of Options. 96 97 static OptionDefinition g_option_table[]; 98 99 CommandOptions m_options; 100 101 virtual Options * 102 GetOptions () 103 { 104 return &m_options; 105 } 106 107 public: 108 CommandObjectCommandsSource(CommandInterpreter &interpreter) : 109 CommandObject (interpreter, 110 "commands source", 111 "Read in debugger commands from the file <filename> and execute them.", 112 NULL), 113 m_options (interpreter) 114 { 115 CommandArgumentEntry arg; 116 CommandArgumentData file_arg; 117 118 // Define the first (and only) variant of this arg. 119 file_arg.arg_type = eArgTypeFilename; 120 file_arg.arg_repetition = eArgRepeatPlain; 121 122 // There is only one variant this argument could be; put it into the argument entry. 123 arg.push_back (file_arg); 124 125 // Push the data for the first argument into the m_arguments vector. 126 m_arguments.push_back (arg); 127 } 128 129 ~CommandObjectCommandsSource () 130 { 131 } 132 133 bool 134 Execute 135 ( 136 Args& args, 137 CommandReturnObject &result 138 ) 139 { 140 const int argc = args.GetArgumentCount(); 141 if (argc == 1) 142 { 143 const char *filename = args.GetArgumentAtIndex(0); 144 145 result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename); 146 147 FileSpec cmd_file (filename, true); 148 ExecutionContext *exe_ctx = NULL; // Just use the default context. 149 bool echo_commands = true; 150 bool print_results = true; 151 152 m_interpreter.HandleCommandsFromFile (cmd_file, 153 exe_ctx, 154 m_options.m_stop_on_continue, 155 m_options.m_stop_on_error, 156 echo_commands, 157 print_results, 158 result); 159 } 160 else 161 { 162 result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName()); 163 result.SetStatus (eReturnStatusFailed); 164 } 165 return result.Succeeded(); 166 167 } 168 }; 169 170 OptionDefinition 171 CommandObjectCommandsSource::CommandOptions::g_option_table[] = 172 { 173 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on error."}, 174 { LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on continue."}, 175 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 176 }; 177 178 #pragma mark CommandObjectCommandsAlias 179 //------------------------------------------------------------------------- 180 // CommandObjectCommandsAlias 181 //------------------------------------------------------------------------- 182 183 class CommandObjectCommandsAlias : public CommandObject 184 { 185 public: 186 CommandObjectCommandsAlias (CommandInterpreter &interpreter) : 187 CommandObject (interpreter, 188 "commands alias", 189 "Allow users to define their own debugger command abbreviations.", 190 NULL) 191 { 192 SetHelpLong( 193 "'alias' allows the user to create a short-cut or abbreviation for long \n\ 194 commands, multi-word commands, and commands that take particular options. \n\ 195 Below are some simple examples of how one might use the 'alias' command: \n\ 196 \n 'commands alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\ 197 // command. \n\ 198 'commands alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\ 199 // command. Since breakpoint commands are two-word \n\ 200 // commands, the user will still need to enter the \n\ 201 // second word after 'bp', e.g. 'bp enable' or \n\ 202 // 'bp delete'. \n\ 203 'commands alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\ 204 // two-word command 'breakpoint list'. \n\ 205 \nAn alias can include some options for the command, with the values either \n\ 206 filled in at the time the alias is created, or specified as positional \n\ 207 arguments, to be filled in when the alias is invoked. The following example \n\ 208 shows how to create aliases with options: \n\ 209 \n\ 210 'commands alias bfl breakpoint set -f %1 -l %2' \n\ 211 \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\ 212 options already part of the alias. So if the user wants to set a breakpoint \n\ 213 by file and line without explicitly having to use the -f and -l options, the \n\ 214 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\ 215 for the actual arguments that will be passed when the alias command is used. \n\ 216 The number in the placeholder refers to the position/order the actual value \n\ 217 occupies when the alias is used. So all the occurrences of '%1' in the alias \n\ 218 will be replaced with the first argument, all the occurrences of '%2' in the \n\ 219 alias will be replaced with the second argument, and so on. This also allows \n\ 220 actual arguments to be used multiple times within an alias (see 'process \n\ 221 launch' example below). So in the 'bfl' case, the actual file value will be \n\ 222 filled in with the first argument following 'bfl' and the actual line number \n\ 223 value will be filled in with the second argument. The user would use this \n\ 224 alias as follows: \n\ 225 \n (lldb) commands alias bfl breakpoint set -f %1 -l %2 \n\ 226 <... some time later ...> \n\ 227 (lldb) bfl my-file.c 137 \n\ 228 \nThis would be the same as if the user had entered \n\ 229 'breakpoint set -f my-file.c -l 137'. \n\ 230 \nAnother example: \n\ 231 \n (lldb) commands alias pltty process launch -s -o %1 -e %1 \n\ 232 (lldb) pltty /dev/tty0 \n\ 233 // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\ 234 \nIf the user always wanted to pass the same value to a particular option, the \n\ 235 alias could be defined with that value directly in the alias as a constant, \n\ 236 rather than using a positional placeholder: \n\ 237 \n commands alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\ 238 // 3 of whatever file is indicated. \n"); 239 240 CommandArgumentEntry arg1; 241 CommandArgumentEntry arg2; 242 CommandArgumentEntry arg3; 243 CommandArgumentData alias_arg; 244 CommandArgumentData cmd_arg; 245 CommandArgumentData options_arg; 246 247 // Define the first (and only) variant of this arg. 248 alias_arg.arg_type = eArgTypeAliasName; 249 alias_arg.arg_repetition = eArgRepeatPlain; 250 251 // There is only one variant this argument could be; put it into the argument entry. 252 arg1.push_back (alias_arg); 253 254 // Define the first (and only) variant of this arg. 255 cmd_arg.arg_type = eArgTypeCommandName; 256 cmd_arg.arg_repetition = eArgRepeatPlain; 257 258 // There is only one variant this argument could be; put it into the argument entry. 259 arg2.push_back (cmd_arg); 260 261 // Define the first (and only) variant of this arg. 262 options_arg.arg_type = eArgTypeAliasOptions; 263 options_arg.arg_repetition = eArgRepeatOptional; 264 265 // There is only one variant this argument could be; put it into the argument entry. 266 arg3.push_back (options_arg); 267 268 // Push the data for the first argument into the m_arguments vector. 269 m_arguments.push_back (arg1); 270 m_arguments.push_back (arg2); 271 m_arguments.push_back (arg3); 272 } 273 274 ~CommandObjectCommandsAlias () 275 { 276 } 277 278 bool 279 WantsRawCommandString () 280 { 281 return true; 282 } 283 284 bool 285 ExecuteRawCommandString (const char *raw_command_line, CommandReturnObject &result) 286 { 287 Args args (raw_command_line); 288 std::string raw_command_string (raw_command_line); 289 290 size_t argc = args.GetArgumentCount(); 291 292 if (argc < 2) 293 { 294 result.AppendError ("'alias' requires at least two arguments"); 295 result.SetStatus (eReturnStatusFailed); 296 return false; 297 } 298 299 // Get the alias command. 300 301 const std::string alias_command = args.GetArgumentAtIndex (0); 302 303 // Strip the new alias name off 'raw_command_string' (leave it on args, which gets passed to 'Execute', which 304 // does the stripping itself. 305 size_t pos = raw_command_string.find (alias_command); 306 if (pos == 0) 307 { 308 raw_command_string = raw_command_string.substr (alias_command.size()); 309 pos = raw_command_string.find_first_not_of (' '); 310 if ((pos != std::string::npos) && (pos > 0)) 311 raw_command_string = raw_command_string.substr (pos); 312 } 313 else 314 { 315 result.AppendError ("Error parsing command string. No alias created."); 316 result.SetStatus (eReturnStatusFailed); 317 return false; 318 } 319 320 321 // Verify that the command is alias-able. 322 if (m_interpreter.CommandExists (alias_command.c_str())) 323 { 324 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", 325 alias_command.c_str()); 326 result.SetStatus (eReturnStatusFailed); 327 return false; 328 } 329 330 // Get CommandObject that is being aliased. The command name is read from the front of raw_command_string. 331 // raw_command_string is returned with the name of the command object stripped off the front. 332 CommandObject *cmd_obj = m_interpreter.GetCommandObjectForCommand (raw_command_string); 333 334 if (!cmd_obj) 335 { 336 result.AppendErrorWithFormat ("Invalid command given to 'alias'. '%s' does not begin with a valid command." 337 " No alias created.", raw_command_string.c_str()); 338 result.SetStatus (eReturnStatusFailed); 339 return false; 340 } 341 else if (!cmd_obj->WantsRawCommandString ()) 342 { 343 // Note that args was initialized with the original command, and has not been updated to this point. 344 // Therefore can we pass it to the version of Execute that does not need/expect raw input in the alias. 345 return Execute (args, result); 346 } 347 else 348 { 349 // Verify & handle any options/arguments passed to the alias command 350 351 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); 352 OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); 353 354 // Check to see if there's anything left in the input command string. 355 if (raw_command_string.size() > 0) 356 { 357 358 // Check to see if the command being aliased can take any command options. 359 Options *options = cmd_obj->GetOptions(); 360 if (options) 361 { 362 // See if any options were specified as part of the alias; if so, handle them appropriately 363 options->NotifyOptionParsingStarting (); 364 Args tmp_args (raw_command_string.c_str()); 365 args.Unshift ("dummy_arg"); 366 args.ParseAliasOptions (*options, result, option_arg_vector, raw_command_string); 367 args.Shift (); 368 if (result.Succeeded()) 369 options->VerifyPartialOptions (result); 370 if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted) 371 { 372 result.AppendError ("Unable to create requested alias.\n"); 373 return false; 374 } 375 } 376 // Anything remaining must be plain raw input. Push it in as a single raw input argument. 377 if (raw_command_string.size() > 0) 378 option_arg_vector->push_back (OptionArgPair ("<argument>", 379 OptionArgValue (-1, 380 raw_command_string))); 381 } 382 383 // Create the alias 384 if (m_interpreter.AliasExists (alias_command.c_str()) 385 || m_interpreter.UserCommandExists (alias_command.c_str())) 386 { 387 OptionArgVectorSP temp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str())); 388 if (temp_option_arg_sp.get()) 389 { 390 if (option_arg_vector->size() == 0) 391 m_interpreter.RemoveAliasOptions (alias_command.c_str()); 392 } 393 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", 394 alias_command.c_str()); 395 } 396 397 CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false); 398 if (cmd_obj_sp) 399 { 400 m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp); 401 if (option_arg_vector->size() > 0) 402 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp); 403 result.SetStatus (eReturnStatusSuccessFinishNoResult); 404 } 405 else 406 { 407 result.AppendError ("Unable to create requested alias.\n"); 408 result.SetStatus (eReturnStatusFailed); 409 } 410 } 411 return result.Succeeded(); 412 } 413 414 bool 415 Execute 416 ( 417 Args& args, 418 CommandReturnObject &result 419 ) 420 { 421 size_t argc = args.GetArgumentCount(); 422 423 if (argc < 2) 424 { 425 result.AppendError ("'alias' requires at least two arguments"); 426 result.SetStatus (eReturnStatusFailed); 427 return false; 428 } 429 430 const std::string alias_command = args.GetArgumentAtIndex(0); 431 const std::string actual_command = args.GetArgumentAtIndex(1); 432 433 args.Shift(); // Shift the alias command word off the argument vector. 434 args.Shift(); // Shift the old command word off the argument vector. 435 436 // Verify that the command is alias'able, and get the appropriate command object. 437 438 if (m_interpreter.CommandExists (alias_command.c_str())) 439 { 440 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", 441 alias_command.c_str()); 442 result.SetStatus (eReturnStatusFailed); 443 } 444 else 445 { 446 CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true)); 447 CommandObjectSP subcommand_obj_sp; 448 bool use_subcommand = false; 449 if (command_obj_sp.get()) 450 { 451 CommandObject *cmd_obj = command_obj_sp.get(); 452 CommandObject *sub_cmd_obj = NULL; 453 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); 454 OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); 455 456 while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0) 457 { 458 if (argc >= 3) 459 { 460 const std::string sub_command = args.GetArgumentAtIndex(0); 461 assert (sub_command.length() != 0); 462 subcommand_obj_sp = 463 (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str())); 464 if (subcommand_obj_sp.get()) 465 { 466 sub_cmd_obj = subcommand_obj_sp.get(); 467 use_subcommand = true; 468 args.Shift(); // Shift the sub_command word off the argument vector. 469 cmd_obj = sub_cmd_obj; 470 } 471 else 472 { 473 result.AppendErrorWithFormat("'%s' is not a valid sub-command of '%s'. " 474 "Unable to create alias.\n", 475 sub_command.c_str(), actual_command.c_str()); 476 result.SetStatus (eReturnStatusFailed); 477 return false; 478 } 479 } 480 } 481 482 // Verify & handle any options/arguments passed to the alias command 483 484 if (args.GetArgumentCount () > 0) 485 { 486 if ((!use_subcommand && (cmd_obj->GetOptions() != NULL)) 487 || (use_subcommand && (sub_cmd_obj->GetOptions() != NULL))) 488 { 489 Options *options; 490 if (use_subcommand) 491 options = sub_cmd_obj->GetOptions(); 492 else 493 options = cmd_obj->GetOptions(); 494 options->NotifyOptionParsingStarting (); 495 std::string empty_string; 496 args.Unshift ("dummy_arg"); 497 args.ParseAliasOptions (*options, result, option_arg_vector, empty_string); 498 args.Shift (); 499 if (result.Succeeded()) 500 options->VerifyPartialOptions (result); 501 if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted) 502 { 503 result.AppendError ("Unable to create requested command alias.\n"); 504 return false; 505 } 506 } 507 508 // Anything remaining in args must be a plain argument. 509 510 argc = args.GetArgumentCount(); 511 for (size_t i = 0; i < argc; ++i) 512 if (strcmp (args.GetArgumentAtIndex (i), "") != 0) 513 option_arg_vector->push_back 514 (OptionArgPair ("<argument>", 515 OptionArgValue (-1, 516 std::string (args.GetArgumentAtIndex (i))))); 517 } 518 519 // Create the alias. 520 521 if (m_interpreter.AliasExists (alias_command.c_str()) 522 || m_interpreter.UserCommandExists (alias_command.c_str())) 523 { 524 OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str())); 525 if (tmp_option_arg_sp.get()) 526 { 527 if (option_arg_vector->size() == 0) 528 m_interpreter.RemoveAliasOptions (alias_command.c_str()); 529 } 530 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", 531 alias_command.c_str()); 532 } 533 534 if (use_subcommand) 535 m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp); 536 else 537 m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp); 538 if (option_arg_vector->size() > 0) 539 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp); 540 result.SetStatus (eReturnStatusSuccessFinishNoResult); 541 } 542 else 543 { 544 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str()); 545 result.SetStatus (eReturnStatusFailed); 546 return false; 547 } 548 } 549 550 return result.Succeeded(); 551 } 552 }; 553 554 #pragma mark CommandObjectCommandsUnalias 555 //------------------------------------------------------------------------- 556 // CommandObjectCommandsUnalias 557 //------------------------------------------------------------------------- 558 559 class CommandObjectCommandsUnalias : public CommandObject 560 { 561 public: 562 CommandObjectCommandsUnalias (CommandInterpreter &interpreter) : 563 CommandObject (interpreter, 564 "commands unalias", 565 "Allow the user to remove/delete a user-defined command abbreviation.", 566 NULL) 567 { 568 CommandArgumentEntry arg; 569 CommandArgumentData alias_arg; 570 571 // Define the first (and only) variant of this arg. 572 alias_arg.arg_type = eArgTypeAliasName; 573 alias_arg.arg_repetition = eArgRepeatPlain; 574 575 // There is only one variant this argument could be; put it into the argument entry. 576 arg.push_back (alias_arg); 577 578 // Push the data for the first argument into the m_arguments vector. 579 m_arguments.push_back (arg); 580 } 581 582 ~CommandObjectCommandsUnalias() 583 { 584 } 585 586 587 bool 588 Execute 589 ( 590 Args& args, 591 CommandReturnObject &result 592 ) 593 { 594 CommandObject::CommandMap::iterator pos; 595 CommandObject *cmd_obj; 596 597 if (args.GetArgumentCount() != 0) 598 { 599 const char *command_name = args.GetArgumentAtIndex(0); 600 cmd_obj = m_interpreter.GetCommandObject(command_name); 601 if (cmd_obj) 602 { 603 if (m_interpreter.CommandExists (command_name)) 604 { 605 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", 606 command_name); 607 result.SetStatus (eReturnStatusFailed); 608 } 609 else 610 { 611 612 if (m_interpreter.RemoveAlias (command_name) == false) 613 { 614 if (m_interpreter.AliasExists (command_name)) 615 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n", 616 command_name); 617 else 618 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name); 619 result.SetStatus (eReturnStatusFailed); 620 } 621 else 622 result.SetStatus (eReturnStatusSuccessFinishNoResult); 623 } 624 } 625 else 626 { 627 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a " 628 "current list of commands.\n", 629 command_name); 630 result.SetStatus (eReturnStatusFailed); 631 } 632 } 633 else 634 { 635 result.AppendError ("must call 'unalias' with a valid alias"); 636 result.SetStatus (eReturnStatusFailed); 637 } 638 639 return result.Succeeded(); 640 } 641 }; 642 643 #pragma mark CommandObjectMultiwordCommands 644 645 //------------------------------------------------------------------------- 646 // CommandObjectMultiwordCommands 647 //------------------------------------------------------------------------- 648 649 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) : 650 CommandObjectMultiword (interpreter, 651 "commands", 652 "A set of commands for managing or customizing the debugger commands.", 653 "commands <subcommand> [<subcommand-options>]") 654 { 655 LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter))); 656 LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter))); 657 LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter))); 658 } 659 660 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands () 661 { 662 } 663 664