1*bd2d88d6SJason Molenda //===-- libdebugserver.cpp --------------------------------------*- C++ -*-===//
2*bd2d88d6SJason Molenda //
3*bd2d88d6SJason Molenda //                     The LLVM Compiler Infrastructure
4*bd2d88d6SJason Molenda //
5*bd2d88d6SJason Molenda // This file is distributed under the University of Illinois Open Source
6*bd2d88d6SJason Molenda // License. See LICENSE.TXT for details.
7*bd2d88d6SJason Molenda //
8*bd2d88d6SJason Molenda //===----------------------------------------------------------------------===//
9d676074dSJason Molenda 
10d676074dSJason Molenda #include <sys/socket.h>
11d676074dSJason Molenda #include <sys/types.h>
12d676074dSJason Molenda #include <errno.h>
13d676074dSJason Molenda #include <getopt.h>
14d676074dSJason Molenda #include <netinet/in.h>
15d676074dSJason Molenda #include <sys/select.h>
16d676074dSJason Molenda #include <sys/sysctl.h>
17d676074dSJason Molenda 
18d676074dSJason Molenda #include "DNB.h"
19d676074dSJason Molenda #include "DNBLog.h"
20d676074dSJason Molenda #include "DNBTimer.h"
21d676074dSJason Molenda #include "PseudoTerminal.h"
22d676074dSJason Molenda #include "RNBContext.h"
23d676074dSJason Molenda #include "RNBServices.h"
24d676074dSJason Molenda #include "RNBSocket.h"
25d676074dSJason Molenda #include "RNBRemote.h"
26d676074dSJason Molenda #include "SysSignal.h"
27d676074dSJason Molenda 
28d676074dSJason Molenda //----------------------------------------------------------------------
29d676074dSJason Molenda // Run loop modes which determine which run loop function will be called
30d676074dSJason Molenda //----------------------------------------------------------------------
31d676074dSJason Molenda typedef enum
32d676074dSJason Molenda {
33d676074dSJason Molenda     eRNBRunLoopModeInvalid = 0,
34d676074dSJason Molenda     eRNBRunLoopModeGetStartModeFromRemoteProtocol,
35d676074dSJason Molenda     eRNBRunLoopModeInferiorExecuting,
36d676074dSJason Molenda     eRNBRunLoopModeExit
37d676074dSJason Molenda } RNBRunLoopMode;
38d676074dSJason Molenda 
39d676074dSJason Molenda 
40d676074dSJason Molenda //----------------------------------------------------------------------
41d676074dSJason Molenda // Global Variables
42d676074dSJason Molenda //----------------------------------------------------------------------
43d676074dSJason Molenda RNBRemoteSP g_remoteSP;
44d676074dSJason Molenda int g_disable_aslr = 0;
45d676074dSJason Molenda int g_isatty = 0;
46d676074dSJason Molenda 
47d676074dSJason Molenda #define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
48d676074dSJason Molenda #define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
49d676074dSJason Molenda 
50d676074dSJason Molenda 
51d676074dSJason Molenda //----------------------------------------------------------------------
52d676074dSJason Molenda // Get our program path and arguments from the remote connection.
53d676074dSJason Molenda // We will need to start up the remote connection without a PID, get the
54d676074dSJason Molenda // arguments, wait for the new process to finish launching and hit its
55d676074dSJason Molenda // entry point,  and then return the run loop mode that should come next.
56d676074dSJason Molenda //----------------------------------------------------------------------
57d676074dSJason Molenda RNBRunLoopMode
58d676074dSJason Molenda RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP)
59d676074dSJason Molenda {
60d676074dSJason Molenda     std::string packet;
61d676074dSJason Molenda 
62d676074dSJason Molenda     if (remoteSP.get() != NULL)
63d676074dSJason Molenda     {
64d676074dSJason Molenda         RNBRemote* remote = remoteSP.get();
65d676074dSJason Molenda         RNBContext& ctx = remote->Context();
66d676074dSJason Molenda         uint32_t event_mask = RNBContext::event_read_packet_available;
67d676074dSJason Molenda 
68d676074dSJason Molenda         // Spin waiting to get the A packet.
69d676074dSJason Molenda         while (1)
70d676074dSJason Molenda         {
71d676074dSJason Molenda             DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask);
72d676074dSJason Molenda             nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
73d676074dSJason Molenda             DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events);
74d676074dSJason Molenda 
75d676074dSJason Molenda             if (set_events & RNBContext::event_read_packet_available)
76d676074dSJason Molenda             {
77d676074dSJason Molenda                 rnb_err_t err = rnb_err;
78d676074dSJason Molenda                 RNBRemote::PacketEnum type;
79d676074dSJason Molenda 
80d676074dSJason Molenda                 err = remote->HandleReceivedPacket (&type);
81d676074dSJason Molenda 
82d676074dSJason Molenda                 // check if we tried to attach to a process
83d676074dSJason Molenda                 if (type == RNBRemote::vattach || type == RNBRemote::vattachwait)
84d676074dSJason Molenda                 {
85d676074dSJason Molenda                     if (err == rnb_success)
86d676074dSJason Molenda                         return eRNBRunLoopModeInferiorExecuting;
87d676074dSJason Molenda                     else
88d676074dSJason Molenda                     {
89d676074dSJason Molenda                         RNBLogSTDERR ("error: attach failed.");
90d676074dSJason Molenda                         return eRNBRunLoopModeExit;
91d676074dSJason Molenda                     }
92d676074dSJason Molenda                 }
93d676074dSJason Molenda 
94d676074dSJason Molenda 
95d676074dSJason Molenda                 if (err == rnb_success)
96d676074dSJason Molenda                 {
97d676074dSJason Molenda                     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Got success...",__FUNCTION__);
98d676074dSJason Molenda 					continue;
99d676074dSJason Molenda 				}
100d676074dSJason Molenda 				else if (err == rnb_not_connected)
101d676074dSJason Molenda                 {
102d676074dSJason Molenda                     RNBLogSTDERR ("error: connection lost.");
103d676074dSJason Molenda                     return eRNBRunLoopModeExit;
104d676074dSJason Molenda                 }
105d676074dSJason Molenda                 else
106d676074dSJason Molenda                 {
107d676074dSJason Molenda                     // a catch all for any other gdb remote packets that failed
108d676074dSJason Molenda                     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__);
109d676074dSJason Molenda                     continue;
110d676074dSJason Molenda                 }
111d676074dSJason Molenda 
112d676074dSJason Molenda                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
113d676074dSJason Molenda             }
114d676074dSJason Molenda             else
115d676074dSJason Molenda             {
116d676074dSJason Molenda                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__);
117d676074dSJason Molenda                 return eRNBRunLoopModeExit;
118d676074dSJason Molenda             }
119d676074dSJason Molenda         }
120d676074dSJason Molenda     }
121d676074dSJason Molenda     return eRNBRunLoopModeExit;
122d676074dSJason Molenda }
123d676074dSJason Molenda 
124d676074dSJason Molenda 
125d676074dSJason Molenda //----------------------------------------------------------------------
126d676074dSJason Molenda // Watch for signals:
127d676074dSJason Molenda // SIGINT: so we can halt our inferior. (disabled for now)
128d676074dSJason Molenda // SIGPIPE: in case our child process dies
129d676074dSJason Molenda //----------------------------------------------------------------------
130d676074dSJason Molenda nub_process_t g_pid;
131d676074dSJason Molenda int g_sigpipe_received = 0;
132d676074dSJason Molenda void
133d676074dSJason Molenda signal_handler(int signo)
134d676074dSJason Molenda {
135d676074dSJason Molenda     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo));
136d676074dSJason Molenda 
137d676074dSJason Molenda     switch (signo)
138d676074dSJason Molenda     {
139d676074dSJason Molenda 			//  case SIGINT:
140d676074dSJason Molenda 			//      DNBProcessKill (g_pid, signo);
141d676074dSJason Molenda 			//      break;
142d676074dSJason Molenda 
143d676074dSJason Molenda 		case SIGPIPE:
144d676074dSJason Molenda 			g_sigpipe_received = 1;
145d676074dSJason Molenda 			break;
146d676074dSJason Molenda     }
147d676074dSJason Molenda }
148d676074dSJason Molenda 
149d676074dSJason Molenda // Return the new run loop mode based off of the current process state
150d676074dSJason Molenda RNBRunLoopMode
151d676074dSJason Molenda HandleProcessStateChange (RNBRemoteSP &remote, bool initialize)
152d676074dSJason Molenda {
153d676074dSJason Molenda     RNBContext& ctx = remote->Context();
154d676074dSJason Molenda     nub_process_t pid = ctx.ProcessID();
155d676074dSJason Molenda 
156d676074dSJason Molenda     if (pid == INVALID_NUB_PROCESS)
157d676074dSJason Molenda     {
158d676074dSJason Molenda         DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
159d676074dSJason Molenda         return eRNBRunLoopModeExit;
160d676074dSJason Molenda     }
161d676074dSJason Molenda     nub_state_t pid_state = DNBProcessGetState (pid);
162d676074dSJason Molenda 
163d676074dSJason Molenda     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state));
164d676074dSJason Molenda 
165d676074dSJason Molenda     switch (pid_state)
166d676074dSJason Molenda     {
167d676074dSJason Molenda 		case eStateInvalid:
168d676074dSJason Molenda 		case eStateUnloaded:
169d676074dSJason Molenda 			// Something bad happened
170d676074dSJason Molenda 			return eRNBRunLoopModeExit;
171d676074dSJason Molenda 			break;
172d676074dSJason Molenda 
173d676074dSJason Molenda 		case eStateAttaching:
174d676074dSJason Molenda 		case eStateLaunching:
175d676074dSJason Molenda 			return eRNBRunLoopModeInferiorExecuting;
176d676074dSJason Molenda 
177d676074dSJason Molenda 		case eStateSuspended:
178d676074dSJason Molenda 		case eStateCrashed:
179d676074dSJason Molenda 		case eStateStopped:
180d676074dSJason Molenda 			if (initialize == false)
181d676074dSJason Molenda 			{
182d676074dSJason Molenda 				// Compare the last stop count to our current notion of a stop count
183d676074dSJason Molenda 				// to make sure we don't notify more than once for a given stop.
184d676074dSJason Molenda 				nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
185d676074dSJason Molenda 				bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid));
186d676074dSJason Molenda 				if (pid_stop_count_changed)
187d676074dSJason Molenda 				{
188d676074dSJason Molenda 					remote->FlushSTDIO();
189d676074dSJason Molenda 
190d676074dSJason Molenda 					if (ctx.GetProcessStopCount() == 1)
191d676074dSJason Molenda 					{
192d676074dSJason Molenda 						DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s pid_stop_count %u (old %u)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
193d676074dSJason Molenda 					}
194d676074dSJason Molenda 					else
195d676074dSJason Molenda 					{
196d676074dSJason Molenda 
197d676074dSJason Molenda 						DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s pid_stop_count %u (old %u)) Notify??? YES!!!", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
198d676074dSJason Molenda 						remote->NotifyThatProcessStopped ();
199d676074dSJason Molenda 					}
200d676074dSJason Molenda 				}
201d676074dSJason Molenda 				else
202d676074dSJason Molenda 				{
203d676074dSJason Molenda 					DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s pid_stop_count %u (old %u)) Notify??? skipping...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
204d676074dSJason Molenda 				}
205d676074dSJason Molenda 			}
206d676074dSJason Molenda 			return eRNBRunLoopModeInferiorExecuting;
207d676074dSJason Molenda 
208d676074dSJason Molenda 		case eStateStepping:
209d676074dSJason Molenda 		case eStateRunning:
210d676074dSJason Molenda 			return eRNBRunLoopModeInferiorExecuting;
211d676074dSJason Molenda 
212d676074dSJason Molenda 		case eStateExited:
213d676074dSJason Molenda 			remote->HandlePacket_last_signal(NULL);
214d676074dSJason Molenda 			return eRNBRunLoopModeExit;
215d676074dSJason Molenda 		case eStateDetached:
216d676074dSJason Molenda             return eRNBRunLoopModeExit;
217d676074dSJason Molenda 
218d676074dSJason Molenda     }
219d676074dSJason Molenda 
220d676074dSJason Molenda     // Catch all...
221d676074dSJason Molenda     return eRNBRunLoopModeExit;
222d676074dSJason Molenda }
223d676074dSJason Molenda // This function handles the case where our inferior program is stopped and
224d676074dSJason Molenda // we are waiting for gdb remote protocol packets. When a packet occurs that
225d676074dSJason Molenda // makes the inferior run, we need to leave this function with a new state
226d676074dSJason Molenda // as the return code.
227d676074dSJason Molenda RNBRunLoopMode
228d676074dSJason Molenda RNBRunLoopInferiorExecuting (RNBRemoteSP &remote)
229d676074dSJason Molenda {
230d676074dSJason Molenda     DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
231d676074dSJason Molenda     RNBContext& ctx = remote->Context();
232d676074dSJason Molenda 
233d676074dSJason Molenda     // Init our mode and set 'is_running' based on the current process state
234d676074dSJason Molenda     RNBRunLoopMode mode = HandleProcessStateChange (remote, true);
235d676074dSJason Molenda 
236d676074dSJason Molenda     while (ctx.ProcessID() != INVALID_NUB_PROCESS)
237d676074dSJason Molenda     {
238d676074dSJason Molenda 
239d676074dSJason Molenda         std::string set_events_str;
240d676074dSJason Molenda         uint32_t event_mask = ctx.NormalEventBits();
241d676074dSJason Molenda 
242d676074dSJason Molenda         if (!ctx.ProcessStateRunning())
243d676074dSJason Molenda         {
244d676074dSJason Molenda             // Clear the stdio bits if we are not running so we don't send any async packets
245d676074dSJason Molenda             event_mask &= ~RNBContext::event_proc_stdio_available;
246d676074dSJason Molenda         }
247d676074dSJason Molenda 
248d676074dSJason Molenda         // We want to make sure we consume all process state changes and have
249d676074dSJason Molenda         // whomever is notifying us to wait for us to reset the event bit before
250d676074dSJason Molenda         // continuing.
251d676074dSJason Molenda         //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
252d676074dSJason Molenda 
253d676074dSJason Molenda         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
254d676074dSJason Molenda         nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
255d676074dSJason Molenda         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)",__FUNCTION__, event_mask, set_events, ctx.EventsAsString(set_events, set_events_str));
256d676074dSJason Molenda 
257d676074dSJason Molenda         if (set_events)
258d676074dSJason Molenda         {
259d676074dSJason Molenda             if ((set_events & RNBContext::event_proc_thread_exiting) ||
260d676074dSJason Molenda                 (set_events & RNBContext::event_proc_stdio_available))
261d676074dSJason Molenda             {
262d676074dSJason Molenda                 remote->FlushSTDIO();
263d676074dSJason Molenda             }
264d676074dSJason Molenda 
265d676074dSJason Molenda             if (set_events & RNBContext::event_read_packet_available)
266d676074dSJason Molenda             {
267d676074dSJason Molenda                 // handleReceivedPacket will take care of resetting the
268d676074dSJason Molenda                 // event_read_packet_available events when there are no more...
269d676074dSJason Molenda                 set_events ^= RNBContext::event_read_packet_available;
270d676074dSJason Molenda 
271d676074dSJason Molenda                 if (ctx.ProcessStateRunning())
272d676074dSJason Molenda                 {
273d676074dSJason Molenda                     if (remote->HandleAsyncPacket() == rnb_not_connected)
274d676074dSJason Molenda                     {
275d676074dSJason Molenda                         // TODO: connect again? Exit?
276d676074dSJason Molenda                     }
277d676074dSJason Molenda                 }
278d676074dSJason Molenda                 else
279d676074dSJason Molenda                 {
280d676074dSJason Molenda                     if (remote->HandleReceivedPacket() == rnb_not_connected)
281d676074dSJason Molenda                     {
282d676074dSJason Molenda                         // TODO: connect again? Exit?
283d676074dSJason Molenda                     }
284d676074dSJason Molenda                 }
285d676074dSJason Molenda             }
286d676074dSJason Molenda 
287d676074dSJason Molenda             if (set_events & RNBContext::event_proc_state_changed)
288d676074dSJason Molenda             {
289d676074dSJason Molenda                 mode = HandleProcessStateChange (remote, false);
290d676074dSJason Molenda                 ctx.Events().ResetEvents(RNBContext::event_proc_state_changed);
291d676074dSJason Molenda                 set_events ^= RNBContext::event_proc_state_changed;
292d676074dSJason Molenda             }
293d676074dSJason Molenda 
294d676074dSJason Molenda             if (set_events & RNBContext::event_proc_thread_exiting)
295d676074dSJason Molenda             {
296d676074dSJason Molenda                 mode = eRNBRunLoopModeExit;
297d676074dSJason Molenda             }
298d676074dSJason Molenda 
299d676074dSJason Molenda             if (set_events & RNBContext::event_read_thread_exiting)
300d676074dSJason Molenda             {
301d676074dSJason Molenda                 // Out remote packet receiving thread exited, exit for now.
302d676074dSJason Molenda                 if (ctx.HasValidProcessID())
303d676074dSJason Molenda                 {
304d676074dSJason Molenda                     // TODO: We should add code that will leave the current process
305d676074dSJason Molenda                     // in its current state and listen for another connection...
306d676074dSJason Molenda                     if (ctx.ProcessStateRunning())
307d676074dSJason Molenda                     {
308d676074dSJason Molenda                         DNBProcessKill (ctx.ProcessID(), SIGINT);
309d676074dSJason Molenda                     }
310d676074dSJason Molenda                 }
311d676074dSJason Molenda                 mode = eRNBRunLoopModeExit;
312d676074dSJason Molenda             }
313d676074dSJason Molenda         }
314d676074dSJason Molenda 
315d676074dSJason Molenda         // Reset all event bits that weren't reset for now...
316d676074dSJason Molenda         if (set_events != 0)
317d676074dSJason Molenda 			ctx.Events().ResetEvents(set_events);
318d676074dSJason Molenda 
319d676074dSJason Molenda         if (mode != eRNBRunLoopModeInferiorExecuting)
320d676074dSJason Molenda 			break;
321d676074dSJason Molenda     }
322d676074dSJason Molenda 
323d676074dSJason Molenda     return mode;
324d676074dSJason Molenda }
325d676074dSJason Molenda 
326d676074dSJason Molenda void
327d676074dSJason Molenda ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
328d676074dSJason Molenda {
329d676074dSJason Molenda #if 0
330d676074dSJason Molenda 	vprintf(format, args);
331d676074dSJason Molenda #endif
332d676074dSJason Molenda }
333d676074dSJason Molenda 
334d676074dSJason Molenda extern "C" int
335d676074dSJason Molenda debug_server_main(int fd)
336d676074dSJason Molenda {
337d676074dSJason Molenda #if 1
338d676074dSJason Molenda 	g_isatty = 0;
339d676074dSJason Molenda #else
340d676074dSJason Molenda 	g_isatty = ::isatty (STDIN_FILENO);
341d676074dSJason Molenda 
342d676074dSJason Molenda 	DNBLogSetDebug(1);
343d676074dSJason Molenda 	DNBLogSetVerbose(1);
344d676074dSJason Molenda 	DNBLogSetLogMask(-1);
345d676074dSJason Molenda 	DNBLogSetLogCallback(ASLLogCallback, NULL);
346d676074dSJason Molenda #endif
347d676074dSJason Molenda 
348d676074dSJason Molenda     signal (SIGPIPE, signal_handler);
349d676074dSJason Molenda 
350d676074dSJason Molenda     g_remoteSP.reset (new RNBRemote);
351d676074dSJason Molenda 
352d676074dSJason Molenda     RNBRemote *remote = g_remoteSP.get();
353d676074dSJason Molenda     if (remote == NULL)
354d676074dSJason Molenda     {
355d676074dSJason Molenda         RNBLogSTDERR ("error: failed to create a remote connection class\n");
356d676074dSJason Molenda         return -1;
357d676074dSJason Molenda     }
358d676074dSJason Molenda 
359d676074dSJason Molenda 
360d676074dSJason Molenda     RNBRunLoopMode mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
361d676074dSJason Molenda 
362d676074dSJason Molenda     while (mode != eRNBRunLoopModeExit)
363d676074dSJason Molenda     {
364d676074dSJason Molenda         switch (mode)
365d676074dSJason Molenda         {
366d676074dSJason Molenda 			case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
367d676074dSJason Molenda 				if (g_remoteSP->Comm().useFD(fd) == rnb_success) {
368d676074dSJason Molenda 					RNBLogSTDOUT("Starting remote data thread.\n");
369d676074dSJason Molenda 					g_remoteSP->StartReadRemoteDataThread();
370d676074dSJason Molenda 
371d676074dSJason Molenda 					RNBLogSTDOUT("Waiting for start mode from remote.\n");
372d676074dSJason Molenda 					mode = RNBRunLoopGetStartModeFromRemote(g_remoteSP);
373d676074dSJason Molenda 				}
374d676074dSJason Molenda 				else
375d676074dSJason Molenda 				{
376d676074dSJason Molenda 					mode = eRNBRunLoopModeExit;
377d676074dSJason Molenda 				}
378d676074dSJason Molenda 				break;
379d676074dSJason Molenda 
380d676074dSJason Molenda 			case eRNBRunLoopModeInferiorExecuting:
381d676074dSJason Molenda 				mode = RNBRunLoopInferiorExecuting(g_remoteSP);
382d676074dSJason Molenda 				break;
383d676074dSJason Molenda 
384d676074dSJason Molenda 			default:
385d676074dSJason Molenda 				mode = eRNBRunLoopModeExit;
386d676074dSJason Molenda 				break;
387d676074dSJason Molenda 
388d676074dSJason Molenda 			case eRNBRunLoopModeExit:
389d676074dSJason Molenda 				break;
390d676074dSJason Molenda         }
391d676074dSJason Molenda     }
392d676074dSJason Molenda 
393d676074dSJason Molenda     g_remoteSP->StopReadRemoteDataThread ();
394d676074dSJason Molenda     g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS);
395d676074dSJason Molenda 
396d676074dSJason Molenda     return 0;
397d676074dSJason Molenda }
398