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, bool no_stdio)
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                                           no_stdio,
213                                           launch_flavor,
214                                           g_disable_aslr,
215                                           launch_err_str,
216                                           sizeof(launch_err_str));
217 
218     g_pid = pid;
219 
220     if (pid == INVALID_NUB_PROCESS && strlen(launch_err_str) > 0)
221     {
222         DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, launch_err_str);
223         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
224         ctx.LaunchStatus().SetErrorString(launch_err_str);
225     }
226     else
227         ctx.LaunchStatus().Clear();
228 
229     if (remote->Comm().IsConnected())
230     {
231         // It we are connected already, the next thing gdb will do is ask
232         // whether the launch succeeded, and if not, whether there is an
233         // error code.  So we need to fetch one packet from gdb before we wait
234         // on the stop from the target.
235 
236         uint32_t event_mask = RNBContext::event_read_packet_available;
237         nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
238 
239         if (set_events & RNBContext::event_read_packet_available)
240         {
241             rnb_err_t err = rnb_err;
242             RNBRemote::PacketEnum type;
243 
244             err = remote->HandleReceivedPacket (&type);
245 
246             if (err != rnb_success)
247             {
248                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__);
249                 return eRNBRunLoopModeExit;
250             }
251             if (type != RNBRemote::query_launch_success)
252             {
253                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__);
254             }
255         }
256     }
257 
258     while (pid != INVALID_NUB_PROCESS)
259     {
260         // Wait for process to start up and hit entry point
261         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid);
262         nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL);
263         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events);
264 
265         if (set_events == 0)
266         {
267             pid = INVALID_NUB_PROCESS;
268             g_pid = pid;
269         }
270         else
271         {
272             if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
273             {
274                 nub_state_t pid_state = DNBProcessGetState (pid);
275                 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
276 
277                 switch (pid_state)
278                 {
279                     default:
280                     case eStateInvalid:
281                     case eStateUnloaded:
282                     case eStateAttaching:
283                     case eStateLaunching:
284                     case eStateSuspended:
285                         break;  // Ignore
286 
287                     case eStateRunning:
288                     case eStateStepping:
289                         // Still waiting to stop at entry point...
290                         break;
291 
292                     case eStateStopped:
293                     case eStateCrashed:
294                         ctx.SetProcessID(pid);
295                         return eRNBRunLoopModeInferiorExecuting;
296 
297                     case eStateDetached:
298                     case eStateExited:
299                         pid = INVALID_NUB_PROCESS;
300                         g_pid = pid;
301                         return eRNBRunLoopModeExit;
302                 }
303             }
304 
305             DNBProcessResetEvents(pid, set_events);
306         }
307     }
308 
309     return eRNBRunLoopModeExit;
310 }
311 
312 
313 //----------------------------------------------------------------------
314 // This run loop mode will wait for the process to launch and hit its
315 // entry point. It will currently ignore all events except for the
316 // process state changed event, where it watches for the process stopped
317 // or crash process state.
318 //----------------------------------------------------------------------
319 RNBRunLoopMode
320 RNBRunLoopLaunchAttaching (RNBRemoteSP &remote, nub_process_t attach_pid, nub_process_t& pid)
321 {
322     RNBContext& ctx = remote->Context();
323 
324     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid);
325     char err_str[1024];
326     pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str));
327     g_pid = pid;
328 
329     if (pid == INVALID_NUB_PROCESS)
330     {
331         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
332         if (err_str[0])
333             ctx.LaunchStatus().SetErrorString(err_str);
334         return eRNBRunLoopModeExit;
335     }
336     else
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     { "arch",               required_argument,  NULL,               'A' },
648     { "debug",              no_argument,        NULL,               'g' },
649     { "verbose",            no_argument,        NULL,               'v' },
650     { "lockdown",           no_argument,        &g_lockdown_opt,    1   },  // short option "-k"
651     { "applist",            no_argument,        &g_applist_opt,     1   },  // short option "-t"
652     { "log-file",           required_argument,  NULL,               'l' },
653     { "log-flags",          required_argument,  NULL,               'f' },
654     { "launch",             required_argument,  NULL,               'x' },  // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
655     { "waitfor",            required_argument,  NULL,               'w' },  // Wait for a process whose name starts with ARG
656     { "waitfor-interval",   required_argument,  NULL,               'i' },  // Time in usecs to wait between sampling the pid list when waiting for a process by name
657     { "waitfor-duration",   required_argument,  NULL,               'd' },  // The time in seconds to wait for a process to show up by name
658     { "native-regs",        no_argument,        NULL,               'r' },  // Specify to use the native registers instead of the gdb defaults for the architecture.
659     { "stdio-path",         required_argument,  NULL,               's' },  // Set the STDIO path to be used when launching applications
660     { "no-stdio",           no_argument,        NULL,               'n' },  // Do not set up any stdio (perhaps the program is a GUI program)
661     { "setsid",             no_argument,        NULL,               'S' },  // call setsid() to make debugserver run in its own sessions
662     { "disable-aslr",       no_argument,        NULL,               'D' },  // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
663     { NULL,                 0,                  NULL,               0   }
664 };
665 
666 
667 //----------------------------------------------------------------------
668 // main
669 //----------------------------------------------------------------------
670 int
671 main (int argc, char *argv[])
672 {
673     g_isatty = ::isatty (STDIN_FILENO);
674 
675     //  ::printf ("uid=%u euid=%u gid=%u egid=%u\n",
676     //            getuid(),
677     //            geteuid(),
678     //            getgid(),
679     //            getegid());
680 
681 
682     //    signal (SIGINT, signal_handler);
683     signal (SIGPIPE, signal_handler);
684     signal (SIGHUP, signal_handler);
685 
686     int i;
687     int attach_pid = INVALID_NUB_PROCESS;
688 
689     FILE* log_file = NULL;
690     uint32_t log_flags = 0;
691     // Parse our options
692     int ch;
693     int long_option_index = 0;
694     int use_native_registers = 0;
695     int debug = 0;
696     std::string compile_options;
697     std::string waitfor_pid_name;           // Wait for a process that starts with this name
698     std::string attach_pid_name;
699     std::string stdio_path;
700     std::string arch_name;
701     useconds_t waitfor_interval = 1000;     // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
702     useconds_t waitfor_duration = 0;        // Time in seconds to wait for a process by name, 0 means wait forever.
703     bool no_stdio = false;
704 
705 #if !defined (DNBLOG_ENABLED)
706     compile_options += "(no-logging) ";
707 #endif
708 
709     RNBRunLoopMode start_mode = eRNBRunLoopModeExit;
710 
711     while ((ch = getopt_long(argc, argv, "a:A:d:gi:vktl:f:w:x:rs:n", g_long_options, &long_option_index)) != -1)
712     {
713         DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
714                     ch, (uint8_t)ch,
715                     g_long_options[long_option_index].name,
716                     g_long_options[long_option_index].has_arg ? '=' : ' ',
717                     optarg ? optarg : "");
718         switch (ch)
719         {
720             case 0:   // Any optional that auto set themselves will return 0
721                 break;
722 
723             case 'A':
724                 if (optarg && optarg[0])
725                     arch_name.assign(optarg);
726                 break;
727 
728             case 'a':
729                 if (optarg && optarg[0])
730                 {
731                     if (isdigit(optarg[0]))
732                     {
733                         char *end = NULL;
734                         attach_pid = strtoul(optarg, &end, 0);
735                         if (end == NULL || *end != '\0')
736                         {
737                             RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg);
738                             exit (4);
739                         }
740                     }
741                     else
742                     {
743                         attach_pid_name = optarg;
744                     }
745                     start_mode = eRNBRunLoopModeInferiorAttaching;
746                 }
747                 break;
748 
749                 // --waitfor=NAME
750             case 'w':
751                 if (optarg && optarg[0])
752                 {
753                     waitfor_pid_name = optarg;
754                     start_mode = eRNBRunLoopModeInferiorAttaching;
755                 }
756                 break;
757 
758                 // --waitfor-interval=USEC
759             case 'i':
760                 if (optarg && optarg[0])
761                 {
762                     char *end = NULL;
763                     waitfor_interval = strtoul(optarg, &end, 0);
764                     if (end == NULL || *end != '\0')
765                     {
766                         RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
767                         exit (6);
768                     }
769                 }
770                 break;
771 
772                 // --waitfor-duration=SEC
773             case 'd':
774                 if (optarg && optarg[0])
775                 {
776                     char *end = NULL;
777                     waitfor_duration = strtoul(optarg, &end, 0);
778                     if (end == NULL || *end != '\0')
779                     {
780                         RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
781                         exit (7);
782                     }
783                 }
784                 break;
785 
786             case 'x':
787                 if (optarg && optarg[0])
788                 {
789                     if (strcasecmp(optarg, "auto") == 0)
790                         g_launch_flavor = eLaunchFlavorDefault;
791                     else if (strcasestr(optarg, "posix") == optarg)
792                         g_launch_flavor = eLaunchFlavorPosixSpawn;
793                     else if (strcasestr(optarg, "fork") == optarg)
794                         g_launch_flavor = eLaunchFlavorForkExec;
795 #if defined (__arm__)
796                     else if (strcasestr(optarg, "spring") == optarg)
797                         g_launch_flavor = eLaunchFlavorSpringBoard;
798 #endif
799                     else
800                     {
801                         RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
802                         RNBLogSTDERR ("Valid values TYPE are:\n");
803                         RNBLogSTDERR ("  auto    Auto-detect the best launch method to use.\n");
804                         RNBLogSTDERR ("  posix   Launch the executable using posix_spawn.\n");
805                         RNBLogSTDERR ("  fork    Launch the executable using fork and exec.\n");
806 #if defined (__arm__)
807                         RNBLogSTDERR ("  spring  Launch the executable through Springboard.\n");
808 #endif
809                         exit (5);
810                     }
811                 }
812                 break;
813 
814             case 'l': // Set Log File
815                 if (optarg && optarg[0])
816                 {
817                     if (strcasecmp(optarg, "stdout") == 0)
818                         log_file = stdout;
819                     else if (strcasecmp(optarg, "stderr") == 0)
820                         log_file = stderr;
821                     else
822                         log_file = fopen(optarg, "w+");
823 
824                     if (log_file == NULL)
825                     {
826                         const char *errno_str = strerror(errno);
827                         RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
828                     }
829                 }
830                 break;
831 
832             case 'f': // Log Flags
833                 if (optarg && optarg[0])
834                     log_flags = strtoul(optarg, NULL, 0);
835                 break;
836 
837             case 'g':
838                 debug = 1;
839                 DNBLogSetDebug(1);
840                 break;
841 
842             case 't':
843                 g_applist_opt = 1;
844                 break;
845 
846             case 'k':
847                 g_lockdown_opt = 1;
848                 break;
849 
850             case 'r':
851                 use_native_registers = 1;
852                 break;
853 
854             case 'v':
855                 DNBLogSetVerbose(1);
856                 break;
857 
858             case 's':
859                 stdio_path = optarg;
860                 break;
861 
862             case 'n':
863                 no_stdio = true;
864                 break;
865 
866             case 'S':
867                 // Put debugserver into a new session. Terminals group processes
868                 // into sessions and when a special terminal key sequences
869                 // (like control+c) are typed they can cause signals to go out to
870                 // all processes in a session. Using this --setsid (-S) option
871                 // will cause debugserver to run in its own sessions and be free
872                 // from such issues.
873                 //
874                 // This is useful when debugserver is spawned from a command
875                 // line application that uses debugserver to do the debugging,
876                 // yet that application doesn't want debugserver receiving the
877                 // signals sent to the session (i.e. dying when anyone hits ^C).
878                 setsid();
879                 break;
880             case 'D':
881                 g_disable_aslr = 1;
882                 break;
883         }
884     }
885 
886     if (arch_name.empty())
887     {
888 #if defined (__i386__)
889         arch_name.assign ("i386");
890 #elif defined (__x86_64__)
891         arch_name.assign ("x86_64");
892 #elif defined (__arm__)
893         arch_name.assign ("arm");
894 #endif
895     }
896     else
897     {
898         DNBSetArchitecture (arch_name.c_str());
899     }
900 
901     if (arch_name.empty())
902     {
903         fprintf(stderr, "error: no architecture was specified\n");
904         exit (8);
905     }
906     // Skip any options we consumed with getopt_long
907     argc -= optind;
908     argv += optind;
909 
910     g_remoteSP.reset (new RNBRemote (use_native_registers, arch_name.c_str()));
911 
912 
913 
914     RNBRemote *remote = g_remoteSP.get();
915     if (remote == NULL)
916     {
917         RNBLogSTDERR ("error: failed to create a remote connection class\n");
918         return -1;
919     }
920 
921     g_remoteSP->Initialize();
922 
923     RNBContext& ctx = remote->Context();
924 
925 
926     // It is ok for us to set NULL as the logfile (this will disable any logging)
927 
928     if (log_file != NULL)
929     {
930         DNBLogSetLogCallback(FileLogCallback, log_file);
931         // If our log file was set, yet we have no log flags, log everything!
932         if (log_flags == 0)
933             log_flags = LOG_ALL | LOG_RNB_ALL;
934 
935         DNBLogSetLogMask (log_flags);
936     }
937     else
938     {
939         // Enable DNB logging
940         DNBLogSetLogCallback(ASLLogCallback, NULL);
941         DNBLogSetLogMask (log_flags);
942 
943     }
944 
945     if (DNBLogEnabled())
946     {
947         for (i=0; i<argc; i++)
948             DNBLogDebug("argv[%i] = %s", i, argv[i]);
949     }
950 
951     // as long as we're dropping remotenub in as a replacement for gdbserver,
952     // explicitly note that this is not gdbserver.
953 
954     RNBLogSTDOUT ("%s-%g %sfor %s.\n",
955                   DEBUGSERVER_PROGRAM_NAME,
956                   DEBUGSERVER_VERSION_NUM,
957                   compile_options.c_str(),
958                   RNB_ARCH);
959 
960     int listen_port = INT32_MAX;
961     char str[PATH_MAX];
962 
963     if (g_lockdown_opt == 0 && g_applist_opt == 0)
964     {
965         // Make sure we at least have port
966         if (argc < 1)
967         {
968             show_usage_and_exit (1);
969         }
970         // accept 'localhost:' prefix on port number
971 
972         int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &listen_port);
973         if (items_scanned == 2)
974         {
975             DNBLogDebug("host = '%s'  port = %i", str, listen_port);
976         }
977         else if (argv[0][0] == '/')
978         {
979             listen_port = INT32_MAX;
980             strncpy(str, argv[0], sizeof(str));
981         }
982         else
983         {
984             show_usage_and_exit (2);
985         }
986 
987         // We just used the 'host:port' or the '/path/file' arg...
988         argc--;
989         argv++;
990 
991     }
992 
993     //  If we know we're waiting to attach, we don't need any of this other info.
994     if (start_mode != eRNBRunLoopModeInferiorAttaching)
995     {
996         if (argc == 0 || g_lockdown_opt)
997         {
998             if (g_lockdown_opt != 0)
999             {
1000                 // Work around for SIGPIPE crashes due to posix_spawn issue.
1001                 // We have to close STDOUT and STDERR, else the first time we
1002                 // try and do any, we get SIGPIPE and die as posix_spawn is
1003                 // doing bad things with our file descriptors at the moment.
1004                 int null = open("/dev/null", O_RDWR);
1005                 dup2(null, STDOUT_FILENO);
1006                 dup2(null, STDERR_FILENO);
1007             }
1008             else if (g_applist_opt != 0)
1009             {
1010                 // List all applications we are able to see
1011                 std::string applist_plist;
1012                 int err = ListApplications(applist_plist, false, false);
1013                 if (err == 0)
1014                 {
1015                     fputs (applist_plist.c_str(), stdout);
1016                 }
1017                 else
1018                 {
1019                     RNBLogSTDERR ("error: ListApplications returned error %i\n", err);
1020                 }
1021                 // Exit with appropriate error if we were asked to list the applications
1022                 // with no other args were given (and we weren't trying to do this over
1023                 // lockdown)
1024                 return err;
1025             }
1026 
1027             DNBLogDebug("Get args from remote protocol...");
1028             start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
1029         }
1030         else
1031         {
1032             start_mode = eRNBRunLoopModeInferiorLaunching;
1033             // Fill in the argv array in the context from the rest of our args.
1034             // Skip the name of this executable and the port number
1035             for (int i = 0; i < argc; i++)
1036             {
1037                 DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]);
1038                 ctx.PushArgument (argv[i]);
1039             }
1040         }
1041     }
1042 
1043     if (start_mode == eRNBRunLoopModeExit)
1044         return -1;
1045 
1046     RNBRunLoopMode mode = start_mode;
1047     char err_str[1024] = {'\0'};
1048 
1049     while (mode != eRNBRunLoopModeExit)
1050     {
1051         switch (mode)
1052         {
1053             case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
1054 #if defined (__arm__)
1055                 if (g_lockdown_opt)
1056                 {
1057                     if (!g_remoteSP->Comm().IsConnected())
1058                     {
1059                         if (g_remoteSP->Comm().ConnectToService () != rnb_success)
1060                         {
1061                             RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
1062                             mode = eRNBRunLoopModeExit;
1063                         }
1064                         else if (g_applist_opt != 0)
1065                         {
1066                             // List all applications we are able to see
1067                             std::string applist_plist;
1068                             if (ListApplications(applist_plist, false, false) == 0)
1069                             {
1070                                 DNBLogDebug("Task list: %s", applist_plist.c_str());
1071 
1072                                 g_remoteSP->Comm().Write(applist_plist.c_str(), applist_plist.size());
1073                                 // Issue a read that will never yield any data until the other side
1074                                 // closes the socket so this process doesn't just exit and cause the
1075                                 // socket to close prematurely on the other end and cause data loss.
1076                                 std::string buf;
1077                                 g_remoteSP->Comm().Read(buf);
1078                             }
1079                             g_remoteSP->Comm().Disconnect(false);
1080                             mode = eRNBRunLoopModeExit;
1081                             break;
1082                         }
1083                         else
1084                         {
1085                             // Start watching for remote packets
1086                             g_remoteSP->StartReadRemoteDataThread();
1087                         }
1088                     }
1089                 }
1090                 else
1091 #endif
1092                     if (listen_port != INT32_MAX)
1093                     {
1094                         if (!StartListening (g_remoteSP, listen_port))
1095                             mode = eRNBRunLoopModeExit;
1096                     }
1097                     else if (str[0] == '/')
1098                     {
1099                         if (g_remoteSP->Comm().OpenFile (str))
1100                             mode = eRNBRunLoopModeExit;
1101                     }
1102                 if (mode != eRNBRunLoopModeExit)
1103                 {
1104                     RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
1105 
1106                     mode = RNBRunLoopGetStartModeFromRemote (g_remoteSP);
1107                 }
1108                 break;
1109 
1110             case eRNBRunLoopModeInferiorAttaching:
1111                 if (!waitfor_pid_name.empty())
1112                 {
1113                     // Set our end wait time if we are using a waitfor-duration
1114                     // option that may have been specified
1115                     struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1116                     if (waitfor_duration != 0)
1117                     {
1118                         DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1119                         timeout_ptr = &attach_timeout_abstime;
1120                     }
1121                     nub_launch_flavor_t launch_flavor = g_launch_flavor;
1122                     if (launch_flavor == eLaunchFlavorDefault)
1123                     {
1124                         // Our default launch method is posix spawn
1125                         launch_flavor = eLaunchFlavorPosixSpawn;
1126 
1127 #if defined (__arm__)
1128                         // Check if we have an app bundle, if so launch using SpringBoard.
1129                         if (waitfor_pid_name.find (".app") != std::string::npos)
1130                         {
1131                             launch_flavor = eLaunchFlavorSpringBoard;
1132                         }
1133 #endif
1134                     }
1135 
1136                     ctx.SetLaunchFlavor(launch_flavor);
1137 
1138                     nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
1139                     g_pid = pid;
1140 
1141                     if (pid == INVALID_NUB_PROCESS)
1142                     {
1143                         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1144                         if (err_str[0])
1145                             ctx.LaunchStatus().SetErrorString(err_str);
1146                         RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
1147                         mode = eRNBRunLoopModeExit;
1148                     }
1149                     else
1150                     {
1151                         ctx.SetProcessID(pid);
1152                         mode = eRNBRunLoopModeInferiorExecuting;
1153                     }
1154                 }
1155                 else if (attach_pid != INVALID_NUB_PROCESS)
1156                 {
1157 
1158                     RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid);
1159                     nub_process_t attached_pid;
1160                     mode = RNBRunLoopLaunchAttaching (g_remoteSP, attach_pid, attached_pid);
1161                     if (mode != eRNBRunLoopModeInferiorExecuting)
1162                     {
1163                         const char *error_str = remote->Context().LaunchStatus().AsString();
1164                         RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
1165                         mode = eRNBRunLoopModeExit;
1166                     }
1167                 }
1168                 else if (!attach_pid_name.empty ())
1169                 {
1170                     struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1171                     if (waitfor_duration != 0)
1172                     {
1173                         DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1174                         timeout_ptr = &attach_timeout_abstime;
1175                     }
1176 
1177                     nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str));
1178                     g_pid = pid;
1179                     if (pid == INVALID_NUB_PROCESS)
1180                     {
1181                         ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1182                         if (err_str[0])
1183                             ctx.LaunchStatus().SetErrorString(err_str);
1184                         RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
1185                         mode = eRNBRunLoopModeExit;
1186                     }
1187                     else
1188                     {
1189                         ctx.SetProcessID(pid);
1190                         mode = eRNBRunLoopModeInferiorExecuting;
1191                     }
1192 
1193                 }
1194                 else
1195                 {
1196                     RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.");
1197                     mode = eRNBRunLoopModeExit;
1198                 }
1199 
1200                 if (mode != eRNBRunLoopModeExit)
1201                 {
1202                     if (listen_port != INT32_MAX)
1203                     {
1204                         if (!StartListening (g_remoteSP, listen_port))
1205                             mode = eRNBRunLoopModeExit;
1206                     }
1207                     else if (str[0] == '/')
1208                     {
1209                         if (g_remoteSP->Comm().OpenFile (str))
1210                             mode = eRNBRunLoopModeExit;
1211                     }
1212                     if (mode != eRNBRunLoopModeExit)
1213                         RNBLogSTDOUT ("Got a connection, waiting for debugger instructions for process %d.\n", attach_pid);
1214                 }
1215                 break;
1216 
1217             case eRNBRunLoopModeInferiorLaunching:
1218                 mode = RNBRunLoopLaunchInferior (g_remoteSP, stdio_path.empty() ? NULL : stdio_path.c_str(), no_stdio);
1219 
1220                 if (mode == eRNBRunLoopModeInferiorExecuting)
1221                 {
1222                     if (listen_port != INT32_MAX)
1223                     {
1224                         if (!StartListening (g_remoteSP, listen_port))
1225                             mode = eRNBRunLoopModeExit;
1226                     }
1227                     else if (str[0] == '/')
1228                     {
1229                         if (g_remoteSP->Comm().OpenFile (str))
1230                             mode = eRNBRunLoopModeExit;
1231                     }
1232 
1233                     if (mode != eRNBRunLoopModeExit)
1234                         RNBLogSTDOUT ("Got a connection, waiting for debugger instructions.\n");
1235                 }
1236                 else
1237                 {
1238                     const char *error_str = remote->Context().LaunchStatus().AsString();
1239                     RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv[0], error_str ? error_str : "unknown error.");
1240                 }
1241                 break;
1242 
1243             case eRNBRunLoopModeInferiorExecuting:
1244                 mode = RNBRunLoopInferiorExecuting(g_remoteSP);
1245                 break;
1246 
1247             default:
1248                 mode = eRNBRunLoopModeExit;
1249             case eRNBRunLoopModeExit:
1250                 break;
1251         }
1252     }
1253 
1254     g_remoteSP->StopReadRemoteDataThread ();
1255     g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS);
1256 
1257     return 0;
1258 }
1259