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