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 243 bool 244 Execute 245 ( 246 Args& args, 247 CommandReturnObject &result 248 ) 249 { 250 size_t argc = args.GetArgumentCount(); 251 252 if (argc < 2) 253 { 254 result.AppendError ("'alias' requires at least two arguments"); 255 result.SetStatus (eReturnStatusFailed); 256 return false; 257 } 258 259 const std::string alias_command = args.GetArgumentAtIndex(0); 260 const std::string actual_command = args.GetArgumentAtIndex(1); 261 262 args.Shift(); // Shift the alias command word off the argument vector. 263 args.Shift(); // Shift the old command word off the argument vector. 264 265 // Verify that the command is alias'able, and get the appropriate command object. 266 267 if (m_interpreter.CommandExists (alias_command.c_str())) 268 { 269 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", 270 alias_command.c_str()); 271 result.SetStatus (eReturnStatusFailed); 272 } 273 else 274 { 275 CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true)); 276 CommandObjectSP subcommand_obj_sp; 277 bool use_subcommand = false; 278 if (command_obj_sp.get()) 279 { 280 CommandObject *cmd_obj = command_obj_sp.get(); 281 CommandObject *sub_cmd_obj = NULL; 282 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); 283 OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); 284 285 if (cmd_obj->IsMultiwordObject()) 286 { 287 if (argc >= 3) 288 { 289 const std::string sub_command = args.GetArgumentAtIndex(0); 290 assert (sub_command.length() != 0); 291 subcommand_obj_sp = 292 (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str())); 293 if (subcommand_obj_sp.get()) 294 { 295 sub_cmd_obj = subcommand_obj_sp.get(); 296 use_subcommand = true; 297 args.Shift(); // Shift the sub_command word off the argument vector. 298 } 299 else 300 { 301 result.AppendErrorWithFormat ("Error occurred while attempting to look up command '%s %s'.\n", 302 alias_command.c_str(), sub_command.c_str()); 303 result.SetStatus (eReturnStatusFailed); 304 return false; 305 } 306 } 307 } 308 309 // Verify & handle any options/arguments passed to the alias command 310 311 if (args.GetArgumentCount () > 0) 312 { 313 //if ((!use_subcommand && (cmd_obj->WantsRawCommandString())) 314 // || (use_subcommand && (sub_cmd_obj->WantsRawCommandString()))) 315 //{ 316 // result.AppendErrorWithFormat ("'%s' cannot be aliased with any options or arguments.\n", 317 // (use_subcommand ? sub_cmd_obj->GetCommandName() 318 // : cmd_obj->GetCommandName())); 319 // result.SetStatus (eReturnStatusFailed); 320 // return false; 321 //} 322 323 // options or arguments have been passed to the alias command, and must be 324 // verified & processed here. 325 if ((!use_subcommand && (cmd_obj->GetOptions() != NULL)) 326 || (use_subcommand && (sub_cmd_obj->GetOptions() != NULL))) 327 { 328 Options *options; 329 if (use_subcommand) 330 options = sub_cmd_obj->GetOptions(); 331 else 332 options = cmd_obj->GetOptions(); 333 options->ResetOptionValues (); 334 args.Unshift ("dummy_arg"); 335 args.ParseAliasOptions (*options, result, option_arg_vector); 336 args.Shift (); 337 if (result.Succeeded()) 338 options->VerifyPartialOptions (result); 339 if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted) 340 { 341 result.AppendError ("Unable to create requested command alias.\n"); 342 } 343 } 344 345 // Anything remaining in args must be a plain argument. 346 347 argc = args.GetArgumentCount(); 348 for (size_t i = 0; i < argc; ++i) 349 if (strcmp (args.GetArgumentAtIndex (i), "") != 0) 350 option_arg_vector->push_back (OptionArgPair ("<argument>", 351 std::string (args.GetArgumentAtIndex (i)))); 352 } 353 354 // Create the alias. 355 356 if (m_interpreter.AliasExists (alias_command.c_str()) 357 || m_interpreter.UserCommandExists (alias_command.c_str())) 358 { 359 OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str())); 360 if (tmp_option_arg_sp.get()) 361 { 362 if (option_arg_vector->size() == 0) 363 m_interpreter.RemoveAliasOptions (alias_command.c_str()); 364 } 365 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", 366 alias_command.c_str()); 367 } 368 369 if (use_subcommand) 370 m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp); 371 else 372 m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp); 373 if (option_arg_vector->size() > 0) 374 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp); 375 result.SetStatus (eReturnStatusSuccessFinishNoResult); 376 } 377 else 378 { 379 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str()); 380 result.SetStatus (eReturnStatusFailed); 381 } 382 } 383 384 return result.Succeeded(); 385 } 386 }; 387 388 #pragma mark CommandObjectCommandsUnalias 389 //------------------------------------------------------------------------- 390 // CommandObjectCommandsUnalias 391 //------------------------------------------------------------------------- 392 393 class CommandObjectCommandsUnalias : public CommandObject 394 { 395 public: 396 CommandObjectCommandsUnalias (CommandInterpreter &interpreter) : 397 CommandObject (interpreter, 398 "commands unalias", 399 "Allow the user to remove/delete a user-defined command abbreviation.", 400 NULL) 401 { 402 CommandArgumentEntry arg; 403 CommandArgumentData alias_arg; 404 405 // Define the first (and only) variant of this arg. 406 alias_arg.arg_type = eArgTypeAliasName; 407 alias_arg.arg_repetition = eArgRepeatPlain; 408 409 // There is only one variant this argument could be; put it into the argument entry. 410 arg.push_back (alias_arg); 411 412 // Push the data for the first argument into the m_arguments vector. 413 m_arguments.push_back (arg); 414 } 415 416 ~CommandObjectCommandsUnalias() 417 { 418 } 419 420 421 bool 422 Execute 423 ( 424 Args& args, 425 CommandReturnObject &result 426 ) 427 { 428 CommandObject::CommandMap::iterator pos; 429 CommandObject *cmd_obj; 430 431 if (args.GetArgumentCount() != 0) 432 { 433 const char *command_name = args.GetArgumentAtIndex(0); 434 cmd_obj = m_interpreter.GetCommandObject(command_name); 435 if (cmd_obj) 436 { 437 if (m_interpreter.CommandExists (command_name)) 438 { 439 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", 440 command_name); 441 result.SetStatus (eReturnStatusFailed); 442 } 443 else 444 { 445 446 if (m_interpreter.RemoveAlias (command_name) == false) 447 { 448 if (m_interpreter.AliasExists (command_name)) 449 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n", 450 command_name); 451 else 452 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name); 453 result.SetStatus (eReturnStatusFailed); 454 } 455 else 456 result.SetStatus (eReturnStatusSuccessFinishNoResult); 457 } 458 } 459 else 460 { 461 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a " 462 "current list of commands.\n", 463 command_name); 464 result.SetStatus (eReturnStatusFailed); 465 } 466 } 467 else 468 { 469 result.AppendError ("must call 'unalias' with a valid alias"); 470 result.SetStatus (eReturnStatusFailed); 471 } 472 473 return result.Succeeded(); 474 } 475 }; 476 477 #pragma mark CommandObjectMultiwordCommands 478 479 //------------------------------------------------------------------------- 480 // CommandObjectMultiwordCommands 481 //------------------------------------------------------------------------- 482 483 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) : 484 CommandObjectMultiword (interpreter, 485 "commands", 486 "A set of commands for managing or customizing the debugger commands.", 487 "commands <subcommand> [<subcommand-options>]") 488 { 489 LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter))); 490 LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter))); 491 LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter))); 492 } 493 494 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands () 495 { 496 } 497 498