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