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