xref: /llvm-project/lldb/source/Commands/CommandObjectProcess.cpp (revision 3a0b9cdf47c72900de3ff192b48dd0c18fa7509f)
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/Interpreter/CommandInterpreter.h"
20 #include "lldb/Interpreter/CommandReturnObject.h"
21 #include "./CommandObjectThread.h"
22 #include "lldb/Target/Process.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Target/Thread.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 //-------------------------------------------------------------------------
30 // CommandObjectProcessLaunch
31 //-------------------------------------------------------------------------
32 
33 class CommandObjectProcessLaunch : public CommandObject
34 {
35 public:
36 
37     class CommandOptions : public Options
38     {
39     public:
40 
41         CommandOptions () :
42             Options()
43         {
44             // Keep default values of all options in one place: ResetOptionValues ()
45             ResetOptionValues ();
46         }
47 
48         ~CommandOptions ()
49         {
50         }
51 
52         Error
53         SetOptionValue (int option_idx, const char *option_arg)
54         {
55             Error error;
56             char short_option = (char) m_getopt_table[option_idx].val;
57 
58             switch (short_option)
59             {
60                 case 's':   stop_at_entry = true;       break;
61                 case 'e':   stderr_path = option_arg;   break;
62                 case 'i':   stdin_path  = option_arg;   break;
63                 case 'o':   stdout_path = option_arg;   break;
64                 case 'p':   plugin_name = option_arg;   break;
65                 default:
66                     error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
67                     break;
68 
69             }
70             return error;
71         }
72 
73         void
74         ResetOptionValues ()
75         {
76             Options::ResetOptionValues();
77             stop_at_entry = false;
78             stdin_path.clear();
79             stdout_path.clear();
80             stderr_path.clear();
81             plugin_name.clear();
82         }
83 
84         const lldb::OptionDefinition*
85         GetDefinitions ()
86         {
87             return g_option_table;
88         }
89 
90         // Options table: Required for subclasses of Options.
91 
92         static lldb::OptionDefinition g_option_table[];
93 
94         // Instance variables to hold the values for command options.
95 
96         bool stop_at_entry;
97         std::string stderr_path;
98         std::string stdin_path;
99         std::string stdout_path;
100         std::string plugin_name;
101 
102     };
103 
104     CommandObjectProcessLaunch () :
105         CommandObject ("process launch",
106                        "Launch the executable in the debugger.",
107                        "process launch [<cmd-options>] [<arguments-for-running-the-program>]")
108     {
109     }
110 
111 
112     ~CommandObjectProcessLaunch ()
113     {
114     }
115 
116     Options *
117     GetOptions ()
118     {
119         return &m_options;
120     }
121 
122     bool
123     Execute (CommandInterpreter &interpreter,
124              Args& launch_args,
125              CommandReturnObject &result)
126     {
127         Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
128         bool synchronous_execution = interpreter.GetSynchronous ();
129     //    bool launched = false;
130     //    bool stopped_after_launch = false;
131 
132         if (target == NULL)
133         {
134             result.AppendError ("invalid target, set executable file using 'file' command");
135             result.SetStatus (eReturnStatusFailed);
136             return false;
137         }
138 
139         // If our listener is NULL, users aren't allows to launch
140         char filename[PATH_MAX];
141         Module *exe_module = target->GetExecutableModule().get();
142         exe_module->GetFileSpec().GetPath(filename, sizeof(filename));
143 
144         Process *process = interpreter.GetDebugger().GetExecutionContext().process;
145         if (process)
146         {
147             if (process->IsAlive())
148             {
149                result.AppendErrorWithFormat ("Process %u is currently being debugged, kill the process before running again.\n",
150                                             process->GetID());
151                 result.SetStatus (eReturnStatusFailed);
152                 return false;
153             }
154         }
155 
156         const char *plugin_name;
157         if (!m_options.plugin_name.empty())
158             plugin_name = m_options.plugin_name.c_str();
159         else
160             plugin_name = NULL;
161 
162         process = target->CreateProcess (interpreter.GetDebugger().GetListener(), plugin_name).get();
163 
164         const char *process_name = process->GetInstanceName().AsCString();
165         const char *debugger_instance_name = interpreter.GetDebugger().GetInstanceName().AsCString();
166         StreamString run_args_var_name;
167         StreamString env_vars_var_name;
168         StreamString disable_aslr_var_name;
169         lldb::SettableVariableType var_type;
170 
171         Args *run_args = NULL;
172         run_args_var_name.Printf ("process.[%s].run-args", process_name);
173         StringList run_args_value = Debugger::GetSettingsController()->GetVariable (run_args_var_name.GetData(),
174                                                                                     var_type, debugger_instance_name);
175 
176         if (run_args_value.GetSize() > 0)
177         {
178             run_args = new Args;
179             for (unsigned i = 0, e = run_args_value.GetSize(); i != e; ++i)
180                 run_args->AppendArgument(run_args_value.GetStringAtIndex(i));
181         }
182 
183         Args *environment = NULL;
184         env_vars_var_name.Printf ("process.[%s].env-vars", process_name);
185         StringList env_vars_value = Debugger::GetSettingsController()->GetVariable (env_vars_var_name.GetData(),
186                                                                                     var_type, debugger_instance_name);
187 
188         if (env_vars_value.GetSize() > 0)
189         {
190             environment = new Args;
191             for (unsigned i = 0, e = env_vars_value.GetSize(); i != e; ++i)
192                 environment->AppendArgument (env_vars_value.GetStringAtIndex (i));
193         }
194 
195         uint32_t launch_flags = eLaunchFlagNone;
196         disable_aslr_var_name.Printf ("process.[%s].disable-aslr", process_name);
197         StringList disable_aslr_value = Debugger::GetSettingsController()->GetVariable(disable_aslr_var_name.GetData(),
198                                                                                        var_type,
199                                                                                        debugger_instance_name);
200 
201         if (disable_aslr_value.GetSize() > 0)
202         {
203             if (strcmp (disable_aslr_value.GetStringAtIndex(0), "true") == 0)
204                 launch_flags |= eLaunchFlagDisableASLR;
205 
206         }
207 
208         // There are two possible sources of args to be passed to the process upon launching:  Those the user
209         // typed at the run command (launch_args); or those the user pre-set in the run-args variable (run_args).
210 
211         // If launch_args is empty, use run_args.
212         if (launch_args.GetArgumentCount() == 0)
213         {
214             if (run_args != NULL)
215                 launch_args.AppendArguments (*run_args);
216         }
217         else
218         {
219             // launch-args was not empty; use that, AND re-set run-args to contains launch-args values.
220             std::string new_run_args;
221             launch_args.GetCommandString (new_run_args);
222             Debugger::GetSettingsController()->SetVariable (run_args_var_name.GetData(), new_run_args.c_str(),
223                                                             lldb::eVarSetOperationAssign, false,
224                                                             interpreter.GetDebugger().GetInstanceName().AsCString());
225         }
226 
227 
228         if (process)
229         {
230             const char *archname = exe_module->GetArchitecture().AsCString();
231 
232             const char * stdin_path = NULL;
233             const char * stdout_path = NULL;
234             const char * stderr_path = NULL;
235 
236             if (!(m_options.stdin_path.empty() &&
237                 m_options.stdout_path.empty() &&
238                 m_options.stderr_path.empty()))
239             {
240                 stdin_path =    m_options.stdin_path.empty()  ? "/dev/null" : m_options.stdin_path.c_str();
241                 stdout_path =   m_options.stdout_path.empty() ? "/dev/null" : m_options.stdout_path.c_str();
242                 stderr_path =   m_options.stderr_path.empty() ? "/dev/null" : m_options.stderr_path.c_str();
243             }
244 
245             Error error (process->Launch (launch_args.GetConstArgumentVector(),
246                                           environment ? environment->GetConstArgumentVector() : NULL,
247                                           launch_flags,
248                                           stdin_path,
249                                           stdout_path,
250                                           stderr_path));
251 
252             if (error.Success())
253             {
254                 result.AppendMessageWithFormat ("Launching '%s'  (%s)\n", filename, archname);
255                 result.SetStatus (eReturnStatusSuccessContinuingNoResult);
256                 if (m_options.stop_at_entry == false)
257                 {
258                     StateType state = process->WaitForProcessToStop (NULL);
259 
260                     if (state == eStateStopped)
261                     {
262                         // Call continue_command.
263                         CommandReturnObject continue_result;
264                         interpreter.HandleCommand("process continue", false, continue_result);
265                     }
266 
267                     if (synchronous_execution)
268                     {
269                         result.SetDidChangeProcessState (true);
270                         result.SetStatus (eReturnStatusSuccessFinishNoResult);
271                     }
272                 }
273             }
274             else
275             {
276                 result.AppendErrorWithFormat ("Process launch failed: %s",
277                                               error.AsCString());
278                 result.SetStatus (eReturnStatusFailed);
279             }
280         }
281         else
282         {
283             result.AppendErrorWithFormat ("Process launch failed: unable to create a process object.\n");
284             result.SetStatus (eReturnStatusFailed);
285             return false;
286         }
287 
288         return result.Succeeded();
289     }
290 
291     virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
292     {
293         // No repeat for "process launch"...
294         return "";
295     }
296 
297 protected:
298 
299     CommandOptions m_options;
300 };
301 
302 
303 lldb::OptionDefinition
304 CommandObjectProcessLaunch::CommandOptions::g_option_table[] =
305 {
306 { LLDB_OPT_SET_1, false, "stop-at-entry", 's', no_argument,       NULL, 0, NULL,        "Stop at the entry point of the program when launching a process."},
307 { LLDB_OPT_SET_1, false, "stdin",         'i', required_argument, NULL, 0, "<path>",    "Redirect stdin for the process to <path>."},
308 { LLDB_OPT_SET_1, false, "stdout",        'o', required_argument, NULL, 0, "<path>",    "Redirect stdout for the process to <path>."},
309 { LLDB_OPT_SET_1, false, "stderr",        'e', required_argument, NULL, 0, "<path>",    "Redirect stderr for the process to <path>."},
310 { LLDB_OPT_SET_1, false, "plugin",        'p', required_argument, NULL, 0, "<plugin>",  "Name of the process plugin you want to use."},
311 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
312 };
313 
314 
315 //-------------------------------------------------------------------------
316 // CommandObjectProcessAttach
317 //-------------------------------------------------------------------------
318 
319 class CommandObjectProcessAttach : public CommandObject
320 {
321 public:
322 
323     class CommandOptions : public Options
324     {
325     public:
326 
327         CommandOptions () :
328             Options()
329         {
330             // Keep default values of all options in one place: ResetOptionValues ()
331             ResetOptionValues ();
332         }
333 
334         ~CommandOptions ()
335         {
336         }
337 
338         Error
339         SetOptionValue (int option_idx, const char *option_arg)
340         {
341             Error error;
342             char short_option = (char) m_getopt_table[option_idx].val;
343             bool success = false;
344             switch (short_option)
345             {
346                 case 'p':
347                     pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success);
348                     if (!success || pid == LLDB_INVALID_PROCESS_ID)
349                     {
350                         error.SetErrorStringWithFormat("Invalid process ID '%s'.\n", option_arg);
351                     }
352                     break;
353 
354                 case 'P':
355                     plugin_name = option_arg;
356                     break;
357 
358                 case 'n':
359                     name.assign(option_arg);
360                     break;
361 
362                 case 'w':
363                     waitfor = true;
364                     break;
365 
366                 default:
367                     error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
368                     break;
369             }
370             return error;
371         }
372 
373         void
374         ResetOptionValues ()
375         {
376             Options::ResetOptionValues();
377             pid = LLDB_INVALID_PROCESS_ID;
378             name.clear();
379             waitfor = false;
380         }
381 
382         const lldb::OptionDefinition*
383         GetDefinitions ()
384         {
385             return g_option_table;
386         }
387 
388         virtual bool
389         HandleOptionArgumentCompletion (CommandInterpreter &interpreter,
390                                         Args &input,
391                                         int cursor_index,
392                                         int char_pos,
393                                         OptionElementVector &opt_element_vector,
394                                         int opt_element_index,
395                                         int match_start_point,
396                                         int max_return_elements,
397                                         bool &word_complete,
398                                         StringList &matches)
399         {
400             int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
401             int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
402 
403             // We are only completing the name option for now...
404 
405             const lldb::OptionDefinition *opt_defs = GetDefinitions();
406             if (opt_defs[opt_defs_index].short_option == 'n')
407             {
408                 // Are we in the name?
409 
410                 // Look to see if there is a -P argument provided, and if so use that plugin, otherwise
411                 // use the default plugin.
412                 Process *process = interpreter.GetDebugger().GetExecutionContext().process;
413                 bool need_to_delete_process = false;
414 
415                 const char *partial_name = NULL;
416                 partial_name = input.GetArgumentAtIndex(opt_arg_pos);
417 
418                 if (process && process->IsAlive())
419                     return true;
420 
421                 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
422                 if (target == NULL)
423                 {
424                     // No target has been set yet, for now do host completion.  Otherwise I don't know how we would
425                     // figure out what the right target to use is...
426                     std::vector<lldb::pid_t> pids;
427                     Host::ListProcessesMatchingName (partial_name, matches, pids);
428                     return true;
429                 }
430                 if (!process)
431                 {
432                     process = target->CreateProcess (interpreter.GetDebugger().GetListener(), partial_name).get();
433                     need_to_delete_process = true;
434                 }
435 
436                 if (process)
437                 {
438                     matches.Clear();
439                     std::vector<lldb::pid_t> pids;
440                     process->ListProcessesMatchingName (NULL, matches, pids);
441                     if (need_to_delete_process)
442                         target->DeleteCurrentProcess();
443                     return true;
444                 }
445             }
446 
447             return false;
448         }
449 
450         // Options table: Required for subclasses of Options.
451 
452         static lldb::OptionDefinition g_option_table[];
453 
454         // Instance variables to hold the values for command options.
455 
456         lldb::pid_t pid;
457         std::string plugin_name;
458         std::string name;
459         bool waitfor;
460     };
461 
462     CommandObjectProcessAttach () :
463         CommandObject ("process attach",
464                        "Attach to a process.",
465                        "process attach <cmd-options>")
466     {
467     }
468 
469     ~CommandObjectProcessAttach ()
470     {
471     }
472 
473     bool
474     Execute (CommandInterpreter &interpreter,
475              Args& command,
476              CommandReturnObject &result)
477     {
478         Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
479 
480         Process *process = interpreter.GetDebugger().GetExecutionContext().process;
481         if (process)
482         {
483             if (process->IsAlive())
484             {
485                 result.AppendErrorWithFormat ("Process %u is currently being debugged, kill the process before attaching.\n",
486                                               process->GetID());
487                 result.SetStatus (eReturnStatusFailed);
488                 return false;
489             }
490         }
491 
492         if (target == NULL)
493         {
494             // If there isn't a current target create one.
495             TargetSP new_target_sp;
496             FileSpec emptyFileSpec;
497             ArchSpec emptyArchSpec;
498             Error error;
499 
500             error = interpreter.GetDebugger().GetTargetList().CreateTarget(interpreter.GetDebugger(),
501                                                                            emptyFileSpec,
502                                                                            emptyArchSpec,
503                                                                            NULL,
504                                                                            false,
505                                                                            new_target_sp);
506             target = new_target_sp.get();
507             if (target == NULL || error.Fail())
508             {
509                 result.AppendError(error.AsCString("Error creating empty target"));
510                 return false;
511             }
512             interpreter.GetDebugger().GetTargetList().SetSelectedTarget(target);
513         }
514 
515         // Record the old executable module, we want to issue a warning if the process of attaching changed the
516         // current executable (like somebody said "file foo" then attached to a PID whose executable was bar.)
517 
518         ModuleSP old_exec_module_sp = target->GetExecutableModule();
519         ArchSpec old_arch_spec = target->GetArchitecture();
520 
521         if (command.GetArgumentCount())
522         {
523             result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
524             result.SetStatus (eReturnStatusFailed);
525         }
526         else
527         {
528             const char *plugin_name = NULL;
529 
530             if (!m_options.plugin_name.empty())
531                 plugin_name = m_options.plugin_name.c_str();
532 
533             process = target->CreateProcess (interpreter.GetDebugger().GetListener(), plugin_name).get();
534 
535             if (process)
536             {
537                 Error error;
538                 int attach_pid = m_options.pid;
539 
540                 const char *wait_name = NULL;
541 
542                 if (m_options.name.empty())
543                 {
544                     if (old_exec_module_sp)
545                     {
546                         wait_name = old_exec_module_sp->GetFileSpec().GetFilename().AsCString();
547                     }
548                 }
549                 else
550                 {
551                     wait_name = m_options.name.c_str();
552                 }
553 
554                 // If we are waiting for a process with this name to show up, do that first.
555                 if (m_options.waitfor)
556                 {
557 
558                     if (wait_name == NULL)
559                     {
560                         result.AppendError("Invalid arguments: must have a file loaded or supply a process name with the waitfor option.\n");
561                         result.SetStatus (eReturnStatusFailed);
562                         return false;
563                     }
564 
565                     interpreter.GetDebugger().GetOutputStream().Printf("Waiting to attach to a process named \"%s\".\n", wait_name);
566                     error = process->Attach (wait_name, m_options.waitfor);
567                     if (error.Success())
568                     {
569                         result.SetStatus (eReturnStatusSuccessContinuingNoResult);
570                     }
571                     else
572                     {
573                         result.AppendErrorWithFormat ("Waiting for a process to launch named '%s': %s\n",
574                                                          wait_name,
575                                                          error.AsCString());
576                         result.SetStatus (eReturnStatusFailed);
577                         return false;
578                     }
579                 }
580                 else
581                 {
582                     // If the process was specified by name look it up, so we can warn if there are multiple
583                     // processes with this pid.
584 
585                     if (attach_pid == LLDB_INVALID_PROCESS_ID && wait_name != NULL)
586                     {
587                         std::vector<lldb::pid_t> pids;
588                         StringList matches;
589 
590                         process->ListProcessesMatchingName(wait_name, matches, pids);
591                         if (matches.GetSize() > 1)
592                         {
593                             result.AppendErrorWithFormat("More than one process named %s\n", wait_name);
594                             result.SetStatus (eReturnStatusFailed);
595                             return false;
596                         }
597                         else if (matches.GetSize() == 0)
598                         {
599                             result.AppendErrorWithFormat("Could not find a process named %s\n", wait_name);
600                             result.SetStatus (eReturnStatusFailed);
601                             return false;
602                         }
603                         else
604                         {
605                             attach_pid = pids[0];
606                         }
607 
608                     }
609 
610                     if (attach_pid != LLDB_INVALID_PROCESS_ID)
611                     {
612                         error = process->Attach (attach_pid);
613                         if (error.Success())
614                         {
615                             result.SetStatus (eReturnStatusSuccessContinuingNoResult);
616                         }
617                         else
618                         {
619                             result.AppendErrorWithFormat ("Attaching to process %i failed: %s.\n",
620                                                          attach_pid,
621                                                          error.AsCString());
622                             result.SetStatus (eReturnStatusFailed);
623                         }
624                     }
625                     else
626                     {
627                         result.AppendErrorWithFormat ("No PID specified for attach\n",
628                                                          attach_pid,
629                                                          error.AsCString());
630                         result.SetStatus (eReturnStatusFailed);
631 
632                     }
633                 }
634             }
635         }
636 
637         if (result.Succeeded())
638         {
639             // Okay, we're done.  Last step is to warn if the executable module has changed:
640             if (!old_exec_module_sp)
641             {
642                 char new_path[PATH_MAX + 1];
643                 target->GetExecutableModule()->GetFileSpec().GetPath(new_path, PATH_MAX);
644 
645                 result.AppendMessageWithFormat("Executable module set to \"%s\".\n",
646                     new_path);
647             }
648             else if (old_exec_module_sp->GetFileSpec() != target->GetExecutableModule()->GetFileSpec())
649             {
650                 char old_path[PATH_MAX + 1];
651                 char new_path[PATH_MAX + 1];
652 
653                 old_exec_module_sp->GetFileSpec().GetPath(old_path, PATH_MAX);
654                 target->GetExecutableModule()->GetFileSpec().GetPath (new_path, PATH_MAX);
655 
656                 result.AppendWarningWithFormat("Executable module changed from \"%s\" to \"%s\".\n",
657                                                     old_path, new_path);
658             }
659 
660             if (!old_arch_spec.IsValid())
661             {
662                 result.AppendMessageWithFormat ("Architecture set to: %s.\n", target->GetArchitecture().AsCString());
663             }
664             else if (old_arch_spec != target->GetArchitecture())
665             {
666                 result.AppendWarningWithFormat("Architecture changed from %s to %s.\n",
667                                                 old_arch_spec.AsCString(), target->GetArchitecture().AsCString());
668             }
669         }
670         return result.Succeeded();
671     }
672 
673     Options *
674     GetOptions ()
675     {
676         return &m_options;
677     }
678 
679 protected:
680 
681     CommandOptions m_options;
682 };
683 
684 
685 lldb::OptionDefinition
686 CommandObjectProcessAttach::CommandOptions::g_option_table[] =
687 {
688 { LLDB_OPT_SET_ALL, false, "plugin",       'P', required_argument, NULL, 0, "<plugin>",        "Name of the process plugin you want to use."},
689 { LLDB_OPT_SET_1, false, "pid",          'p', required_argument, NULL, 0, "<pid>",           "The process ID of an existing process to attach to."},
690 { LLDB_OPT_SET_2, false,  "name",         'n', required_argument, NULL, 0, "<process-name>",  "The name of the process to attach to."},
691 { LLDB_OPT_SET_2, false, "waitfor",      'w', no_argument,       NULL, 0, NULL,              "Wait for the the process with <process-name> to launch."},
692 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
693 };
694 
695 //-------------------------------------------------------------------------
696 // CommandObjectProcessContinue
697 //-------------------------------------------------------------------------
698 
699 class CommandObjectProcessContinue : public CommandObject
700 {
701 public:
702 
703     CommandObjectProcessContinue () :
704         CommandObject ("process continue",
705                        "Continue execution of all threads in the current process.",
706                        "process continue",
707                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
708     {
709     }
710 
711 
712     ~CommandObjectProcessContinue ()
713     {
714     }
715 
716     bool
717     Execute (CommandInterpreter &interpreter,
718              Args& command,
719              CommandReturnObject &result)
720     {
721         Process *process = interpreter.GetDebugger().GetExecutionContext().process;
722         bool synchronous_execution = interpreter.GetSynchronous ();
723 
724         if (process == NULL)
725         {
726             result.AppendError ("no process to continue");
727             result.SetStatus (eReturnStatusFailed);
728             return false;
729          }
730 
731         StateType state = process->GetState();
732         if (state == eStateStopped)
733         {
734             if (command.GetArgumentCount() != 0)
735             {
736                 result.AppendErrorWithFormat ("The '%s' command does not take any arguments.\n", m_cmd_name.c_str());
737                 result.SetStatus (eReturnStatusFailed);
738                 return false;
739             }
740 
741             const uint32_t num_threads = process->GetThreadList().GetSize();
742 
743             // Set the actions that the threads should each take when resuming
744             for (uint32_t idx=0; idx<num_threads; ++idx)
745             {
746                 process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState (eStateRunning);
747             }
748 
749             Error error(process->Resume());
750             if (error.Success())
751             {
752                 result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID());
753                 if (synchronous_execution)
754                 {
755                     state = process->WaitForProcessToStop (NULL);
756 
757                     result.SetDidChangeProcessState (true);
758                     result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
759                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
760                 }
761                 else
762                 {
763                     result.SetStatus (eReturnStatusSuccessContinuingNoResult);
764                 }
765             }
766             else
767             {
768                 result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString());
769                 result.SetStatus (eReturnStatusFailed);
770             }
771         }
772         else
773         {
774             result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n",
775                                          StateAsCString(state));
776             result.SetStatus (eReturnStatusFailed);
777         }
778         return result.Succeeded();
779     }
780 };
781 
782 //-------------------------------------------------------------------------
783 // CommandObjectProcessDetach
784 //-------------------------------------------------------------------------
785 
786 class CommandObjectProcessDetach : public CommandObject
787 {
788 public:
789 
790     CommandObjectProcessDetach () :
791         CommandObject ("process detach",
792                        "Detach from the current process being debugged.",
793                        "process detach",
794                        eFlagProcessMustBeLaunched)
795     {
796     }
797 
798     ~CommandObjectProcessDetach ()
799     {
800     }
801 
802     bool
803     Execute (CommandInterpreter &interpreter,
804              Args& command,
805              CommandReturnObject &result)
806     {
807         Process *process = interpreter.GetDebugger().GetExecutionContext().process;
808         if (process == NULL)
809         {
810             result.AppendError ("must have a valid process in order to detach");
811             result.SetStatus (eReturnStatusFailed);
812             return false;
813         }
814 
815         Error error (process->Detach());
816         if (error.Success())
817         {
818             result.SetStatus (eReturnStatusSuccessFinishResult);
819         }
820         else
821         {
822             result.AppendErrorWithFormat ("Detach failed: %s\n", error.AsCString());
823             result.SetStatus (eReturnStatusFailed);
824             return false;
825         }
826         return result.Succeeded();
827     }
828 };
829 
830 //-------------------------------------------------------------------------
831 // CommandObjectProcessSignal
832 //-------------------------------------------------------------------------
833 
834 class CommandObjectProcessSignal : public CommandObject
835 {
836 public:
837 
838     CommandObjectProcessSignal () :
839         CommandObject ("process signal",
840                        "Send a UNIX signal to the current process being debugged.",
841                        "process signal <unix-signal-number>")
842     {
843     }
844 
845     ~CommandObjectProcessSignal ()
846     {
847     }
848 
849     bool
850     Execute (CommandInterpreter &interpreter,
851              Args& command,
852              CommandReturnObject &result)
853     {
854         Process *process = interpreter.GetDebugger().GetExecutionContext().process;
855         if (process == NULL)
856         {
857             result.AppendError ("no process to signal");
858             result.SetStatus (eReturnStatusFailed);
859             return false;
860         }
861 
862         if (command.GetArgumentCount() == 1)
863         {
864             int signo = Args::StringToSInt32(command.GetArgumentAtIndex(0), -1, 0);
865             if (signo == -1)
866             {
867                 result.AppendErrorWithFormat ("Invalid signal argument '%s'.\n", command.GetArgumentAtIndex(0));
868                 result.SetStatus (eReturnStatusFailed);
869             }
870             else
871             {
872                 Error error (process->Signal (signo));
873                 if (error.Success())
874                 {
875                     result.SetStatus (eReturnStatusSuccessFinishResult);
876                 }
877                 else
878                 {
879                     result.AppendErrorWithFormat ("Failed to send signal %i: %s\n", signo, error.AsCString());
880                     result.SetStatus (eReturnStatusFailed);
881                 }
882             }
883         }
884         else
885         {
886             result.AppendErrorWithFormat("'%s' takes exactly one signal number argument:\nUsage: \n", m_cmd_name.c_str(),
887                                         m_cmd_syntax.c_str());
888             result.SetStatus (eReturnStatusFailed);
889         }
890         return result.Succeeded();
891     }
892 };
893 
894 
895 //-------------------------------------------------------------------------
896 // CommandObjectProcessInterrupt
897 //-------------------------------------------------------------------------
898 
899 class CommandObjectProcessInterrupt : public CommandObject
900 {
901 public:
902 
903 
904     CommandObjectProcessInterrupt () :
905     CommandObject ("process interrupt",
906                    "Interrupt the current process being debugged.",
907                    "process interrupt",
908                    eFlagProcessMustBeLaunched)
909     {
910     }
911 
912     ~CommandObjectProcessInterrupt ()
913     {
914     }
915 
916     bool
917     Execute (CommandInterpreter &interpreter,
918              Args& command,
919              CommandReturnObject &result)
920     {
921         Process *process = interpreter.GetDebugger().GetExecutionContext().process;
922         if (process == NULL)
923         {
924             result.AppendError ("no process to halt");
925             result.SetStatus (eReturnStatusFailed);
926             return false;
927         }
928 
929         if (command.GetArgumentCount() == 0)
930         {
931             Error error(process->Halt ());
932             if (error.Success())
933             {
934                 result.SetStatus (eReturnStatusSuccessFinishResult);
935 
936                 // Maybe we should add a "SuspendThreadPlans so we
937                 // can halt, and keep in place all the current thread plans.
938                 process->GetThreadList().DiscardThreadPlans();
939             }
940             else
941             {
942                 result.AppendErrorWithFormat ("Failed to halt process: %s\n", error.AsCString());
943                 result.SetStatus (eReturnStatusFailed);
944             }
945         }
946         else
947         {
948             result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: \n",
949                                         m_cmd_name.c_str(),
950                                         m_cmd_syntax.c_str());
951             result.SetStatus (eReturnStatusFailed);
952         }
953         return result.Succeeded();
954     }
955 };
956 
957 //-------------------------------------------------------------------------
958 // CommandObjectProcessKill
959 //-------------------------------------------------------------------------
960 
961 class CommandObjectProcessKill : public CommandObject
962 {
963 public:
964 
965     CommandObjectProcessKill () :
966     CommandObject ("process kill",
967                    "Terminate the current process being debugged.",
968                    "process kill",
969                    eFlagProcessMustBeLaunched)
970     {
971     }
972 
973     ~CommandObjectProcessKill ()
974     {
975     }
976 
977     bool
978     Execute (CommandInterpreter &interpreter,
979              Args& command,
980              CommandReturnObject &result)
981     {
982         Process *process = interpreter.GetDebugger().GetExecutionContext().process;
983         if (process == NULL)
984         {
985             result.AppendError ("no process to kill");
986             result.SetStatus (eReturnStatusFailed);
987             return false;
988         }
989 
990         if (command.GetArgumentCount() == 0)
991         {
992             Error error (process->Destroy());
993             if (error.Success())
994             {
995                 result.SetStatus (eReturnStatusSuccessFinishResult);
996             }
997             else
998             {
999                 result.AppendErrorWithFormat ("Failed to kill process: %s\n", error.AsCString());
1000                 result.SetStatus (eReturnStatusFailed);
1001             }
1002         }
1003         else
1004         {
1005             result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: \n",
1006                                         m_cmd_name.c_str(),
1007                                         m_cmd_syntax.c_str());
1008             result.SetStatus (eReturnStatusFailed);
1009         }
1010         return result.Succeeded();
1011     }
1012 };
1013 
1014 //-------------------------------------------------------------------------
1015 // CommandObjectProcessStatus
1016 //-------------------------------------------------------------------------
1017 class CommandObjectProcessStatus : public CommandObject
1018 {
1019 public:
1020     CommandObjectProcessStatus () :
1021     CommandObject ("process status",
1022                    "Show the current status and location of executing process.",
1023                    "process status",
1024                    0)
1025     {
1026     }
1027 
1028     ~CommandObjectProcessStatus()
1029     {
1030     }
1031 
1032 
1033     bool
1034     Execute
1035     (
1036         CommandInterpreter &interpreter,
1037         Args& command,
1038         CommandReturnObject &result
1039     )
1040     {
1041         StreamString &output_stream = result.GetOutputStream();
1042         result.SetStatus (eReturnStatusSuccessFinishNoResult);
1043         ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext());
1044         if (exe_ctx.process)
1045         {
1046             const StateType state = exe_ctx.process->GetState();
1047             if (StateIsStoppedState(state))
1048             {
1049                 if (state == eStateExited)
1050                 {
1051                     int exit_status = exe_ctx.process->GetExitStatus();
1052                     const char *exit_description = exe_ctx.process->GetExitDescription();
1053                     output_stream.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n",
1054                                           exe_ctx.process->GetID(),
1055                                           exit_status,
1056                                           exit_status,
1057                                           exit_description ? exit_description : "");
1058                 }
1059                 else
1060                 {
1061                     output_stream.Printf ("Process %d %s\n", exe_ctx.process->GetID(), StateAsCString (state));
1062                     if (exe_ctx.thread == NULL)
1063                         exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get();
1064                     if (exe_ctx.thread != NULL)
1065                     {
1066                         DisplayThreadsInfo (interpreter, &exe_ctx, result, true, true);
1067                     }
1068                     else
1069                     {
1070                         result.AppendError ("No valid thread found in current process.");
1071                         result.SetStatus (eReturnStatusFailed);
1072                     }
1073                 }
1074             }
1075             else
1076             {
1077                 output_stream.Printf ("Process %d is running.\n",
1078                                           exe_ctx.process->GetID());
1079             }
1080         }
1081         else
1082         {
1083             result.AppendError ("No current location or status available.");
1084             result.SetStatus (eReturnStatusFailed);
1085         }
1086         return result.Succeeded();
1087     }
1088 };
1089 
1090 //-------------------------------------------------------------------------
1091 // CommandObjectMultiwordProcess
1092 //-------------------------------------------------------------------------
1093 
1094 CommandObjectMultiwordProcess::CommandObjectMultiwordProcess (CommandInterpreter &interpreter) :
1095     CommandObjectMultiword ("process",
1096                               "A set of commands for operating on a process.",
1097                               "process <subcommand> [<subcommand-options>]")
1098 {
1099     LoadSubCommand (interpreter, "attach",      CommandObjectSP (new CommandObjectProcessAttach ()));
1100     LoadSubCommand (interpreter, "launch",      CommandObjectSP (new CommandObjectProcessLaunch ()));
1101     LoadSubCommand (interpreter, "continue",    CommandObjectSP (new CommandObjectProcessContinue ()));
1102     LoadSubCommand (interpreter, "detach",      CommandObjectSP (new CommandObjectProcessDetach ()));
1103     LoadSubCommand (interpreter, "signal",      CommandObjectSP (new CommandObjectProcessSignal ()));
1104     LoadSubCommand (interpreter, "status",      CommandObjectSP (new CommandObjectProcessStatus ()));
1105     LoadSubCommand (interpreter, "interrupt",   CommandObjectSP (new CommandObjectProcessInterrupt ()));
1106     LoadSubCommand (interpreter, "kill",        CommandObjectSP (new CommandObjectProcessKill ()));
1107 }
1108 
1109 CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess ()
1110 {
1111 }
1112 
1113