debugserver.cpp revision 91a1dabac7ef4a1c8a60dbbb8340d33b7d25f863
1de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//===-- debugserver.cpp -----------------------------------------*- C++ -*-===//
2de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//
336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines//                     The LLVM Compiler Infrastructure
4de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//
5de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak// This file is distributed under the University of Illinois Open Source
6de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak// License. See LICENSE.TXT for details.
7de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//
8de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//===----------------------------------------------------------------------===//
9de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak
10de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include <sys/socket.h>
11de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include <sys/types.h>
12de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include <errno.h>
13de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include <getopt.h>
14de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include <netinet/in.h>
15de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include <sys/select.h>
16de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include <sys/sysctl.h>
17de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include <string>
18255f89faee13dc491cb64fbeae3c763e7e2ea4e6Chandler Carruth#include <vector>
19de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include <asl.h>
20255f89faee13dc491cb64fbeae3c763e7e2ea4e6Chandler Carruth
21de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include "CFString.h"
22de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include "DNB.h"
23de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include "DNBLog.h"
24de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include "DNBTimer.h"
25de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include "PseudoTerminal.h"
26de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include "RNBContext.h"
27de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include "RNBServices.h"
28de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include "RNBSocket.h"
29de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include "RNBRemote.h"
30de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#include "SysSignal.h"
31de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak
32354362524a72b3fa43a6c09380b7ae3b2380cbbaJuergen Ributzka// Global PID in case we get a signal and need to stop the process...
33de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszaknub_process_t g_pid = INVALID_NUB_PROCESS;
34de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak
35de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//----------------------------------------------------------------------
36b21ab43cfc3fa0dacf5c95f04e58b6d804b59a16Alexey Samsonov// Run loop modes which determine which run loop function will be called
37de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//----------------------------------------------------------------------
38de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszaktypedef enum
39de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak{
40de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak    eRNBRunLoopModeInvalid = 0,
41de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak    eRNBRunLoopModeGetStartModeFromRemoteProtocol,
42cd81d94322a39503e4a3e87b6ee03d4fcb3465fbStephen Hines    eRNBRunLoopModeInferiorAttaching,
43cd81d94322a39503e4a3e87b6ee03d4fcb3465fbStephen Hines    eRNBRunLoopModeInferiorLaunching,
44de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak    eRNBRunLoopModeInferiorExecuting,
45de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak    eRNBRunLoopModeExit
46de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak} RNBRunLoopMode;
47de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak
48f12745f7a7e68c05c89ebd515b9b4faedce37dd0Rafael Espindola
49de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//----------------------------------------------------------------------
50de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak// Global Variables
51de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//----------------------------------------------------------------------
5236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen HinesRNBRemoteSP g_remoteSP;
53de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszakstatic int g_lockdown_opt  = 0;
54de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszakstatic int g_applist_opt = 0;
55de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszakstatic nub_launch_flavor_t g_launch_flavor = eLaunchFlavorDefault;
56de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszakint g_disable_aslr = 0;
57de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak
58de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszakint g_isatty = 0;
59de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak
6036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
61de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak#define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
62de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak
63b21ab43cfc3fa0dacf5c95f04e58b6d804b59a16Alexey Samsonov//----------------------------------------------------------------------
64de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak// Run Loop function prototypes
65de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//----------------------------------------------------------------------
66de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub StaszakRNBRunLoopMode RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remote);
67de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub StaszakRNBRunLoopMode RNBRunLoopInferiorExecuting (RNBRemoteSP &remote);
68de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak
69de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak
70de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//----------------------------------------------------------------------
71de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak// Get our program path and arguments from the remote connection.
7236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines// We will need to start up the remote connection without a PID, get the
7336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines// arguments, wait for the new process to finish launching and hit its
74de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak// entry point,  and then return the run loop mode that should come next.
75de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak//----------------------------------------------------------------------
76de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub StaszakRNBRunLoopMode
77de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub StaszakRNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP)
7836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines{
79de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak    std::string packet;
80de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak
81de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak    if (remoteSP.get() != NULL)
82de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak    {
83de7c8530c85181c78fbb30a305749ee3a71cfc51Jakub Staszak        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//----------------------------------------------------------------------
153RNBRunLoopMode
154RNBRunLoopLaunchInferior (RNBRemoteSP &remote, const char *stdio_path)
155{
156    RNBContext& ctx = remote->Context();
157
158    // The Process stuff takes a c array, the RNBContext has a vector...
159    // So make up a c array.
160
161    DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, ctx.ArgumentAtIndex(0));
162
163    size_t inferior_argc = ctx.ArgumentCount();
164    // Initialize inferior_argv with inferior_argc + 1 NULLs
165    std::vector<const char *> inferior_argv(inferior_argc + 1, NULL);
166
167    size_t i;
168    for (i = 0; i < inferior_argc; i++)
169        inferior_argv[i] = ctx.ArgumentAtIndex(i);
170
171    // Pass the environment array the same way:
172
173    size_t inferior_envc = ctx.EnvironmentCount();
174    // Initialize inferior_argv with inferior_argc + 1 NULLs
175    std::vector<const char *> inferior_envp(inferior_envc + 1, NULL);
176
177    for (i = 0; i < inferior_envc; i++)
178        inferior_envp[i] = ctx.EnvironmentAtIndex(i);
179
180    // Our launch type hasn't been set to anything concrete, so we need to
181    // figure our how we are going to launch automatically.
182
183    nub_launch_flavor_t launch_flavor = g_launch_flavor;
184    if (launch_flavor == eLaunchFlavorDefault)
185    {
186        // Our default launch method is posix spawn
187        launch_flavor = eLaunchFlavorPosixSpawn;
188
189#if defined (__arm__)
190        // Check if we have an app bundle, if so launch using SpringBoard.
191        if (strstr(inferior_argv[0], ".app"))
192        {
193            launch_flavor = eLaunchFlavorSpringBoard;
194        }
195#endif
196    }
197
198    ctx.SetLaunchFlavor(launch_flavor);
199    char resolved_path[PATH_MAX];
200
201    // If we fail to resolve the path to our executable, then just use what we
202    // were given and hope for the best
203    if ( !DNBResolveExecutablePath (inferior_argv[0], resolved_path, sizeof(resolved_path)) )
204        ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path));
205
206    char launch_err_str[PATH_MAX];
207    launch_err_str[0] = '\0';
208    nub_process_t pid = DNBProcessLaunch (resolved_path,
209                                          &inferior_argv[0],
210                                          &inferior_envp[0],
211                                          stdio_path,
212                                          launch_flavor,
213                                          g_disable_aslr,
214                                          launch_err_str,
215                                          sizeof(launch_err_str));
216
217    g_pid = pid;
218
219    if (pid == INVALID_NUB_PROCESS && strlen(launch_err_str) > 0)
220    {
221        DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, launch_err_str);
222        ctx.LaunchStatus().SetError(-1, DNBError::Generic);
223        ctx.LaunchStatus().SetErrorString(launch_err_str);
224    }
225    else
226        ctx.LaunchStatus().Clear();
227
228    if (remote->Comm().IsConnected())
229    {
230        // It we are connected already, the next thing gdb will do is ask
231        // whether the launch succeeded, and if not, whether there is an
232        // error code.  So we need to fetch one packet from gdb before we wait
233        // on the stop from the target.
234
235        uint32_t event_mask = RNBContext::event_read_packet_available;
236        nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
237
238        if (set_events & RNBContext::event_read_packet_available)
239        {
240            rnb_err_t err = rnb_err;
241            RNBRemote::PacketEnum type;
242
243            err = remote->HandleReceivedPacket (&type);
244
245            if (err != rnb_success)
246            {
247                DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__);
248                return eRNBRunLoopModeExit;
249            }
250            if (type != RNBRemote::query_launch_success)
251            {
252                DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__);
253            }
254        }
255    }
256
257    while (pid != INVALID_NUB_PROCESS)
258    {
259        // Wait for process to start up and hit entry point
260        DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid);
261        nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL);
262        DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events);
263
264        if (set_events == 0)
265        {
266            pid = INVALID_NUB_PROCESS;
267            g_pid = pid;
268        }
269        else
270        {
271            if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
272            {
273                nub_state_t pid_state = DNBProcessGetState (pid);
274                DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
275
276                switch (pid_state)
277                {
278                    default:
279                    case eStateInvalid:
280                    case eStateUnloaded:
281                    case eStateAttaching:
282                    case eStateLaunching:
283                    case eStateSuspended:
284                        break;  // Ignore
285
286                    case eStateRunning:
287                    case eStateStepping:
288                        // Still waiting to stop at entry point...
289                        break;
290
291                    case eStateStopped:
292                    case eStateCrashed:
293                        ctx.SetProcessID(pid);
294                        return eRNBRunLoopModeInferiorExecuting;
295
296                    case eStateDetached:
297                    case eStateExited:
298                        pid = INVALID_NUB_PROCESS;
299                        g_pid = pid;
300                        return eRNBRunLoopModeExit;
301                }
302            }
303
304            DNBProcessResetEvents(pid, set_events);
305        }
306    }
307
308    return eRNBRunLoopModeExit;
309}
310
311
312//----------------------------------------------------------------------
313// This run loop mode will wait for the process to launch and hit its
314// entry point. It will currently ignore all events except for the
315// process state changed event, where it watches for the process stopped
316// or crash process state.
317//----------------------------------------------------------------------
318RNBRunLoopMode
319RNBRunLoopLaunchAttaching (RNBRemoteSP &remote, nub_process_t attach_pid, nub_process_t& pid)
320{
321    RNBContext& ctx = remote->Context();
322
323    DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid);
324    char err_str[1024];
325    pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str));
326    g_pid = pid;
327
328    if (pid == INVALID_NUB_PROCESS)
329    {
330        ctx.LaunchStatus().SetError(-1, DNBError::Generic);
331        if (err_str[0])
332            ctx.LaunchStatus().SetErrorString(err_str);
333        return eRNBRunLoopModeExit;
334    }
335    else
336    {
337
338        ctx.SetProcessID(pid);
339        return eRNBRunLoopModeInferiorExecuting;
340    }
341}
342
343//----------------------------------------------------------------------
344// Watch for signals:
345// SIGINT: so we can halt our inferior. (disabled for now)
346// SIGPIPE: in case our child process dies
347//----------------------------------------------------------------------
348int g_sigint_received = 0;
349int g_sigpipe_received = 0;
350void
351signal_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
383RNBRunLoopMode
384HandleProcessStateChange (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.
462RNBRunLoopMode
463RNBRunLoopInferiorExecuting (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
567static int
568StartListening (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//----------------------------------------------------------------------
589void
590ASLLogCallback(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//----------------------------------------------------------------------
617void
618FileLogCallback(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
628void
629show_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//----------------------------------------------------------------------
644static struct option g_long_options[] =
645{
646    { "attach",             required_argument,  NULL,               'a' },
647    { "debug",              no_argument,        NULL,               'g' },
648    { "verbose",            no_argument,        NULL,               'v' },
649    { "lockdown",           no_argument,        &g_lockdown_opt,    1   },  // short option "-k"
650    { "applist",            no_argument,        &g_applist_opt,     1   },  // short option "-t"
651    { "log-file",           required_argument,  NULL,               'l' },
652    { "log-flags",          required_argument,  NULL,               'f' },
653    { "launch",             required_argument,  NULL,               'x' },  // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
654    { "waitfor",            required_argument,  NULL,               'w' },  // Wait for a process whose name starts with ARG
655    { "waitfor-interval",   required_argument,  NULL,               'i' },  // Time in usecs to wait between sampling the pid list when waiting for a process by name
656    { "waitfor-duration",   required_argument,  NULL,               'd' },  // The time in seconds to wait for a process to show up by name
657    { "native-regs",        no_argument,        NULL,               'r' },  // Specify to use the native registers instead of the gdb defaults for the architecture.
658    { "stdio-path",         required_argument,  NULL,               's' },  // Set the STDIO path to be used when launching applications
659    { "setsid",             no_argument,        NULL,               'S' },  // call setsid() to make debugserver run in its own sessions
660    { "disable-aslr",       no_argument,        NULL,               'D' },  // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
661    { NULL,                 0,                  NULL,               0   }
662};
663
664
665//----------------------------------------------------------------------
666// main
667//----------------------------------------------------------------------
668int
669main (int argc, char *argv[])
670{
671    g_isatty = ::isatty (STDIN_FILENO);
672
673    //  ::printf ("uid=%u euid=%u gid=%u egid=%u\n",
674    //            getuid(),
675    //            geteuid(),
676    //            getgid(),
677    //            getegid());
678
679
680    //    signal (SIGINT, signal_handler);
681    signal (SIGPIPE, signal_handler);
682    signal (SIGHUP, signal_handler);
683
684    int i;
685    int attach_pid = INVALID_NUB_PROCESS;
686
687    FILE* log_file = NULL;
688    uint32_t log_flags = 0;
689    // Parse our options
690    int ch;
691    int long_option_index = 0;
692    int use_native_registers = 0;
693    int debug = 0;
694    std::string compile_options;
695    std::string waitfor_pid_name;           // Wait for a process that starts with this name
696    std::string attach_pid_name;
697    std::string stdio_path;
698    useconds_t waitfor_interval = 1000;     // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
699    useconds_t waitfor_duration = 0;        // Time in seconds to wait for a process by name, 0 means wait forever.
700
701#if !defined (DNBLOG_ENABLED)
702    compile_options += "(no-logging) ";
703#endif
704
705    RNBRunLoopMode start_mode = eRNBRunLoopModeExit;
706
707    while ((ch = getopt_long(argc, argv, "a:d:gi:vktl:f:w:x:rs:", g_long_options, &long_option_index)) != -1)
708    {
709        DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
710                    ch, (uint8_t)ch,
711                    g_long_options[long_option_index].name,
712                    g_long_options[long_option_index].has_arg ? '=' : ' ',
713                    optarg ? optarg : "");
714        switch (ch)
715        {
716            case 0:   // Any optional that auto set themselves will return 0
717                break;
718
719            case 'a':
720                if (optarg && optarg[0])
721                {
722                    if (isdigit(optarg[0]))
723                    {
724                        char *end = NULL;
725                        attach_pid = strtoul(optarg, &end, 0);
726                        if (end == NULL || *end != '\0')
727                        {
728                            RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg);
729                            exit (4);
730                        }
731                    }
732                    else
733                    {
734                        attach_pid_name = optarg;
735                    }
736                    start_mode = eRNBRunLoopModeInferiorAttaching;
737                }
738                break;
739
740                // --waitfor=NAME
741            case 'w':
742                if (optarg && optarg[0])
743                {
744                    waitfor_pid_name = optarg;
745                    start_mode = eRNBRunLoopModeInferiorAttaching;
746                }
747                break;
748
749                // --waitfor-interval=USEC
750            case 'i':
751                if (optarg && optarg[0])
752                {
753                    char *end = NULL;
754                    waitfor_interval = strtoul(optarg, &end, 0);
755                    if (end == NULL || *end != '\0')
756                    {
757                        RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
758                        exit (6);
759                    }
760                }
761                break;
762
763                // --waitfor-duration=SEC
764            case 'd':
765                if (optarg && optarg[0])
766                {
767                    char *end = NULL;
768                    waitfor_duration = strtoul(optarg, &end, 0);
769                    if (end == NULL || *end != '\0')
770                    {
771                        RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
772                        exit (7);
773                    }
774                }
775                break;
776
777            case 'x':
778                if (optarg && optarg[0])
779                {
780                    if (strcasecmp(optarg, "auto") == 0)
781                        g_launch_flavor = eLaunchFlavorDefault;
782                    else if (strcasestr(optarg, "posix") == optarg)
783                        g_launch_flavor = eLaunchFlavorPosixSpawn;
784                    else if (strcasestr(optarg, "fork") == optarg)
785                        g_launch_flavor = eLaunchFlavorForkExec;
786#if defined (__arm__)
787                    else if (strcasestr(optarg, "spring") == optarg)
788                        g_launch_flavor = eLaunchFlavorSpringBoard;
789#endif
790                    else
791                    {
792                        RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
793                        RNBLogSTDERR ("Valid values TYPE are:\n");
794                        RNBLogSTDERR ("  auto    Auto-detect the best launch method to use.\n");
795                        RNBLogSTDERR ("  posix   Launch the executable using posix_spawn.\n");
796                        RNBLogSTDERR ("  fork    Launch the executable using fork and exec.\n");
797#if defined (__arm__)
798                        RNBLogSTDERR ("  spring  Launch the executable through Springboard.\n");
799#endif
800                        exit (5);
801                    }
802                }
803                break;
804
805            case 'l': // Set Log File
806                if (optarg && optarg[0])
807                {
808                    if (strcasecmp(optarg, "stdout") == 0)
809                        log_file = stdout;
810                    else if (strcasecmp(optarg, "stderr") == 0)
811                        log_file = stderr;
812                    else
813                        log_file = fopen(optarg, "w+");
814
815                    if (log_file == NULL)
816                    {
817                        const char *errno_str = strerror(errno);
818                        RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
819                    }
820                }
821                break;
822
823            case 'f': // Log Flags
824                if (optarg && optarg[0])
825                    log_flags = strtoul(optarg, NULL, 0);
826                break;
827
828            case 'g':
829                debug = 1;
830                DNBLogSetDebug(1);
831                break;
832
833            case 't':
834                g_applist_opt = 1;
835                break;
836
837            case 'k':
838                g_lockdown_opt = 1;
839                break;
840
841            case 'r':
842                use_native_registers = 1;
843                break;
844
845            case 'v':
846                DNBLogSetVerbose(1);
847                break;
848
849            case 's':
850                stdio_path = optarg;
851                break;
852
853            case 'S':
854                // Put debugserver into a new session. Terminals group processes
855                // into sessions and when a special terminal key sequences
856                // (like control+c) are typed they can cause signals to go out to
857                // all processes in a session. Using this --setsid (-S) option
858                // will cause debugserver to run in its own sessions and be free
859                // from such issues.
860                //
861                // This is useful when debugserver is spawned from a command
862                // line application that uses debugserver to do the debugging,
863                // yet that application doesn't want debugserver receiving the
864                // signals sent to the session (i.e. dying when anyone hits ^C).
865                setsid();
866                break;
867            case 'D':
868                g_disable_aslr = 1;
869                break;
870        }
871    }
872
873    // Skip any options we consumed with getopt_long
874    argc -= optind;
875    argv += optind;
876
877    g_remoteSP.reset (new RNBRemote (use_native_registers));
878
879    RNBRemote *remote = g_remoteSP.get();
880    if (remote == NULL)
881    {
882        RNBLogSTDERR ("error: failed to create a remote connection class\n");
883        return -1;
884    }
885
886    RNBContext& ctx = remote->Context();
887
888
889    // It is ok for us to set NULL as the logfile (this will disable any logging)
890
891    if (log_file != NULL)
892    {
893        DNBLogSetLogCallback(FileLogCallback, log_file);
894        // If our log file was set, yet we have no log flags, log everything!
895        if (log_flags == 0)
896            log_flags = LOG_ALL | LOG_RNB_ALL;
897
898        DNBLogSetLogMask (log_flags);
899    }
900    else
901    {
902        // Enable DNB logging
903        DNBLogSetLogCallback(ASLLogCallback, NULL);
904        DNBLogSetLogMask (log_flags);
905
906    }
907
908    if (DNBLogEnabled())
909    {
910        for (i=0; i<argc; i++)
911            DNBLogDebug("argv[%i] = %s", i, argv[i]);
912    }
913
914    // Now that we have read in the options and enabled logging, initialize
915    // the rest of RNBRemote
916    RNBRemote::InitializeRegisters (use_native_registers);
917
918
919    // as long as we're dropping remotenub in as a replacement for gdbserver,
920    // explicitly note that this is not gdbserver.
921
922    RNBLogSTDOUT ("%s-%g %sfor %s.\n",
923                  DEBUGSERVER_PROGRAM_NAME,
924                  DEBUGSERVER_VERSION_NUM,
925                  compile_options.c_str(),
926                  RNB_ARCH);
927
928    int listen_port = INT32_MAX;
929    char str[PATH_MAX];
930
931    if (g_lockdown_opt == 0 && g_applist_opt == 0)
932    {
933        // Make sure we at least have port
934        if (argc < 1)
935        {
936            show_usage_and_exit (1);
937        }
938        // accept 'localhost:' prefix on port number
939
940        int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &listen_port);
941        if (items_scanned == 2)
942        {
943            DNBLogDebug("host = '%s'  port = %i", str, listen_port);
944        }
945        else if (argv[0][0] == '/')
946        {
947            listen_port = INT32_MAX;
948            strncpy(str, argv[0], sizeof(str));
949        }
950        else
951        {
952            show_usage_and_exit (2);
953        }
954
955        // We just used the 'host:port' or the '/path/file' arg...
956        argc--;
957        argv++;
958
959    }
960
961    //  If we know we're waiting to attach, we don't need any of this other info.
962    if (start_mode != eRNBRunLoopModeInferiorAttaching)
963    {
964        if (argc == 0 || g_lockdown_opt)
965        {
966            if (g_lockdown_opt != 0)
967            {
968                // Work around for SIGPIPE crashes due to posix_spawn issue.
969                // We have to close STDOUT and STDERR, else the first time we
970                // try and do any, we get SIGPIPE and die as posix_spawn is
971                // doing bad things with our file descriptors at the moment.
972                int null = open("/dev/null", O_RDWR);
973                dup2(null, STDOUT_FILENO);
974                dup2(null, STDERR_FILENO);
975            }
976            else if (g_applist_opt != 0)
977            {
978                // List all applications we are able to see
979                std::string applist_plist;
980                int err = ListApplications(applist_plist, false, false);
981                if (err == 0)
982                {
983                    fputs (applist_plist.c_str(), stdout);
984                }
985                else
986                {
987                    RNBLogSTDERR ("error: ListApplications returned error %i\n", err);
988                }
989                // Exit with appropriate error if we were asked to list the applications
990                // with no other args were given (and we weren't trying to do this over
991                // lockdown)
992                return err;
993            }
994
995            DNBLogDebug("Get args from remote protocol...");
996            start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
997        }
998        else
999        {
1000            start_mode = eRNBRunLoopModeInferiorLaunching;
1001            // Fill in the argv array in the context from the rest of our args.
1002            // Skip the name of this executable and the port number
1003            for (int i = 0; i < argc; i++)
1004            {
1005                DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]);
1006                ctx.PushArgument (argv[i]);
1007            }
1008        }
1009    }
1010
1011    if (start_mode == eRNBRunLoopModeExit)
1012        return -1;
1013
1014    RNBRunLoopMode mode = start_mode;
1015    char err_str[1024] = {'\0'};
1016
1017    while (mode != eRNBRunLoopModeExit)
1018    {
1019        switch (mode)
1020        {
1021            case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
1022#if defined (__arm__)
1023                if (g_lockdown_opt)
1024                {
1025                    if (!g_remoteSP->Comm().IsConnected())
1026                    {
1027                        if (g_remoteSP->Comm().ConnectToService () != rnb_success)
1028                        {
1029                            RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
1030                            mode = eRNBRunLoopModeExit;
1031                        }
1032                        else if (g_applist_opt != 0)
1033                        {
1034                            // List all applications we are able to see
1035                            std::string applist_plist;
1036                            if (ListApplications(applist_plist, false, false) == 0)
1037                            {
1038                                DNBLogDebug("Task list: %s", applist_plist.c_str());
1039
1040                                g_remoteSP->Comm().Write(applist_plist.c_str(), applist_plist.size());
1041                                // Issue a read that will never yield any data until the other side
1042                                // closes the socket so this process doesn't just exit and cause the
1043                                // socket to close prematurely on the other end and cause data loss.
1044                                std::string buf;
1045                                g_remoteSP->Comm().Read(buf);
1046                            }
1047                            g_remoteSP->Comm().Disconnect(false);
1048                            mode = eRNBRunLoopModeExit;
1049                            break;
1050                        }
1051                        else
1052                        {
1053                            // Start watching for remote packets
1054                            g_remoteSP->StartReadRemoteDataThread();
1055                        }
1056                    }
1057                }
1058                else
1059#endif
1060                    if (listen_port != INT32_MAX)
1061                    {
1062                        if (!StartListening (g_remoteSP, listen_port))
1063                            mode = eRNBRunLoopModeExit;
1064                    }
1065                    else if (str[0] == '/')
1066                    {
1067                        if (g_remoteSP->Comm().OpenFile (str))
1068                            mode = eRNBRunLoopModeExit;
1069                    }
1070                if (mode != eRNBRunLoopModeExit)
1071                {
1072                    RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
1073
1074                    mode = RNBRunLoopGetStartModeFromRemote (g_remoteSP);
1075                }
1076                break;
1077
1078            case eRNBRunLoopModeInferiorAttaching:
1079                if (!waitfor_pid_name.empty())
1080                {
1081                    // Set our end wait time if we are using a waitfor-duration
1082                    // option that may have been specified
1083                    struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1084                    if (waitfor_duration != 0)
1085                    {
1086                        DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1087                        timeout_ptr = &attach_timeout_abstime;
1088                    }
1089                    nub_launch_flavor_t launch_flavor = g_launch_flavor;
1090                    if (launch_flavor == eLaunchFlavorDefault)
1091                    {
1092                        // Our default launch method is posix spawn
1093                        launch_flavor = eLaunchFlavorPosixSpawn;
1094
1095#if defined (__arm__)
1096                        // Check if we have an app bundle, if so launch using SpringBoard.
1097                        if (waitfor_pid_name.find (".app") != std::string::npos)
1098                        {
1099                            launch_flavor = eLaunchFlavorSpringBoard;
1100                        }
1101#endif
1102                    }
1103
1104                    ctx.SetLaunchFlavor(launch_flavor);
1105
1106                    nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
1107                    g_pid = pid;
1108
1109                    if (pid == INVALID_NUB_PROCESS)
1110                    {
1111                        ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1112                        if (err_str[0])
1113                            ctx.LaunchStatus().SetErrorString(err_str);
1114                        RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
1115                        mode = eRNBRunLoopModeExit;
1116                    }
1117                    else
1118                    {
1119                        ctx.SetProcessID(pid);
1120                        mode = eRNBRunLoopModeInferiorExecuting;
1121                    }
1122                }
1123                else if (attach_pid != INVALID_NUB_PROCESS)
1124                {
1125
1126                    RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid);
1127                    nub_process_t attached_pid;
1128                    mode = RNBRunLoopLaunchAttaching (g_remoteSP, attach_pid, attached_pid);
1129                    if (mode != eRNBRunLoopModeInferiorExecuting)
1130                    {
1131                        const char *error_str = remote->Context().LaunchStatus().AsString();
1132                        RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
1133                        mode = eRNBRunLoopModeExit;
1134                    }
1135                }
1136                else if (!attach_pid_name.empty ())
1137                {
1138                    struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1139                    if (waitfor_duration != 0)
1140                    {
1141                        DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1142                        timeout_ptr = &attach_timeout_abstime;
1143                    }
1144
1145                    nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str));
1146                    g_pid = pid;
1147                    if (pid == INVALID_NUB_PROCESS)
1148                    {
1149                        ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1150                        if (err_str[0])
1151                            ctx.LaunchStatus().SetErrorString(err_str);
1152                        RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
1153                        mode = eRNBRunLoopModeExit;
1154                    }
1155                    else
1156                    {
1157                        ctx.SetProcessID(pid);
1158                        mode = eRNBRunLoopModeInferiorExecuting;
1159                    }
1160
1161                }
1162                else
1163                {
1164                    RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.");
1165                    mode = eRNBRunLoopModeExit;
1166                }
1167
1168                if (mode != eRNBRunLoopModeExit)
1169                {
1170                    if (listen_port != INT32_MAX)
1171                    {
1172                        if (!StartListening (g_remoteSP, listen_port))
1173                            mode = eRNBRunLoopModeExit;
1174                    }
1175                    else if (str[0] == '/')
1176                    {
1177                        if (g_remoteSP->Comm().OpenFile (str))
1178                            mode = eRNBRunLoopModeExit;
1179                    }
1180                    if (mode != eRNBRunLoopModeExit)
1181                        RNBLogSTDOUT ("Got a connection, waiting for debugger instructions for process %d.\n", attach_pid);
1182                }
1183                break;
1184
1185            case eRNBRunLoopModeInferiorLaunching:
1186                mode = RNBRunLoopLaunchInferior (g_remoteSP, stdio_path.empty() ? NULL : stdio_path.c_str());
1187
1188                if (mode == eRNBRunLoopModeInferiorExecuting)
1189                {
1190                    if (listen_port != INT32_MAX)
1191                    {
1192                        if (!StartListening (g_remoteSP, listen_port))
1193                            mode = eRNBRunLoopModeExit;
1194                    }
1195                    else if (str[0] == '/')
1196                    {
1197                        if (g_remoteSP->Comm().OpenFile (str))
1198                            mode = eRNBRunLoopModeExit;
1199                    }
1200
1201                    if (mode != eRNBRunLoopModeExit)
1202                        RNBLogSTDOUT ("Got a connection, waiting for debugger instructions.\n");
1203                }
1204                else
1205                {
1206                    const char *error_str = remote->Context().LaunchStatus().AsString();
1207                    RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv[0], error_str ? error_str : "unknown error.");
1208                }
1209                break;
1210
1211            case eRNBRunLoopModeInferiorExecuting:
1212                mode = RNBRunLoopInferiorExecuting(g_remoteSP);
1213                break;
1214
1215            default:
1216                mode = eRNBRunLoopModeExit;
1217            case eRNBRunLoopModeExit:
1218                break;
1219        }
1220    }
1221
1222    g_remoteSP->StopReadRemoteDataThread ();
1223    g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS);
1224
1225    return 0;
1226}
1227