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