xref: /llvm-project/lldb/source/Commands/CommandObjectProcess.cpp (revision c982b3d6e654b5e909948d6c511fc6c7e2b670e3)
1 //===-- CommandObjectProcess.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 "CommandObjectProcess.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/Interpreter/Options.h"
18 #include "lldb/Core/State.h"
19 #include "lldb/Host/Host.h"
20 #include "lldb/Interpreter/CommandInterpreter.h"
21 #include "lldb/Interpreter/CommandReturnObject.h"
22 #include "lldb/Target/Platform.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Target/Thread.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 //-------------------------------------------------------------------------
31 // CommandObjectProcessLaunch
32 //-------------------------------------------------------------------------
33 #pragma mark CommandObjectProjectLaunch
34 class CommandObjectProcessLaunch : public CommandObject
35 {
36 public:
37 
38 //    class CommandOptions : public Options
39 //    {
40 //    public:
41 //
42 //        CommandOptions (CommandInterpreter &interpreter) :
43 //            Options(interpreter)
44 //        {
45 //            // Keep default values of all options in one place: OptionParsingStarting ()
46 //            OptionParsingStarting ();
47 //        }
48 //
49 //        ~CommandOptions ()
50 //        {
51 //        }
52 //
53 //        Error
54 //        SetOptionValue (uint32_t option_idx, const char *option_arg)
55 //        {
56 //            Error error;
57 //            char short_option = (char) m_getopt_table[option_idx].val;
58 //
59 //            switch (short_option)
60 //            {
61 //                case 's':   stop_at_entry = true;               break;
62 //                case 'e':   stderr_path.assign (option_arg);    break;
63 //                case 'i':   stdin_path.assign (option_arg);     break;
64 //                case 'o':   stdout_path.assign (option_arg);    break;
65 //                case 'p':   plugin_name.assign (option_arg);    break;
66 //                case 'n':   no_stdio = true;                    break;
67 //                case 'w':   working_dir.assign (option_arg);    break;
68 //                case 't':
69 //                    if (option_arg && option_arg[0])
70 //                        tty_name.assign (option_arg);
71 //                    in_new_tty = true;
72 //                    break;
73 //                default:
74 //                    error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
75 //                    break;
76 //
77 //            }
78 //            return error;
79 //        }
80 //
81 //        void
82 //        OptionParsingStarting ()
83 //        {
84 //            stop_at_entry = false;
85 //            in_new_tty = false;
86 //            tty_name.clear();
87 //            stdin_path.clear();
88 //            stdout_path.clear();
89 //            stderr_path.clear();
90 //            plugin_name.clear();
91 //            working_dir.clear();
92 //            no_stdio = false;
93 //        }
94 //
95 //        const OptionDefinition*
96 //        GetDefinitions ()
97 //        {
98 //            return g_option_table;
99 //        }
100 //
101 //        // Options table: Required for subclasses of Options.
102 //
103 //        static OptionDefinition g_option_table[];
104 //
105 //        // Instance variables to hold the values for command options.
106 //
107 //        bool stop_at_entry;
108 //        bool in_new_tty;
109 //        bool no_stdio;
110 //        std::string tty_name;
111 //        std::string stderr_path;
112 //        std::string stdin_path;
113 //        std::string stdout_path;
114 //        std::string plugin_name;
115 //        std::string working_dir;
116 //
117 //    };
118 
119     CommandObjectProcessLaunch (CommandInterpreter &interpreter) :
120         CommandObject (interpreter,
121                        "process launch",
122                        "Launch the executable in the debugger.",
123                        NULL),
124         m_options (interpreter)
125     {
126         CommandArgumentEntry arg;
127         CommandArgumentData run_args_arg;
128 
129         // Define the first (and only) variant of this arg.
130         run_args_arg.arg_type = eArgTypeRunArgs;
131         run_args_arg.arg_repetition = eArgRepeatOptional;
132 
133         // There is only one variant this argument could be; put it into the argument entry.
134         arg.push_back (run_args_arg);
135 
136         // Push the data for the first argument into the m_arguments vector.
137         m_arguments.push_back (arg);
138     }
139 
140 
141     ~CommandObjectProcessLaunch ()
142     {
143     }
144 
145     Options *
146     GetOptions ()
147     {
148         return &m_options;
149     }
150 
151     bool
152     Execute (Args& launch_args, CommandReturnObject &result)
153     {
154         Debugger &debugger = m_interpreter.GetDebugger();
155         Target *target = debugger.GetSelectedTarget().get();
156         Error error;
157 
158         if (target == NULL)
159         {
160             result.AppendError ("invalid target, create a debug target using the 'target create' command");
161             result.SetStatus (eReturnStatusFailed);
162             return false;
163         }
164         // If our listener is NULL, users aren't allows to launch
165         char filename[PATH_MAX];
166         const Module *exe_module = target->GetExecutableModulePointer();
167 
168         if (exe_module == NULL)
169         {
170             result.AppendError ("no file in target, create a debug target using the 'target create' command");
171             result.SetStatus (eReturnStatusFailed);
172             return false;
173         }
174 
175         exe_module->GetFileSpec().GetPath (filename, sizeof(filename));
176 
177         const bool add_exe_file_as_first_arg = true;
178         m_options.launch_info.SetExecutableFile(exe_module->GetFileSpec(), add_exe_file_as_first_arg);
179 
180         StateType state = eStateInvalid;
181         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
182         if (process)
183         {
184             state = process->GetState();
185 
186             if (process->IsAlive() && state != eStateConnected)
187             {
188                 char message[1024];
189                 if (process->GetState() == eStateAttaching)
190                     ::strncpy (message, "There is a pending attach, abort it and launch a new process?", sizeof(message));
191                 else
192                     ::strncpy (message, "There is a running process, kill it and restart?", sizeof(message));
193 
194                 if (!m_interpreter.Confirm (message, true))
195                 {
196                     result.SetStatus (eReturnStatusFailed);
197                     return false;
198                 }
199                 else
200                 {
201                     Error destroy_error (process->Destroy());
202                     if (destroy_error.Success())
203                     {
204                         result.SetStatus (eReturnStatusSuccessFinishResult);
205                     }
206                     else
207                     {
208                         result.AppendErrorWithFormat ("Failed to kill process: %s\n", destroy_error.AsCString());
209                         result.SetStatus (eReturnStatusFailed);
210                     }
211                 }
212             }
213         }
214 
215         if (launch_args.GetArgumentCount() == 0)
216         {
217             const Args &process_args = target->GetRunArguments();
218             if (process_args.GetArgumentCount() > 0)
219                 m_options.launch_info.GetArguments().AppendArguments (process_args);
220         }
221         else
222         {
223             // Save the arguments for subsequent runs in the current target.
224             target->SetRunArguments (launch_args);
225 
226             m_options.launch_info.GetArguments().AppendArguments (launch_args);
227         }
228 
229         if (target->GetDisableASLR())
230             m_options.launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
231 
232         if (target->GetDisableSTDIO())
233             m_options.launch_info.GetFlags().Set (eLaunchFlagDisableSTDIO);
234 
235         m_options.launch_info.GetFlags().Set (eLaunchFlagDebug);
236 
237         Args environment;
238         target->GetEnvironmentAsArgs (environment);
239         if (environment.GetArgumentCount() > 0)
240             m_options.launch_info.GetEnvironmentEntries ().AppendArguments (environment);
241 
242         // Finalize the file actions, and if none were given, default to opening
243         // up a pseudo terminal
244         const bool default_to_use_pty = true;
245         m_options.launch_info.FinalizeFileActions (target, default_to_use_pty);
246 
247         if (state == eStateConnected)
248         {
249             if (m_options.launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY))
250             {
251                 result.AppendWarning("can't launch in tty when launching through a remote connection");
252                 m_options.launch_info.GetFlags().Clear (eLaunchFlagLaunchInTTY);
253             }
254         }
255         else
256         {
257             if (!m_options.launch_info.GetArchitecture().IsValid())
258                 m_options.launch_info.GetArchitecture() = target->GetArchitecture();
259 
260             PlatformSP platform_sp (target->GetPlatform());
261 
262             if (platform_sp && platform_sp->CanDebugProcess ())
263             {
264                 process = target->GetPlatform()->DebugProcess (m_options.launch_info,
265                                                                debugger,
266                                                                target,
267                                                                debugger.GetListener(),
268                                                                error).get();
269             }
270             else
271             {
272                 const char *plugin_name = m_options.launch_info.GetProcessPluginName();
273                 process = target->CreateProcess (debugger.GetListener(), plugin_name).get();
274                 if (process)
275                     error = process->Launch (m_options.launch_info);
276             }
277 
278             if (process == NULL)
279             {
280                 result.SetError (error, "failed to launch or debug process");
281                 return false;
282             }
283         }
284 
285         if (error.Success())
286         {
287             const char *archname = exe_module->GetArchitecture().GetArchitectureName();
288 
289             result.AppendMessageWithFormat ("Process %llu launched: '%s' (%s)\n", process->GetID(), filename, archname);
290             result.SetDidChangeProcessState (true);
291             if (m_options.launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == false)
292             {
293                 result.SetStatus (eReturnStatusSuccessContinuingNoResult);
294                 StateType state = process->WaitForProcessToStop (NULL);
295 
296                 if (state == eStateStopped)
297                 {
298                     error = process->Resume();
299                     if (error.Success())
300                     {
301                         bool synchronous_execution = m_interpreter.GetSynchronous ();
302                         if (synchronous_execution)
303                         {
304                             state = process->WaitForProcessToStop (NULL);
305                             const bool must_be_alive = true;
306                             if (!StateIsStoppedState(state, must_be_alive))
307                             {
308                                 result.AppendErrorWithFormat ("process isn't stopped: %s", StateAsCString(state));
309                             }
310                             result.SetDidChangeProcessState (true);
311                             result.SetStatus (eReturnStatusSuccessFinishResult);
312                         }
313                         else
314                         {
315                             result.SetStatus (eReturnStatusSuccessContinuingNoResult);
316                         }
317                     }
318                     else
319                     {
320                         result.AppendErrorWithFormat ("process resume at entry point failed: %s", error.AsCString());
321                         result.SetStatus (eReturnStatusFailed);
322                     }
323                 }
324                 else
325                 {
326                     result.AppendErrorWithFormat ("initial process state wasn't stopped: %s", StateAsCString(state));
327                     result.SetStatus (eReturnStatusFailed);
328                 }
329             }
330         }
331         else
332         {
333             result.AppendErrorWithFormat ("process launch failed: %s", error.AsCString());
334             result.SetStatus (eReturnStatusFailed);
335         }
336 
337         return result.Succeeded();
338     }
339 
340     virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
341     {
342         // No repeat for "process launch"...
343         return "";
344     }
345 
346 protected:
347     ProcessLaunchCommandOptions m_options;
348 };
349 
350 
351 //#define SET1 LLDB_OPT_SET_1
352 //#define SET2 LLDB_OPT_SET_2
353 //#define SET3 LLDB_OPT_SET_3
354 //
355 //OptionDefinition
356 //CommandObjectProcessLaunch::CommandOptions::g_option_table[] =
357 //{
358 //{ SET1 | SET2 | SET3, false, "stop-at-entry", 's', no_argument,       NULL, 0, eArgTypeNone,    "Stop at the entry point of the program when launching a process."},
359 //{ SET1              , false, "stdin",         'i', required_argument, NULL, 0, eArgTypePath,    "Redirect stdin for the process to <path>."},
360 //{ SET1              , false, "stdout",        'o', required_argument, NULL, 0, eArgTypePath,    "Redirect stdout for the process to <path>."},
361 //{ SET1              , false, "stderr",        'e', required_argument, NULL, 0, eArgTypePath,    "Redirect stderr for the process to <path>."},
362 //{ SET1 | SET2 | SET3, false, "plugin",        'p', required_argument, NULL, 0, eArgTypePlugin,  "Name of the process plugin you want to use."},
363 //{        SET2       , false, "tty",           't', optional_argument, NULL, 0, eArgTypePath,    "Start the process in a terminal. If <path> is specified, look for a terminal whose name contains <path>, else start the process in a new terminal."},
364 //{               SET3, false, "no-stdio",      'n', no_argument,       NULL, 0, eArgTypeNone,    "Do not set up for terminal I/O to go to running process."},
365 //{ SET1 | SET2 | SET3, false, "working-dir",   'w', required_argument, NULL, 0, eArgTypePath,    "Set the current working directory to <path> when running the inferior."},
366 //{ 0,                  false, NULL,             0,  0,                 NULL, 0, eArgTypeNone,    NULL }
367 //};
368 //
369 //#undef SET1
370 //#undef SET2
371 //#undef SET3
372 
373 //-------------------------------------------------------------------------
374 // CommandObjectProcessAttach
375 //-------------------------------------------------------------------------
376 #pragma mark CommandObjectProcessAttach
377 class CommandObjectProcessAttach : public CommandObject
378 {
379 public:
380 
381     class CommandOptions : public Options
382     {
383     public:
384 
385         CommandOptions (CommandInterpreter &interpreter) :
386             Options(interpreter)
387         {
388             // Keep default values of all options in one place: OptionParsingStarting ()
389             OptionParsingStarting ();
390         }
391 
392         ~CommandOptions ()
393         {
394         }
395 
396         Error
397         SetOptionValue (uint32_t option_idx, const char *option_arg)
398         {
399             Error error;
400             char short_option = (char) m_getopt_table[option_idx].val;
401             bool success = false;
402             switch (short_option)
403             {
404                 case 'p':
405                     {
406                         lldb::pid_t pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success);
407                         if (!success || pid == LLDB_INVALID_PROCESS_ID)
408                         {
409                             error.SetErrorStringWithFormat("invalid process ID '%s'", option_arg);
410                         }
411                         else
412                         {
413                             attach_info.SetProcessID (pid);
414                         }
415                     }
416                     break;
417 
418                 case 'P':
419                     attach_info.SetProcessPluginName (option_arg);
420                     break;
421 
422                 case 'n':
423                     attach_info.GetExecutableFile().SetFile(option_arg, false);
424                     break;
425 
426                 case 'w':
427                     attach_info.SetWaitForLaunch(true);
428                     break;
429 
430                 default:
431                     error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
432                     break;
433             }
434             return error;
435         }
436 
437         void
438         OptionParsingStarting ()
439         {
440             attach_info.Clear();
441         }
442 
443         const OptionDefinition*
444         GetDefinitions ()
445         {
446             return g_option_table;
447         }
448 
449         virtual bool
450         HandleOptionArgumentCompletion (Args &input,
451                                         int cursor_index,
452                                         int char_pos,
453                                         OptionElementVector &opt_element_vector,
454                                         int opt_element_index,
455                                         int match_start_point,
456                                         int max_return_elements,
457                                         bool &word_complete,
458                                         StringList &matches)
459         {
460             int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
461             int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
462 
463             // We are only completing the name option for now...
464 
465             const OptionDefinition *opt_defs = GetDefinitions();
466             if (opt_defs[opt_defs_index].short_option == 'n')
467             {
468                 // Are we in the name?
469 
470                 // Look to see if there is a -P argument provided, and if so use that plugin, otherwise
471                 // use the default plugin.
472 
473                 const char *partial_name = NULL;
474                 partial_name = input.GetArgumentAtIndex(opt_arg_pos);
475 
476                 PlatformSP platform_sp (m_interpreter.GetPlatform (true));
477                 if (platform_sp)
478                 {
479                     ProcessInstanceInfoList process_infos;
480                     ProcessInstanceInfoMatch match_info;
481                     if (partial_name)
482                     {
483                         match_info.GetProcessInfo().GetExecutableFile().SetFile(partial_name, false);
484                         match_info.SetNameMatchType(eNameMatchStartsWith);
485                     }
486                     platform_sp->FindProcesses (match_info, process_infos);
487                     const uint32_t num_matches = process_infos.GetSize();
488                     if (num_matches > 0)
489                     {
490                         for (uint32_t i=0; i<num_matches; ++i)
491                         {
492                             matches.AppendString (process_infos.GetProcessNameAtIndex(i),
493                                                   process_infos.GetProcessNameLengthAtIndex(i));
494                         }
495                     }
496                 }
497             }
498 
499             return false;
500         }
501 
502         // Options table: Required for subclasses of Options.
503 
504         static OptionDefinition g_option_table[];
505 
506         // Instance variables to hold the values for command options.
507 
508         ProcessAttachInfo attach_info;
509     };
510 
511     CommandObjectProcessAttach (CommandInterpreter &interpreter) :
512         CommandObject (interpreter,
513                        "process attach",
514                        "Attach to a process.",
515                        "process attach <cmd-options>"),
516         m_options (interpreter)
517     {
518     }
519 
520     ~CommandObjectProcessAttach ()
521     {
522     }
523 
524     bool
525     Execute (Args& command,
526              CommandReturnObject &result)
527     {
528         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
529         // N.B. The attach should be synchronous.  It doesn't help much to get the prompt back between initiating the attach
530         // and the target actually stopping.  So even if the interpreter is set to be asynchronous, we wait for the stop
531         // ourselves here.
532 
533         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
534         StateType state = eStateInvalid;
535         if (process)
536         {
537             state = process->GetState();
538             if (process->IsAlive() && state != eStateConnected)
539             {
540                 result.AppendErrorWithFormat ("Process %llu is currently being debugged, kill the process before attaching.\n",
541                                               process->GetID());
542                 result.SetStatus (eReturnStatusFailed);
543                 return false;
544             }
545         }
546 
547         if (target == NULL)
548         {
549             // If there isn't a current target create one.
550             TargetSP new_target_sp;
551             FileSpec emptyFileSpec;
552             Error error;
553 
554             error = m_interpreter.GetDebugger().GetTargetList().CreateTarget (m_interpreter.GetDebugger(),
555                                                                               emptyFileSpec,
556                                                                               NULL,
557                                                                               false,
558                                                                               NULL, // No platform options
559                                                                               new_target_sp);
560             target = new_target_sp.get();
561             if (target == NULL || error.Fail())
562             {
563                 result.AppendError(error.AsCString("Error creating target"));
564                 return false;
565             }
566             m_interpreter.GetDebugger().GetTargetList().SetSelectedTarget(target);
567         }
568 
569         // Record the old executable module, we want to issue a warning if the process of attaching changed the
570         // current executable (like somebody said "file foo" then attached to a PID whose executable was bar.)
571 
572         ModuleSP old_exec_module_sp = target->GetExecutableModule();
573         ArchSpec old_arch_spec = target->GetArchitecture();
574 
575         if (command.GetArgumentCount())
576         {
577             result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
578             result.SetStatus (eReturnStatusFailed);
579         }
580         else
581         {
582             if (state != eStateConnected)
583             {
584                 const char *plugin_name = m_options.attach_info.GetProcessPluginName();
585                 process = target->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name).get();
586             }
587 
588             if (process)
589             {
590                 Error error;
591                 // If no process info was specified, then use the target executable
592                 // name as the process to attach to by default
593                 if (!m_options.attach_info.ProcessInfoSpecified ())
594                 {
595                     if (old_exec_module_sp)
596                         m_options.attach_info.GetExecutableFile().GetFilename() = old_exec_module_sp->GetFileSpec().GetFilename();
597 
598                     if (!m_options.attach_info.ProcessInfoSpecified ())
599                     {
600                         error.SetErrorString ("no process specified, create a target with a file, or specify the --pid or --name command option");
601                     }
602                 }
603 
604                 if (error.Success())
605                 {
606                     error = process->Attach (m_options.attach_info);
607 
608                     if (error.Success())
609                     {
610                         result.SetStatus (eReturnStatusSuccessContinuingNoResult);
611                     }
612                     else
613                     {
614                         result.AppendErrorWithFormat ("attach failed: %s\n", error.AsCString());
615                         result.SetStatus (eReturnStatusFailed);
616                         return false;
617                     }
618                     // If we're synchronous, wait for the stopped event and report that.
619                     // Otherwise just return.
620                     // FIXME: in the async case it will now be possible to get to the command
621                     // interpreter with a state eStateAttaching.  Make sure we handle that correctly.
622                     StateType state = process->WaitForProcessToStop (NULL);
623 
624                     result.SetDidChangeProcessState (true);
625                     result.AppendMessageWithFormat ("Process %llu %s\n", process->GetID(), StateAsCString (state));
626                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
627                 }
628             }
629         }
630 
631         if (result.Succeeded())
632         {
633             // Okay, we're done.  Last step is to warn if the executable module has changed:
634             char new_path[PATH_MAX];
635             ModuleSP new_exec_module_sp (target->GetExecutableModule());
636             if (!old_exec_module_sp)
637             {
638                 // We might not have a module if we attached to a raw pid...
639                 if (new_exec_module_sp)
640                 {
641                     new_exec_module_sp->GetFileSpec().GetPath(new_path, PATH_MAX);
642                     result.AppendMessageWithFormat("Executable module set to \"%s\".\n", new_path);
643                 }
644             }
645             else if (old_exec_module_sp->GetFileSpec() != new_exec_module_sp->GetFileSpec())
646             {
647                 char old_path[PATH_MAX];
648 
649                 old_exec_module_sp->GetFileSpec().GetPath (old_path, PATH_MAX);
650                 new_exec_module_sp->GetFileSpec().GetPath (new_path, PATH_MAX);
651 
652                 result.AppendWarningWithFormat("Executable module changed from \"%s\" to \"%s\".\n",
653                                                     old_path, new_path);
654             }
655 
656             if (!old_arch_spec.IsValid())
657             {
658                 result.AppendMessageWithFormat ("Architecture set to: %s.\n", target->GetArchitecture().GetArchitectureName());
659             }
660             else if (old_arch_spec != target->GetArchitecture())
661             {
662                 result.AppendWarningWithFormat("Architecture changed from %s to %s.\n",
663                                                 old_arch_spec.GetArchitectureName(), target->GetArchitecture().GetArchitectureName());
664             }
665         }
666         return result.Succeeded();
667     }
668 
669     Options *
670     GetOptions ()
671     {
672         return &m_options;
673     }
674 
675 protected:
676 
677     CommandOptions m_options;
678 };
679 
680 
681 OptionDefinition
682 CommandObjectProcessAttach::CommandOptions::g_option_table[] =
683 {
684 { LLDB_OPT_SET_ALL, false, "plugin", 'P', required_argument, NULL, 0, eArgTypePlugin,        "Name of the process plugin you want to use."},
685 { LLDB_OPT_SET_1,   false, "pid",    'p', required_argument, NULL, 0, eArgTypePid,           "The process ID of an existing process to attach to."},
686 { LLDB_OPT_SET_2,   false, "name",   'n', required_argument, NULL, 0, eArgTypeProcessName,  "The name of the process to attach to."},
687 { LLDB_OPT_SET_2,   false, "waitfor",'w', no_argument,       NULL, 0, eArgTypeNone,              "Wait for the the process with <process-name> to launch."},
688 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
689 };
690 
691 //-------------------------------------------------------------------------
692 // CommandObjectProcessContinue
693 //-------------------------------------------------------------------------
694 #pragma mark CommandObjectProcessContinue
695 
696 class CommandObjectProcessContinue : public CommandObject
697 {
698 public:
699 
700     CommandObjectProcessContinue (CommandInterpreter &interpreter) :
701         CommandObject (interpreter,
702                        "process continue",
703                        "Continue execution of all threads in the current process.",
704                        "process continue",
705                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
706     {
707     }
708 
709 
710     ~CommandObjectProcessContinue ()
711     {
712     }
713 
714     bool
715     Execute (Args& command,
716              CommandReturnObject &result)
717     {
718         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
719         bool synchronous_execution = m_interpreter.GetSynchronous ();
720 
721         if (process == NULL)
722         {
723             result.AppendError ("no process to continue");
724             result.SetStatus (eReturnStatusFailed);
725             return false;
726          }
727 
728         StateType state = process->GetState();
729         if (state == eStateStopped)
730         {
731             if (command.GetArgumentCount() != 0)
732             {
733                 result.AppendErrorWithFormat ("The '%s' command does not take any arguments.\n", m_cmd_name.c_str());
734                 result.SetStatus (eReturnStatusFailed);
735                 return false;
736             }
737 
738             const uint32_t num_threads = process->GetThreadList().GetSize();
739 
740             // Set the actions that the threads should each take when resuming
741             for (uint32_t idx=0; idx<num_threads; ++idx)
742             {
743                 process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState (eStateRunning);
744             }
745 
746             Error error(process->Resume());
747             if (error.Success())
748             {
749                 result.AppendMessageWithFormat ("Process %llu resuming\n", process->GetID());
750                 if (synchronous_execution)
751                 {
752                     state = process->WaitForProcessToStop (NULL);
753 
754                     result.SetDidChangeProcessState (true);
755                     result.AppendMessageWithFormat ("Process %llu %s\n", process->GetID(), StateAsCString (state));
756                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
757                 }
758                 else
759                 {
760                     result.SetStatus (eReturnStatusSuccessContinuingNoResult);
761                 }
762             }
763             else
764             {
765                 result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString());
766                 result.SetStatus (eReturnStatusFailed);
767             }
768         }
769         else
770         {
771             result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n",
772                                          StateAsCString(state));
773             result.SetStatus (eReturnStatusFailed);
774         }
775         return result.Succeeded();
776     }
777 };
778 
779 //-------------------------------------------------------------------------
780 // CommandObjectProcessDetach
781 //-------------------------------------------------------------------------
782 #pragma mark CommandObjectProcessDetach
783 
784 class CommandObjectProcessDetach : public CommandObject
785 {
786 public:
787 
788     CommandObjectProcessDetach (CommandInterpreter &interpreter) :
789         CommandObject (interpreter,
790                        "process detach",
791                        "Detach from the current process being debugged.",
792                        "process detach",
793                        eFlagProcessMustBeLaunched)
794     {
795     }
796 
797     ~CommandObjectProcessDetach ()
798     {
799     }
800 
801     bool
802     Execute (Args& command,
803              CommandReturnObject &result)
804     {
805         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
806         if (process == NULL)
807         {
808             result.AppendError ("must have a valid process in order to detach");
809             result.SetStatus (eReturnStatusFailed);
810             return false;
811         }
812 
813         result.AppendMessageWithFormat ("Detaching from process %llu\n", process->GetID());
814         Error error (process->Detach());
815         if (error.Success())
816         {
817             result.SetStatus (eReturnStatusSuccessFinishResult);
818         }
819         else
820         {
821             result.AppendErrorWithFormat ("Detach failed: %s\n", error.AsCString());
822             result.SetStatus (eReturnStatusFailed);
823             return false;
824         }
825         return result.Succeeded();
826     }
827 };
828 
829 //-------------------------------------------------------------------------
830 // CommandObjectProcessConnect
831 //-------------------------------------------------------------------------
832 #pragma mark CommandObjectProcessConnect
833 
834 class CommandObjectProcessConnect : public CommandObject
835 {
836 public:
837 
838     class CommandOptions : public Options
839     {
840     public:
841 
842         CommandOptions (CommandInterpreter &interpreter) :
843             Options(interpreter)
844         {
845             // Keep default values of all options in one place: OptionParsingStarting ()
846             OptionParsingStarting ();
847         }
848 
849         ~CommandOptions ()
850         {
851         }
852 
853         Error
854         SetOptionValue (uint32_t option_idx, const char *option_arg)
855         {
856             Error error;
857             char short_option = (char) m_getopt_table[option_idx].val;
858 
859             switch (short_option)
860             {
861             case 'p':
862                 plugin_name.assign (option_arg);
863                 break;
864 
865             default:
866                 error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
867                 break;
868             }
869             return error;
870         }
871 
872         void
873         OptionParsingStarting ()
874         {
875             plugin_name.clear();
876         }
877 
878         const OptionDefinition*
879         GetDefinitions ()
880         {
881             return g_option_table;
882         }
883 
884         // Options table: Required for subclasses of Options.
885 
886         static OptionDefinition g_option_table[];
887 
888         // Instance variables to hold the values for command options.
889 
890         std::string plugin_name;
891     };
892 
893     CommandObjectProcessConnect (CommandInterpreter &interpreter) :
894         CommandObject (interpreter,
895                        "process connect",
896                        "Connect to a remote debug service.",
897                        "process connect <remote-url>",
898                        0),
899         m_options (interpreter)
900     {
901     }
902 
903     ~CommandObjectProcessConnect ()
904     {
905     }
906 
907 
908     bool
909     Execute (Args& command,
910              CommandReturnObject &result)
911     {
912 
913         TargetSP target_sp (m_interpreter.GetDebugger().GetSelectedTarget());
914         Error error;
915         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
916         if (process)
917         {
918             if (process->IsAlive())
919             {
920                 result.AppendErrorWithFormat ("Process %llu is currently being debugged, kill the process before connecting.\n",
921                                               process->GetID());
922                 result.SetStatus (eReturnStatusFailed);
923                 return false;
924             }
925         }
926 
927         if (!target_sp)
928         {
929             // If there isn't a current target create one.
930             FileSpec emptyFileSpec;
931 
932             error = m_interpreter.GetDebugger().GetTargetList().CreateTarget (m_interpreter.GetDebugger(),
933                                                                               emptyFileSpec,
934                                                                               NULL,
935                                                                               false,
936                                                                               NULL, // No platform options
937                                                                               target_sp);
938             if (!target_sp || error.Fail())
939             {
940                 result.AppendError(error.AsCString("Error creating target"));
941                 result.SetStatus (eReturnStatusFailed);
942                 return false;
943             }
944             m_interpreter.GetDebugger().GetTargetList().SetSelectedTarget(target_sp.get());
945         }
946 
947         if (command.GetArgumentCount() == 1)
948         {
949             const char *plugin_name = NULL;
950             if (!m_options.plugin_name.empty())
951                 plugin_name = m_options.plugin_name.c_str();
952 
953             const char *remote_url = command.GetArgumentAtIndex(0);
954             process = target_sp->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name).get();
955 
956             if (process)
957             {
958                 error = process->ConnectRemote (remote_url);
959 
960                 if (error.Fail())
961                 {
962                     result.AppendError(error.AsCString("Remote connect failed"));
963                     result.SetStatus (eReturnStatusFailed);
964                     return false;
965                 }
966             }
967             else
968             {
969                 result.AppendErrorWithFormat ("Unable to find process plug-in for remote URL '%s'.\nPlease specify a process plug-in name with the --plugin option, or specify an object file using the \"file\" command.\n",
970                                               m_cmd_name.c_str());
971                 result.SetStatus (eReturnStatusFailed);
972             }
973         }
974         else
975         {
976             result.AppendErrorWithFormat ("'%s' takes exactly one argument:\nUsage: %s\n",
977                                           m_cmd_name.c_str(),
978                                           m_cmd_syntax.c_str());
979             result.SetStatus (eReturnStatusFailed);
980         }
981         return result.Succeeded();
982     }
983 
984     Options *
985     GetOptions ()
986     {
987         return &m_options;
988     }
989 
990 protected:
991 
992     CommandOptions m_options;
993 };
994 
995 
996 OptionDefinition
997 CommandObjectProcessConnect::CommandOptions::g_option_table[] =
998 {
999     { LLDB_OPT_SET_ALL, false, "plugin", 'p', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
1000     { 0,                false, NULL,      0 , 0,                 NULL, 0, eArgTypeNone,   NULL }
1001 };
1002 
1003 //-------------------------------------------------------------------------
1004 // CommandObjectProcessLoad
1005 //-------------------------------------------------------------------------
1006 #pragma mark CommandObjectProcessLoad
1007 
1008 class CommandObjectProcessLoad : public CommandObject
1009 {
1010 public:
1011 
1012     CommandObjectProcessLoad (CommandInterpreter &interpreter) :
1013         CommandObject (interpreter,
1014                        "process load",
1015                        "Load a shared library into the current process.",
1016                        "process load <filename> [<filename> ...]",
1017                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
1018     {
1019     }
1020 
1021     ~CommandObjectProcessLoad ()
1022     {
1023     }
1024 
1025     bool
1026     Execute (Args& command,
1027              CommandReturnObject &result)
1028     {
1029         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
1030         if (process == NULL)
1031         {
1032             result.AppendError ("must have a valid process in order to load a shared library");
1033             result.SetStatus (eReturnStatusFailed);
1034             return false;
1035         }
1036 
1037         const uint32_t argc = command.GetArgumentCount();
1038 
1039         for (uint32_t i=0; i<argc; ++i)
1040         {
1041             Error error;
1042             const char *image_path = command.GetArgumentAtIndex(i);
1043             FileSpec image_spec (image_path, false);
1044             process->GetTarget().GetPlatform()->ResolveRemotePath(image_spec, image_spec);
1045             uint32_t image_token = process->LoadImage(image_spec, error);
1046             if (image_token != LLDB_INVALID_IMAGE_TOKEN)
1047             {
1048                 result.AppendMessageWithFormat ("Loading \"%s\"...ok\nImage %u loaded.\n", image_path, image_token);
1049                 result.SetStatus (eReturnStatusSuccessFinishResult);
1050             }
1051             else
1052             {
1053                 result.AppendErrorWithFormat ("failed to load '%s': %s", image_path, error.AsCString());
1054                 result.SetStatus (eReturnStatusFailed);
1055             }
1056         }
1057         return result.Succeeded();
1058     }
1059 };
1060 
1061 
1062 //-------------------------------------------------------------------------
1063 // CommandObjectProcessUnload
1064 //-------------------------------------------------------------------------
1065 #pragma mark CommandObjectProcessUnload
1066 
1067 class CommandObjectProcessUnload : public CommandObject
1068 {
1069 public:
1070 
1071     CommandObjectProcessUnload (CommandInterpreter &interpreter) :
1072         CommandObject (interpreter,
1073                        "process unload",
1074                        "Unload a shared library from the current process using the index returned by a previous call to \"process load\".",
1075                        "process unload <index>",
1076                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
1077     {
1078     }
1079 
1080     ~CommandObjectProcessUnload ()
1081     {
1082     }
1083 
1084     bool
1085     Execute (Args& command,
1086              CommandReturnObject &result)
1087     {
1088         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
1089         if (process == NULL)
1090         {
1091             result.AppendError ("must have a valid process in order to load a shared library");
1092             result.SetStatus (eReturnStatusFailed);
1093             return false;
1094         }
1095 
1096         const uint32_t argc = command.GetArgumentCount();
1097 
1098         for (uint32_t i=0; i<argc; ++i)
1099         {
1100             const char *image_token_cstr = command.GetArgumentAtIndex(i);
1101             uint32_t image_token = Args::StringToUInt32(image_token_cstr, LLDB_INVALID_IMAGE_TOKEN, 0);
1102             if (image_token == LLDB_INVALID_IMAGE_TOKEN)
1103             {
1104                 result.AppendErrorWithFormat ("invalid image index argument '%s'", image_token_cstr);
1105                 result.SetStatus (eReturnStatusFailed);
1106                 break;
1107             }
1108             else
1109             {
1110                 Error error (process->UnloadImage(image_token));
1111                 if (error.Success())
1112                 {
1113                     result.AppendMessageWithFormat ("Unloading shared library with index %u...ok\n", image_token);
1114                     result.SetStatus (eReturnStatusSuccessFinishResult);
1115                 }
1116                 else
1117                 {
1118                     result.AppendErrorWithFormat ("failed to unload image: %s", error.AsCString());
1119                     result.SetStatus (eReturnStatusFailed);
1120                     break;
1121                 }
1122             }
1123         }
1124         return result.Succeeded();
1125     }
1126 };
1127 
1128 //-------------------------------------------------------------------------
1129 // CommandObjectProcessSignal
1130 //-------------------------------------------------------------------------
1131 #pragma mark CommandObjectProcessSignal
1132 
1133 class CommandObjectProcessSignal : public CommandObject
1134 {
1135 public:
1136 
1137     CommandObjectProcessSignal (CommandInterpreter &interpreter) :
1138         CommandObject (interpreter,
1139                        "process signal",
1140                        "Send a UNIX signal to the current process being debugged.",
1141                        NULL)
1142     {
1143         CommandArgumentEntry arg;
1144         CommandArgumentData signal_arg;
1145 
1146         // Define the first (and only) variant of this arg.
1147         signal_arg.arg_type = eArgTypeUnixSignal;
1148         signal_arg.arg_repetition = eArgRepeatPlain;
1149 
1150         // There is only one variant this argument could be; put it into the argument entry.
1151         arg.push_back (signal_arg);
1152 
1153         // Push the data for the first argument into the m_arguments vector.
1154         m_arguments.push_back (arg);
1155     }
1156 
1157     ~CommandObjectProcessSignal ()
1158     {
1159     }
1160 
1161     bool
1162     Execute (Args& command,
1163              CommandReturnObject &result)
1164     {
1165         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
1166         if (process == NULL)
1167         {
1168             result.AppendError ("no process to signal");
1169             result.SetStatus (eReturnStatusFailed);
1170             return false;
1171         }
1172 
1173         if (command.GetArgumentCount() == 1)
1174         {
1175             int signo = LLDB_INVALID_SIGNAL_NUMBER;
1176 
1177             const char *signal_name = command.GetArgumentAtIndex(0);
1178             if (::isxdigit (signal_name[0]))
1179                 signo = Args::StringToSInt32(signal_name, LLDB_INVALID_SIGNAL_NUMBER, 0);
1180             else
1181                 signo = process->GetUnixSignals().GetSignalNumberFromName (signal_name);
1182 
1183             if (signo == LLDB_INVALID_SIGNAL_NUMBER)
1184             {
1185                 result.AppendErrorWithFormat ("Invalid signal argument '%s'.\n", command.GetArgumentAtIndex(0));
1186                 result.SetStatus (eReturnStatusFailed);
1187             }
1188             else
1189             {
1190                 Error error (process->Signal (signo));
1191                 if (error.Success())
1192                 {
1193                     result.SetStatus (eReturnStatusSuccessFinishResult);
1194                 }
1195                 else
1196                 {
1197                     result.AppendErrorWithFormat ("Failed to send signal %i: %s\n", signo, error.AsCString());
1198                     result.SetStatus (eReturnStatusFailed);
1199                 }
1200             }
1201         }
1202         else
1203         {
1204             result.AppendErrorWithFormat("'%s' takes exactly one signal number argument:\nUsage: %s\n", m_cmd_name.c_str(),
1205                                         m_cmd_syntax.c_str());
1206             result.SetStatus (eReturnStatusFailed);
1207         }
1208         return result.Succeeded();
1209     }
1210 };
1211 
1212 
1213 //-------------------------------------------------------------------------
1214 // CommandObjectProcessInterrupt
1215 //-------------------------------------------------------------------------
1216 #pragma mark CommandObjectProcessInterrupt
1217 
1218 class CommandObjectProcessInterrupt : public CommandObject
1219 {
1220 public:
1221 
1222 
1223     CommandObjectProcessInterrupt (CommandInterpreter &interpreter) :
1224     CommandObject (interpreter,
1225                    "process interrupt",
1226                    "Interrupt the current process being debugged.",
1227                    "process interrupt",
1228                    eFlagProcessMustBeLaunched)
1229     {
1230     }
1231 
1232     ~CommandObjectProcessInterrupt ()
1233     {
1234     }
1235 
1236     bool
1237     Execute (Args& command,
1238              CommandReturnObject &result)
1239     {
1240         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
1241         if (process == NULL)
1242         {
1243             result.AppendError ("no process to halt");
1244             result.SetStatus (eReturnStatusFailed);
1245             return false;
1246         }
1247 
1248         if (command.GetArgumentCount() == 0)
1249         {
1250             Error error(process->Halt ());
1251             if (error.Success())
1252             {
1253                 result.SetStatus (eReturnStatusSuccessFinishResult);
1254 
1255                 // Maybe we should add a "SuspendThreadPlans so we
1256                 // can halt, and keep in place all the current thread plans.
1257                 process->GetThreadList().DiscardThreadPlans();
1258             }
1259             else
1260             {
1261                 result.AppendErrorWithFormat ("Failed to halt process: %s\n", error.AsCString());
1262                 result.SetStatus (eReturnStatusFailed);
1263             }
1264         }
1265         else
1266         {
1267             result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
1268                                         m_cmd_name.c_str(),
1269                                         m_cmd_syntax.c_str());
1270             result.SetStatus (eReturnStatusFailed);
1271         }
1272         return result.Succeeded();
1273     }
1274 };
1275 
1276 //-------------------------------------------------------------------------
1277 // CommandObjectProcessKill
1278 //-------------------------------------------------------------------------
1279 #pragma mark CommandObjectProcessKill
1280 
1281 class CommandObjectProcessKill : public CommandObject
1282 {
1283 public:
1284 
1285     CommandObjectProcessKill (CommandInterpreter &interpreter) :
1286     CommandObject (interpreter,
1287                    "process kill",
1288                    "Terminate the current process being debugged.",
1289                    "process kill",
1290                    eFlagProcessMustBeLaunched)
1291     {
1292     }
1293 
1294     ~CommandObjectProcessKill ()
1295     {
1296     }
1297 
1298     bool
1299     Execute (Args& command,
1300              CommandReturnObject &result)
1301     {
1302         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
1303         if (process == NULL)
1304         {
1305             result.AppendError ("no process to kill");
1306             result.SetStatus (eReturnStatusFailed);
1307             return false;
1308         }
1309 
1310         if (command.GetArgumentCount() == 0)
1311         {
1312             Error error (process->Destroy());
1313             if (error.Success())
1314             {
1315                 result.SetStatus (eReturnStatusSuccessFinishResult);
1316             }
1317             else
1318             {
1319                 result.AppendErrorWithFormat ("Failed to kill process: %s\n", error.AsCString());
1320                 result.SetStatus (eReturnStatusFailed);
1321             }
1322         }
1323         else
1324         {
1325             result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
1326                                         m_cmd_name.c_str(),
1327                                         m_cmd_syntax.c_str());
1328             result.SetStatus (eReturnStatusFailed);
1329         }
1330         return result.Succeeded();
1331     }
1332 };
1333 
1334 //-------------------------------------------------------------------------
1335 // CommandObjectProcessStatus
1336 //-------------------------------------------------------------------------
1337 #pragma mark CommandObjectProcessStatus
1338 
1339 class CommandObjectProcessStatus : public CommandObject
1340 {
1341 public:
1342     CommandObjectProcessStatus (CommandInterpreter &interpreter) :
1343     CommandObject (interpreter,
1344                    "process status",
1345                    "Show the current status and location of executing process.",
1346                    "process status",
1347                    0)
1348     {
1349     }
1350 
1351     ~CommandObjectProcessStatus()
1352     {
1353     }
1354 
1355 
1356     bool
1357     Execute
1358     (
1359         Args& command,
1360         CommandReturnObject &result
1361     )
1362     {
1363         Stream &strm = result.GetOutputStream();
1364         result.SetStatus (eReturnStatusSuccessFinishNoResult);
1365         ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
1366         Process *process = exe_ctx.GetProcessPtr();
1367         if (process)
1368         {
1369             const bool only_threads_with_stop_reason = true;
1370             const uint32_t start_frame = 0;
1371             const uint32_t num_frames = 1;
1372             const uint32_t num_frames_with_source = 1;
1373             process->GetStatus(strm);
1374             process->GetThreadStatus (strm,
1375                                       only_threads_with_stop_reason,
1376                                       start_frame,
1377                                       num_frames,
1378                                       num_frames_with_source);
1379 
1380         }
1381         else
1382         {
1383             result.AppendError ("No process.");
1384             result.SetStatus (eReturnStatusFailed);
1385         }
1386         return result.Succeeded();
1387     }
1388 };
1389 
1390 //-------------------------------------------------------------------------
1391 // CommandObjectProcessHandle
1392 //-------------------------------------------------------------------------
1393 #pragma mark CommandObjectProcessHandle
1394 
1395 class CommandObjectProcessHandle : public CommandObject
1396 {
1397 public:
1398 
1399     class CommandOptions : public Options
1400     {
1401     public:
1402 
1403         CommandOptions (CommandInterpreter &interpreter) :
1404             Options (interpreter)
1405         {
1406             OptionParsingStarting ();
1407         }
1408 
1409         ~CommandOptions ()
1410         {
1411         }
1412 
1413         Error
1414         SetOptionValue (uint32_t option_idx, const char *option_arg)
1415         {
1416             Error error;
1417             char short_option = (char) m_getopt_table[option_idx].val;
1418 
1419             switch (short_option)
1420             {
1421                 case 's':
1422                     stop = option_arg;
1423                     break;
1424                 case 'n':
1425                     notify = option_arg;
1426                     break;
1427                 case 'p':
1428                     pass = option_arg;
1429                     break;
1430                 default:
1431                     error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
1432                     break;
1433             }
1434             return error;
1435         }
1436 
1437         void
1438         OptionParsingStarting ()
1439         {
1440             stop.clear();
1441             notify.clear();
1442             pass.clear();
1443         }
1444 
1445         const OptionDefinition*
1446         GetDefinitions ()
1447         {
1448             return g_option_table;
1449         }
1450 
1451         // Options table: Required for subclasses of Options.
1452 
1453         static OptionDefinition g_option_table[];
1454 
1455         // Instance variables to hold the values for command options.
1456 
1457         std::string stop;
1458         std::string notify;
1459         std::string pass;
1460     };
1461 
1462 
1463     CommandObjectProcessHandle (CommandInterpreter &interpreter) :
1464         CommandObject (interpreter,
1465                        "process handle",
1466                        "Show or update what the process and debugger should do with various signals received from the OS.",
1467                        NULL),
1468         m_options (interpreter)
1469     {
1470         SetHelpLong ("If no signals are specified, update them all.  If no update option is specified, list the current values.\n");
1471         CommandArgumentEntry arg;
1472         CommandArgumentData signal_arg;
1473 
1474         signal_arg.arg_type = eArgTypeUnixSignal;
1475         signal_arg.arg_repetition = eArgRepeatStar;
1476 
1477         arg.push_back (signal_arg);
1478 
1479         m_arguments.push_back (arg);
1480     }
1481 
1482     ~CommandObjectProcessHandle ()
1483     {
1484     }
1485 
1486     Options *
1487     GetOptions ()
1488     {
1489         return &m_options;
1490     }
1491 
1492     bool
1493     VerifyCommandOptionValue (const std::string &option, int &real_value)
1494     {
1495         bool okay = true;
1496 
1497         bool success = false;
1498         bool tmp_value = Args::StringToBoolean (option.c_str(), false, &success);
1499 
1500         if (success && tmp_value)
1501             real_value = 1;
1502         else if (success && !tmp_value)
1503             real_value = 0;
1504         else
1505         {
1506             // If the value isn't 'true' or 'false', it had better be 0 or 1.
1507             real_value = Args::StringToUInt32 (option.c_str(), 3);
1508             if (real_value != 0 && real_value != 1)
1509                 okay = false;
1510         }
1511 
1512         return okay;
1513     }
1514 
1515     void
1516     PrintSignalHeader (Stream &str)
1517     {
1518         str.Printf ("NAME        PASS   STOP   NOTIFY\n");
1519         str.Printf ("==========  =====  =====  ======\n");
1520     }
1521 
1522     void
1523     PrintSignal (Stream &str, int32_t signo, const char *sig_name, UnixSignals &signals)
1524     {
1525         bool stop;
1526         bool suppress;
1527         bool notify;
1528 
1529         str.Printf ("%-10s  ", sig_name);
1530         if (signals.GetSignalInfo (signo, suppress, stop, notify))
1531         {
1532             bool pass = !suppress;
1533             str.Printf ("%s  %s  %s",
1534                         (pass ? "true " : "false"),
1535                         (stop ? "true " : "false"),
1536                         (notify ? "true " : "false"));
1537         }
1538         str.Printf ("\n");
1539     }
1540 
1541     void
1542     PrintSignalInformation (Stream &str, Args &signal_args, int num_valid_signals, UnixSignals &signals)
1543     {
1544         PrintSignalHeader (str);
1545 
1546         if (num_valid_signals > 0)
1547         {
1548             size_t num_args = signal_args.GetArgumentCount();
1549             for (size_t i = 0; i < num_args; ++i)
1550             {
1551                 int32_t signo = signals.GetSignalNumberFromName (signal_args.GetArgumentAtIndex (i));
1552                 if (signo != LLDB_INVALID_SIGNAL_NUMBER)
1553                     PrintSignal (str, signo, signal_args.GetArgumentAtIndex (i), signals);
1554             }
1555         }
1556         else // Print info for ALL signals
1557         {
1558             int32_t signo = signals.GetFirstSignalNumber();
1559             while (signo != LLDB_INVALID_SIGNAL_NUMBER)
1560             {
1561                 PrintSignal (str, signo, signals.GetSignalAsCString (signo), signals);
1562                 signo = signals.GetNextSignalNumber (signo);
1563             }
1564         }
1565     }
1566 
1567     bool
1568     Execute (Args &signal_args, CommandReturnObject &result)
1569     {
1570         TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget();
1571 
1572         if (!target_sp)
1573         {
1574             result.AppendError ("No current target;"
1575                                 " cannot handle signals until you have a valid target and process.\n");
1576             result.SetStatus (eReturnStatusFailed);
1577             return false;
1578         }
1579 
1580         ProcessSP process_sp = target_sp->GetProcessSP();
1581 
1582         if (!process_sp)
1583         {
1584             result.AppendError ("No current process; cannot handle signals until you have a valid process.\n");
1585             result.SetStatus (eReturnStatusFailed);
1586             return false;
1587         }
1588 
1589         int stop_action = -1;   // -1 means leave the current setting alone
1590         int pass_action = -1;   // -1 means leave the current setting alone
1591         int notify_action = -1; // -1 means leave the current setting alone
1592 
1593         if (! m_options.stop.empty()
1594             && ! VerifyCommandOptionValue (m_options.stop, stop_action))
1595         {
1596             result.AppendError ("Invalid argument for command option --stop; must be true or false.\n");
1597             result.SetStatus (eReturnStatusFailed);
1598             return false;
1599         }
1600 
1601         if (! m_options.notify.empty()
1602             && ! VerifyCommandOptionValue (m_options.notify, notify_action))
1603         {
1604             result.AppendError ("Invalid argument for command option --notify; must be true or false.\n");
1605             result.SetStatus (eReturnStatusFailed);
1606             return false;
1607         }
1608 
1609         if (! m_options.pass.empty()
1610             && ! VerifyCommandOptionValue (m_options.pass, pass_action))
1611         {
1612             result.AppendError ("Invalid argument for command option --pass; must be true or false.\n");
1613             result.SetStatus (eReturnStatusFailed);
1614             return false;
1615         }
1616 
1617         size_t num_args = signal_args.GetArgumentCount();
1618         UnixSignals &signals = process_sp->GetUnixSignals();
1619         int num_signals_set = 0;
1620 
1621         if (num_args > 0)
1622         {
1623             for (size_t i = 0; i < num_args; ++i)
1624             {
1625                 int32_t signo = signals.GetSignalNumberFromName (signal_args.GetArgumentAtIndex (i));
1626                 if (signo != LLDB_INVALID_SIGNAL_NUMBER)
1627                 {
1628                     // Casting the actions as bools here should be okay, because VerifyCommandOptionValue guarantees
1629                     // the value is either 0 or 1.
1630                     if (stop_action != -1)
1631                         signals.SetShouldStop (signo, (bool) stop_action);
1632                     if (pass_action != -1)
1633                     {
1634                         bool suppress = ! ((bool) pass_action);
1635                         signals.SetShouldSuppress (signo, suppress);
1636                     }
1637                     if (notify_action != -1)
1638                         signals.SetShouldNotify (signo, (bool) notify_action);
1639                     ++num_signals_set;
1640                 }
1641                 else
1642                 {
1643                     result.AppendErrorWithFormat ("Invalid signal name '%s'\n", signal_args.GetArgumentAtIndex (i));
1644                 }
1645             }
1646         }
1647         else
1648         {
1649             // No signal specified, if any command options were specified, update ALL signals.
1650             if ((notify_action != -1) || (stop_action != -1) || (pass_action != -1))
1651             {
1652                 if (m_interpreter.Confirm ("Do you really want to update all the signals?", false))
1653                 {
1654                     int32_t signo = signals.GetFirstSignalNumber();
1655                     while (signo != LLDB_INVALID_SIGNAL_NUMBER)
1656                     {
1657                         if (notify_action != -1)
1658                             signals.SetShouldNotify (signo, (bool) notify_action);
1659                         if (stop_action != -1)
1660                             signals.SetShouldStop (signo, (bool) stop_action);
1661                         if (pass_action != -1)
1662                         {
1663                             bool suppress = ! ((bool) pass_action);
1664                             signals.SetShouldSuppress (signo, suppress);
1665                         }
1666                         signo = signals.GetNextSignalNumber (signo);
1667                     }
1668                 }
1669             }
1670         }
1671 
1672         PrintSignalInformation (result.GetOutputStream(), signal_args, num_signals_set, signals);
1673 
1674         if (num_signals_set > 0)
1675             result.SetStatus (eReturnStatusSuccessFinishNoResult);
1676         else
1677             result.SetStatus (eReturnStatusFailed);
1678 
1679         return result.Succeeded();
1680     }
1681 
1682 protected:
1683 
1684     CommandOptions m_options;
1685 };
1686 
1687 OptionDefinition
1688 CommandObjectProcessHandle::CommandOptions::g_option_table[] =
1689 {
1690 { LLDB_OPT_SET_1, false, "stop",   's', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the process should be stopped if the signal is received." },
1691 { LLDB_OPT_SET_1, false, "notify", 'n', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the debugger should notify the user if the signal is received." },
1692 { LLDB_OPT_SET_1, false, "pass",  'p', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the signal should be passed to the process." },
1693 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
1694 };
1695 
1696 //-------------------------------------------------------------------------
1697 // CommandObjectMultiwordProcess
1698 //-------------------------------------------------------------------------
1699 
1700 CommandObjectMultiwordProcess::CommandObjectMultiwordProcess (CommandInterpreter &interpreter) :
1701     CommandObjectMultiword (interpreter,
1702                             "process",
1703                             "A set of commands for operating on a process.",
1704                             "process <subcommand> [<subcommand-options>]")
1705 {
1706     LoadSubCommand ("attach",      CommandObjectSP (new CommandObjectProcessAttach    (interpreter)));
1707     LoadSubCommand ("launch",      CommandObjectSP (new CommandObjectProcessLaunch    (interpreter)));
1708     LoadSubCommand ("continue",    CommandObjectSP (new CommandObjectProcessContinue  (interpreter)));
1709     LoadSubCommand ("connect",     CommandObjectSP (new CommandObjectProcessConnect   (interpreter)));
1710     LoadSubCommand ("detach",      CommandObjectSP (new CommandObjectProcessDetach    (interpreter)));
1711     LoadSubCommand ("load",        CommandObjectSP (new CommandObjectProcessLoad      (interpreter)));
1712     LoadSubCommand ("unload",      CommandObjectSP (new CommandObjectProcessUnload    (interpreter)));
1713     LoadSubCommand ("signal",      CommandObjectSP (new CommandObjectProcessSignal    (interpreter)));
1714     LoadSubCommand ("handle",      CommandObjectSP (new CommandObjectProcessHandle    (interpreter)));
1715     LoadSubCommand ("status",      CommandObjectSP (new CommandObjectProcessStatus    (interpreter)));
1716     LoadSubCommand ("interrupt",   CommandObjectSP (new CommandObjectProcessInterrupt (interpreter)));
1717     LoadSubCommand ("kill",        CommandObjectSP (new CommandObjectProcessKill      (interpreter)));
1718 }
1719 
1720 CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess ()
1721 {
1722 }
1723 
1724