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