“process launch” should “detach” not “kill” if the current process was one we attached to.
“process attach” should ask the same questions as process launch if there is a current process.
“process connect” then “process launch” or “process attach” should actually work.

<rdar://problem/13524210>
<rdar://problem/13524208>
<rdar://problem/13488919>

git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@178324 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp
index f39c322..2221514 100644
--- a/source/Commands/CommandObjectProcess.cpp
+++ b/source/Commands/CommandObjectProcess.cpp
@@ -34,20 +34,95 @@
 using namespace lldb;
 using namespace lldb_private;
 
+class CommandObjectProcessLaunchOrAttach : public CommandObjectParsed
+{
+public:
+    CommandObjectProcessLaunchOrAttach (CommandInterpreter &interpreter,
+                                       const char *name,
+                                       const char *help,
+                                       const char *syntax,
+                                       uint32_t flags,
+                                       const char *new_process_action) :
+        CommandObjectParsed (interpreter, name, help, syntax, flags),
+        m_new_process_action (new_process_action) {}
+    
+    virtual ~CommandObjectProcessLaunchOrAttach () {}
+protected:
+    bool
+    StopProcessIfNecessary (Process *&process, StateType &state, CommandReturnObject &result)
+    {
+        state = eStateInvalid;
+        if (process)
+        {
+            state = process->GetState();
+            
+            if (process->IsAlive() && state != eStateConnected)
+            {       
+                char message[1024];
+                if (process->GetState() == eStateAttaching)
+                    ::snprintf (message, sizeof(message), "There is a pending attach, abort it and %s?", m_new_process_action.c_str());
+                else if (process->GetShouldDetach())
+                    ::snprintf (message, sizeof(message), "There is a running process, detach from it and %s?", m_new_process_action.c_str());
+                else
+                    ::snprintf (message, sizeof(message), "There is a running process, kill it and %s?", m_new_process_action.c_str());
+        
+                if (!m_interpreter.Confirm (message, true))
+                {
+                    result.SetStatus (eReturnStatusFailed);
+                    return false;
+                }
+                else
+                {
+                    if (process->GetShouldDetach())
+                    {
+                        Error detach_error (process->Detach());
+                        if (detach_error.Success())
+                        {
+                            result.SetStatus (eReturnStatusSuccessFinishResult);
+                            process = NULL;
+                        }
+                        else
+                        {
+                            result.AppendErrorWithFormat ("Failed to detach from process: %s\n", detach_error.AsCString());
+                            result.SetStatus (eReturnStatusFailed);
+                        }
+                    }
+                    else
+                    {
+                        Error destroy_error (process->Destroy());
+                        if (destroy_error.Success())
+                        {
+                            result.SetStatus (eReturnStatusSuccessFinishResult);
+                            process = NULL;
+                        }
+                        else
+                        {
+                            result.AppendErrorWithFormat ("Failed to kill process: %s\n", destroy_error.AsCString());
+                            result.SetStatus (eReturnStatusFailed);
+                        }
+                    }
+                }
+            }
+        }
+        return result.Succeeded();
+    }
+    std::string m_new_process_action;
+};
 //-------------------------------------------------------------------------
 // CommandObjectProcessLaunch
 //-------------------------------------------------------------------------
 #pragma mark CommandObjectProcessLaunch
-class CommandObjectProcessLaunch : public CommandObjectParsed
+class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach
 {
 public:
 
     CommandObjectProcessLaunch (CommandInterpreter &interpreter) :
-        CommandObjectParsed (interpreter,
-                             "process launch",
-                             "Launch the executable in the debugger.",
-                             NULL,
-                             eFlagRequiresTarget),
+        CommandObjectProcessLaunchOrAttach (interpreter,
+                                            "process launch",
+                                            "Launch the executable in the debugger.",
+                                            NULL,
+                                            eFlagRequiresTarget,
+                                            "restart"),
         m_options (interpreter)
     {
         CommandArgumentEntry arg;
@@ -125,38 +200,9 @@
         
         StateType state = eStateInvalid;
         Process *process = m_exe_ctx.GetProcessPtr();
-        if (process)
-        {
-            state = process->GetState();
-            
-            if (process->IsAlive() && state != eStateConnected)
-            {       
-                char message[1024];
-                if (process->GetState() == eStateAttaching)
-                    ::strncpy (message, "There is a pending attach, abort it and launch a new process?", sizeof(message));
-                else
-                    ::strncpy (message, "There is a running process, kill it and restart?", sizeof(message));
         
-                if (!m_interpreter.Confirm (message, true))
-                {
-                    result.SetStatus (eReturnStatusFailed);
-                    return false;
-                }
-                else
-                {
-                    Error destroy_error (process->Destroy());
-                    if (destroy_error.Success())
-                    {
-                        result.SetStatus (eReturnStatusSuccessFinishResult);
-                    }
-                    else
-                    {
-                        result.AppendErrorWithFormat ("Failed to kill process: %s\n", destroy_error.AsCString());
-                        result.SetStatus (eReturnStatusFailed);
-                    }
-                }
-            }
-        }
+        if (!StopProcessIfNecessary(process, state, result))
+            return false;
         
         const char *target_settings_argv0 = target->GetArg0();
         
@@ -217,35 +263,34 @@
                 m_options.launch_info.GetFlags().Clear (eLaunchFlagLaunchInTTY);
             }
         }
+        
+        if (!m_options.launch_info.GetArchitecture().IsValid())
+            m_options.launch_info.GetArchitecture() = target->GetArchitecture();
+
+        PlatformSP platform_sp (target->GetPlatform());
+        
+        if (platform_sp && platform_sp->CanDebugProcess ())
+        {
+            process = target->GetPlatform()->DebugProcess (m_options.launch_info, 
+                                                           debugger,
+                                                           target,
+                                                           debugger.GetListener(),
+                                                           error).get();
+        }
         else
         {
-            if (!m_options.launch_info.GetArchitecture().IsValid())
-                m_options.launch_info.GetArchitecture() = target->GetArchitecture();
-
-            PlatformSP platform_sp (target->GetPlatform());
-            
-            if (platform_sp && platform_sp->CanDebugProcess ())
-            {
-                process = target->GetPlatform()->DebugProcess (m_options.launch_info, 
-                                                               debugger,
-                                                               target,
-                                                               debugger.GetListener(),
-                                                               error).get();
-            }
-            else
-            {
-                const char *plugin_name = m_options.launch_info.GetProcessPluginName();
-                process = target->CreateProcess (debugger.GetListener(), plugin_name, NULL).get();
-                if (process)
-                    error = process->Launch (m_options.launch_info);
-            }
-
-            if (process == NULL)
-            {
-                result.SetError (error, "failed to launch or debug process");
-                return false;
-            }
+            const char *plugin_name = m_options.launch_info.GetProcessPluginName();
+            process = target->CreateProcess (debugger.GetListener(), plugin_name, NULL).get();
+            if (process)
+                error = process->Launch (m_options.launch_info);
         }
+
+        if (process == NULL)
+        {
+            result.SetError (error, "failed to launch or debug process");
+            return false;
+        }
+
              
         if (error.Success())
         {
@@ -332,7 +377,7 @@
 // CommandObjectProcessAttach
 //-------------------------------------------------------------------------
 #pragma mark CommandObjectProcessAttach
-class CommandObjectProcessAttach : public CommandObjectParsed
+class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach
 {
 public:
 
@@ -475,10 +520,12 @@
     };
 
     CommandObjectProcessAttach (CommandInterpreter &interpreter) :
-        CommandObjectParsed (interpreter,
-                             "process attach",
-                             "Attach to a process.",
-                             "process attach <cmd-options>"),
+        CommandObjectProcessLaunchOrAttach (interpreter,
+                                            "process attach",
+                                            "Attach to a process.",
+                                            "process attach <cmd-options>",
+                                            0,
+                                            "attach"),
         m_options (interpreter)
     {
     }
@@ -503,20 +550,12 @@
         // and the target actually stopping.  So even if the interpreter is set to be asynchronous, we wait for the stop
         // ourselves here.
         
-        Process *process = m_exe_ctx.GetProcessPtr();
         StateType state = eStateInvalid;
-        if (process)
-        {
-            state = process->GetState();
-            if (process->IsAlive() && state != eStateConnected)
-            {
-                result.AppendErrorWithFormat ("Process %" PRIu64 " is currently being debugged, kill the process before attaching.\n",
-                                              process->GetID());
-                result.SetStatus (eReturnStatusFailed);
-                return false;
-            }
-        }
-
+        Process *process = m_exe_ctx.GetProcessPtr();
+        
+        if (!StopProcessIfNecessary (process, state, result))
+            return false;
+        
         if (target == NULL)
         {
             // If there isn't a current target create one.