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 
21 #include "CFString.h"
22 #include "DNB.h"
23 #include "DNBLog.h"
24 #include "DNBTimer.h"
25 #include "PseudoTerminal.h"
26 #include "RNBContext.h"
27 #include "RNBServices.h"
28 #include "RNBSocket.h"
29 #include "RNBRemote.h"
30 #include "SysSignal.h"
31 
32 // Global PID in case we get a signal and need to stop the process...
33 nub_process_t g_pid = INVALID_NUB_PROCESS;
34 
35 //----------------------------------------------------------------------
36 // Run loop modes which determine which run loop function will be called
37 //----------------------------------------------------------------------
38 typedef enum
39 {
40     eRNBRunLoopModeInvalid = 0,
41     eRNBRunLoopModeGetStartModeFromRemoteProtocol,
42     eRNBRunLoopModeInferiorAttaching,
43     eRNBRunLoopModeInferiorLaunching,
44     eRNBRunLoopModeInferiorExecuting,
45     eRNBRunLoopModeExit
46 } RNBRunLoopMode;
47 
48 
49 //----------------------------------------------------------------------
50 // Global Variables
51 //----------------------------------------------------------------------
52 RNBRemoteSP g_remoteSP;
53 static int g_lockdown_opt  = 0;
54 static int g_applist_opt = 0;
55 static nub_launch_flavor_t g_launch_flavor = eLaunchFlavorDefault;
56 int g_disable_aslr = 0;
57 
58 int g_isatty = 0;
59 
60 #define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
61 #define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
62 
63 //----------------------------------------------------------------------
64 // Run Loop function prototypes
65 //----------------------------------------------------------------------
66 RNBRunLoopMode RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remote);
67 RNBRunLoopMode RNBRunLoopInferiorExecuting (RNBRemoteSP &remote);
68 
69 
70 //----------------------------------------------------------------------
71 // Get our program path and arguments from the remote connection.
72 // We will need to start up the remote connection without a PID, get the
73 // arguments, wait for the new process to finish launching and hit its
74 // entry point,  and then return the run loop mode that should come next.
75 //----------------------------------------------------------------------
76 RNBRunLoopMode
77 RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP)
78 {
79     std::string packet;
80 
81     if (remoteSP.get() != NULL)
82     {
83         RNBRemote* remote = remoteSP.get();
84         RNBContext& ctx = remote->Context();
85         uint32_t event_mask = RNBContext::event_read_packet_available;
86 
87         // Spin waiting to get the A packet.
88         while (1)
89         {
90             DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask);
91             nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
92             DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events);
93 
94             if (set_events & RNBContext::event_read_packet_available)
95             {
96                 rnb_err_t err = rnb_err;
97                 RNBRemote::PacketEnum type;
98 
99                 err = remote->HandleReceivedPacket (&type);
100 
101                 // check if we tried to attach to a process
102                 if (type == RNBRemote::vattach || type == RNBRemote::vattachwait)
103                 {
104                     if (err == rnb_success)
105                         return eRNBRunLoopModeInferiorExecuting;
106                     else
107                     {
108                         RNBLogSTDERR ("error: attach failed.");
109                         return eRNBRunLoopModeExit;
110                     }
111                 }
112 
113                 if (err == rnb_success)
114                 {
115                     // If we got our arguments we are ready to launch using the arguments
116                     // and any environment variables we received.
117                     if (type == RNBRemote::set_argv)
118                     {
119                         return eRNBRunLoopModeInferiorLaunching;
120                     }
121                 }
122                 else if (err == rnb_not_connected)
123                 {
124                     RNBLogSTDERR ("error: connection lost.");
125                     return eRNBRunLoopModeExit;
126                 }
127                 else
128                 {
129                     // a catch all for any other gdb remote packets that failed
130                     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__);
131                     continue;
132                 }
133 
134                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
135             }
136             else
137             {
138                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__);
139                 return eRNBRunLoopModeExit;
140             }
141         }
142     }
143     return eRNBRunLoopModeExit;
144 }
145 
146 
147 //----------------------------------------------------------------------
148 // This run loop mode will wait for the process to launch and hit its
149 // entry point. It will currently ignore all events except for the
150 // process state changed event, where it watches for the process stopped
151 // or crash process state.
152 //----------------------------------------------------------------------
153 RNBRunLoopMode
154 RNBRunLoopLaunchInferior (RNBRemoteSP &remote, const char *stdio_path)
155 {
156     RNBContext& ctx = remote->Context();
157 
158     // The Process stuff takes a c array, the RNBContext has a vector...
159     // So make up a c array.
160 
161     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, ctx.ArgumentAtIndex(0));
162 
163     size_t inferior_argc = ctx.ArgumentCount();
164     // Initialize inferior_argv with inferior_argc + 1 NULLs
165     std::vector<const char *> inferior_argv(inferior_argc + 1, NULL);
166 
167     size_t i;
168     for (i = 0; i < inferior_argc; i++)
169         inferior_argv[i] = ctx.ArgumentAtIndex(i);
170 
171     // Pass the environment array the same way:
172 
173     size_t inferior_envc = ctx.EnvironmentCount();
174     // Initialize inferior_argv with inferior_argc + 1 NULLs
175     std::vector<const char *> inferior_envp(inferior_envc + 1, NULL);
176 
177     for (i = 0; i < inferior_envc; i++)
178         inferior_envp[i] = ctx.EnvironmentAtIndex(i);
179 
180     // Our launch type hasn't been set to anything concrete, so we need to
181     // figure our how we are going to launch automatically.
182 
183     nub_launch_flavor_t launch_flavor = g_launch_flavor;
184     if (launch_flavor == eLaunchFlavorDefault)
185     {
186         // Our default launch method is posix spawn
187         launch_flavor = eLaunchFlavorPosixSpawn;
188 
189 #if defined (__arm__)
190         // Check if we have an app bundle, if so launch using SpringBoard.
191         if (strstr(inferior_argv[0], ".app"))
192         {
193             launch_flavor = eLaunchFlavorSpringBoard;
194         }
195 #endif
196     }
197 
198     ctx.SetLaunchFlavor(launch_flavor);
199     char resolved_path[PATH_MAX];
200 
201     // If we fail to resolve the path to our executable, then just use what we
202     // were given and hope for the best
203     if ( !DNBResolveExecutablePath (inferior_argv[0], resolved_path, sizeof(resolved_path)) )
204         ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path));
205 
206     char launch_err_str[PATH_MAX];
207     launch_err_str[0] = '\0';
208     nub_process_t pid = DNBProcessLaunch (resolved_path,
209                                           &inferior_argv[0],
210                                           &inferior_envp[0],
211                                           stdio_path,
212                                           launch_flavor,
213                                           g_disable_aslr,
214                                           launch_err_str,
215                                           sizeof(launch_err_str));
216 
217     g_pid = pid;
218 
219     if (pid == INVALID_NUB_PROCESS && strlen(launch_err_str) > 0)
220     {
221         DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, launch_err_str);
222         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
223         ctx.LaunchStatus().SetErrorString(launch_err_str);
224     }
225     else
226         ctx.LaunchStatus().Clear();
227 
228     if (remote->Comm().IsConnected())
229     {
230         // It we are connected already, the next thing gdb will do is ask
231         // whether the launch succeeded, and if not, whether there is an
232         // error code.  So we need to fetch one packet from gdb before we wait
233         // on the stop from the target.
234 
235         uint32_t event_mask = RNBContext::event_read_packet_available;
236         nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
237 
238         if (set_events & RNBContext::event_read_packet_available)
239         {
240             rnb_err_t err = rnb_err;
241             RNBRemote::PacketEnum type;
242 
243             err = remote->HandleReceivedPacket (&type);
244 
245             if (err != rnb_success)
246             {
247                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__);
248                 return eRNBRunLoopModeExit;
249             }
250             if (type != RNBRemote::query_launch_success)
251             {
252                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__);
253             }
254         }
255     }
256 
257     while (pid != INVALID_NUB_PROCESS)
258     {
259         // Wait for process to start up and hit entry point
260         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid);
261         nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL);
262         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events);
263 
264         if (set_events == 0)
265         {
266             pid = INVALID_NUB_PROCESS;
267             g_pid = pid;
268         }
269         else
270         {
271             if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
272             {
273                 nub_state_t pid_state = DNBProcessGetState (pid);
274                 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
275 
276                 switch (pid_state)
277                 {
278                     default:
279                     case eStateInvalid:
280                     case eStateUnloaded:
281                     case eStateAttaching:
282                     case eStateLaunching:
283                     case eStateSuspended:
284                         break;  // Ignore
285 
286                     case eStateRunning:
287                     case eStateStepping:
288                         // Still waiting to stop at entry point...
289                         break;
290 
291                     case eStateStopped:
292                     case eStateCrashed:
293                         ctx.SetProcessID(pid);
294                         return eRNBRunLoopModeInferiorExecuting;
295 
296                     case eStateDetached:
297                     case eStateExited:
298                         pid = INVALID_NUB_PROCESS;
299                         g_pid = pid;
300                         return eRNBRunLoopModeExit;
301                 }
302             }
303 
304             DNBProcessResetEvents(pid, set_events);
305         }
306     }
307 
308     return eRNBRunLoopModeExit;
309 }
310 
311 
312 //----------------------------------------------------------------------
313 // This run loop mode will wait for the process to launch and hit its
314 // entry point. It will currently ignore all events except for the
315 // process state changed event, where it watches for the process stopped
316 // or crash process state.
317 //----------------------------------------------------------------------
318 RNBRunLoopMode
319 RNBRunLoopLaunchAttaching (RNBRemoteSP &remote, nub_process_t attach_pid, nub_process_t& pid)
320 {
321     RNBContext& ctx = remote->Context();
322 
323     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid);
324     char err_str[1024];
325     pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str));
326     g_pid = pid;
327 
328     if (pid == INVALID_NUB_PROCESS)
329     {
330         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
331         if (err_str[0])
332             ctx.LaunchStatus().SetErrorString(err_str);
333         return eRNBRunLoopModeExit;
334     }
335     else
336     {
337 
338         ctx.SetProcessID(pid);
339         return eRNBRunLoopModeInferiorExecuting;
340     }
341 }
342 
343 //----------------------------------------------------------------------
344 // Watch for signals:
345 // SIGINT: so we can halt our inferior. (disabled for now)
346 // SIGPIPE: in case our child process dies
347 //----------------------------------------------------------------------
348 int g_sigint_received = 0;
349 int g_sigpipe_received = 0;
350 void
351 signal_handler(int signo)
352 {
353     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo));
354 
355     switch (signo)
356     {
357         case SIGINT:
358             g_sigint_received++;
359             if (g_pid != INVALID_NUB_PROCESS)
360             {
361                 // Only send a SIGINT once...
362                 if (g_sigint_received == 1)
363                 {
364                     switch (DNBProcessGetState (g_pid))
365                     {
366                         case eStateRunning:
367                         case eStateStepping:
368                             DNBProcessSignal (g_pid, SIGSTOP);
369                             return;
370                     }
371                 }
372             }
373             exit (SIGINT);
374             break;
375 
376         case SIGPIPE:
377             g_sigpipe_received = 1;
378             break;
379     }
380 }
381 
382 // Return the new run loop mode based off of the current process state
383 RNBRunLoopMode
384 HandleProcessStateChange (RNBRemoteSP &remote, bool initialize)
385 {
386     RNBContext& ctx = remote->Context();
387     nub_process_t pid = ctx.ProcessID();
388 
389     if (pid == INVALID_NUB_PROCESS)
390     {
391         DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
392         return eRNBRunLoopModeExit;
393     }
394     nub_state_t pid_state = DNBProcessGetState (pid);
395 
396     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state));
397 
398     switch (pid_state)
399     {
400         case eStateInvalid:
401         case eStateUnloaded:
402             // Something bad happened
403             return eRNBRunLoopModeExit;
404             break;
405 
406         case eStateAttaching:
407         case eStateLaunching:
408             return eRNBRunLoopModeInferiorExecuting;
409 
410         case eStateSuspended:
411         case eStateCrashed:
412         case eStateStopped:
413             // If we stop due to a signal, so clear the fact that we got a SIGINT
414             // so we can stop ourselves again (but only while our inferior
415             // process is running..)
416             g_sigint_received = 0;
417             if (initialize == false)
418             {
419                 // Compare the last stop count to our current notion of a stop count
420                 // to make sure we don't notify more than once for a given stop.
421                 nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
422                 bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid));
423                 if (pid_stop_count_changed)
424                 {
425                     remote->FlushSTDIO();
426 
427                     if (ctx.GetProcessStopCount() == 1)
428                     {
429                         DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s pid_stop_count %u (old %u)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
430                     }
431                     else
432                     {
433 
434                         DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s pid_stop_count %u (old %u)) Notify??? YES!!!", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
435                         remote->NotifyThatProcessStopped ();
436                     }
437                 }
438                 else
439                 {
440                     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s pid_stop_count %u (old %u)) Notify??? skipping...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
441                 }
442             }
443             return eRNBRunLoopModeInferiorExecuting;
444 
445         case eStateStepping:
446         case eStateRunning:
447             return eRNBRunLoopModeInferiorExecuting;
448 
449         case eStateExited:
450             remote->HandlePacket_last_signal(NULL);
451             return eRNBRunLoopModeExit;
452 
453     }
454 
455     // Catch all...
456     return eRNBRunLoopModeExit;
457 }
458 // This function handles the case where our inferior program is stopped and
459 // we are waiting for gdb remote protocol packets. When a packet occurs that
460 // makes the inferior run, we need to leave this function with a new state
461 // as the return code.
462 RNBRunLoopMode
463 RNBRunLoopInferiorExecuting (RNBRemoteSP &remote)
464 {
465     DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
466     RNBContext& ctx = remote->Context();
467 
468     // Init our mode and set 'is_running' based on the current process state
469     RNBRunLoopMode mode = HandleProcessStateChange (remote, true);
470 
471     while (ctx.ProcessID() != INVALID_NUB_PROCESS)
472     {
473 
474         std::string set_events_str;
475         uint32_t event_mask = ctx.NormalEventBits();
476 
477         if (!ctx.ProcessStateRunning())
478         {
479             // Clear the stdio bits if we are not running so we don't send any async packets
480             event_mask &= ~RNBContext::event_proc_stdio_available;
481         }
482 
483         // We want to make sure we consume all process state changes and have
484         // whomever is notifying us to wait for us to reset the event bit before
485         // continuing.
486         //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
487 
488         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
489         nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
490         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));
491 
492         if (set_events)
493         {
494             if ((set_events & RNBContext::event_proc_thread_exiting) ||
495                 (set_events & RNBContext::event_proc_stdio_available))
496             {
497                 remote->FlushSTDIO();
498             }
499 
500             if (set_events & RNBContext::event_read_packet_available)
501             {
502                 // handleReceivedPacket will take care of resetting the
503                 // event_read_packet_available events when there are no more...
504                 set_events ^= RNBContext::event_read_packet_available;
505 
506                 if (ctx.ProcessStateRunning())
507                 {
508                     if (remote->HandleAsyncPacket() == rnb_not_connected)
509                     {
510                         // TODO: connect again? Exit?
511                     }
512                 }
513                 else
514                 {
515                     if (remote->HandleReceivedPacket() == rnb_not_connected)
516                     {
517                         // TODO: connect again? Exit?
518                     }
519                 }
520             }
521 
522             if (set_events & RNBContext::event_proc_state_changed)
523             {
524                 mode = HandleProcessStateChange (remote, false);
525                 ctx.Events().ResetEvents(RNBContext::event_proc_state_changed);
526                 set_events ^= RNBContext::event_proc_state_changed;
527             }
528 
529             if (set_events & RNBContext::event_proc_thread_exiting)
530             {
531                 mode = eRNBRunLoopModeExit;
532             }
533 
534             if (set_events & RNBContext::event_read_thread_exiting)
535             {
536                 // Out remote packet receiving thread exited, exit for now.
537                 if (ctx.HasValidProcessID())
538                 {
539                     // TODO: We should add code that will leave the current process
540                     // in its current state and listen for another connection...
541                     if (ctx.ProcessStateRunning())
542                     {
543                         DNBProcessKill (ctx.ProcessID());
544                     }
545                 }
546                 mode = eRNBRunLoopModeExit;
547             }
548         }
549 
550         // Reset all event bits that weren't reset for now...
551         if (set_events != 0)
552             ctx.Events().ResetEvents(set_events);
553 
554         if (mode != eRNBRunLoopModeInferiorExecuting)
555             break;
556     }
557 
558     return mode;
559 }
560 
561 
562 //----------------------------------------------------------------------
563 // Convenience function to set up the remote listening port
564 // Returns 1 for success 0 for failure.
565 //----------------------------------------------------------------------
566 
567 static int
568 StartListening (RNBRemoteSP remoteSP, int listen_port)
569 {
570     if (!remoteSP->Comm().IsConnected())
571     {
572         RNBLogSTDOUT ("Listening to port %i...\n", listen_port);
573         if (remoteSP->Comm().Listen(listen_port) != rnb_success)
574         {
575             RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
576             return 0;
577         }
578         else
579         {
580             remoteSP->StartReadRemoteDataThread();
581         }
582     }
583     return 1;
584 }
585 
586 //----------------------------------------------------------------------
587 // ASL Logging callback that can be registered with DNBLogSetLogCallback
588 //----------------------------------------------------------------------
589 void
590 ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
591 {
592     if (format == NULL)
593         return;
594     static aslmsg g_aslmsg = NULL;
595     if (g_aslmsg == NULL)
596     {
597         g_aslmsg = ::asl_new (ASL_TYPE_MSG);
598         char asl_key_sender[PATH_MAX];
599         snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.%s-%g", DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_NUM);
600         ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
601     }
602 
603     int asl_level;
604     if (flags & DNBLOG_FLAG_FATAL)        asl_level = ASL_LEVEL_CRIT;
605     else if (flags & DNBLOG_FLAG_ERROR)   asl_level = ASL_LEVEL_ERR;
606     else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING;
607     else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO;
608     else                                  asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG;
609 
610     ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
611 }
612 
613 //----------------------------------------------------------------------
614 // FILE based Logging callback that can be registered with
615 // DNBLogSetLogCallback
616 //----------------------------------------------------------------------
617 void
618 FileLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
619 {
620     if (baton == NULL || format == NULL)
621         return;
622 
623     ::vfprintf ((FILE *)baton, format, args);
624     ::fprintf ((FILE *)baton, "\n");
625 }
626 
627 
628 void
629 show_usage_and_exit (int exit_code)
630 {
631     RNBLogSTDERR ("Usage:\n  %s host:port [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
632     RNBLogSTDERR ("  %s /path/file [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
633     RNBLogSTDERR ("  %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
634     RNBLogSTDERR ("  %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
635     RNBLogSTDERR ("  %s host:port --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
636     RNBLogSTDERR ("  %s /path/file --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
637     exit (exit_code);
638 }
639 
640 
641 //----------------------------------------------------------------------
642 // option descriptors for getopt_long()
643 //----------------------------------------------------------------------
644 static struct option g_long_options[] =
645 {
646     { "attach",             required_argument,  NULL,               'a' },
647     { "debug",              no_argument,        NULL,               'g' },
648     { "verbose",            no_argument,        NULL,               'v' },
649     { "lockdown",           no_argument,        &g_lockdown_opt,    1   },  // short option "-k"
650     { "applist",            no_argument,        &g_applist_opt,     1   },  // short option "-t"
651     { "log-file",           required_argument,  NULL,               'l' },
652     { "log-flags",          required_argument,  NULL,               'f' },
653     { "launch",             required_argument,  NULL,               'x' },  // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
654     { "waitfor",            required_argument,  NULL,               'w' },  // Wait for a process whose name starts with ARG
655     { "waitfor-interval",   required_argument,  NULL,               'i' },  // Time in usecs to wait between sampling the pid list when waiting for a process by name
656     { "waitfor-duration",   required_argument,  NULL,               'd' },  // The time in seconds to wait for a process to show up by name
657     { "native-regs",        no_argument,        NULL,               'r' },  // Specify to use the native registers instead of the gdb defaults for the architecture.
658     { "stdio-path",         required_argument,  NULL,               's' },  // Set the STDIO path to be used when launching applications
659     { "setsid",             no_argument,        NULL,               'S' },  // call setsid() to make debugserver run in its own sessions
660     { "disable-aslr",       no_argument,        NULL,               'D' },  // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
661     { NULL,                 0,                  NULL,               0   }
662 };
663 
664 
665 //----------------------------------------------------------------------
666 // main
667 //----------------------------------------------------------------------
668 int
669 main (int argc, char *argv[])
670 {
671     g_isatty = ::isatty (STDIN_FILENO);
672 
673     //  ::printf ("uid=%u euid=%u gid=%u egid=%u\n",
674     //            getuid(),
675     //            geteuid(),
676     //            getgid(),
677     //            getegid());
678 
679 
680     //    signal (SIGINT, signal_handler);
681     signal (SIGPIPE, signal_handler);
682     signal (SIGHUP, signal_handler);
683 
684     int i;
685     int attach_pid = INVALID_NUB_PROCESS;
686 
687     FILE* log_file = NULL;
688     uint32_t log_flags = 0;
689     // Parse our options
690     int ch;
691     int long_option_index = 0;
692     int use_native_registers = 0;
693     int debug = 0;
694     std::string compile_options;
695     std::string waitfor_pid_name;           // Wait for a process that starts with this name
696     std::string attach_pid_name;
697     std::string stdio_path;
698     useconds_t waitfor_interval = 1000;     // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
699     useconds_t waitfor_duration = 0;        // Time in seconds to wait for a process by name, 0 means wait forever.
700 
701 #if !defined (DNBLOG_ENABLED)
702     compile_options += "(no-logging) ";
703 #endif
704 
705     RNBRunLoopMode start_mode = eRNBRunLoopModeExit;
706 
707     while ((ch = getopt_long(argc, argv, "a:d:gi:vktl:f:w:x:r", g_long_options, &long_option_index)) != -1)
708     {
709         DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
710                     ch, (uint8_t)ch,
711                     g_long_options[long_option_index].name,
712                     g_long_options[long_option_index].has_arg ? '=' : ' ',
713                     optarg ? optarg : "");
714         switch (ch)
715         {
716             case 0:   // Any optional that auto set themselves will return 0
717                 break;
718 
719             case 'a':
720                 if (optarg && optarg[0])
721                 {
722                     if (isdigit(optarg[0]))
723                     {
724                         char *end = NULL;
725                         attach_pid = strtoul(optarg, &end, 0);
726                         if (end == NULL || *end != '\0')
727                         {
728                             RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg);
729                             exit (4);
730                         }
731                     }
732                     else
733                     {
734                         attach_pid_name = optarg;
735                     }
736                     start_mode = eRNBRunLoopModeInferiorAttaching;
737                 }
738                 break;
739 
740                 // --waitfor=NAME
741             case 'w':
742                 if (optarg && optarg[0])
743                 {
744                     waitfor_pid_name = optarg;
745                     start_mode = eRNBRunLoopModeInferiorAttaching;
746                 }
747                 break;
748 
749                 // --waitfor-interval=USEC
750             case 'i':
751                 if (optarg && optarg[0])
752                 {
753                     char *end = NULL;
754                     waitfor_interval = strtoul(optarg, &end, 0);
755                     if (end == NULL || *end != '\0')
756                     {
757                         RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
758                         exit (6);
759                     }
760                 }
761                 break;
762 
763                 // --waitfor-duration=SEC
764             case 'd':
765                 if (optarg && optarg[0])
766                 {
767                     char *end = NULL;
768                     waitfor_duration = strtoul(optarg, &end, 0);
769                     if (end == NULL || *end != '\0')
770                     {
771                         RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
772                         exit (7);
773                     }
774                 }
775                 break;
776 
777             case 'x':
778                 if (optarg && optarg[0])
779                 {
780                     if (strcasecmp(optarg, "auto") == 0)
781                         g_launch_flavor = eLaunchFlavorDefault;
782                     else if (strcasestr(optarg, "posix") == optarg)
783                         g_launch_flavor = eLaunchFlavorPosixSpawn;
784                     else if (strcasestr(optarg, "fork") == optarg)
785                         g_launch_flavor = eLaunchFlavorForkExec;
786 #if defined (__arm__)
787                     else if (strcasestr(optarg, "spring") == optarg)
788                         g_launch_flavor = eLaunchFlavorSpringBoard;
789 #endif
790                     else
791                     {
792                         RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
793                         RNBLogSTDERR ("Valid values TYPE are:\n");
794                         RNBLogSTDERR ("  auto    Auto-detect the best launch method to use.\n");
795                         RNBLogSTDERR ("  posix   Launch the executable using posix_spawn.\n");
796                         RNBLogSTDERR ("  fork    Launch the executable using fork and exec.\n");
797 #if defined (__arm__)
798                         RNBLogSTDERR ("  spring  Launch the executable through Springboard.\n");
799 #endif
800                         exit (5);
801                     }
802                 }
803                 break;
804 
805             case 'l': // Set Log File
806                 if (optarg && optarg[0])
807                 {
808                     if (strcasecmp(optarg, "stdout") == 0)
809                         log_file = stdout;
810                     else if (strcasecmp(optarg, "stderr") == 0)
811                         log_file = stderr;
812                     else
813                         log_file = fopen(optarg, "w+");
814 
815                     if (log_file == NULL)
816                     {
817                         const char *errno_str = strerror(errno);
818                         RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
819                     }
820                 }
821                 break;
822 
823             case 'f': // Log Flags
824                 if (optarg && optarg[0])
825                     log_flags = strtoul(optarg, NULL, 0);
826                 break;
827 
828             case 'g':
829                 debug = 1;
830                 DNBLogSetDebug(1);
831                 break;
832 
833             case 't':
834                 g_applist_opt = 1;
835                 break;
836 
837             case 'k':
838                 g_lockdown_opt = 1;
839                 break;
840 
841             case 'r':
842                 use_native_registers = 1;
843                 break;
844 
845             case 'v':
846                 DNBLogSetVerbose(1);
847                 break;
848 
849             case 's':
850                 stdio_path = optarg;
851                 break;
852 
853             case 'S':
854                 // Put debugserver into a new session. Terminals group processes
855                 // into sessions and when a special terminal key sequences
856                 // (like control+c) are typed they can cause signals to go out to
857                 // all processes in a session. Using this --setsid (-S) option
858                 // will cause debugserver to run in its own sessions and be free
859                 // from such issues.
860                 //
861                 // This is useful when debugserver is spawned from a command
862                 // line application that uses debugserver to do the debugging,
863                 // yet that application doesn't want debugserver receiving the
864                 // signals sent to the session (i.e. dying when anyone hits ^C).
865                 setsid();
866                 break;
867             case 'D':
868                 g_disable_aslr = 1;
869                 break;
870         }
871     }
872 
873     // Skip any options we consumed with getopt_long
874     argc -= optind;
875     argv += optind;
876 
877     g_remoteSP.reset (new RNBRemote (use_native_registers));
878 
879     RNBRemote *remote = g_remoteSP.get();
880     if (remote == NULL)
881     {
882         RNBLogSTDERR ("error: failed to create a remote connection class\n");
883         return -1;
884     }
885 
886     RNBContext& ctx = remote->Context();
887 
888 
889     // It is ok for us to set NULL as the logfile (this will disable any logging)
890 
891     if (log_file != NULL)
892     {
893         DNBLogSetLogCallback(FileLogCallback, log_file);
894         // If our log file was set, yet we have no log flags, log everything!
895         if (log_flags == 0)
896             log_flags = LOG_ALL | LOG_RNB_ALL;
897 
898         DNBLogSetLogMask (log_flags);
899     }
900     else
901     {
902         // Enable DNB logging
903         DNBLogSetLogCallback(ASLLogCallback, NULL);
904         DNBLogSetLogMask (log_flags);
905 
906     }
907 
908     if (DNBLogEnabled())
909     {
910         for (i=0; i<argc; i++)
911             DNBLogDebug("argv[%i] = %s", i, argv[i]);
912     }
913 
914     // Now that we have read in the options and enabled logging, initialize
915     // the rest of RNBRemote
916     RNBRemote::InitializeRegisters (use_native_registers);
917 
918 
919     // as long as we're dropping remotenub in as a replacement for gdbserver,
920     // explicitly note that this is not gdbserver.
921 
922     RNBLogSTDOUT ("%s-%g %sfor %s.\n",
923                   DEBUGSERVER_PROGRAM_NAME,
924                   DEBUGSERVER_VERSION_NUM,
925                   compile_options.c_str(),
926                   RNB_ARCH);
927 
928     int listen_port = INT32_MAX;
929     char str[PATH_MAX];
930 
931     if (g_lockdown_opt == 0 && g_applist_opt == 0)
932     {
933         // Make sure we at least have port
934         if (argc < 1)
935         {
936             show_usage_and_exit (1);
937         }
938         // accept 'localhost:' prefix on port number
939 
940         int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &listen_port);
941         if (items_scanned == 2)
942         {
943             DNBLogDebug("host = '%s'  port = %i", str, listen_port);
944         }
945         else if (argv[0][0] == '/')
946         {
947             listen_port = INT32_MAX;
948             strncpy(str, argv[0], sizeof(str));
949         }
950         else
951         {
952             show_usage_and_exit (2);
953         }
954 
955         // We just used the 'host:port' or the '/path/file' arg...
956         argc--;
957         argv++;
958 
959     }
960 
961     //  If we know we're waiting to attach, we don't need any of this other info.
962     if (start_mode != eRNBRunLoopModeInferiorAttaching)
963     {
964         if (argc == 0 || g_lockdown_opt)
965         {
966             if (g_lockdown_opt != 0)
967             {
968                 // Work around for SIGPIPE crashes due to posix_spawn issue.
969                 // We have to close STDOUT and STDERR, else the first time we
970                 // try and do any, we get SIGPIPE and die as posix_spawn is
971                 // doing bad things with our file descriptors at the moment.
972                 int null = open("/dev/null", O_RDWR);
973                 dup2(null, STDOUT_FILENO);
974                 dup2(null, STDERR_FILENO);
975             }
976             else if (g_applist_opt != 0)
977             {
978                 // List all applications we are able to see
979                 std::string applist_plist;
980                 int err = ListApplications(applist_plist, false, false);
981                 if (err == 0)
982                 {
983                     fputs (applist_plist.c_str(), stdout);
984                 }
985                 else
986                 {
987                     RNBLogSTDERR ("error: ListApplications returned error %i\n", err);
988                 }
989                 // Exit with appropriate error if we were asked to list the applications
990                 // with no other args were given (and we weren't trying to do this over
991                 // lockdown)
992                 return err;
993             }
994 
995             DNBLogDebug("Get args from remote protocol...");
996             start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
997         }
998         else
999         {
1000             start_mode = eRNBRunLoopModeInferiorLaunching;
1001             // Fill in the argv array in the context from the rest of our args.
1002             // Skip the name of this executable and the port number
1003             for (int i = 0; i < argc; i++)
1004             {
1005                 DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]);
1006                 ctx.PushArgument (argv[i]);
1007             }
1008         }
1009     }
1010 
1011     if (start_mode == eRNBRunLoopModeExit)
1012         return -1;
1013 
1014     RNBRunLoopMode mode = start_mode;
1015     char err_str[1024] = {'\0'};
1016 
1017     while (mode != eRNBRunLoopModeExit)
1018     {
1019         switch (mode)
1020         {
1021             case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
1022 #if defined (__arm__)
1023                 if (g_lockdown_opt)
1024                 {
1025                     if (!g_remoteSP->Comm().IsConnected())
1026                     {
1027                         if (g_remoteSP->Comm().ConnectToService () != rnb_success)
1028                         {
1029                             RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
1030                             mode = eRNBRunLoopModeExit;
1031                         }
1032                         else if (g_applist_opt != 0)
1033                         {
1034                             // List all applications we are able to see
1035                             std::string applist_plist;
1036                             if (ListApplications(applist_plist, false, false) == 0)
1037                             {
1038                                 DNBLogDebug("Task list: %s", applist_plist.c_str());
1039 
1040                                 g_remoteSP->Comm().Write(applist_plist.c_str(), applist_plist.size());
1041                                 // Issue a read that will never yield any data until the other side
1042                                 // closes the socket so this process doesn't just exit and cause the
1043                                 // socket to close prematurely on the other end and cause data loss.
1044                                 std::string buf;
1045                                 g_remoteSP->Comm().Read(buf);
1046                             }
1047                             g_remoteSP->Comm().Disconnect(false);
1048                             mode = eRNBRunLoopModeExit;
1049                             break;
1050                         }
1051                         else
1052                         {
1053                             // Start watching for remote packets
1054                             g_remoteSP->StartReadRemoteDataThread();
1055                         }
1056                     }
1057                 }
1058                 else
1059 #endif
1060                     if (listen_port != INT32_MAX)
1061                     {
1062                         if (!StartListening (g_remoteSP, listen_port))
1063                             mode = eRNBRunLoopModeExit;
1064                     }
1065                     else if (str[0] == '/')
1066                     {
1067                         if (g_remoteSP->Comm().OpenFile (str))
1068                             mode = eRNBRunLoopModeExit;
1069                     }
1070                 if (mode != eRNBRunLoopModeExit)
1071                 {
1072                     RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
1073 
1074                     mode = RNBRunLoopGetStartModeFromRemote (g_remoteSP);
1075                 }
1076                 break;
1077 
1078             case eRNBRunLoopModeInferiorAttaching:
1079                 if (!waitfor_pid_name.empty())
1080                 {
1081                     // Set our end wait time if we are using a waitfor-duration
1082                     // option that may have been specified
1083                     struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1084                     if (waitfor_duration != 0)
1085                     {
1086                         DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1087                         timeout_ptr = &attach_timeout_abstime;
1088                     }
1089                     nub_launch_flavor_t launch_flavor = g_launch_flavor;
1090                     if (launch_flavor == eLaunchFlavorDefault)
1091                     {
1092                         // Our default launch method is posix spawn
1093                         launch_flavor = eLaunchFlavorPosixSpawn;
1094 
1095 #if defined (__arm__)
1096                         // Check if we have an app bundle, if so launch using SpringBoard.
1097                         if (waitfor_pid_name.find (".app") != std::string::npos)
1098                         {
1099                             launch_flavor = eLaunchFlavorSpringBoard;
1100                         }
1101 #endif
1102                     }
1103 
1104                     ctx.SetLaunchFlavor(launch_flavor);
1105 
1106                     nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
1107                     g_pid = pid;
1108 
1109                     if (pid == INVALID_NUB_PROCESS)
1110                     {
1111                         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1112                         if (err_str[0])
1113                             ctx.LaunchStatus().SetErrorString(err_str);
1114                         RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
1115                         mode = eRNBRunLoopModeExit;
1116                     }
1117                     else
1118                     {
1119                         ctx.SetProcessID(pid);
1120                         mode = eRNBRunLoopModeInferiorExecuting;
1121                     }
1122                 }
1123                 else if (attach_pid != INVALID_NUB_PROCESS)
1124                 {
1125 
1126                     RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid);
1127                     nub_process_t attached_pid;
1128                     mode = RNBRunLoopLaunchAttaching (g_remoteSP, attach_pid, attached_pid);
1129                     if (mode != eRNBRunLoopModeInferiorExecuting)
1130                     {
1131                         const char *error_str = remote->Context().LaunchStatus().AsString();
1132                         RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
1133                         mode = eRNBRunLoopModeExit;
1134                     }
1135                 }
1136                 else if (!attach_pid_name.empty ())
1137                 {
1138                     struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1139                     if (waitfor_duration != 0)
1140                     {
1141                         DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1142                         timeout_ptr = &attach_timeout_abstime;
1143                     }
1144 
1145                     nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str));
1146                     g_pid = pid;
1147                     if (pid == INVALID_NUB_PROCESS)
1148                     {
1149                         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1150                         if (err_str[0])
1151                             ctx.LaunchStatus().SetErrorString(err_str);
1152                         RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
1153                         mode = eRNBRunLoopModeExit;
1154                     }
1155                     else
1156                     {
1157                         ctx.SetProcessID(pid);
1158                         mode = eRNBRunLoopModeInferiorExecuting;
1159                     }
1160 
1161                 }
1162                 else
1163                 {
1164                     RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.");
1165                     mode = eRNBRunLoopModeExit;
1166                 }
1167 
1168                 if (mode != eRNBRunLoopModeExit)
1169                 {
1170                     if (listen_port != INT32_MAX)
1171                     {
1172                         if (!StartListening (g_remoteSP, listen_port))
1173                             mode = eRNBRunLoopModeExit;
1174                     }
1175                     else if (str[0] == '/')
1176                     {
1177                         if (g_remoteSP->Comm().OpenFile (str))
1178                             mode = eRNBRunLoopModeExit;
1179                     }
1180                     if (mode != eRNBRunLoopModeExit)
1181                         RNBLogSTDOUT ("Got a connection, waiting for debugger instructions for process %d.\n", attach_pid);
1182                 }
1183                 break;
1184 
1185             case eRNBRunLoopModeInferiorLaunching:
1186                 mode = RNBRunLoopLaunchInferior (g_remoteSP, stdio_path.empty() ? NULL : stdio_path.c_str());
1187 
1188                 if (mode == eRNBRunLoopModeInferiorExecuting)
1189                 {
1190                     if (listen_port != INT32_MAX)
1191                     {
1192                         if (!StartListening (g_remoteSP, listen_port))
1193                             mode = eRNBRunLoopModeExit;
1194                     }
1195                     else if (str[0] == '/')
1196                     {
1197                         if (g_remoteSP->Comm().OpenFile (str))
1198                             mode = eRNBRunLoopModeExit;
1199                     }
1200 
1201                     if (mode != eRNBRunLoopModeExit)
1202                         RNBLogSTDOUT ("Got a connection, waiting for debugger instructions.\n");
1203                 }
1204                 else
1205                 {
1206                     const char *error_str = remote->Context().LaunchStatus().AsString();
1207                     RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv[0], error_str ? error_str : "unknown error.");
1208                 }
1209                 break;
1210 
1211             case eRNBRunLoopModeInferiorExecuting:
1212                 mode = RNBRunLoopInferiorExecuting(g_remoteSP);
1213                 break;
1214 
1215             default:
1216                 mode = eRNBRunLoopModeExit;
1217             case eRNBRunLoopModeExit:
1218                 break;
1219         }
1220     }
1221 
1222     g_remoteSP->StopReadRemoteDataThread ();
1223     g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS);
1224 
1225     return 0;
1226 }
1227