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