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