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