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