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