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