Change Target & Process so they can really be initialized with an invalid architecture. 
Arrange that this then gets properly set on attach, or when a "file" is set.
Add a completer for "process attach -n".

Caveats: there isn't currently a way to handle multiple processes with the same name.  That
will have to wait on a way to pass annotations along with the completion strings.



git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@110624 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Commands/CommandObjectFile.cpp b/source/Commands/CommandObjectFile.cpp
index 2700e20..25576e1 100644
--- a/source/Commands/CommandObjectFile.cpp
+++ b/source/Commands/CommandObjectFile.cpp
@@ -126,31 +126,14 @@
 
         TargetSP target_sp;
 
-        ArchSpec arch;
-        if (m_options.m_arch.IsValid())
-            arch = m_options.m_arch;
-        else
-        {
-            arch = lldb_private::GetDefaultArchitecture ();
-            if (!arch.IsValid())
-                arch = LLDB_ARCH_DEFAULT;
-        }
+        ArchSpec arch = m_options.m_arch;
         Debugger &debugger = interpreter.GetDebugger();
-        Error error = debugger.GetTargetList().CreateTarget (debugger, file_spec, arch, NULL, true, target_sp);
-
-        if (error.Fail() && !m_options.m_arch.IsValid())
-        {
-            if (arch == LLDB_ARCH_DEFAULT_32BIT)
-                arch = LLDB_ARCH_DEFAULT_64BIT;
-            else
-                arch = LLDB_ARCH_DEFAULT_32BIT;
-            error = debugger.GetTargetList().CreateTarget (debugger, file_spec, arch, NULL, true, target_sp);
-        }
+        Error error = debugger.GetTargetList().CreateTarget (debugger, file_spec, m_options.m_arch, NULL, true, target_sp);
 
         if (target_sp)
         {
             debugger.GetTargetList().SetCurrentTarget(target_sp.get());
-            result.AppendMessageWithFormat ("Current executable set to '%s' (%s).\n", file_path, arch.AsCString());
+            result.AppendMessageWithFormat ("Current executable set to '%s' (%s).\n", file_path, target_sp->GetArchitecture().AsCString());
             result.SetStatus (eReturnStatusSuccessFinishNoResult);
         }
         else
diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp
index 20b008f..7f4d536 100644
--- a/source/Commands/CommandObjectProcess.cpp
+++ b/source/Commands/CommandObjectProcess.cpp
@@ -279,110 +279,6 @@
 {
 public:
 
-    CommandObjectProcessAttach () :
-        CommandObject ("process attach",
-                       "Attaches to a process.",
-                       "process attach <cmd-options>")
-    {
-        SetHelpLong("Currently, you must set the executable file before you can attach "
-                    "to a process.\n");
-    }
-
-    ~CommandObjectProcessAttach ()
-    {
-    }
-
-    bool
-    Execute (CommandInterpreter &interpreter,
-             Args& command,
-             CommandReturnObject &result)
-    {
-        Target *target = interpreter.GetDebugger().GetCurrentTarget().get();
-        if (target == NULL)
-        {
-            result.AppendError ("invalid target, set executable file using 'file' command");
-            result.SetStatus (eReturnStatusFailed);
-            return false;
-        }
-
-        // If our listener is NULL, users aren't allows to launch
-
-        Process *process = interpreter.GetDebugger().GetExecutionContext().process;
-        if (process)
-        {
-            if (process->IsAlive())
-            {
-                result.AppendErrorWithFormat ("Process %u is currently being debugged, kill the process before attaching.\n", process->GetID());
-                result.SetStatus (eReturnStatusFailed);
-                return false;
-            }
-        }
-
-        if (command.GetArgumentCount())
-        {
-            result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
-            result.SetStatus (eReturnStatusFailed);
-        }
-        else
-        {
-            const char *plugin_name = NULL;
-            
-            if (!m_options.plugin_name.empty())
-                plugin_name = m_options.plugin_name.c_str();
-
-            process = target->CreateProcess (interpreter.GetDebugger().GetListener(), plugin_name).get();
-
-            if (process)
-            {
-                Error error;
-                int attach_pid = m_options.pid;
-
-                if (attach_pid != LLDB_INVALID_PROCESS_ID)
-                {
-                    error = process->Attach (attach_pid);
-                    if (error.Success())
-                    {
-                        result.SetStatus (eReturnStatusSuccessContinuingNoResult);
-                    }
-                    else
-                    {
-                        result.AppendErrorWithFormat ("Attaching to process %i failed: %s.\n", 
-                                                     attach_pid, 
-                                                     error.AsCString());
-                        result.SetStatus (eReturnStatusFailed);
-                    }
-                }
-                else if (!m_options.name.empty())
-                {
-                    error = process->Attach (m_options.name.c_str(), m_options.waitfor);
-                    if (error.Success())
-                    {
-                        result.SetStatus (eReturnStatusSuccessContinuingNoResult);
-                    }
-                    else
-                    {
-                        if (m_options.waitfor)
-                            result.AppendErrorWithFormat ("Waiting for a process to launch named '%s': %s\n", 
-                                                         m_options.name.c_str(),
-                                                         error.AsCString());
-                        else
-                            result.AppendErrorWithFormat ("Failed to a process named '%s': %s\n", 
-                                                         m_options.name.c_str(),
-                                                         error.AsCString());
-                        result.SetStatus (eReturnStatusFailed);
-                    }
-                }
-            }
-        }
-        return result.Succeeded();
-    }
-    
-    Options *
-    GetOptions ()
-    {
-        return &m_options;
-    }
-
     class CommandOptions : public Options
     {
     public:
@@ -448,6 +344,68 @@
             return g_option_table;
         }
 
+        virtual bool
+        HandleOptionArgumentCompletion (CommandInterpreter &interpreter,
+                                        Args &input,
+                                        int cursor_index,
+                                        int char_pos,
+                                        OptionElementVector &opt_element_vector,
+                                        int opt_element_index,
+                                        int match_start_point,
+                                        int max_return_elements,
+                                        bool &word_complete,
+                                        StringList &matches)
+        {
+            int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
+            int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
+    
+            // We are only completing the name option for now...
+            
+            const lldb::OptionDefinition *opt_defs = GetDefinitions();
+            if (opt_defs[opt_defs_index].short_option == 'n')
+            {
+                // Are we in the name?
+                
+                // Look to see if there is a -P argument provided, and if so use that plugin, otherwise
+                // use the default plugin.
+                Process *process = interpreter.GetDebugger().GetExecutionContext().process;
+                bool need_to_delete_process = false;
+                
+                const char *partial_name = NULL;
+                partial_name = input.GetArgumentAtIndex(opt_arg_pos);
+                
+                if (process && process->IsAlive())
+                    return true;
+                    
+                Target *target = interpreter.GetDebugger().GetCurrentTarget().get();
+                if (target == NULL)
+                {
+                    // No target has been set yet, for now do host completion.  Otherwise I don't know how we would
+                    // figure out what the right target to use is...
+                    std::vector<lldb::pid_t> pids;
+                    Host::ListProcessesMatchingName (partial_name, matches, pids);
+                    return true;
+                }
+                if (!process)
+                {
+                    process = target->CreateProcess (interpreter.GetDebugger().GetListener(), partial_name).get();
+                    need_to_delete_process = true;
+                }
+                
+                if (process)
+                {
+                    matches.Clear();
+                    std::vector<lldb::pid_t> pids;
+                    process->ListProcessesMatchingName (NULL, matches, pids);
+                    if (need_to_delete_process)
+                        target->DeleteCurrentProcess();
+                    return true;
+                }
+            }
+            
+            return false;
+        }
+
         // Options table: Required for subclasses of Options.
 
         static lldb::OptionDefinition g_option_table[];
@@ -460,6 +418,211 @@
         bool waitfor;
     };
 
+    CommandObjectProcessAttach () :
+        CommandObject ("process attach",
+                       "Attaches to a process.",
+                       "process attach <cmd-options>")
+    {
+        SetHelpLong("Currently, you must set the executable file before you can attach "
+                    "to a process.\n");
+    }
+
+    ~CommandObjectProcessAttach ()
+    {
+    }
+
+    bool
+    Execute (CommandInterpreter &interpreter,
+             Args& command,
+             CommandReturnObject &result)
+    {
+        Target *target = interpreter.GetDebugger().GetCurrentTarget().get();
+
+        Process *process = interpreter.GetDebugger().GetExecutionContext().process;
+        if (process)
+        {
+            if (process->IsAlive())
+            {
+                result.AppendErrorWithFormat ("Process %u is currently being debugged, kill the process before attaching.\n", 
+                                              process->GetID());
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+        }
+
+        if (target == NULL)
+        {
+            // If there isn't a current target create one.
+            TargetSP new_target_sp;
+            FileSpec emptyFileSpec;
+            ArchSpec emptyArchSpec;
+            Error error;
+            
+            error = interpreter.GetDebugger().GetTargetList().CreateTarget(interpreter.GetDebugger(), 
+                                                                           emptyFileSpec,
+                                                                           emptyArchSpec, 
+                                                                           NULL, 
+                                                                           false,
+                                                                           new_target_sp);
+            target = new_target_sp.get();
+            if (target == NULL || error.Fail())
+            {
+                result.AppendError(error.AsCString("Error creating empty target"));
+                return false;
+            }
+            interpreter.GetDebugger().GetTargetList().SetCurrentTarget(target);
+        }
+        
+        // Record the old executable module, we want to issue a warning if the process of attaching changed the
+        // current executable (like somebody said "file foo" then attached to a PID whose executable was bar.)
+         
+        ModuleSP old_exec_module_sp = target->GetExecutableModule();
+        ArchSpec old_arch_spec = target->GetArchitecture();
+
+        if (command.GetArgumentCount())
+        {
+            result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
+            result.SetStatus (eReturnStatusFailed);
+        }
+        else
+        {
+            const char *plugin_name = NULL;
+            
+            if (!m_options.plugin_name.empty())
+                plugin_name = m_options.plugin_name.c_str();
+
+            process = target->CreateProcess (interpreter.GetDebugger().GetListener(), plugin_name).get();
+
+            if (process)
+            {
+                Error error;
+                int attach_pid = m_options.pid;
+                
+                // If we are waiting for a process with this name to show up, do that first.
+                if (m_options.waitfor)
+                {
+                    if (m_options.name.empty())
+                    {
+                        result.AppendError("Invalid arguments: must supply a process name with the waitfor option.\n");
+                        result.SetStatus (eReturnStatusFailed);
+                        return false;
+                    }
+                    else
+                    {
+                        error = process->Attach (m_options.name.c_str(), m_options.waitfor);
+                        if (error.Success())
+                        {
+                            result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+                        }
+                        else
+                        {
+                            result.AppendErrorWithFormat ("Waiting for a process to launch named '%s': %s\n", 
+                                                             m_options.name.c_str(),
+                                                             error.AsCString());
+                            result.SetStatus (eReturnStatusFailed);
+                            return false;                
+                        }
+                    }
+                }
+                else
+                {
+                    // If the process was specified by name look it up, so we can warn if there are multiple
+                    // processes with this pid.
+                    
+                    if (attach_pid == LLDB_INVALID_PROCESS_ID && !m_options.name.empty())
+                    {
+                        std::vector<lldb::pid_t> pids;
+                        StringList matches;
+                        
+                        process->ListProcessesMatchingName(m_options.name.c_str(), matches, pids);
+                        if (matches.GetSize() > 1)
+                        {
+                            result.AppendErrorWithFormat("More than one process named %s\n", m_options.name.c_str());
+                            result.SetStatus (eReturnStatusFailed);
+                            return false;
+                        }
+                        else if (matches.GetSize() == 0)
+                        {
+                            result.AppendErrorWithFormat("Could not find a process named %s\n", m_options.name.c_str());
+                            result.SetStatus (eReturnStatusFailed);
+                            return false;
+                        }
+                        else 
+                        {
+                            attach_pid = pids[0];
+                        }
+
+                    }
+
+                    if (attach_pid != LLDB_INVALID_PROCESS_ID)
+                    {
+                        error = process->Attach (attach_pid);
+                        if (error.Success())
+                        {
+                            result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+                        }
+                        else
+                        {
+                            result.AppendErrorWithFormat ("Attaching to process %i failed: %s.\n", 
+                                                         attach_pid, 
+                                                         error.AsCString());
+                            result.SetStatus (eReturnStatusFailed);
+                        }
+                    }
+                    else
+                    {
+                        result.AppendErrorWithFormat ("No PID specified for attach\n", 
+                                                         attach_pid, 
+                                                         error.AsCString());
+                        result.SetStatus (eReturnStatusFailed);
+                    
+                    }
+                }
+            }
+        }
+        
+        if (result.Succeeded())
+        {
+            // Okay, we're done.  Last step is to warn if the executable module has changed:
+            if (!old_exec_module_sp)
+            {
+                char new_path[PATH_MAX + 1];
+                target->GetExecutableModule()->GetFileSpec().GetPath(new_path, PATH_MAX);
+                
+                result.AppendMessageWithFormat("Executable module set to \"%s\".\n",
+                    new_path);
+            }
+            else if (old_exec_module_sp->GetFileSpec() != target->GetExecutableModule()->GetFileSpec())
+            {
+                char old_path[PATH_MAX + 1];
+                char new_path[PATH_MAX + 1];
+                
+                old_exec_module_sp->GetFileSpec().GetPath(old_path, PATH_MAX);
+                target->GetExecutableModule()->GetFileSpec().GetPath (new_path, PATH_MAX);
+                
+                result.AppendWarningWithFormat("Executable module changed from \"%s\" to \"%s\".\n",
+                                                    old_path, new_path);
+            }
+            
+            if (!old_arch_spec.IsValid())
+            {
+                result.AppendMessageWithFormat ("Architecture set to: %s.\n", target->GetArchitecture().AsCString());
+            }
+            else if (old_arch_spec != target->GetArchitecture())
+            {
+                result.AppendWarningWithFormat("Architecture changed from %s to %s.\n", 
+                                                old_arch_spec.AsCString(), target->GetArchitecture().AsCString());
+            }
+        }
+        return result.Succeeded();
+    }
+    
+    Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+
 protected:
 
     CommandOptions m_options;