[Lldb-commits] [lldb] r124049 - in /lldb/trunk: include/lldb/Target/ source/API/ source/Plugins/Process/gdb-remote/ source/Target/ tools/debugserver/source/ tools/debugserver/source/MacOSX/

Greg Clayton gclayton at apple.com
Sat Jan 22 15:43:18 PST 2011


Author: gclayton
Date: Sat Jan 22 17:43:18 2011
New Revision: 124049

URL: http://llvm.org/viewvc/llvm-project?rev=124049&view=rev
Log:
Fixed an issue in "SBError SBProcess::Destroy ()" where it wasn't properly
checking the validity of the shared pointer prior to using it.

Fixed the GDB remote plug-in to once again watch for a reply from the "k" 
packet, and fixed the logic to make sure the thread requesting the kill
and the async thread play nice (and very quickly) by synchronizing the
packet sending and reply. I also tweaked some of the shut down packet
("k" kill, "D" detach, and the halt packet) to make sure they do the right
thing.

Fixed "StateType Process::WaitForProcessStopPrivate (...)" to correctly pass
the timeout along to WaitForStateChangedEventsPrivate() and made the function
behave correctly with respect to timing out.

Added separate STDIN, STDOUT, and STDERR support to debugserver. Also added
the start of being able to set the working directory for the inferior process.


Modified:
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/source/API/SBProcess.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/tools/debugserver/source/DNB.cpp
    lldb/trunk/tools/debugserver/source/DNB.h
    lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.cpp
    lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h
    lldb/trunk/tools/debugserver/source/RNBContext.cpp
    lldb/trunk/tools/debugserver/source/RNBContext.h
    lldb/trunk/tools/debugserver/source/RNBRemote.cpp
    lldb/trunk/tools/debugserver/source/debugserver.cpp

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Sat Jan 22 17:43:18 2011
@@ -1260,7 +1260,7 @@
     ///
     /// @see lldb::StateType
     //------------------------------------------------------------------
-    virtual void
+    virtual bool
     SetExitStatus (int exit_status, const char *cstr);
 
     //------------------------------------------------------------------

Modified: lldb/trunk/source/API/SBProcess.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBProcess.cpp?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/source/API/SBProcess.cpp (original)
+++ lldb/trunk/source/API/SBProcess.cpp Sat Jan 22 17:43:18 2011
@@ -421,11 +421,12 @@
 SBError
 SBProcess::Destroy ()
 {
-    Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
-
     SBError sb_error;
     if (m_opaque_sp)
+    {
+        Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
         sb_error.SetError(m_opaque_sp->Destroy());
+    }
     else
         sb_error.SetErrorString ("SBProcess is invalid");
 
@@ -434,7 +435,10 @@
     {
         SBStream sstr;
         sb_error.GetDescription (sstr);
-        log->Printf ("SBProcess(%p)::Destroy () => SBError (%p): %s", m_opaque_sp.get(), sb_error.get(), sstr.GetData());
+        log->Printf ("SBProcess(%p)::Destroy () => SBError (%p): %s", 
+                     m_opaque_sp.get(), 
+                     sb_error.get(), 
+                     sstr.GetData());
     }
 
     return sb_error;

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp Sat Jan 22 17:43:18 2011
@@ -511,6 +511,18 @@
     return false;
 }
 
+bool
+GDBRemoteCommunication::WaitForNotRunning (const TimeValue *timeout_ptr)
+{
+    return m_public_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
+}
+
+bool
+GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
+{
+    return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
+}
+
 size_t
 GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, uint32_t timeout_seconds)
 {
@@ -522,14 +534,14 @@
 }
 
 size_t
-GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, TimeValue* timeout_time_ptr)
+GDBRemoteCommunication::WaitForPacket (StringExtractorGDBRemote &response, const TimeValue* timeout_time_ptr)
 {
     Mutex::Locker locker(m_sequence_mutex);
     return WaitForPacketNoLock (response, timeout_time_ptr);
 }
 
 size_t
-GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &response, TimeValue* timeout_time_ptr)
+GDBRemoteCommunication::WaitForPacketNoLock (StringExtractorGDBRemote &response, const TimeValue* timeout_time_ptr)
 {
     bool checksum_error = false;
     response.Clear ();

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h Sat Jan 22 17:43:18 2011
@@ -81,7 +81,7 @@
     // wait indefinitely.
     size_t
     WaitForPacket (StringExtractorGDBRemote &response,
-                   lldb_private::TimeValue* timeout);
+                   const lldb_private::TimeValue* timeout);
 
     char
     GetAck (uint32_t timeout_seconds);
@@ -222,7 +222,10 @@
     {
         return m_public_is_running.GetValue();
     }
-    
+
+    bool
+    WaitForNotRunning (const lldb_private::TimeValue *timeout_ptr);
+
     bool
     GetHostInfo (uint32_t timeout_seconds);
 
@@ -256,7 +259,10 @@
 
     size_t
     WaitForPacketNoLock (StringExtractorGDBRemote &response, 
-                         lldb_private::TimeValue* timeout_time_ptr);
+                         const lldb_private::TimeValue* timeout_ptr);
+
+    bool
+    WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr);
 
     //------------------------------------------------------------------
     // Classes that inherit from GDBRemoteCommunication can see and modify these

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Sat Jan 22 17:43:18 2011
@@ -1157,7 +1157,13 @@
 }
 
 Error
-ProcessGDBRemote::WillDetach ()
+ProcessGDBRemote::InterruptIfRunning 
+(
+    bool discard_thread_plans, 
+    bool catch_stop_event, 
+    bool resume_private_state_thread,
+    EventSP &stop_event_sp
+)
 {
     Error error;
 
@@ -1166,30 +1172,54 @@
         bool timed_out = false;
         bool sent_interrupt = false;
         Mutex::Locker locker;
-        PausePrivateStateThread();
-        m_thread_list.DiscardThreadPlans();
-        m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
-        if (!m_gdb_comm.SendInterrupt (locker, 2, sent_interrupt, timed_out))
+        
+        if (catch_stop_event)
+            PausePrivateStateThread();
+        
+        if (discard_thread_plans)
+            m_thread_list.DiscardThreadPlans();
+
+        //m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+        if (!m_gdb_comm.SendInterrupt (locker, 1, sent_interrupt, timed_out))
         {
             if (timed_out)
                 error.SetErrorString("timed out sending interrupt packet");
             else
                 error.SetErrorString("unknown error sending interrupt packet");
-            ResumePrivateStateThread();
+            if (catch_stop_event)
+                ResumePrivateStateThread();
+            return error;
+        }
+        
+        
+        if (catch_stop_event)
+        {
+            TimeValue timeout_time;
+            timeout_time = TimeValue::Now();
+            timeout_time.OffsetWithSeconds(1);
+            StateType state = WaitForProcessStopPrivate (&timeout_time, stop_event_sp);
+
+            if (state == eStateInvalid)
+                error.SetErrorString("unable to verify target stopped");
         }
-        TimeValue timeout_time;
-        timeout_time = TimeValue::Now();
-        timeout_time.OffsetWithSeconds(2);
-
-        EventSP event_sp;
-        StateType state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp);
-        if (state != eStateStopped)
-            error.SetErrorString("unable to stop target");
+        
+        if (catch_stop_event && resume_private_state_thread)
+            ResumePrivateStateThread();
     }
     return error;
 }
 
 Error
+ProcessGDBRemote::WillDetach ()
+{
+    bool discard_thread_plans = true; 
+    bool catch_stop_event = true;
+    bool resume_private_state_thread = false; // DoDetach will resume the thread
+    EventSP event_sp;
+    return InterruptIfRunning (discard_thread_plans, catch_stop_event, resume_private_state_thread, event_sp);
+}
+
+Error
 ProcessGDBRemote::DoDetach()
 {
     Error error;
@@ -1223,6 +1253,16 @@
 }
 
 Error
+ProcessGDBRemote::WillDestroy ()
+{
+    bool discard_thread_plans = true; 
+    bool catch_stop_event = true;
+    bool resume_private_state_thread = true;
+    EventSP event_sp;
+    return InterruptIfRunning (discard_thread_plans, catch_stop_event, resume_private_state_thread, event_sp);    
+}
+
+Error
 ProcessGDBRemote::DoDestroy ()
 {
     Error error;
@@ -1233,10 +1273,40 @@
     // Interrupt if our inferior is running...
     if (m_gdb_comm.IsConnected())
     {
-        // Don't get a response when killing our
-        m_gdb_comm.SendPacket ("k", 1);
-    }
+        m_continue_packet.Clear();
+        m_continue_packet.Printf("k");
+        Listener listener ("gdb-remote.kill-packet-sent");
+        if (listener.StartListeningForEvents (&m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent))
+        {
+            EventSP event_sp;
+            TimeValue timeout;
+            timeout = TimeValue::Now();
+            timeout.OffsetWithSeconds (1);
+            m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (m_continue_packet.GetData(), m_continue_packet.GetSize()));
 
+            // Wait for the async thread to send the "k" packet
+            if (listener.WaitForEvent (&timeout, event_sp))
+            {
+                if (log)
+                    log->Printf ("ProcessGDBRemote::DoDestroy() got confirmation the \"k\" packet was sent");
+            }
+            else
+            {
+                if (log)
+                    log->Printf ("ProcessGDBRemote::DoDestroy() timed out waiting for \"k\" packet to be sent");
+                error.SetErrorString("Resume timed out.");
+            }
+            
+            // Wait for the async thread to exit which will indicate we stopped.
+            // Hopefully the stop will be a process exited state since we are
+            // asking the process to go away.
+            if (!m_gdb_comm.WaitForNotRunning (&timeout))
+            {
+                if (log)
+                    log->Printf ("ProcessGDBRemote::DoDestroy() timed out waiting for \"k\" stop reply packet");
+            }
+        }
+    }
     StopAsyncThread ();
     m_gdb_comm.StopReadThread();
     KillDebugserverProcess ();
@@ -1851,14 +1921,14 @@
                 log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData());
             }
 
-            error.SetError(::posix_spawnp (&m_debugserver_pid,
-                                             debugserver_path,
-                                             file_actions_err.Success() ? &file_actions : NULL,
-                                             &attr,
-                                             debugserver_args.GetArgumentVector(),
-                                             (char * const*)inferior_envp),
-                             eErrorTypePOSIX);
-
+            error.SetError (::posix_spawnp (&m_debugserver_pid,
+                                            debugserver_path,
+                                            file_actions_err.Success() ? &file_actions : NULL,
+                                            &attr,
+                                            debugserver_args.GetArgumentVector(),
+                                            (char * const*)inferior_envp),
+                            eErrorTypePOSIX);
+            
 
             ::posix_spawnattr_destroy (&attr);
 
@@ -1907,7 +1977,11 @@
     // debugserver that we are tracking...
 
     ProcessGDBRemote *process = (ProcessGDBRemote *)callback_baton;
-    
+
+    LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+    if (log)
+        log->Printf ("ProcessGDBRemote::MonitorDebugserverProcess (baton=%p, pid=%i, signo=%i (0x%x), exit_status=%i)", callback_baton, debugserver_pid, signo, signo, exit_status);
+
     if (process)
     {
         // Sleep for a half a second to make sure our inferior process has

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h Sat Jan 22 17:43:18 2011
@@ -149,6 +149,9 @@
     DoSignal (int signal);
 
     virtual lldb_private::Error
+    WillDestroy ();
+
+    virtual lldb_private::Error
     DoDestroy ();
 
     virtual void
@@ -382,6 +385,12 @@
                                const char *bytes, 
                                size_t bytes_len);
 
+    lldb_private::Error
+    InterruptIfRunning (bool discard_thread_plans, 
+                        bool catch_stop_event, 
+                        bool resume_private_state_thread,
+                        lldb::EventSP &stop_event_sp);
+
 private:
     //------------------------------------------------------------------
     // For ProcessGDBRemote only

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Sat Jan 22 17:43:18 2011
@@ -452,17 +452,22 @@
         log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
 
     StateType state = eStateInvalid;
-    if (m_private_state_listener.WaitForEventForBroadcasterWithType(timeout,
-                                                                    &m_private_state_broadcaster,
-                                                                    eBroadcastBitStateChanged,
-                                                                    event_sp))
+    if (m_private_state_listener.WaitForEventForBroadcasterWithType (timeout,
+                                                                     &m_private_state_broadcaster,
+                                                                     eBroadcastBitStateChanged,
+                                                                     event_sp))
         state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
 
     // This is a bit of a hack, but when we wait here we could very well return
     // to the command-line, and that could disable the log, which would render the
     // log we got above invalid.
     if (log)
-        log->Printf ("Process::%s (timeout = %p, event_sp) => %s", __FUNCTION__, timeout, StateAsCString(state));
+    {
+        if (state == eStateInvalid)
+            log->Printf ("Process::%s (timeout = %p, event_sp) => TIMEOUT", __FUNCTION__, timeout);
+        else
+            log->Printf ("Process::%s (timeout = %p, event_sp) => %s", __FUNCTION__, timeout, StateAsCString(state));
+    }
     return state;
 }
 
@@ -547,21 +552,23 @@
     return NULL;
 }
 
-void
+bool
 Process::SetExitStatus (int status, const char *cstr)
 {
-    if (m_private_state.GetValue() != eStateExited)
-    {
-        m_exit_status = status;
-        if (cstr)
-            m_exit_string = cstr;
-        else
-            m_exit_string.clear();
+    // We were already in the exited state
+    if (m_private_state.GetValue() == eStateExited)
+        return false;
+    
+    m_exit_status = status;
+    if (cstr)
+        m_exit_string = cstr;
+    else
+        m_exit_string.clear();
 
-        DidExit ();
+    DidExit ();
 
-        SetPrivateState (eStateExited);
-    }
+    SetPrivateState (eStateExited);
+    return true;
 }
 
 // This static callback can be used to watch for local child processes on
@@ -1425,11 +1432,17 @@
     // call DidLaunch:
     while (1)
     {
-        // FIXME: Might want to put a timeout in here:
-        state = WaitForStateChangedEventsPrivate (NULL, event_sp);
-        if (state == eStateStopped || state == eStateCrashed || state == eStateExited)
+        event_sp.reset();
+        state = WaitForStateChangedEventsPrivate (timeout, event_sp);
+
+        if (StateIsStoppedState(state))
             break;
-        else
+
+        // If state is invalid, then we timed out
+        if (state == eStateInvalid)
+            break;
+
+        if (event_sp)
             HandlePrivateEvent (event_sp);
     }
     return state;
@@ -1744,7 +1757,7 @@
                 // Wait for 2 seconds for the process to stop.
                 TimeValue timeout_time;
                 timeout_time = TimeValue::Now();
-                timeout_time.OffsetWithSeconds(2);
+                timeout_time.OffsetWithSeconds(1);
                 StateType state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp);
                 
                 if (state == eStateInvalid)

Modified: lldb/trunk/tools/debugserver/source/DNB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNB.cpp?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNB.cpp (original)
+++ lldb/trunk/tools/debugserver/source/DNB.cpp Sat Jan 22 17:43:18 2011
@@ -175,7 +175,10 @@
 DNBProcessLaunch (const char *path,
                   char const *argv[],
                   const char *envp[],
-                  const char *stdio_path,
+                  const char *working_directory, // NULL => dont' change, non-NULL => set working directory for inferior to this
+                  const char *stdin_path,
+                  const char *stdout_path,
+                  const char *stderr_path,
                   bool no_stdio,
                   nub_launch_flavor_t launch_flavor,
                   int disable_aslr,
@@ -199,7 +202,17 @@
     if (processSP.get())
     {
         DNBError launch_err;
-        pid_t pid = processSP->LaunchForDebug(path, argv, envp, stdio_path, no_stdio, launch_flavor, disable_aslr, launch_err);
+        pid_t pid = processSP->LaunchForDebug (path, 
+                                               argv, 
+                                               envp, 
+                                               working_directory, 
+                                               stdin_path, 
+                                               stdout_path, 
+                                               stderr_path, 
+                                               no_stdio, 
+                                               launch_flavor, 
+                                               disable_aslr, 
+                                               launch_err);
         if (err_str)
         {
             *err_str = '\0';

Modified: lldb/trunk/tools/debugserver/source/DNB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNB.h?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNB.h (original)
+++ lldb/trunk/tools/debugserver/source/DNB.h Sat Jan 22 17:43:18 2011
@@ -33,7 +33,19 @@
 //----------------------------------------------------------------------
 // Process control
 //----------------------------------------------------------------------
-nub_process_t   DNBProcessLaunch        (const char *path, char const *argv[], const char *envp[], const char *stdio_path, bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, char *err_str, size_t err_len) DNB_EXPORT;
+nub_process_t   DNBProcessLaunch        (const char *path, 
+                                         char const *argv[], 
+                                         const char *envp[], 
+                                         const char *working_directory, // NULL => dont' change, non-NULL => set working directory for inferior to this
+                                         const char *stdin_path,
+                                         const char *stdout_path,
+                                         const char *stderr_path,
+                                         bool no_stdio, 
+                                         nub_launch_flavor_t launch_flavor, 
+                                         int disable_aslr, 
+                                         char *err_str, 
+                                         size_t err_len) DNB_EXPORT;
+
 nub_process_t   DNBProcessAttach        (nub_process_t pid, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT;
 nub_process_t   DNBProcessAttachByName  (const char *name, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT;
 nub_process_t   DNBProcessAttachWait    (const char *wait_name, nub_launch_flavor_t launch_flavor, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL) DNB_EXPORT;

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.cpp?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.cpp Sat Jan 22 17:43:18 2011
@@ -1491,7 +1491,10 @@
     const char *path,
     char const *argv[],
     char const *envp[],
-    const char *stdio_path,
+    const char *working_directory, // NULL => dont' change, non-NULL => set working directory for inferior to this
+    const char *stdin_path,
+    const char *stdout_path,
+    const char *stderr_path,
     bool no_stdio,
     nub_launch_flavor_t launch_flavor,
     int disable_aslr,
@@ -1517,7 +1520,10 @@
                                                                 DNBArchProtocol::GetArchitecture (),
                                                                 argv, 
                                                                 envp, 
-                                                                stdio_path,
+                                                                working_directory,
+                                                                stdin_path,
+                                                                stdout_path,
+                                                                stderr_path,
                                                                 no_stdio, 
                                                                 this, 
                                                                 disable_aslr, 
@@ -1607,7 +1613,10 @@
     cpu_type_t cpu_type,
     char const *argv[],
     char const *envp[],
-    const char *stdio_path,
+    const char *working_directory,
+    const char *stdin_path,
+    const char *stdout_path,
+    const char *stderr_path,
     bool no_stdio,
     MachProcess* process,
     int disable_aslr,
@@ -1665,14 +1674,13 @@
     pid_t pid = INVALID_NUB_PROCESS;
     if (file_actions_valid)
     {
-        if (stdio_path == NULL && !no_stdio)
+        if (stdin_path == NULL && stdout_path == NULL && stderr_path == NULL && !no_stdio)
         {
             pty_error = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY);
             if (pty_error == PseudoTerminal::success)
-                stdio_path = pty.SlaveName();
-            // Make sure we were able to get the slave name
-            if (stdio_path == NULL)
-                stdio_path = "/dev/null";
+            {
+                stdin_path = stdout_path = stderr_path = pty.SlaveName();
+            }
         }
 
 		// if no_stdio, then do open file actions, opening /dev/null.
@@ -1693,11 +1701,11 @@
             if (err.Fail() || DNBLogCheckLogBit (LOG_PROCESS))
                 err.LogThreaded ("::posix_spawn_file_actions_addopen (&file_actions, filedes=STDERR_FILENO, path=/dev/null)");
         }
-        else if (stdio_path != NULL)
+        else
         {
-            int slave_fd_err = open (stdio_path, O_RDWR, 0);
-            int slave_fd_in = open (stdio_path, O_RDONLY, 0);
-            int slave_fd_out = open (stdio_path, O_WRONLY, 0);
+            int slave_fd_err = open (stderr_path ? stderr_path : "/dev/null", O_RDWR  , 0);
+            int slave_fd_in  = open (stdin_path  ? stdin_path  : "/dev/null", O_RDONLY, 0);
+            int slave_fd_out = open (stdout_path ? stdout_path : "/dev/null", O_WRONLY, 0);
 
             err.SetError( ::posix_spawn_file_actions_adddup2(&file_actions, slave_fd_err, STDERR_FILENO), DNBError::POSIX);
             if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachProcess.h Sat Jan 22 17:43:18 2011
@@ -47,9 +47,30 @@
     // Child process control
     //----------------------------------------------------------------------
     pid_t                   AttachForDebug (pid_t pid, char *err_str, size_t err_len);
-    pid_t                   LaunchForDebug (const char *path, char const *argv[], char const *envp[], const char *stdio_path, bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, DNBError &err);
+    pid_t                   LaunchForDebug (const char *path, 
+                                            char const *argv[], 
+                                            char const *envp[], 
+                                            const char *working_directory,
+                                            const char *stdin_path,
+                                            const char *stdout_path,
+                                            const char *stderr_path,
+                                            bool no_stdio, 
+                                            nub_launch_flavor_t launch_flavor, 
+                                            int disable_aslr, 
+                                            DNBError &err);
     static pid_t            ForkChildForPTraceDebugging (const char *path, char const *argv[], char const *envp[], MachProcess* process, DNBError &err);
-    static pid_t            PosixSpawnChildForPTraceDebugging (const char *path, cpu_type_t cpu_type, char const *argv[], char const *envp[], const char *stdio_path, bool no_stdio, MachProcess* process, int disable_aslr, DNBError& err);
+    static pid_t            PosixSpawnChildForPTraceDebugging (const char *path, 
+                                                               cpu_type_t cpu_type, 
+                                                               char const *argv[], 
+                                                               char const *envp[], 
+                                                               const char *working_directory,
+                                                               const char *stdin_path,
+                                                               const char *stdout_path,
+                                                               const char *stderr_path,
+                                                               bool no_stdio, 
+                                                               MachProcess* process, 
+                                                               int disable_aslr, 
+                                                               DNBError& err);
     nub_addr_t              GetDYLDAllImageInfosAddress ();
     static const void *     PrepareForAttach (const char *path, nub_launch_flavor_t launch_flavor, bool waitfor, DNBError &err_str);
     static void             CleanupAfterAttach (const void *attach_token, bool success, DNBError &err_str);

Modified: lldb/trunk/tools/debugserver/source/RNBContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBContext.cpp?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBContext.cpp (original)
+++ lldb/trunk/tools/debugserver/source/RNBContext.cpp Sat Jan 22 17:43:18 2011
@@ -12,11 +12,15 @@
 //===----------------------------------------------------------------------===//
 
 #include "RNBContext.h"
+
+#include <sys/stat.h>
+#include <sstream>
+
 #include "RNBRemote.h"
 #include "DNB.h"
 #include "DNBLog.h"
 #include "CFString.h"
-#include <sstream>
+
 
 //----------------------------------------------------------------------
 // Destructor
@@ -49,6 +53,20 @@
         return NULL;
 }
 
+bool
+RNBContext::SetWorkingDirectory (const char *path)
+{
+    struct stat working_directory_stat;
+    if (::stat (path, &working_directory_stat) != 0)
+    {
+        m_working_directory.clear();
+        return false;
+    }
+    m_working_directory.assign(path);
+    return true;
+}
+
+
 void
 RNBContext::SetProcessID (nub_process_t pid)
 {

Modified: lldb/trunk/tools/debugserver/source/RNBContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBContext.h?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBContext.h (original)
+++ lldb/trunk/tools/debugserver/source/RNBContext.h Sat Jan 22 17:43:18 2011
@@ -95,6 +95,16 @@
     const char *    LaunchStatusAsString (std::string& s);
     nub_launch_flavor_t LaunchFlavor () const { return m_launch_flavor; }
     void            SetLaunchFlavor (nub_launch_flavor_t flavor) { m_launch_flavor = flavor; }
+    
+    const char *    GetWorkingDirectory () const 
+                    { 
+                        if (!m_working_directory.empty())
+                            return m_working_directory.c_str();
+                        return NULL;
+                    }
+
+    bool            SetWorkingDirectory (const char *path);
+                        
 protected:
     //------------------------------------------------------------------
     // Classes that inherit from RNBContext can see and modify these
@@ -107,6 +117,7 @@
     DNBError        m_launch_status;    // This holds the status from the last launch attempt.
     std::vector<std::string> m_arg_vec;
     std::vector<std::string> m_env_vec; // This will be unparsed - entries FOO=value
+    std::string     m_working_directory;
 
     void    StartProcessStatusThread();
     void    StopProcessStatusThread();

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.cpp (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.cpp Sat Jan 22 17:43:18 2011
@@ -3126,6 +3126,7 @@
     // No response to should be sent to the kill packet
     if (m_ctx.HasValidProcessID())
         DNBProcessKill (m_ctx.ProcessID());
+    SendPacket ("W09");
     return rnb_success;
 }
 

Modified: lldb/trunk/tools/debugserver/source/debugserver.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/debugserver.cpp?rev=124049&r1=124048&r2=124049&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/debugserver.cpp (original)
+++ lldb/trunk/tools/debugserver/source/debugserver.cpp Sat Jan 22 17:43:18 2011
@@ -61,26 +61,18 @@
 #define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
 
 //----------------------------------------------------------------------
-// Run Loop function prototypes
-//----------------------------------------------------------------------
-RNBRunLoopMode RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remote);
-RNBRunLoopMode RNBRunLoopInferiorExecuting (RNBRemoteSP &remote);
-
-
-//----------------------------------------------------------------------
 // Get our program path and arguments from the remote connection.
 // We will need to start up the remote connection without a PID, get the
 // arguments, wait for the new process to finish launching and hit its
 // entry point,  and then return the run loop mode that should come next.
 //----------------------------------------------------------------------
 RNBRunLoopMode
-RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP)
+RNBRunLoopGetStartModeFromRemote (RNBRemote* remote)
 {
     std::string packet;
 
-    if (remoteSP.get() != NULL)
+    if (remote)
     {
-        RNBRemote* remote = remoteSP.get();
         RNBContext& ctx = remote->Context();
         uint32_t event_mask = RNBContext::event_read_packet_available;
 
@@ -151,7 +143,7 @@
 // or crash process state.
 //----------------------------------------------------------------------
 RNBRunLoopMode
-RNBRunLoopLaunchInferior (RNBRemoteSP &remote, const char *stdio_path, bool no_stdio)
+RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char *stdout_path, const char *stderr_path, bool no_stdio)
 {
     RNBContext& ctx = remote->Context();
 
@@ -208,7 +200,10 @@
     nub_process_t pid = DNBProcessLaunch (resolved_path,
                                           &inferior_argv[0],
                                           &inferior_envp[0],
-                                          stdio_path,
+                                          ctx.GetWorkingDirectory(),
+                                          stdin_path,
+                                          stdout_path,
+                                          stderr_path,
                                           no_stdio,
                                           launch_flavor,
                                           g_disable_aslr,
@@ -317,7 +312,7 @@
 // or crash process state.
 //----------------------------------------------------------------------
 RNBRunLoopMode
-RNBRunLoopLaunchAttaching (RNBRemoteSP &remote, nub_process_t attach_pid, nub_process_t& pid)
+RNBRunLoopLaunchAttaching (RNBRemote *remote, nub_process_t attach_pid, nub_process_t& pid)
 {
     RNBContext& ctx = remote->Context();
 
@@ -381,7 +376,7 @@
 
 // Return the new run loop mode based off of the current process state
 RNBRunLoopMode
-HandleProcessStateChange (RNBRemoteSP &remote, bool initialize)
+HandleProcessStateChange (RNBRemote *remote, bool initialize)
 {
     RNBContext& ctx = remote->Context();
     nub_process_t pid = ctx.ProcessID();
@@ -460,7 +455,7 @@
 // makes the inferior run, we need to leave this function with a new state
 // as the return code.
 RNBRunLoopMode
-RNBRunLoopInferiorExecuting (RNBRemoteSP &remote)
+RNBRunLoopInferiorExecuting (RNBRemote *remote)
 {
     DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
     RNBContext& ctx = remote->Context();
@@ -565,19 +560,19 @@
 //----------------------------------------------------------------------
 
 static int
-StartListening (RNBRemoteSP remoteSP, int listen_port)
+StartListening (RNBRemote *remote, int listen_port)
 {
-    if (!remoteSP->Comm().IsConnected())
+    if (!remote->Comm().IsConnected())
     {
         RNBLogSTDOUT ("Listening to port %i...\n", listen_port);
-        if (remoteSP->Comm().Listen(listen_port) != rnb_success)
+        if (remote->Comm().Listen(listen_port) != rnb_success)
         {
             RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
             return 0;
         }
         else
         {
-            remoteSP->StartReadRemoteDataThread();
+            remote->StartReadRemoteDataThread();
         }
     }
     return 1;
@@ -656,10 +651,14 @@
     { "waitfor-interval",   required_argument,  NULL,               'i' },  // Time in usecs to wait between sampling the pid list when waiting for a process by name
     { "waitfor-duration",   required_argument,  NULL,               'd' },  // The time in seconds to wait for a process to show up by name
     { "native-regs",        no_argument,        NULL,               'r' },  // Specify to use the native registers instead of the gdb defaults for the architecture.
-    { "stdio-path",         required_argument,  NULL,               's' },  // Set the STDIO path to be used when launching applications
+    { "stdio-path",         required_argument,  NULL,               's' },  // Set the STDIO path to be used when launching applications (STDIN, STDOUT and STDERR)
+    { "stdin-path",         required_argument,  NULL,               'I' },  // Set the STDIN path to be used when launching applications
+    { "stdout-path",        required_argument,  NULL,               'O' },  // Set the STDIN path to be used when launching applications
+    { "stderr-path",        required_argument,  NULL,               'E' },  // Set the STDIN path to be used when launching applications
     { "no-stdio",           no_argument,        NULL,               'n' },  // Do not set up any stdio (perhaps the program is a GUI program)
     { "setsid",             no_argument,        NULL,               'S' },  // call setsid() to make debugserver run in its own sessions
     { "disable-aslr",       no_argument,        NULL,               'D' },  // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
+    { "chdir",              no_argument,        NULL,               'c' },  // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
     { NULL,                 0,                  NULL,               0   }
 };
 
@@ -696,8 +695,11 @@
     std::string compile_options;
     std::string waitfor_pid_name;           // Wait for a process that starts with this name
     std::string attach_pid_name;
-    std::string stdio_path;
+    std::string stdin_path;
+    std::string stdout_path;
+    std::string stderr_path;
     std::string arch_name;
+    std::string working_directory;          // The new working directory to use for the inferior
     useconds_t waitfor_interval = 1000;     // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
     useconds_t waitfor_duration = 0;        // Time in seconds to wait for a process by name, 0 means wait forever.
     bool no_stdio = false;
@@ -783,6 +785,11 @@
                 }
                 break;
 
+            case 'c':
+                if (optarg && optarg[0])
+                    working_directory.assign(optarg);
+                break;
+
             case 'x':
                 if (optarg && optarg[0])
                 {
@@ -856,7 +863,21 @@
                 break;
 
             case 's':
-                stdio_path = optarg;
+                stdin_path.assign(optarg);
+                stdout_path.assign(optarg);
+                stderr_path.assign(optarg);
+                break;
+
+            case 'I':
+                stdin_path.assign(optarg);
+                break;
+
+            case 'O':
+                stdout_path.assign(optarg);
+                break;
+            
+            case 'E':
+                stderr_path.assign(optarg);
                 break;
 
             case 'n':
@@ -910,7 +931,6 @@
     g_remoteSP.reset (new RNBRemote (use_native_registers, arch_name.c_str()));
     
     
-
     RNBRemote *remote = g_remoteSP.get();
     if (remote == NULL)
     {
@@ -918,7 +938,16 @@
         return -1;
     }
 
-    g_remoteSP->Initialize();
+    if (!working_directory.empty())
+    {
+        if (remote->Context().SetWorkingDirectory (working_directory.c_str()) == false)
+        {
+            RNBLogSTDERR ("error: working directory doesn't exist '%s'.\n", working_directory.c_str());
+            exit (8);
+        }
+    }
+
+    remote->Initialize();
 
     RNBContext& ctx = remote->Context();
 
@@ -1054,9 +1083,9 @@
 #if defined (__arm__)
                 if (g_lockdown_opt)
                 {
-                    if (!g_remoteSP->Comm().IsConnected())
+                    if (!remote->Comm().IsConnected())
                     {
-                        if (g_remoteSP->Comm().ConnectToService () != rnb_success)
+                        if (remote->Comm().ConnectToService () != rnb_success)
                         {
                             RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
                             mode = eRNBRunLoopModeExit;
@@ -1069,21 +1098,21 @@
                             {
                                 DNBLogDebug("Task list: %s", applist_plist.c_str());
 
-                                g_remoteSP->Comm().Write(applist_plist.c_str(), applist_plist.size());
+                                remote->Comm().Write(applist_plist.c_str(), applist_plist.size());
                                 // Issue a read that will never yield any data until the other side
                                 // closes the socket so this process doesn't just exit and cause the
                                 // socket to close prematurely on the other end and cause data loss.
                                 std::string buf;
-                                g_remoteSP->Comm().Read(buf);
+                                remote->Comm().Read(buf);
                             }
-                            g_remoteSP->Comm().Disconnect(false);
+                            remote->Comm().Disconnect(false);
                             mode = eRNBRunLoopModeExit;
                             break;
                         }
                         else
                         {
                             // Start watching for remote packets
-                            g_remoteSP->StartReadRemoteDataThread();
+                            remote->StartReadRemoteDataThread();
                         }
                     }
                 }
@@ -1091,19 +1120,19 @@
 #endif
                     if (listen_port != INT32_MAX)
                     {
-                        if (!StartListening (g_remoteSP, listen_port))
+                        if (!StartListening (remote, listen_port))
                             mode = eRNBRunLoopModeExit;
                     }
                     else if (str[0] == '/')
                     {
-                        if (g_remoteSP->Comm().OpenFile (str))
+                        if (remote->Comm().OpenFile (str))
                             mode = eRNBRunLoopModeExit;
                     }
                 if (mode != eRNBRunLoopModeExit)
                 {
                     RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
 
-                    mode = RNBRunLoopGetStartModeFromRemote (g_remoteSP);
+                    mode = RNBRunLoopGetStartModeFromRemote (remote);
                 }
                 break;
 
@@ -1157,7 +1186,7 @@
 
                     RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid);
                     nub_process_t attached_pid;
-                    mode = RNBRunLoopLaunchAttaching (g_remoteSP, attach_pid, attached_pid);
+                    mode = RNBRunLoopLaunchAttaching (remote, attach_pid, attached_pid);
                     if (mode != eRNBRunLoopModeInferiorExecuting)
                     {
                         const char *error_str = remote->Context().LaunchStatus().AsString();
@@ -1201,12 +1230,12 @@
                 {
                     if (listen_port != INT32_MAX)
                     {
-                        if (!StartListening (g_remoteSP, listen_port))
+                        if (!StartListening (remote, listen_port))
                             mode = eRNBRunLoopModeExit;
                     }
                     else if (str[0] == '/')
                     {
-                        if (g_remoteSP->Comm().OpenFile (str))
+                        if (remote->Comm().OpenFile (str))
                             mode = eRNBRunLoopModeExit;
                     }
                     if (mode != eRNBRunLoopModeExit)
@@ -1215,33 +1244,39 @@
                 break;
 
             case eRNBRunLoopModeInferiorLaunching:
-                mode = RNBRunLoopLaunchInferior (g_remoteSP, stdio_path.empty() ? NULL : stdio_path.c_str(), no_stdio);
-
-                if (mode == eRNBRunLoopModeInferiorExecuting)
                 {
-                    if (listen_port != INT32_MAX)
+                    mode = RNBRunLoopLaunchInferior (remote, 
+                                                     stdin_path.empty() ? NULL : stdin_path.c_str(), 
+                                                     stdout_path.empty() ? NULL : stdout_path.c_str(), 
+                                                     stderr_path.empty() ? NULL : stderr_path.c_str(), 
+                                                     no_stdio);
+
+                    if (mode == eRNBRunLoopModeInferiorExecuting)
                     {
-                        if (!StartListening (g_remoteSP, listen_port))
-                            mode = eRNBRunLoopModeExit;
+                        if (listen_port != INT32_MAX)
+                        {
+                            if (!StartListening (remote, listen_port))
+                                mode = eRNBRunLoopModeExit;
+                        }
+                        else if (str[0] == '/')
+                        {
+                            if (remote->Comm().OpenFile (str))
+                                mode = eRNBRunLoopModeExit;
+                        }
+
+                        if (mode != eRNBRunLoopModeExit)
+                            RNBLogSTDOUT ("Got a connection, waiting for debugger instructions.\n");
                     }
-                    else if (str[0] == '/')
+                    else
                     {
-                        if (g_remoteSP->Comm().OpenFile (str))
-                            mode = eRNBRunLoopModeExit;
+                        const char *error_str = remote->Context().LaunchStatus().AsString();
+                        RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv[0], error_str ? error_str : "unknown error.");
                     }
-
-                    if (mode != eRNBRunLoopModeExit)
-                        RNBLogSTDOUT ("Got a connection, waiting for debugger instructions.\n");
-                }
-                else
-                {
-                    const char *error_str = remote->Context().LaunchStatus().AsString();
-                    RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv[0], error_str ? error_str : "unknown error.");
                 }
                 break;
 
             case eRNBRunLoopModeInferiorExecuting:
-                mode = RNBRunLoopInferiorExecuting(g_remoteSP);
+                mode = RNBRunLoopInferiorExecuting(remote);
                 break;
 
             default:
@@ -1251,8 +1286,8 @@
         }
     }
 
-    g_remoteSP->StopReadRemoteDataThread ();
-    g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS);
+    remote->StopReadRemoteDataThread ();
+    remote->Context().SetProcessID(INVALID_NUB_PROCESS);
 
     return 0;
 }





More information about the lldb-commits mailing list