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