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