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