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