1 //===-- debugserver.cpp -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include <sys/socket.h>
11 #include <sys/types.h>
12 #include <errno.h>
13 #include <getopt.h>
14 #include <netinet/in.h>
15 #include <sys/select.h>
16 #include <sys/sysctl.h>
17 #include <string>
18 #include <vector>
19 #include <asl.h>
20 #include <arpa/inet.h>
21 #include <netdb.h>
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <sys/un.h>
25 #include <sys/types.h>
26 
27 #include "CFString.h"
28 #include "DNB.h"
29 #include "DNBLog.h"
30 #include "DNBTimer.h"
31 #include "PseudoTerminal.h"
32 #include "RNBContext.h"
33 #include "RNBServices.h"
34 #include "RNBSocket.h"
35 #include "RNBRemote.h"
36 #include "SysSignal.h"
37 
38 // Global PID in case we get a signal and need to stop the process...
39 nub_process_t g_pid = INVALID_NUB_PROCESS;
40 
41 //----------------------------------------------------------------------
42 // Run loop modes which determine which run loop function will be called
43 //----------------------------------------------------------------------
44 typedef enum
45 {
46     eRNBRunLoopModeInvalid = 0,
47     eRNBRunLoopModeGetStartModeFromRemoteProtocol,
48     eRNBRunLoopModeInferiorAttaching,
49     eRNBRunLoopModeInferiorLaunching,
50     eRNBRunLoopModeInferiorExecuting,
51     eRNBRunLoopModePlatformMode,
52     eRNBRunLoopModeExit
53 } RNBRunLoopMode;
54 
55 
56 //----------------------------------------------------------------------
57 // Global Variables
58 //----------------------------------------------------------------------
59 RNBRemoteSP g_remoteSP;
60 static int g_lockdown_opt  = 0;
61 static int g_applist_opt = 0;
62 static nub_launch_flavor_t g_launch_flavor = eLaunchFlavorDefault;
63 int g_disable_aslr = 0;
64 
65 int g_isatty = 0;
66 
67 #define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
68 #define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
69 
70 //----------------------------------------------------------------------
71 // Get our program path and arguments from the remote connection.
72 // We will need to start up the remote connection without a PID, get the
73 // arguments, wait for the new process to finish launching and hit its
74 // entry point,  and then return the run loop mode that should come next.
75 //----------------------------------------------------------------------
76 RNBRunLoopMode
77 RNBRunLoopGetStartModeFromRemote (RNBRemote* remote)
78 {
79     std::string packet;
80 
81     if (remote)
82     {
83         RNBContext& ctx = remote->Context();
84         uint32_t event_mask = RNBContext::event_read_packet_available |
85                               RNBContext::event_read_thread_exiting;
86 
87         // Spin waiting to get the A packet.
88         while (1)
89         {
90             DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask);
91             nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
92             DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events);
93 
94             if (set_events & RNBContext::event_read_thread_exiting)
95             {
96                 RNBLogSTDERR ("error: packet read thread exited.");
97                 return eRNBRunLoopModeExit;
98             }
99 
100             if (set_events & RNBContext::event_read_packet_available)
101             {
102                 rnb_err_t err = rnb_err;
103                 RNBRemote::PacketEnum type;
104 
105                 err = remote->HandleReceivedPacket (&type);
106 
107                 // check if we tried to attach to a process
108                 if (type == RNBRemote::vattach || type == RNBRemote::vattachwait || type == RNBRemote::vattachorwait)
109                 {
110                     if (err == rnb_success)
111                         return eRNBRunLoopModeInferiorExecuting;
112                     else
113                     {
114                         RNBLogSTDERR ("error: attach failed.");
115                         return eRNBRunLoopModeExit;
116                     }
117                 }
118 
119                 if (err == rnb_success)
120                 {
121                     // If we got our arguments we are ready to launch using the arguments
122                     // and any environment variables we received.
123                     if (type == RNBRemote::set_argv)
124                     {
125                         return eRNBRunLoopModeInferiorLaunching;
126                     }
127                 }
128                 else if (err == rnb_not_connected)
129                 {
130                     RNBLogSTDERR ("error: connection lost.");
131                     return eRNBRunLoopModeExit;
132                 }
133                 else
134                 {
135                     // a catch all for any other gdb remote packets that failed
136                     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__);
137                     continue;
138                 }
139 
140                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
141             }
142             else
143             {
144                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__);
145                 return eRNBRunLoopModeExit;
146             }
147         }
148     }
149     return eRNBRunLoopModeExit;
150 }
151 
152 
153 //----------------------------------------------------------------------
154 // This run loop mode will wait for the process to launch and hit its
155 // entry point. It will currently ignore all events except for the
156 // process state changed event, where it watches for the process stopped
157 // or crash process state.
158 //----------------------------------------------------------------------
159 RNBRunLoopMode
160 RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char *stdout_path, const char *stderr_path, bool no_stdio)
161 {
162     RNBContext& ctx = remote->Context();
163 
164     // The Process stuff takes a c array, the RNBContext has a vector...
165     // So make up a c array.
166 
167     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, ctx.ArgumentAtIndex(0));
168 
169     size_t inferior_argc = ctx.ArgumentCount();
170     // Initialize inferior_argv with inferior_argc + 1 NULLs
171     std::vector<const char *> inferior_argv(inferior_argc + 1, NULL);
172 
173     size_t i;
174     for (i = 0; i < inferior_argc; i++)
175         inferior_argv[i] = ctx.ArgumentAtIndex(i);
176 
177     // Pass the environment array the same way:
178 
179     size_t inferior_envc = ctx.EnvironmentCount();
180     // Initialize inferior_argv with inferior_argc + 1 NULLs
181     std::vector<const char *> inferior_envp(inferior_envc + 1, NULL);
182 
183     for (i = 0; i < inferior_envc; i++)
184         inferior_envp[i] = ctx.EnvironmentAtIndex(i);
185 
186     // Our launch type hasn't been set to anything concrete, so we need to
187     // figure our how we are going to launch automatically.
188 
189     nub_launch_flavor_t launch_flavor = g_launch_flavor;
190     if (launch_flavor == eLaunchFlavorDefault)
191     {
192         // Our default launch method is posix spawn
193         launch_flavor = eLaunchFlavorPosixSpawn;
194 
195 #ifdef WITH_SPRINGBOARD
196         // Check if we have an app bundle, if so launch using SpringBoard.
197         if (strstr(inferior_argv[0], ".app"))
198         {
199             launch_flavor = eLaunchFlavorSpringBoard;
200         }
201 #endif
202     }
203 
204     ctx.SetLaunchFlavor(launch_flavor);
205     char resolved_path[PATH_MAX];
206 
207     // If we fail to resolve the path to our executable, then just use what we
208     // were given and hope for the best
209     if ( !DNBResolveExecutablePath (inferior_argv[0], resolved_path, sizeof(resolved_path)) )
210         ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path));
211 
212     char launch_err_str[PATH_MAX];
213     launch_err_str[0] = '\0';
214     const char * cwd = (ctx.GetWorkingDirPath() != NULL ? ctx.GetWorkingDirPath()
215                                                         : ctx.GetWorkingDirectory());
216     nub_process_t pid = DNBProcessLaunch (resolved_path,
217                                           &inferior_argv[0],
218                                           &inferior_envp[0],
219                                           cwd,
220                                           stdin_path,
221                                           stdout_path,
222                                           stderr_path,
223                                           no_stdio,
224                                           launch_flavor,
225                                           g_disable_aslr,
226                                           launch_err_str,
227                                           sizeof(launch_err_str));
228 
229     g_pid = pid;
230 
231     if (pid == INVALID_NUB_PROCESS && strlen (launch_err_str) > 0)
232     {
233         DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, launch_err_str);
234         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
235         ctx.LaunchStatus().SetErrorString(launch_err_str);
236     }
237     else if (pid == INVALID_NUB_PROCESS)
238     {
239         DNBLogThreaded ("%s DNBProcessLaunch() failed to launch process, unknown failure", __FUNCTION__);
240         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
241         ctx.LaunchStatus().SetErrorString(launch_err_str);
242     }
243     else
244     {
245         ctx.LaunchStatus().Clear();
246     }
247 
248     if (remote->Comm().IsConnected())
249     {
250         // It we are connected already, the next thing gdb will do is ask
251         // whether the launch succeeded, and if not, whether there is an
252         // error code.  So we need to fetch one packet from gdb before we wait
253         // on the stop from the target.
254 
255         uint32_t event_mask = RNBContext::event_read_packet_available;
256         nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
257 
258         if (set_events & RNBContext::event_read_packet_available)
259         {
260             rnb_err_t err = rnb_err;
261             RNBRemote::PacketEnum type;
262 
263             err = remote->HandleReceivedPacket (&type);
264 
265             if (err != rnb_success)
266             {
267                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__);
268                 return eRNBRunLoopModeExit;
269             }
270             if (type != RNBRemote::query_launch_success)
271             {
272                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__);
273             }
274         }
275     }
276 
277     while (pid != INVALID_NUB_PROCESS)
278     {
279         // Wait for process to start up and hit entry point
280         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid);
281         nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL);
282         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events);
283 
284         if (set_events == 0)
285         {
286             pid = INVALID_NUB_PROCESS;
287             g_pid = pid;
288         }
289         else
290         {
291             if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
292             {
293                 nub_state_t pid_state = DNBProcessGetState (pid);
294                 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
295 
296                 switch (pid_state)
297                 {
298                     default:
299                     case eStateInvalid:
300                     case eStateUnloaded:
301                     case eStateAttaching:
302                     case eStateLaunching:
303                     case eStateSuspended:
304                         break;  // Ignore
305 
306                     case eStateRunning:
307                     case eStateStepping:
308                         // Still waiting to stop at entry point...
309                         break;
310 
311                     case eStateStopped:
312                     case eStateCrashed:
313                         ctx.SetProcessID(pid);
314                         return eRNBRunLoopModeInferiorExecuting;
315 
316                     case eStateDetached:
317                     case eStateExited:
318                         pid = INVALID_NUB_PROCESS;
319                         g_pid = pid;
320                         return eRNBRunLoopModeExit;
321                 }
322             }
323 
324             DNBProcessResetEvents(pid, set_events);
325         }
326     }
327 
328     return eRNBRunLoopModeExit;
329 }
330 
331 
332 //----------------------------------------------------------------------
333 // This run loop mode will wait for the process to launch and hit its
334 // entry point. It will currently ignore all events except for the
335 // process state changed event, where it watches for the process stopped
336 // or crash process state.
337 //----------------------------------------------------------------------
338 RNBRunLoopMode
339 RNBRunLoopLaunchAttaching (RNBRemote *remote, nub_process_t attach_pid, nub_process_t& pid)
340 {
341     RNBContext& ctx = remote->Context();
342 
343     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid);
344     char err_str[1024];
345     pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str));
346     g_pid = pid;
347 
348     if (pid == INVALID_NUB_PROCESS)
349     {
350         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
351         if (err_str[0])
352             ctx.LaunchStatus().SetErrorString(err_str);
353         return eRNBRunLoopModeExit;
354     }
355     else
356     {
357         ctx.SetProcessID(pid);
358         return eRNBRunLoopModeInferiorExecuting;
359     }
360 }
361 
362 //----------------------------------------------------------------------
363 // Watch for signals:
364 // SIGINT: so we can halt our inferior. (disabled for now)
365 // SIGPIPE: in case our child process dies
366 //----------------------------------------------------------------------
367 int g_sigint_received = 0;
368 int g_sigpipe_received = 0;
369 void
370 signal_handler(int signo)
371 {
372     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo));
373 
374     switch (signo)
375     {
376         case SIGINT:
377             g_sigint_received++;
378             if (g_pid != INVALID_NUB_PROCESS)
379             {
380                 // Only send a SIGINT once...
381                 if (g_sigint_received == 1)
382                 {
383                     switch (DNBProcessGetState (g_pid))
384                     {
385                         case eStateRunning:
386                         case eStateStepping:
387                             DNBProcessSignal (g_pid, SIGSTOP);
388                             return;
389                         default:
390                             break;
391                     }
392                 }
393             }
394             exit (SIGINT);
395             break;
396 
397         case SIGPIPE:
398             g_sigpipe_received = 1;
399             break;
400     }
401 }
402 
403 // Return the new run loop mode based off of the current process state
404 RNBRunLoopMode
405 HandleProcessStateChange (RNBRemote *remote, bool initialize)
406 {
407     RNBContext& ctx = remote->Context();
408     nub_process_t pid = ctx.ProcessID();
409 
410     if (pid == INVALID_NUB_PROCESS)
411     {
412         DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
413         return eRNBRunLoopModeExit;
414     }
415     nub_state_t pid_state = DNBProcessGetState (pid);
416 
417     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state));
418 
419     switch (pid_state)
420     {
421         case eStateInvalid:
422         case eStateUnloaded:
423             // Something bad happened
424             return eRNBRunLoopModeExit;
425             break;
426 
427         case eStateAttaching:
428         case eStateLaunching:
429             return eRNBRunLoopModeInferiorExecuting;
430 
431         case eStateSuspended:
432         case eStateCrashed:
433         case eStateStopped:
434             // If we stop due to a signal, so clear the fact that we got a SIGINT
435             // so we can stop ourselves again (but only while our inferior
436             // process is running..)
437             g_sigint_received = 0;
438             if (initialize == false)
439             {
440                 // Compare the last stop count to our current notion of a stop count
441                 // to make sure we don't notify more than once for a given stop.
442                 nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
443                 bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid));
444                 if (pid_stop_count_changed)
445                 {
446                     remote->FlushSTDIO();
447 
448                     if (ctx.GetProcessStopCount() == 1)
449                     {
450                         DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s pid_stop_count %llu (old %llu)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), (uint64_t)ctx.GetProcessStopCount(), (uint64_t)prev_pid_stop_count);
451                     }
452                     else
453                     {
454 
455                         DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s pid_stop_count %llu (old %llu)) Notify??? YES!!!", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), (uint64_t)ctx.GetProcessStopCount(), (uint64_t)prev_pid_stop_count);
456                         remote->NotifyThatProcessStopped ();
457                     }
458                 }
459                 else
460                 {
461                     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s pid_stop_count %llu (old %llu)) Notify??? skipping...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), (uint64_t)ctx.GetProcessStopCount(), (uint64_t)prev_pid_stop_count);
462                 }
463             }
464             return eRNBRunLoopModeInferiorExecuting;
465 
466         case eStateStepping:
467         case eStateRunning:
468             return eRNBRunLoopModeInferiorExecuting;
469 
470         case eStateExited:
471             remote->HandlePacket_last_signal(NULL);
472         case eStateDetached:
473             return eRNBRunLoopModeExit;
474 
475     }
476 
477     // Catch all...
478     return eRNBRunLoopModeExit;
479 }
480 // This function handles the case where our inferior program is stopped and
481 // we are waiting for gdb remote protocol packets. When a packet occurs that
482 // makes the inferior run, we need to leave this function with a new state
483 // as the return code.
484 RNBRunLoopMode
485 RNBRunLoopInferiorExecuting (RNBRemote *remote)
486 {
487     DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
488     RNBContext& ctx = remote->Context();
489 
490     // Init our mode and set 'is_running' based on the current process state
491     RNBRunLoopMode mode = HandleProcessStateChange (remote, true);
492 
493     while (ctx.ProcessID() != INVALID_NUB_PROCESS)
494     {
495 
496         std::string set_events_str;
497         uint32_t event_mask = ctx.NormalEventBits();
498 
499         if (!ctx.ProcessStateRunning())
500         {
501             // Clear some bits if we are not running so we don't send any async packets
502             event_mask &= ~RNBContext::event_proc_stdio_available;
503             event_mask &= ~RNBContext::event_proc_profile_data;
504         }
505 
506         // We want to make sure we consume all process state changes and have
507         // whomever is notifying us to wait for us to reset the event bit before
508         // continuing.
509         //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
510 
511         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
512         nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
513         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));
514 
515         if (set_events)
516         {
517             if ((set_events & RNBContext::event_proc_thread_exiting) ||
518                 (set_events & RNBContext::event_proc_stdio_available))
519             {
520                 remote->FlushSTDIO();
521             }
522 
523             if (set_events & RNBContext::event_proc_profile_data)
524             {
525                 remote->SendAsyncProfileData();
526             }
527 
528             if (set_events & RNBContext::event_read_packet_available)
529             {
530                 // handleReceivedPacket will take care of resetting the
531                 // event_read_packet_available events when there are no more...
532                 set_events ^= RNBContext::event_read_packet_available;
533 
534                 if (ctx.ProcessStateRunning())
535                 {
536                     if (remote->HandleAsyncPacket() == rnb_not_connected)
537                     {
538                         // TODO: connect again? Exit?
539                     }
540                 }
541                 else
542                 {
543                     if (remote->HandleReceivedPacket() == rnb_not_connected)
544                     {
545                         // TODO: connect again? Exit?
546                     }
547                 }
548             }
549 
550             if (set_events & RNBContext::event_proc_state_changed)
551             {
552                 mode = HandleProcessStateChange (remote, false);
553                 ctx.Events().ResetEvents(RNBContext::event_proc_state_changed);
554                 set_events ^= RNBContext::event_proc_state_changed;
555             }
556 
557             if (set_events & RNBContext::event_proc_thread_exiting)
558             {
559                 mode = eRNBRunLoopModeExit;
560             }
561 
562             if (set_events & RNBContext::event_read_thread_exiting)
563             {
564                 // Out remote packet receiving thread exited, exit for now.
565                 if (ctx.HasValidProcessID())
566                 {
567                     // TODO: We should add code that will leave the current process
568                     // in its current state and listen for another connection...
569                     if (ctx.ProcessStateRunning())
570                     {
571                         DNBProcessKill (ctx.ProcessID());
572                     }
573                 }
574                 mode = eRNBRunLoopModeExit;
575             }
576         }
577 
578         // Reset all event bits that weren't reset for now...
579         if (set_events != 0)
580             ctx.Events().ResetEvents(set_events);
581 
582         if (mode != eRNBRunLoopModeInferiorExecuting)
583             break;
584     }
585 
586     return mode;
587 }
588 
589 
590 RNBRunLoopMode
591 RNBRunLoopPlatform (RNBRemote *remote)
592 {
593     RNBRunLoopMode mode = eRNBRunLoopModePlatformMode;
594     RNBContext& ctx = remote->Context();
595 
596     while (mode == eRNBRunLoopModePlatformMode)
597     {
598         std::string set_events_str;
599         const uint32_t event_mask = RNBContext::event_read_packet_available |
600                                     RNBContext::event_read_thread_exiting;
601 
602         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
603         nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
604         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));
605 
606         if (set_events)
607         {
608             if (set_events & RNBContext::event_read_packet_available)
609             {
610                 if (remote->HandleReceivedPacket() == rnb_not_connected)
611                     mode = eRNBRunLoopModeExit;
612             }
613 
614             if (set_events & RNBContext::event_read_thread_exiting)
615             {
616                 mode = eRNBRunLoopModeExit;
617             }
618             ctx.Events().ResetEvents(set_events);
619         }
620     }
621     return eRNBRunLoopModeExit;
622 }
623 
624 //----------------------------------------------------------------------
625 // Convenience function to set up the remote listening port
626 // Returns 1 for success 0 for failure.
627 //----------------------------------------------------------------------
628 
629 static void
630 PortWasBoundCallback (const void *baton, in_port_t port)
631 {
632     //::printf ("PortWasBoundCallback (baton = %p, port = %u)\n", baton, port);
633 
634     const char *unix_socket_name = (const char *)baton;
635 
636     if (unix_socket_name && unix_socket_name[0])
637     {
638         // We were given a unix socket name to use to communicate the port
639         // that we ended up binding to back to our parent process
640         struct sockaddr_un saddr_un;
641         int s = ::socket (AF_UNIX, SOCK_STREAM, 0);
642         if (s < 0)
643         {
644             perror("error: socket (AF_UNIX, SOCK_STREAM, 0)");
645             exit(1);
646         }
647 
648         saddr_un.sun_family = AF_UNIX;
649         ::strncpy(saddr_un.sun_path, unix_socket_name, sizeof(saddr_un.sun_path) - 1);
650         saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
651         saddr_un.sun_len = SUN_LEN (&saddr_un);
652 
653         if (::connect (s, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0)
654         {
655             perror("error: connect (socket, &saddr_un, saddr_un_len)");
656             exit(1);
657         }
658 
659         //::printf ("connect () sucess!!\n");
660 
661 
662         // We were able to connect to the socket, now write our PID so whomever
663         // launched us will know this process's ID
664         RNBLogSTDOUT ("Listening to port %i...\n", port);
665 
666         char pid_str[64];
667         const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%u", port);
668         const int bytes_sent = ::send (s, pid_str, pid_str_len, 0);
669 
670         if (pid_str_len != bytes_sent)
671         {
672             perror("error: send (s, pid_str, pid_str_len, 0)");
673             exit (1);
674         }
675 
676         //::printf ("send () sucess!!\n");
677 
678         // We are done with the socket
679         close (s);
680     }
681 }
682 
683 static int
684 StartListening (RNBRemote *remote, int listen_port, const char *unix_socket_name)
685 {
686     if (!remote->Comm().IsConnected())
687     {
688         if (listen_port != 0)
689             RNBLogSTDOUT ("Listening to port %i...\n", listen_port);
690         if (remote->Comm().Listen(listen_port, PortWasBoundCallback, unix_socket_name) != rnb_success)
691         {
692             RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
693             return 0;
694         }
695         else
696         {
697             remote->StartReadRemoteDataThread();
698         }
699     }
700     return 1;
701 }
702 
703 //----------------------------------------------------------------------
704 // ASL Logging callback that can be registered with DNBLogSetLogCallback
705 //----------------------------------------------------------------------
706 void
707 ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
708 {
709     if (format == NULL)
710         return;
711     static aslmsg g_aslmsg = NULL;
712     if (g_aslmsg == NULL)
713     {
714         g_aslmsg = ::asl_new (ASL_TYPE_MSG);
715         char asl_key_sender[PATH_MAX];
716         snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.%s-%g", DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_NUM);
717         ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
718     }
719 
720     int asl_level;
721     if (flags & DNBLOG_FLAG_FATAL)        asl_level = ASL_LEVEL_CRIT;
722     else if (flags & DNBLOG_FLAG_ERROR)   asl_level = ASL_LEVEL_ERR;
723     else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING;
724     else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO;
725     else                                  asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG;
726 
727     ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
728 }
729 
730 //----------------------------------------------------------------------
731 // FILE based Logging callback that can be registered with
732 // DNBLogSetLogCallback
733 //----------------------------------------------------------------------
734 void
735 FileLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
736 {
737     if (baton == NULL || format == NULL)
738         return;
739 
740     ::vfprintf ((FILE *)baton, format, args);
741     ::fprintf ((FILE *)baton, "\n");
742 }
743 
744 
745 void
746 show_usage_and_exit (int exit_code)
747 {
748     RNBLogSTDERR ("Usage:\n  %s host:port [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
749     RNBLogSTDERR ("  %s /path/file [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
750     RNBLogSTDERR ("  %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
751     RNBLogSTDERR ("  %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
752     RNBLogSTDERR ("  %s host:port --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
753     RNBLogSTDERR ("  %s /path/file --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
754     exit (exit_code);
755 }
756 
757 
758 //----------------------------------------------------------------------
759 // option descriptors for getopt_long()
760 //----------------------------------------------------------------------
761 static struct option g_long_options[] =
762 {
763     { "attach",             required_argument,  NULL,               'a' },
764     { "arch",               required_argument,  NULL,               'A' },
765     { "debug",              no_argument,        NULL,               'g' },
766     { "verbose",            no_argument,        NULL,               'v' },
767     { "lockdown",           no_argument,        &g_lockdown_opt,    1   },  // short option "-k"
768     { "applist",            no_argument,        &g_applist_opt,     1   },  // short option "-t"
769     { "log-file",           required_argument,  NULL,               'l' },
770     { "log-flags",          required_argument,  NULL,               'f' },
771     { "launch",             required_argument,  NULL,               'x' },  // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
772     { "waitfor",            required_argument,  NULL,               'w' },  // Wait for a process whose name starts with ARG
773     { "waitfor-interval",   required_argument,  NULL,               'i' },  // Time in usecs to wait between sampling the pid list when waiting for a process by name
774     { "waitfor-duration",   required_argument,  NULL,               'd' },  // The time in seconds to wait for a process to show up by name
775     { "native-regs",        no_argument,        NULL,               'r' },  // Specify to use the native registers instead of the gdb defaults for the architecture.
776     { "stdio-path",         required_argument,  NULL,               's' },  // Set the STDIO path to be used when launching applications (STDIN, STDOUT and STDERR) (only if debugserver launches the process)
777     { "stdin-path",         required_argument,  NULL,               'I' },  // Set the STDIN path to be used when launching applications (only if debugserver launches the process)
778     { "stdout-path",        required_argument,  NULL,               'O' },  // Set the STDOUT path to be used when launching applications (only if debugserver launches the process)
779     { "stderr-path",        required_argument,  NULL,               'E' },  // Set the STDERR path to be used when launching applications (only if debugserver launches the process)
780     { "no-stdio",           no_argument,        NULL,               'n' },  // Do not set up any stdio (perhaps the program is a GUI program) (only if debugserver launches the process)
781     { "setsid",             no_argument,        NULL,               'S' },  // call setsid() to make debugserver run in its own session
782     { "disable-aslr",       no_argument,        NULL,               'D' },  // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
783     { "working-dir",        required_argument,  NULL,               'W' },  // The working directory that the inferior process should have (only if debugserver launches the process)
784     { "platform",           required_argument,  NULL,               'p' },  // Put this executable into a remote platform mode
785     { "unix-socket",        required_argument,  NULL,               'u' },  // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use
786     { NULL,                 0,                  NULL,               0   }
787 };
788 
789 
790 //----------------------------------------------------------------------
791 // main
792 //----------------------------------------------------------------------
793 int
794 main (int argc, char *argv[])
795 {
796     const char *argv_sub_zero = argv[0]; // save a copy of argv[0] for error reporting post-launch
797 
798     g_isatty = ::isatty (STDIN_FILENO);
799 
800     //  ::printf ("uid=%u euid=%u gid=%u egid=%u\n",
801     //            getuid(),
802     //            geteuid(),
803     //            getgid(),
804     //            getegid());
805 
806 
807     //    signal (SIGINT, signal_handler);
808     signal (SIGPIPE, signal_handler);
809     signal (SIGHUP, signal_handler);
810 
811     g_remoteSP.reset (new RNBRemote ());
812 
813 
814     RNBRemote *remote = g_remoteSP.get();
815     if (remote == NULL)
816     {
817         RNBLogSTDERR ("error: failed to create a remote connection class\n");
818         return -1;
819     }
820 
821     RNBContext& ctx = remote->Context();
822 
823     int i;
824     int attach_pid = INVALID_NUB_PROCESS;
825 
826     FILE* log_file = NULL;
827     uint32_t log_flags = 0;
828     // Parse our options
829     int ch;
830     int long_option_index = 0;
831     int debug = 0;
832     std::string compile_options;
833     std::string waitfor_pid_name;           // Wait for a process that starts with this name
834     std::string attach_pid_name;
835     std::string arch_name;
836     std::string working_dir;                // The new working directory to use for the inferior
837     std::string unix_socket_name;           // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use
838     useconds_t waitfor_interval = 1000;     // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
839     useconds_t waitfor_duration = 0;        // Time in seconds to wait for a process by name, 0 means wait forever.
840     bool no_stdio = false;
841 
842 #if !defined (DNBLOG_ENABLED)
843     compile_options += "(no-logging) ";
844 #endif
845 
846     RNBRunLoopMode start_mode = eRNBRunLoopModeExit;
847 
848     char short_options[512];
849     uint32_t short_options_idx = 0;
850 
851      // Handle the two case that don't have short options in g_long_options
852     short_options[short_options_idx++] = 'k';
853     short_options[short_options_idx++] = 't';
854 
855     for (i=0; g_long_options[i].name != NULL; ++i)
856     {
857         if (isalpha(g_long_options[i].val))
858         {
859             short_options[short_options_idx++] = g_long_options[i].val;
860             switch (g_long_options[i].has_arg)
861             {
862                 default:
863                 case no_argument:
864                     break;
865 
866                 case optional_argument:
867                     short_options[short_options_idx++] = ':';
868                     // Fall through to required_argument case below...
869                 case required_argument:
870                     short_options[short_options_idx++] = ':';
871                     break;
872             }
873         }
874     }
875     // NULL terminate the short option string.
876     short_options[short_options_idx++] = '\0';
877     while ((ch = getopt_long(argc, argv, short_options, g_long_options, &long_option_index)) != -1)
878     {
879         DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
880                     ch, (uint8_t)ch,
881                     g_long_options[long_option_index].name,
882                     g_long_options[long_option_index].has_arg ? '=' : ' ',
883                     optarg ? optarg : "");
884         switch (ch)
885         {
886             case 0:   // Any optional that auto set themselves will return 0
887                 break;
888 
889             case 'A':
890                 if (optarg && optarg[0])
891                     arch_name.assign(optarg);
892                 break;
893 
894             case 'a':
895                 if (optarg && optarg[0])
896                 {
897                     if (isdigit(optarg[0]))
898                     {
899                         char *end = NULL;
900                         attach_pid = strtoul(optarg, &end, 0);
901                         if (end == NULL || *end != '\0')
902                         {
903                             RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg);
904                             exit (4);
905                         }
906                     }
907                     else
908                     {
909                         attach_pid_name = optarg;
910                     }
911                     start_mode = eRNBRunLoopModeInferiorAttaching;
912                 }
913                 break;
914 
915                 // --waitfor=NAME
916             case 'w':
917                 if (optarg && optarg[0])
918                 {
919                     waitfor_pid_name = optarg;
920                     start_mode = eRNBRunLoopModeInferiorAttaching;
921                 }
922                 break;
923 
924                 // --waitfor-interval=USEC
925             case 'i':
926                 if (optarg && optarg[0])
927                 {
928                     char *end = NULL;
929                     waitfor_interval = strtoul(optarg, &end, 0);
930                     if (end == NULL || *end != '\0')
931                     {
932                         RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
933                         exit (6);
934                     }
935                 }
936                 break;
937 
938                 // --waitfor-duration=SEC
939             case 'd':
940                 if (optarg && optarg[0])
941                 {
942                     char *end = NULL;
943                     waitfor_duration = strtoul(optarg, &end, 0);
944                     if (end == NULL || *end != '\0')
945                     {
946                         RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
947                         exit (7);
948                     }
949                 }
950                 break;
951 
952             case 'W':
953                 if (optarg && optarg[0])
954                     working_dir.assign(optarg);
955                 break;
956 
957             case 'x':
958                 if (optarg && optarg[0])
959                 {
960                     if (strcasecmp(optarg, "auto") == 0)
961                         g_launch_flavor = eLaunchFlavorDefault;
962                     else if (strcasestr(optarg, "posix") == optarg)
963                         g_launch_flavor = eLaunchFlavorPosixSpawn;
964                     else if (strcasestr(optarg, "fork") == optarg)
965                         g_launch_flavor = eLaunchFlavorForkExec;
966 #ifdef WITH_SPRINGBOARD
967                     else if (strcasestr(optarg, "spring") == optarg)
968                         g_launch_flavor = eLaunchFlavorSpringBoard;
969 #endif
970                     else
971                     {
972                         RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
973                         RNBLogSTDERR ("Valid values TYPE are:\n");
974                         RNBLogSTDERR ("  auto    Auto-detect the best launch method to use.\n");
975                         RNBLogSTDERR ("  posix   Launch the executable using posix_spawn.\n");
976                         RNBLogSTDERR ("  fork    Launch the executable using fork and exec.\n");
977 #ifdef WITH_SPRINGBOARD
978                         RNBLogSTDERR ("  spring  Launch the executable through Springboard.\n");
979 #endif
980                         exit (5);
981                     }
982                 }
983                 break;
984 
985             case 'l': // Set Log File
986                 if (optarg && optarg[0])
987                 {
988                     if (strcasecmp(optarg, "stdout") == 0)
989                         log_file = stdout;
990                     else if (strcasecmp(optarg, "stderr") == 0)
991                         log_file = stderr;
992                     else
993                     {
994                         log_file = fopen(optarg, "w");
995                         if (log_file != NULL)
996                             setlinebuf(log_file);
997                     }
998 
999                     if (log_file == NULL)
1000                     {
1001                         const char *errno_str = strerror(errno);
1002                         RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
1003                     }
1004                 }
1005                 break;
1006 
1007             case 'f': // Log Flags
1008                 if (optarg && optarg[0])
1009                     log_flags = strtoul(optarg, NULL, 0);
1010                 break;
1011 
1012             case 'g':
1013                 debug = 1;
1014                 DNBLogSetDebug(debug);
1015                 break;
1016 
1017             case 't':
1018                 g_applist_opt = 1;
1019                 break;
1020 
1021             case 'k':
1022                 g_lockdown_opt = 1;
1023                 break;
1024 
1025             case 'r':
1026                 remote->SetUseNativeRegisters (true);
1027                 break;
1028 
1029             case 'v':
1030                 DNBLogSetVerbose(1);
1031                 break;
1032 
1033             case 's':
1034                 ctx.GetSTDIN().assign(optarg);
1035                 ctx.GetSTDOUT().assign(optarg);
1036                 ctx.GetSTDERR().assign(optarg);
1037                 break;
1038 
1039             case 'I':
1040                 ctx.GetSTDIN().assign(optarg);
1041                 break;
1042 
1043             case 'O':
1044                 ctx.GetSTDOUT().assign(optarg);
1045                 break;
1046 
1047             case 'E':
1048                 ctx.GetSTDERR().assign(optarg);
1049                 break;
1050 
1051             case 'n':
1052                 no_stdio = true;
1053                 break;
1054 
1055             case 'S':
1056                 // Put debugserver into a new session. Terminals group processes
1057                 // into sessions and when a special terminal key sequences
1058                 // (like control+c) are typed they can cause signals to go out to
1059                 // all processes in a session. Using this --setsid (-S) option
1060                 // will cause debugserver to run in its own sessions and be free
1061                 // from such issues.
1062                 //
1063                 // This is useful when debugserver is spawned from a command
1064                 // line application that uses debugserver to do the debugging,
1065                 // yet that application doesn't want debugserver receiving the
1066                 // signals sent to the session (i.e. dying when anyone hits ^C).
1067                 setsid();
1068                 break;
1069             case 'D':
1070                 g_disable_aslr = 1;
1071                 break;
1072 
1073             case 'p':
1074                 start_mode = eRNBRunLoopModePlatformMode;
1075                 break;
1076 
1077             case 'u':
1078                 unix_socket_name.assign (optarg);
1079                 break;
1080 
1081         }
1082     }
1083 
1084     if (arch_name.empty())
1085     {
1086 #if defined (__arm__)
1087         arch_name.assign ("arm");
1088 #endif
1089     }
1090     else
1091     {
1092         DNBSetArchitecture (arch_name.c_str());
1093     }
1094 
1095 //    if (arch_name.empty())
1096 //    {
1097 //        fprintf(stderr, "error: no architecture was specified\n");
1098 //        exit (8);
1099 //    }
1100     // Skip any options we consumed with getopt_long
1101     argc -= optind;
1102     argv += optind;
1103 
1104 
1105     if (!working_dir.empty())
1106     {
1107         if (remote->Context().SetWorkingDirectory (working_dir.c_str()) == false)
1108         {
1109             RNBLogSTDERR ("error: working directory doesn't exist '%s'.\n", working_dir.c_str());
1110             exit (8);
1111         }
1112     }
1113 
1114     remote->Initialize();
1115 
1116     // It is ok for us to set NULL as the logfile (this will disable any logging)
1117 
1118     if (log_file != NULL)
1119     {
1120         DNBLogSetLogCallback(FileLogCallback, log_file);
1121         // If our log file was set, yet we have no log flags, log everything!
1122         if (log_flags == 0)
1123             log_flags = LOG_ALL | LOG_RNB_ALL;
1124 
1125         DNBLogSetLogMask (log_flags);
1126     }
1127     else
1128     {
1129         // Enable DNB logging
1130         DNBLogSetLogCallback(ASLLogCallback, NULL);
1131         DNBLogSetLogMask (log_flags);
1132 
1133     }
1134 
1135     if (DNBLogEnabled())
1136     {
1137         for (i=0; i<argc; i++)
1138             DNBLogDebug("argv[%i] = %s", i, argv[i]);
1139     }
1140 
1141     // as long as we're dropping remotenub in as a replacement for gdbserver,
1142     // explicitly note that this is not gdbserver.
1143 
1144     RNBLogSTDOUT ("%s-%g %sfor %s.\n",
1145                   DEBUGSERVER_PROGRAM_NAME,
1146                   DEBUGSERVER_VERSION_NUM,
1147                   compile_options.c_str(),
1148                   RNB_ARCH);
1149 
1150     int listen_port = INT32_MAX;
1151     char str[PATH_MAX];
1152     str[0] = '\0';
1153 
1154     if (g_lockdown_opt == 0 && g_applist_opt == 0)
1155     {
1156         // Make sure we at least have port
1157         if (argc < 1)
1158         {
1159             show_usage_and_exit (1);
1160         }
1161         // accept 'localhost:' prefix on port number
1162 
1163         int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &listen_port);
1164         if (items_scanned == 2)
1165         {
1166             DNBLogDebug("host = '%s'  port = %i", str, listen_port);
1167         }
1168         else if (argv[0][0] == '/')
1169         {
1170             listen_port = INT32_MAX;
1171             strncpy(str, argv[0], sizeof(str));
1172         }
1173         else
1174         {
1175             show_usage_and_exit (2);
1176         }
1177 
1178         // We just used the 'host:port' or the '/path/file' arg...
1179         argc--;
1180         argv++;
1181 
1182     }
1183 
1184     //  If we know we're waiting to attach, we don't need any of this other info.
1185     if (start_mode != eRNBRunLoopModeInferiorAttaching &&
1186         start_mode != eRNBRunLoopModePlatformMode)
1187     {
1188         if (argc == 0 || g_lockdown_opt)
1189         {
1190             if (g_lockdown_opt != 0)
1191             {
1192                 // Work around for SIGPIPE crashes due to posix_spawn issue.
1193                 // We have to close STDOUT and STDERR, else the first time we
1194                 // try and do any, we get SIGPIPE and die as posix_spawn is
1195                 // doing bad things with our file descriptors at the moment.
1196                 int null = open("/dev/null", O_RDWR);
1197                 dup2(null, STDOUT_FILENO);
1198                 dup2(null, STDERR_FILENO);
1199             }
1200             else if (g_applist_opt != 0)
1201             {
1202                 // List all applications we are able to see
1203                 std::string applist_plist;
1204                 int err = ListApplications(applist_plist, false, false);
1205                 if (err == 0)
1206                 {
1207                     fputs (applist_plist.c_str(), stdout);
1208                 }
1209                 else
1210                 {
1211                     RNBLogSTDERR ("error: ListApplications returned error %i\n", err);
1212                 }
1213                 // Exit with appropriate error if we were asked to list the applications
1214                 // with no other args were given (and we weren't trying to do this over
1215                 // lockdown)
1216                 return err;
1217             }
1218 
1219             DNBLogDebug("Get args from remote protocol...");
1220             start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
1221         }
1222         else
1223         {
1224             start_mode = eRNBRunLoopModeInferiorLaunching;
1225             // Fill in the argv array in the context from the rest of our args.
1226             // Skip the name of this executable and the port number
1227             for (int i = 0; i < argc; i++)
1228             {
1229                 DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]);
1230                 ctx.PushArgument (argv[i]);
1231             }
1232         }
1233     }
1234 
1235     if (start_mode == eRNBRunLoopModeExit)
1236         return -1;
1237 
1238     RNBRunLoopMode mode = start_mode;
1239     char err_str[1024] = {'\0'};
1240 
1241     while (mode != eRNBRunLoopModeExit)
1242     {
1243         switch (mode)
1244         {
1245             case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
1246 #ifdef WITH_LOCKDOWN
1247                 if (g_lockdown_opt)
1248                 {
1249                     if (!remote->Comm().IsConnected())
1250                     {
1251                         if (remote->Comm().ConnectToService () != rnb_success)
1252                         {
1253                             RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
1254                             mode = eRNBRunLoopModeExit;
1255                         }
1256                         else if (g_applist_opt != 0)
1257                         {
1258                             // List all applications we are able to see
1259                             std::string applist_plist;
1260                             if (ListApplications(applist_plist, false, false) == 0)
1261                             {
1262                                 DNBLogDebug("Task list: %s", applist_plist.c_str());
1263 
1264                                 remote->Comm().Write(applist_plist.c_str(), applist_plist.size());
1265                                 // Issue a read that will never yield any data until the other side
1266                                 // closes the socket so this process doesn't just exit and cause the
1267                                 // socket to close prematurely on the other end and cause data loss.
1268                                 std::string buf;
1269                                 remote->Comm().Read(buf);
1270                             }
1271                             remote->Comm().Disconnect(false);
1272                             mode = eRNBRunLoopModeExit;
1273                             break;
1274                         }
1275                         else
1276                         {
1277                             // Start watching for remote packets
1278                             remote->StartReadRemoteDataThread();
1279                         }
1280                     }
1281                 }
1282                 else
1283 #endif
1284                 if (listen_port != INT32_MAX)
1285                 {
1286                     if (!StartListening (remote, listen_port, unix_socket_name.c_str()))
1287                         mode = eRNBRunLoopModeExit;
1288                 }
1289                 else if (str[0] == '/')
1290                 {
1291                     if (remote->Comm().OpenFile (str))
1292                         mode = eRNBRunLoopModeExit;
1293                 }
1294 
1295                 if (mode != eRNBRunLoopModeExit)
1296                 {
1297                     RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
1298 
1299                     mode = RNBRunLoopGetStartModeFromRemote (remote);
1300                 }
1301                 break;
1302 
1303             case eRNBRunLoopModeInferiorAttaching:
1304                 if (!waitfor_pid_name.empty())
1305                 {
1306                     // Set our end wait time if we are using a waitfor-duration
1307                     // option that may have been specified
1308                     struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1309                     if (waitfor_duration != 0)
1310                     {
1311                         DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1312                         timeout_ptr = &attach_timeout_abstime;
1313                     }
1314                     nub_launch_flavor_t launch_flavor = g_launch_flavor;
1315                     if (launch_flavor == eLaunchFlavorDefault)
1316                     {
1317                         // Our default launch method is posix spawn
1318                         launch_flavor = eLaunchFlavorPosixSpawn;
1319 
1320 #ifdef WITH_SPRINGBOARD
1321                         // Check if we have an app bundle, if so launch using SpringBoard.
1322                         if (waitfor_pid_name.find (".app") != std::string::npos)
1323                         {
1324                             launch_flavor = eLaunchFlavorSpringBoard;
1325                         }
1326 #endif
1327                     }
1328 
1329                     ctx.SetLaunchFlavor(launch_flavor);
1330                     bool ignore_existing = false;
1331                     nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, ignore_existing, timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
1332                     g_pid = pid;
1333 
1334                     if (pid == INVALID_NUB_PROCESS)
1335                     {
1336                         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1337                         if (err_str[0])
1338                             ctx.LaunchStatus().SetErrorString(err_str);
1339                         RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
1340                         mode = eRNBRunLoopModeExit;
1341                     }
1342                     else
1343                     {
1344                         ctx.SetProcessID(pid);
1345                         mode = eRNBRunLoopModeInferiorExecuting;
1346                     }
1347                 }
1348                 else if (attach_pid != INVALID_NUB_PROCESS)
1349                 {
1350 
1351                     RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid);
1352                     nub_process_t attached_pid;
1353                     mode = RNBRunLoopLaunchAttaching (remote, attach_pid, attached_pid);
1354                     if (mode != eRNBRunLoopModeInferiorExecuting)
1355                     {
1356                         const char *error_str = remote->Context().LaunchStatus().AsString();
1357                         RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
1358                         mode = eRNBRunLoopModeExit;
1359                     }
1360                 }
1361                 else if (!attach_pid_name.empty ())
1362                 {
1363                     struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1364                     if (waitfor_duration != 0)
1365                     {
1366                         DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1367                         timeout_ptr = &attach_timeout_abstime;
1368                     }
1369 
1370                     nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str));
1371                     g_pid = pid;
1372                     if (pid == INVALID_NUB_PROCESS)
1373                     {
1374                         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1375                         if (err_str[0])
1376                             ctx.LaunchStatus().SetErrorString(err_str);
1377                         RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
1378                         mode = eRNBRunLoopModeExit;
1379                     }
1380                     else
1381                     {
1382                         ctx.SetProcessID(pid);
1383                         mode = eRNBRunLoopModeInferiorExecuting;
1384                     }
1385 
1386                 }
1387                 else
1388                 {
1389                     RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.");
1390                     mode = eRNBRunLoopModeExit;
1391                 }
1392 
1393                 if (mode != eRNBRunLoopModeExit)
1394                 {
1395                     if (listen_port != INT32_MAX)
1396                     {
1397                         if (!StartListening (remote, listen_port, unix_socket_name.c_str()))
1398                             mode = eRNBRunLoopModeExit;
1399                     }
1400                     else if (str[0] == '/')
1401                     {
1402                         if (remote->Comm().OpenFile (str))
1403                             mode = eRNBRunLoopModeExit;
1404                     }
1405                     if (mode != eRNBRunLoopModeExit)
1406                         RNBLogSTDOUT ("Got a connection, waiting for debugger instructions for process %d.\n", attach_pid);
1407                 }
1408                 break;
1409 
1410             case eRNBRunLoopModeInferiorLaunching:
1411                 {
1412                     mode = RNBRunLoopLaunchInferior (remote,
1413                                                      ctx.GetSTDINPath(),
1414                                                      ctx.GetSTDOUTPath(),
1415                                                      ctx.GetSTDERRPath(),
1416                                                      no_stdio);
1417 
1418                     if (mode == eRNBRunLoopModeInferiorExecuting)
1419                     {
1420                         if (listen_port != INT32_MAX)
1421                         {
1422                             if (!StartListening (remote, listen_port, unix_socket_name.c_str()))
1423                                 mode = eRNBRunLoopModeExit;
1424                         }
1425                         else if (str[0] == '/')
1426                         {
1427                             if (remote->Comm().OpenFile (str))
1428                                 mode = eRNBRunLoopModeExit;
1429                         }
1430 
1431                         if (mode != eRNBRunLoopModeExit)
1432                             RNBLogSTDOUT ("Got a connection, waiting for debugger instructions.\n");
1433                     }
1434                     else
1435                     {
1436                         const char *error_str = remote->Context().LaunchStatus().AsString();
1437                         RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv_sub_zero, error_str ? error_str : "unknown error.");
1438                     }
1439                 }
1440                 break;
1441 
1442             case eRNBRunLoopModeInferiorExecuting:
1443                 mode = RNBRunLoopInferiorExecuting(remote);
1444                 break;
1445 
1446             case eRNBRunLoopModePlatformMode:
1447                 if (listen_port != INT32_MAX)
1448                 {
1449                     if (!StartListening (remote, listen_port, unix_socket_name.c_str()))
1450                         mode = eRNBRunLoopModeExit;
1451                 }
1452                 else if (str[0] == '/')
1453                 {
1454                     if (remote->Comm().OpenFile (str))
1455                         mode = eRNBRunLoopModeExit;
1456                 }
1457 
1458                 if (mode != eRNBRunLoopModeExit)
1459                     mode = RNBRunLoopPlatform (remote);
1460                 break;
1461 
1462             default:
1463                 mode = eRNBRunLoopModeExit;
1464             case eRNBRunLoopModeExit:
1465                 break;
1466         }
1467     }
1468 
1469     remote->StopReadRemoteDataThread ();
1470     remote->Context().SetProcessID(INVALID_NUB_PROCESS);
1471 
1472     return 0;
1473 }
1474