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