blob: 4fb5077b2ba907080a0ec02eb9d7045e53ee4c34 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- 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>
Greg Clayton8b82f082011-04-12 05:54:46 +000020#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>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000026
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...
39nub_process_t g_pid = INVALID_NUB_PROCESS;
40
41//----------------------------------------------------------------------
42// Run loop modes which determine which run loop function will be called
43//----------------------------------------------------------------------
44typedef enum
45{
46 eRNBRunLoopModeInvalid = 0,
47 eRNBRunLoopModeGetStartModeFromRemoteProtocol,
48 eRNBRunLoopModeInferiorAttaching,
49 eRNBRunLoopModeInferiorLaunching,
50 eRNBRunLoopModeInferiorExecuting,
Greg Clayton7a5388b2011-03-20 04:57:14 +000051 eRNBRunLoopModePlatformMode,
Chris Lattner30fdc8d2010-06-08 16:52:24 +000052 eRNBRunLoopModeExit
53} RNBRunLoopMode;
54
55
56//----------------------------------------------------------------------
57// Global Variables
58//----------------------------------------------------------------------
59RNBRemoteSP g_remoteSP;
60static int g_lockdown_opt = 0;
61static int g_applist_opt = 0;
62static nub_launch_flavor_t g_launch_flavor = eLaunchFlavorDefault;
Greg Clayton6f35f5c2010-09-09 06:32:46 +000063int g_disable_aslr = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000064
65int g_isatty = 0;
Jim Ingham5689a212014-02-25 19:57:47 +000066bool g_detach_on_error = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000067
68#define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
69#define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
70
71//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +000072// Get our program path and arguments from the remote connection.
73// We will need to start up the remote connection without a PID, get the
74// arguments, wait for the new process to finish launching and hit its
75// entry point, and then return the run loop mode that should come next.
76//----------------------------------------------------------------------
77RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +000078RNBRunLoopGetStartModeFromRemote (RNBRemote* remote)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000079{
80 std::string packet;
81
Greg Clayton6779606a2011-01-22 23:43:18 +000082 if (remote)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000083 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +000084 RNBContext& ctx = remote->Context();
Greg Clayton71337622011-02-24 22:24:29 +000085 uint32_t event_mask = RNBContext::event_read_packet_available |
86 RNBContext::event_read_thread_exiting;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000087
88 // Spin waiting to get the A packet.
89 while (1)
90 {
91 DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask);
92 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
93 DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events);
94
Greg Clayton71337622011-02-24 22:24:29 +000095 if (set_events & RNBContext::event_read_thread_exiting)
96 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +000097 RNBLogSTDERR ("error: packet read thread exited.\n");
Greg Clayton71337622011-02-24 22:24:29 +000098 return eRNBRunLoopModeExit;
99 }
100
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000101 if (set_events & RNBContext::event_read_packet_available)
102 {
103 rnb_err_t err = rnb_err;
104 RNBRemote::PacketEnum type;
105
106 err = remote->HandleReceivedPacket (&type);
107
108 // check if we tried to attach to a process
Jim Inghamcd16df92012-07-20 21:37:13 +0000109 if (type == RNBRemote::vattach || type == RNBRemote::vattachwait || type == RNBRemote::vattachorwait)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000110 {
111 if (err == rnb_success)
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000112 {
113 RNBLogSTDOUT ("Attach succeeded, ready to debug.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000114 return eRNBRunLoopModeInferiorExecuting;
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000115 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000116 else
117 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000118 RNBLogSTDERR ("error: attach failed.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000119 return eRNBRunLoopModeExit;
120 }
121 }
122
123 if (err == rnb_success)
124 {
125 // If we got our arguments we are ready to launch using the arguments
126 // and any environment variables we received.
127 if (type == RNBRemote::set_argv)
128 {
129 return eRNBRunLoopModeInferiorLaunching;
130 }
131 }
132 else if (err == rnb_not_connected)
133 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000134 RNBLogSTDERR ("error: connection lost.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000135 return eRNBRunLoopModeExit;
136 }
137 else
138 {
139 // a catch all for any other gdb remote packets that failed
140 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__);
141 continue;
142 }
143
144 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
145 }
146 else
147 {
148 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__);
149 return eRNBRunLoopModeExit;
150 }
151 }
152 }
153 return eRNBRunLoopModeExit;
154}
155
156
157//----------------------------------------------------------------------
158// This run loop mode will wait for the process to launch and hit its
159// entry point. It will currently ignore all events except for the
160// process state changed event, where it watches for the process stopped
161// or crash process state.
162//----------------------------------------------------------------------
163RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000164RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char *stdout_path, const char *stderr_path, bool no_stdio)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000165{
166 RNBContext& ctx = remote->Context();
167
168 // The Process stuff takes a c array, the RNBContext has a vector...
169 // So make up a c array.
170
171 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, ctx.ArgumentAtIndex(0));
172
173 size_t inferior_argc = ctx.ArgumentCount();
174 // Initialize inferior_argv with inferior_argc + 1 NULLs
175 std::vector<const char *> inferior_argv(inferior_argc + 1, NULL);
176
177 size_t i;
178 for (i = 0; i < inferior_argc; i++)
179 inferior_argv[i] = ctx.ArgumentAtIndex(i);
180
181 // Pass the environment array the same way:
182
183 size_t inferior_envc = ctx.EnvironmentCount();
184 // Initialize inferior_argv with inferior_argc + 1 NULLs
185 std::vector<const char *> inferior_envp(inferior_envc + 1, NULL);
186
187 for (i = 0; i < inferior_envc; i++)
188 inferior_envp[i] = ctx.EnvironmentAtIndex(i);
189
190 // Our launch type hasn't been set to anything concrete, so we need to
191 // figure our how we are going to launch automatically.
192
193 nub_launch_flavor_t launch_flavor = g_launch_flavor;
194 if (launch_flavor == eLaunchFlavorDefault)
195 {
196 // Our default launch method is posix spawn
197 launch_flavor = eLaunchFlavorPosixSpawn;
198
Jason Molenda42999a42012-02-22 02:18:59 +0000199#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000200 // Check if we have an app bundle, if so launch using SpringBoard.
201 if (strstr(inferior_argv[0], ".app"))
202 {
203 launch_flavor = eLaunchFlavorSpringBoard;
204 }
205#endif
206 }
207
208 ctx.SetLaunchFlavor(launch_flavor);
209 char resolved_path[PATH_MAX];
210
211 // If we fail to resolve the path to our executable, then just use what we
212 // were given and hope for the best
213 if ( !DNBResolveExecutablePath (inferior_argv[0], resolved_path, sizeof(resolved_path)) )
214 ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path));
215
216 char launch_err_str[PATH_MAX];
217 launch_err_str[0] = '\0';
Johnny Chen725269a2011-02-26 01:36:13 +0000218 const char * cwd = (ctx.GetWorkingDirPath() != NULL ? ctx.GetWorkingDirPath()
219 : ctx.GetWorkingDirectory());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000220 nub_process_t pid = DNBProcessLaunch (resolved_path,
221 &inferior_argv[0],
222 &inferior_envp[0],
Johnny Chen725269a2011-02-26 01:36:13 +0000223 cwd,
Greg Clayton6779606a2011-01-22 23:43:18 +0000224 stdin_path,
225 stdout_path,
226 stderr_path,
Caroline Ticef8da8632010-12-03 18:46:09 +0000227 no_stdio,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000228 launch_flavor,
Greg Claytonf681b942010-08-31 18:35:14 +0000229 g_disable_aslr,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000230 launch_err_str,
231 sizeof(launch_err_str));
232
233 g_pid = pid;
234
Jason Molenda4e0c94b2011-07-08 00:00:32 +0000235 if (pid == INVALID_NUB_PROCESS && strlen (launch_err_str) > 0)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000236 {
Greg Clayton3382c2c2010-07-30 23:14:42 +0000237 DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, launch_err_str);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000238 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
239 ctx.LaunchStatus().SetErrorString(launch_err_str);
240 }
Jason Molenda4e0c94b2011-07-08 00:00:32 +0000241 else if (pid == INVALID_NUB_PROCESS)
242 {
243 DNBLogThreaded ("%s DNBProcessLaunch() failed to launch process, unknown failure", __FUNCTION__);
244 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
245 ctx.LaunchStatus().SetErrorString(launch_err_str);
246 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000247 else
Greg Clayton71337622011-02-24 22:24:29 +0000248 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000249 ctx.LaunchStatus().Clear();
Greg Clayton71337622011-02-24 22:24:29 +0000250 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000251
252 if (remote->Comm().IsConnected())
253 {
254 // It we are connected already, the next thing gdb will do is ask
255 // whether the launch succeeded, and if not, whether there is an
256 // error code. So we need to fetch one packet from gdb before we wait
257 // on the stop from the target.
258
259 uint32_t event_mask = RNBContext::event_read_packet_available;
260 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
261
262 if (set_events & RNBContext::event_read_packet_available)
263 {
264 rnb_err_t err = rnb_err;
265 RNBRemote::PacketEnum type;
266
267 err = remote->HandleReceivedPacket (&type);
268
269 if (err != rnb_success)
270 {
271 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__);
272 return eRNBRunLoopModeExit;
273 }
274 if (type != RNBRemote::query_launch_success)
275 {
276 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__);
277 }
278 }
279 }
280
281 while (pid != INVALID_NUB_PROCESS)
282 {
283 // Wait for process to start up and hit entry point
284 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid);
285 nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL);
286 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events);
287
288 if (set_events == 0)
289 {
290 pid = INVALID_NUB_PROCESS;
291 g_pid = pid;
292 }
293 else
294 {
295 if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
296 {
297 nub_state_t pid_state = DNBProcessGetState (pid);
298 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
299
300 switch (pid_state)
301 {
302 default:
303 case eStateInvalid:
304 case eStateUnloaded:
305 case eStateAttaching:
306 case eStateLaunching:
307 case eStateSuspended:
308 break; // Ignore
309
310 case eStateRunning:
311 case eStateStepping:
312 // Still waiting to stop at entry point...
313 break;
314
315 case eStateStopped:
316 case eStateCrashed:
317 ctx.SetProcessID(pid);
318 return eRNBRunLoopModeInferiorExecuting;
319
320 case eStateDetached:
321 case eStateExited:
322 pid = INVALID_NUB_PROCESS;
323 g_pid = pid;
324 return eRNBRunLoopModeExit;
325 }
326 }
327
328 DNBProcessResetEvents(pid, set_events);
329 }
330 }
331
332 return eRNBRunLoopModeExit;
333}
334
335
336//----------------------------------------------------------------------
337// This run loop mode will wait for the process to launch and hit its
338// entry point. It will currently ignore all events except for the
339// process state changed event, where it watches for the process stopped
340// or crash process state.
341//----------------------------------------------------------------------
342RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000343RNBRunLoopLaunchAttaching (RNBRemote *remote, nub_process_t attach_pid, nub_process_t& pid)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000344{
345 RNBContext& ctx = remote->Context();
346
347 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid);
348 char err_str[1024];
349 pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str));
350 g_pid = pid;
351
352 if (pid == INVALID_NUB_PROCESS)
353 {
354 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
355 if (err_str[0])
356 ctx.LaunchStatus().SetErrorString(err_str);
357 return eRNBRunLoopModeExit;
358 }
359 else
360 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000361 ctx.SetProcessID(pid);
362 return eRNBRunLoopModeInferiorExecuting;
363 }
364}
365
366//----------------------------------------------------------------------
367// Watch for signals:
368// SIGINT: so we can halt our inferior. (disabled for now)
369// SIGPIPE: in case our child process dies
370//----------------------------------------------------------------------
371int g_sigint_received = 0;
372int g_sigpipe_received = 0;
373void
374signal_handler(int signo)
375{
376 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo));
377
378 switch (signo)
379 {
380 case SIGINT:
381 g_sigint_received++;
382 if (g_pid != INVALID_NUB_PROCESS)
383 {
384 // Only send a SIGINT once...
385 if (g_sigint_received == 1)
386 {
387 switch (DNBProcessGetState (g_pid))
388 {
389 case eStateRunning:
390 case eStateStepping:
391 DNBProcessSignal (g_pid, SIGSTOP);
392 return;
Greg Clayton95bf0fd2011-04-01 00:29:43 +0000393 default:
394 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000395 }
396 }
397 }
398 exit (SIGINT);
399 break;
400
401 case SIGPIPE:
402 g_sigpipe_received = 1;
403 break;
404 }
405}
406
407// Return the new run loop mode based off of the current process state
408RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000409HandleProcessStateChange (RNBRemote *remote, bool initialize)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000410{
411 RNBContext& ctx = remote->Context();
412 nub_process_t pid = ctx.ProcessID();
413
414 if (pid == INVALID_NUB_PROCESS)
415 {
416 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
417 return eRNBRunLoopModeExit;
418 }
419 nub_state_t pid_state = DNBProcessGetState (pid);
420
421 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state));
422
423 switch (pid_state)
424 {
425 case eStateInvalid:
426 case eStateUnloaded:
427 // Something bad happened
428 return eRNBRunLoopModeExit;
429 break;
430
431 case eStateAttaching:
432 case eStateLaunching:
433 return eRNBRunLoopModeInferiorExecuting;
434
435 case eStateSuspended:
436 case eStateCrashed:
437 case eStateStopped:
438 // If we stop due to a signal, so clear the fact that we got a SIGINT
439 // so we can stop ourselves again (but only while our inferior
440 // process is running..)
441 g_sigint_received = 0;
442 if (initialize == false)
443 {
444 // Compare the last stop count to our current notion of a stop count
445 // to make sure we don't notify more than once for a given stop.
446 nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
447 bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid));
448 if (pid_stop_count_changed)
449 {
450 remote->FlushSTDIO();
451
452 if (ctx.GetProcessStopCount() == 1)
453 {
Greg Clayton43e0af02012-09-18 18:04:04 +0000454 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);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000455 }
456 else
457 {
458
Greg Clayton43e0af02012-09-18 18:04:04 +0000459 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);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000460 remote->NotifyThatProcessStopped ();
461 }
462 }
463 else
464 {
Greg Clayton43e0af02012-09-18 18:04:04 +0000465 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);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000466 }
467 }
468 return eRNBRunLoopModeInferiorExecuting;
469
470 case eStateStepping:
471 case eStateRunning:
472 return eRNBRunLoopModeInferiorExecuting;
473
474 case eStateExited:
475 remote->HandlePacket_last_signal(NULL);
Greg Clayton95bf0fd2011-04-01 00:29:43 +0000476 case eStateDetached:
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000477 return eRNBRunLoopModeExit;
478
479 }
480
481 // Catch all...
482 return eRNBRunLoopModeExit;
483}
484// This function handles the case where our inferior program is stopped and
485// we are waiting for gdb remote protocol packets. When a packet occurs that
486// makes the inferior run, we need to leave this function with a new state
487// as the return code.
488RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000489RNBRunLoopInferiorExecuting (RNBRemote *remote)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000490{
491 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
492 RNBContext& ctx = remote->Context();
493
494 // Init our mode and set 'is_running' based on the current process state
495 RNBRunLoopMode mode = HandleProcessStateChange (remote, true);
496
497 while (ctx.ProcessID() != INVALID_NUB_PROCESS)
498 {
499
500 std::string set_events_str;
501 uint32_t event_mask = ctx.NormalEventBits();
502
503 if (!ctx.ProcessStateRunning())
504 {
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000505 // Clear some bits if we are not running so we don't send any async packets
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000506 event_mask &= ~RNBContext::event_proc_stdio_available;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000507 event_mask &= ~RNBContext::event_proc_profile_data;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000508 }
509
510 // We want to make sure we consume all process state changes and have
511 // whomever is notifying us to wait for us to reset the event bit before
512 // continuing.
513 //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
514
515 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
516 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
517 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));
518
519 if (set_events)
520 {
521 if ((set_events & RNBContext::event_proc_thread_exiting) ||
522 (set_events & RNBContext::event_proc_stdio_available))
523 {
524 remote->FlushSTDIO();
525 }
526
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000527 if (set_events & RNBContext::event_proc_profile_data)
528 {
529 remote->SendAsyncProfileData();
530 }
531
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000532 if (set_events & RNBContext::event_read_packet_available)
533 {
534 // handleReceivedPacket will take care of resetting the
535 // event_read_packet_available events when there are no more...
536 set_events ^= RNBContext::event_read_packet_available;
537
538 if (ctx.ProcessStateRunning())
539 {
540 if (remote->HandleAsyncPacket() == rnb_not_connected)
541 {
542 // TODO: connect again? Exit?
543 }
544 }
545 else
546 {
547 if (remote->HandleReceivedPacket() == rnb_not_connected)
548 {
549 // TODO: connect again? Exit?
550 }
551 }
552 }
553
554 if (set_events & RNBContext::event_proc_state_changed)
555 {
556 mode = HandleProcessStateChange (remote, false);
557 ctx.Events().ResetEvents(RNBContext::event_proc_state_changed);
558 set_events ^= RNBContext::event_proc_state_changed;
559 }
560
561 if (set_events & RNBContext::event_proc_thread_exiting)
562 {
563 mode = eRNBRunLoopModeExit;
564 }
565
566 if (set_events & RNBContext::event_read_thread_exiting)
567 {
568 // Out remote packet receiving thread exited, exit for now.
569 if (ctx.HasValidProcessID())
570 {
571 // TODO: We should add code that will leave the current process
572 // in its current state and listen for another connection...
573 if (ctx.ProcessStateRunning())
574 {
Jim Ingham58813182014-02-25 04:53:13 +0000575 if (ctx.GetDetachOnError())
576 {
577 DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process.");
578 DNBProcessDetach (ctx.ProcessID());
579 }
580 else
581 {
582 DNBLog ("debugserver's event read thread is exiting, killing the inferior process.");
583 DNBProcessKill (ctx.ProcessID());
584 }
585 }
586 else
587 {
588 if (ctx.GetDetachOnError())
589 {
590 DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process.");
591 DNBProcessDetach (ctx.ProcessID());
592 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000593 }
594 }
595 mode = eRNBRunLoopModeExit;
596 }
597 }
598
599 // Reset all event bits that weren't reset for now...
600 if (set_events != 0)
601 ctx.Events().ResetEvents(set_events);
602
603 if (mode != eRNBRunLoopModeInferiorExecuting)
604 break;
605 }
606
607 return mode;
608}
609
610
Greg Clayton7a5388b2011-03-20 04:57:14 +0000611RNBRunLoopMode
612RNBRunLoopPlatform (RNBRemote *remote)
613{
614 RNBRunLoopMode mode = eRNBRunLoopModePlatformMode;
615 RNBContext& ctx = remote->Context();
616
617 while (mode == eRNBRunLoopModePlatformMode)
618 {
619 std::string set_events_str;
620 const uint32_t event_mask = RNBContext::event_read_packet_available |
621 RNBContext::event_read_thread_exiting;
622
623 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
624 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
625 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));
626
627 if (set_events)
628 {
629 if (set_events & RNBContext::event_read_packet_available)
630 {
631 if (remote->HandleReceivedPacket() == rnb_not_connected)
632 mode = eRNBRunLoopModeExit;
633 }
634
635 if (set_events & RNBContext::event_read_thread_exiting)
636 {
637 mode = eRNBRunLoopModeExit;
638 }
639 ctx.Events().ResetEvents(set_events);
640 }
641 }
642 return eRNBRunLoopModeExit;
643}
644
Greg Claytonc93068b2013-12-10 19:36:45 +0000645//----------------------------------------------------------------------
646// Convenience function to set up the remote listening port
647// Returns 1 for success 0 for failure.
648//----------------------------------------------------------------------
649
650static void
651PortWasBoundCallbackUnixSocket (const void *baton, in_port_t port)
652{
653 //::printf ("PortWasBoundCallbackUnixSocket (baton = %p, port = %u)\n", baton, port);
654
655 const char *unix_socket_name = (const char *)baton;
656
657 if (unix_socket_name && unix_socket_name[0])
658 {
659 // We were given a unix socket name to use to communicate the port
660 // that we ended up binding to back to our parent process
661 struct sockaddr_un saddr_un;
662 int s = ::socket (AF_UNIX, SOCK_STREAM, 0);
663 if (s < 0)
664 {
665 perror("error: socket (AF_UNIX, SOCK_STREAM, 0)");
666 exit(1);
667 }
668
669 saddr_un.sun_family = AF_UNIX;
670 ::strncpy(saddr_un.sun_path, unix_socket_name, sizeof(saddr_un.sun_path) - 1);
671 saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
672 saddr_un.sun_len = SUN_LEN (&saddr_un);
673
674 if (::connect (s, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0)
675 {
676 perror("error: connect (socket, &saddr_un, saddr_un_len)");
677 exit(1);
678 }
679
680 //::printf ("connect () sucess!!\n");
681
682
683 // We were able to connect to the socket, now write our PID so whomever
684 // launched us will know this process's ID
685 RNBLogSTDOUT ("Listening to port %i...\n", port);
686
687 char pid_str[64];
688 const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%u", port);
689 const int bytes_sent = ::send (s, pid_str, pid_str_len, 0);
690
691 if (pid_str_len != bytes_sent)
692 {
693 perror("error: send (s, pid_str, pid_str_len, 0)");
694 exit (1);
695 }
696
697 //::printf ("send () sucess!!\n");
698
699 // We are done with the socket
700 close (s);
701 }
702}
703
Greg Clayton8b82f082011-04-12 05:54:46 +0000704static void
Greg Claytond6299802013-12-06 17:46:35 +0000705PortWasBoundCallbackNamedPipe (const void *baton, uint16_t port)
Greg Clayton8b82f082011-04-12 05:54:46 +0000706{
Greg Clayton91a9b2472013-12-04 19:19:12 +0000707 const char *named_pipe = (const char *)baton;
708 if (named_pipe && named_pipe[0])
Greg Clayton8b82f082011-04-12 05:54:46 +0000709 {
Greg Clayton91a9b2472013-12-04 19:19:12 +0000710 int fd = ::open(named_pipe, O_WRONLY);
711 if (fd > -1)
Greg Clayton8b82f082011-04-12 05:54:46 +0000712 {
Greg Clayton91a9b2472013-12-04 19:19:12 +0000713 char port_str[64];
714 const ssize_t port_str_len = ::snprintf (port_str, sizeof(port_str), "%u", port);
715 // Write the port number as a C string with the NULL terminator
716 ::write (fd, port_str, port_str_len + 1);
717 close (fd);
Greg Clayton8b82f082011-04-12 05:54:46 +0000718 }
Greg Clayton8b82f082011-04-12 05:54:46 +0000719 }
720}
721
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000722static int
Greg Claytonc93068b2013-12-10 19:36:45 +0000723ConnectRemote (RNBRemote *remote,
724 const char *host,
725 int port,
726 bool reverse_connect,
727 const char *named_pipe_path,
728 const char *unix_socket_name)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000729{
Greg Clayton6779606a2011-01-22 23:43:18 +0000730 if (!remote->Comm().IsConnected())
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000731 {
Greg Clayton00fe87b2013-12-05 22:58:22 +0000732 if (reverse_connect)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000733 {
Greg Clayton00fe87b2013-12-05 22:58:22 +0000734 if (port == 0)
735 {
736 DNBLogThreaded("error: invalid port supplied for reverse connection: %i.\n", port);
737 return 0;
738 }
739 if (remote->Comm().Connect(host, port) != rnb_success)
740 {
741 DNBLogThreaded("Failed to reverse connect to %s:%i.\n", host, port);
742 return 0;
743 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000744 }
745 else
746 {
Greg Clayton00fe87b2013-12-05 22:58:22 +0000747 if (port != 0)
748 RNBLogSTDOUT ("Listening to port %i for a connection from %s...\n", port, host ? host : "localhost");
Greg Claytonc93068b2013-12-10 19:36:45 +0000749 if (unix_socket_name && unix_socket_name[0])
Greg Clayton00fe87b2013-12-05 22:58:22 +0000750 {
Greg Claytonc93068b2013-12-10 19:36:45 +0000751 if (remote->Comm().Listen(host, port, PortWasBoundCallbackUnixSocket, unix_socket_name) != rnb_success)
752 {
753 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
754 return 0;
755 }
756 }
757 else
758 {
759 if (remote->Comm().Listen(host, port, PortWasBoundCallbackNamedPipe, named_pipe_path) != rnb_success)
760 {
761 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
762 return 0;
763 }
Greg Clayton00fe87b2013-12-05 22:58:22 +0000764 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000765 }
Greg Clayton00fe87b2013-12-05 22:58:22 +0000766 remote->StartReadRemoteDataThread();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000767 }
768 return 1;
769}
770
771//----------------------------------------------------------------------
772// ASL Logging callback that can be registered with DNBLogSetLogCallback
773//----------------------------------------------------------------------
774void
775ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
776{
777 if (format == NULL)
778 return;
779 static aslmsg g_aslmsg = NULL;
780 if (g_aslmsg == NULL)
781 {
782 g_aslmsg = ::asl_new (ASL_TYPE_MSG);
783 char asl_key_sender[PATH_MAX];
784 snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.%s-%g", DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_NUM);
785 ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
786 }
787
788 int asl_level;
789 if (flags & DNBLOG_FLAG_FATAL) asl_level = ASL_LEVEL_CRIT;
790 else if (flags & DNBLOG_FLAG_ERROR) asl_level = ASL_LEVEL_ERR;
791 else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING;
792 else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO;
793 else asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG;
794
795 ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
796}
797
798//----------------------------------------------------------------------
799// FILE based Logging callback that can be registered with
800// DNBLogSetLogCallback
801//----------------------------------------------------------------------
802void
803FileLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
804{
805 if (baton == NULL || format == NULL)
806 return;
807
808 ::vfprintf ((FILE *)baton, format, args);
809 ::fprintf ((FILE *)baton, "\n");
810}
811
812
813void
814show_usage_and_exit (int exit_code)
815{
816 RNBLogSTDERR ("Usage:\n %s host:port [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
817 RNBLogSTDERR (" %s /path/file [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
818 RNBLogSTDERR (" %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
819 RNBLogSTDERR (" %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
820 RNBLogSTDERR (" %s host:port --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
821 RNBLogSTDERR (" %s /path/file --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
822 exit (exit_code);
823}
824
825
826//----------------------------------------------------------------------
Greg Claytonb7ad58a2013-04-04 20:35:24 +0000827// option descriptors for getopt_long_only()
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000828//----------------------------------------------------------------------
829static struct option g_long_options[] =
830{
831 { "attach", required_argument, NULL, 'a' },
Greg Clayton3af9ea52010-11-18 05:57:03 +0000832 { "arch", required_argument, NULL, 'A' },
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000833 { "debug", no_argument, NULL, 'g' },
Jim Ingham5689a212014-02-25 19:57:47 +0000834 { "kill-on-error", no_argument, NULL, 'K' },
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000835 { "verbose", no_argument, NULL, 'v' },
836 { "lockdown", no_argument, &g_lockdown_opt, 1 }, // short option "-k"
837 { "applist", no_argument, &g_applist_opt, 1 }, // short option "-t"
838 { "log-file", required_argument, NULL, 'l' },
839 { "log-flags", required_argument, NULL, 'f' },
840 { "launch", required_argument, NULL, 'x' }, // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
841 { "waitfor", required_argument, NULL, 'w' }, // Wait for a process whose name starts with ARG
842 { "waitfor-interval", required_argument, NULL, 'i' }, // Time in usecs to wait between sampling the pid list when waiting for a process by name
843 { "waitfor-duration", required_argument, NULL, 'd' }, // The time in seconds to wait for a process to show up by name
844 { "native-regs", no_argument, NULL, 'r' }, // Specify to use the native registers instead of the gdb defaults for the architecture.
Greg Claytonbd82a5d2011-01-23 05:56:20 +0000845 { "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)
846 { "stdin-path", required_argument, NULL, 'I' }, // Set the STDIN path to be used when launching applications (only if debugserver launches the process)
Johnny Chena3435452011-01-25 16:56:01 +0000847 { "stdout-path", required_argument, NULL, 'O' }, // Set the STDOUT path to be used when launching applications (only if debugserver launches the process)
848 { "stderr-path", required_argument, NULL, 'E' }, // Set the STDERR path to be used when launching applications (only if debugserver launches the process)
Greg Claytonbd82a5d2011-01-23 05:56:20 +0000849 { "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)
850 { "setsid", no_argument, NULL, 'S' }, // call setsid() to make debugserver run in its own session
Greg Claytonf681b942010-08-31 18:35:14 +0000851 { "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
Greg Claytonbd82a5d2011-01-23 05:56:20 +0000852 { "working-dir", required_argument, NULL, 'W' }, // The working directory that the inferior process should have (only if debugserver launches the process)
Greg Clayton7a5388b2011-03-20 04:57:14 +0000853 { "platform", required_argument, NULL, 'p' }, // Put this executable into a remote platform mode
Greg Claytonc93068b2013-12-10 19:36:45 +0000854 { "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
Greg Clayton91a9b2472013-12-04 19:19:12 +0000855 { "named-pipe", required_argument, NULL, 'P' },
Greg Clayton00fe87b2013-12-05 22:58:22 +0000856 { "reverse-connect", no_argument, NULL, 'R' },
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000857 { NULL, 0, NULL, 0 }
858};
859
860
861//----------------------------------------------------------------------
862// main
863//----------------------------------------------------------------------
864int
865main (int argc, char *argv[])
866{
Jason Molenda0b2dbe02012-11-01 02:02:59 +0000867 const char *argv_sub_zero = argv[0]; // save a copy of argv[0] for error reporting post-launch
868
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000869 g_isatty = ::isatty (STDIN_FILENO);
870
871 // ::printf ("uid=%u euid=%u gid=%u egid=%u\n",
872 // getuid(),
873 // geteuid(),
874 // getgid(),
875 // getegid());
876
877
878 // signal (SIGINT, signal_handler);
879 signal (SIGPIPE, signal_handler);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000880 signal (SIGHUP, signal_handler);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000881
Greg Clayton71337622011-02-24 22:24:29 +0000882 g_remoteSP.reset (new RNBRemote ());
883
884
885 RNBRemote *remote = g_remoteSP.get();
886 if (remote == NULL)
887 {
888 RNBLogSTDERR ("error: failed to create a remote connection class\n");
889 return -1;
890 }
891
892 RNBContext& ctx = remote->Context();
893
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000894 int i;
895 int attach_pid = INVALID_NUB_PROCESS;
896
897 FILE* log_file = NULL;
898 uint32_t log_flags = 0;
899 // Parse our options
900 int ch;
901 int long_option_index = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000902 int debug = 0;
903 std::string compile_options;
904 std::string waitfor_pid_name; // Wait for a process that starts with this name
905 std::string attach_pid_name;
Greg Clayton3af9ea52010-11-18 05:57:03 +0000906 std::string arch_name;
Greg Clayton8b82f082011-04-12 05:54:46 +0000907 std::string working_dir; // The new working directory to use for the inferior
Greg Claytonc93068b2013-12-10 19:36:45 +0000908 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
Greg Clayton91a9b2472013-12-04 19:19:12 +0000909 std::string named_pipe_path; // If we need to handshake with our parent process, an option will be passed down that specifies a named pipe to use
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000910 useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
911 useconds_t waitfor_duration = 0; // Time in seconds to wait for a process by name, 0 means wait forever.
Caroline Ticef8da8632010-12-03 18:46:09 +0000912 bool no_stdio = false;
Greg Clayton00fe87b2013-12-05 22:58:22 +0000913 bool reverse_connect = false; // Set to true by an option to indicate we should reverse connect to the host:port supplied as the first debugserver argument
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000914
915#if !defined (DNBLOG_ENABLED)
916 compile_options += "(no-logging) ";
917#endif
918
919 RNBRunLoopMode start_mode = eRNBRunLoopModeExit;
920
Greg Clayton8d400e172011-05-23 18:04:09 +0000921 char short_options[512];
922 uint32_t short_options_idx = 0;
923
924 // Handle the two case that don't have short options in g_long_options
925 short_options[short_options_idx++] = 'k';
926 short_options[short_options_idx++] = 't';
927
928 for (i=0; g_long_options[i].name != NULL; ++i)
929 {
930 if (isalpha(g_long_options[i].val))
931 {
932 short_options[short_options_idx++] = g_long_options[i].val;
933 switch (g_long_options[i].has_arg)
934 {
935 default:
936 case no_argument:
937 break;
938
939 case optional_argument:
940 short_options[short_options_idx++] = ':';
941 // Fall through to required_argument case below...
942 case required_argument:
943 short_options[short_options_idx++] = ':';
944 break;
945 }
946 }
947 }
948 // NULL terminate the short option string.
949 short_options[short_options_idx++] = '\0';
Greg Claytond4724cf2013-11-22 18:55:04 +0000950
951#if __GLIBC__
952 optind = 0;
953#else
954 optreset = 1;
955 optind = 1;
956#endif
957
Greg Claytonb7ad58a2013-04-04 20:35:24 +0000958 while ((ch = getopt_long_only(argc, argv, short_options, g_long_options, &long_option_index)) != -1)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000959 {
960 DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
961 ch, (uint8_t)ch,
962 g_long_options[long_option_index].name,
963 g_long_options[long_option_index].has_arg ? '=' : ' ',
964 optarg ? optarg : "");
965 switch (ch)
966 {
967 case 0: // Any optional that auto set themselves will return 0
968 break;
969
Greg Clayton3af9ea52010-11-18 05:57:03 +0000970 case 'A':
971 if (optarg && optarg[0])
972 arch_name.assign(optarg);
973 break;
974
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000975 case 'a':
976 if (optarg && optarg[0])
977 {
978 if (isdigit(optarg[0]))
979 {
980 char *end = NULL;
981 attach_pid = strtoul(optarg, &end, 0);
982 if (end == NULL || *end != '\0')
983 {
984 RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg);
985 exit (4);
986 }
987 }
988 else
989 {
990 attach_pid_name = optarg;
991 }
992 start_mode = eRNBRunLoopModeInferiorAttaching;
993 }
994 break;
995
996 // --waitfor=NAME
997 case 'w':
998 if (optarg && optarg[0])
999 {
1000 waitfor_pid_name = optarg;
1001 start_mode = eRNBRunLoopModeInferiorAttaching;
1002 }
1003 break;
1004
1005 // --waitfor-interval=USEC
1006 case 'i':
1007 if (optarg && optarg[0])
1008 {
1009 char *end = NULL;
1010 waitfor_interval = strtoul(optarg, &end, 0);
1011 if (end == NULL || *end != '\0')
1012 {
1013 RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
1014 exit (6);
1015 }
1016 }
1017 break;
1018
1019 // --waitfor-duration=SEC
1020 case 'd':
1021 if (optarg && optarg[0])
1022 {
1023 char *end = NULL;
1024 waitfor_duration = strtoul(optarg, &end, 0);
1025 if (end == NULL || *end != '\0')
1026 {
1027 RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
1028 exit (7);
1029 }
1030 }
1031 break;
Jim Ingham58813182014-02-25 04:53:13 +00001032
Jim Ingham5689a212014-02-25 19:57:47 +00001033 case 'K':
1034 g_detach_on_error = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001035
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001036 case 'W':
Greg Clayton6779606a2011-01-22 23:43:18 +00001037 if (optarg && optarg[0])
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001038 working_dir.assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001039 break;
1040
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001041 case 'x':
1042 if (optarg && optarg[0])
1043 {
1044 if (strcasecmp(optarg, "auto") == 0)
1045 g_launch_flavor = eLaunchFlavorDefault;
1046 else if (strcasestr(optarg, "posix") == optarg)
1047 g_launch_flavor = eLaunchFlavorPosixSpawn;
1048 else if (strcasestr(optarg, "fork") == optarg)
1049 g_launch_flavor = eLaunchFlavorForkExec;
Jason Molenda42999a42012-02-22 02:18:59 +00001050#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001051 else if (strcasestr(optarg, "spring") == optarg)
1052 g_launch_flavor = eLaunchFlavorSpringBoard;
1053#endif
1054 else
1055 {
1056 RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
1057 RNBLogSTDERR ("Valid values TYPE are:\n");
1058 RNBLogSTDERR (" auto Auto-detect the best launch method to use.\n");
1059 RNBLogSTDERR (" posix Launch the executable using posix_spawn.\n");
1060 RNBLogSTDERR (" fork Launch the executable using fork and exec.\n");
Jason Molenda42999a42012-02-22 02:18:59 +00001061#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001062 RNBLogSTDERR (" spring Launch the executable through Springboard.\n");
1063#endif
1064 exit (5);
1065 }
1066 }
1067 break;
1068
1069 case 'l': // Set Log File
1070 if (optarg && optarg[0])
1071 {
1072 if (strcasecmp(optarg, "stdout") == 0)
1073 log_file = stdout;
1074 else if (strcasecmp(optarg, "stderr") == 0)
1075 log_file = stderr;
1076 else
Jim Inghamc530be62011-01-24 03:46:59 +00001077 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001078 log_file = fopen(optarg, "w");
Jim Inghamc530be62011-01-24 03:46:59 +00001079 if (log_file != NULL)
1080 setlinebuf(log_file);
1081 }
1082
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001083 if (log_file == NULL)
1084 {
1085 const char *errno_str = strerror(errno);
1086 RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
1087 }
1088 }
1089 break;
1090
1091 case 'f': // Log Flags
1092 if (optarg && optarg[0])
1093 log_flags = strtoul(optarg, NULL, 0);
1094 break;
1095
1096 case 'g':
1097 debug = 1;
Johnny Chen2fe7dd42011-08-10 23:01:39 +00001098 DNBLogSetDebug(debug);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001099 break;
1100
1101 case 't':
1102 g_applist_opt = 1;
1103 break;
1104
1105 case 'k':
1106 g_lockdown_opt = 1;
1107 break;
1108
1109 case 'r':
Greg Clayton85480022013-11-09 00:33:46 +00001110 // Do nothing, native regs is the default these days
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001111 break;
1112
Greg Clayton00fe87b2013-12-05 22:58:22 +00001113 case 'R':
1114 reverse_connect = true;
1115 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001116 case 'v':
1117 DNBLogSetVerbose(1);
1118 break;
1119
1120 case 's':
Greg Clayton71337622011-02-24 22:24:29 +00001121 ctx.GetSTDIN().assign(optarg);
1122 ctx.GetSTDOUT().assign(optarg);
1123 ctx.GetSTDERR().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001124 break;
1125
1126 case 'I':
Greg Clayton71337622011-02-24 22:24:29 +00001127 ctx.GetSTDIN().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001128 break;
1129
1130 case 'O':
Greg Clayton71337622011-02-24 22:24:29 +00001131 ctx.GetSTDOUT().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001132 break;
1133
1134 case 'E':
Greg Clayton71337622011-02-24 22:24:29 +00001135 ctx.GetSTDERR().assign(optarg);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001136 break;
1137
Caroline Ticef8da8632010-12-03 18:46:09 +00001138 case 'n':
1139 no_stdio = true;
1140 break;
1141
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001142 case 'S':
1143 // Put debugserver into a new session. Terminals group processes
1144 // into sessions and when a special terminal key sequences
1145 // (like control+c) are typed they can cause signals to go out to
1146 // all processes in a session. Using this --setsid (-S) option
1147 // will cause debugserver to run in its own sessions and be free
1148 // from such issues.
1149 //
1150 // This is useful when debugserver is spawned from a command
1151 // line application that uses debugserver to do the debugging,
1152 // yet that application doesn't want debugserver receiving the
1153 // signals sent to the session (i.e. dying when anyone hits ^C).
1154 setsid();
1155 break;
Greg Claytonf681b942010-08-31 18:35:14 +00001156 case 'D':
1157 g_disable_aslr = 1;
1158 break;
Greg Clayton7a5388b2011-03-20 04:57:14 +00001159
1160 case 'p':
1161 start_mode = eRNBRunLoopModePlatformMode;
1162 break;
Greg Clayton8b82f082011-04-12 05:54:46 +00001163
Greg Claytonc93068b2013-12-10 19:36:45 +00001164 case 'u':
1165 unix_socket_name.assign (optarg);
1166 break;
1167
Greg Clayton91a9b2472013-12-04 19:19:12 +00001168 case 'P':
1169 named_pipe_path.assign (optarg);
Greg Clayton8b82f082011-04-12 05:54:46 +00001170 break;
Greg Claytonc93068b2013-12-10 19:36:45 +00001171
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001172 }
1173 }
Greg Clayton3af9ea52010-11-18 05:57:03 +00001174
1175 if (arch_name.empty())
1176 {
Greg Clayton71337622011-02-24 22:24:29 +00001177#if defined (__arm__)
Greg Clayton3af9ea52010-11-18 05:57:03 +00001178 arch_name.assign ("arm");
1179#endif
1180 }
Greg Clayton3c144382010-12-01 22:45:40 +00001181 else
1182 {
1183 DNBSetArchitecture (arch_name.c_str());
1184 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001185
Greg Clayton71337622011-02-24 22:24:29 +00001186// if (arch_name.empty())
1187// {
1188// fprintf(stderr, "error: no architecture was specified\n");
1189// exit (8);
1190// }
Greg Claytonb7ad58a2013-04-04 20:35:24 +00001191 // Skip any options we consumed with getopt_long_only
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001192 argc -= optind;
1193 argv += optind;
1194
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001195
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001196 if (!working_dir.empty())
Greg Clayton6779606a2011-01-22 23:43:18 +00001197 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001198 if (remote->Context().SetWorkingDirectory (working_dir.c_str()) == false)
Greg Clayton6779606a2011-01-22 23:43:18 +00001199 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001200 RNBLogSTDERR ("error: working directory doesn't exist '%s'.\n", working_dir.c_str());
Greg Clayton6779606a2011-01-22 23:43:18 +00001201 exit (8);
1202 }
1203 }
1204
Jim Ingham58813182014-02-25 04:53:13 +00001205 remote->Context().SetDetachOnError(g_detach_on_error);
1206
Greg Clayton6779606a2011-01-22 23:43:18 +00001207 remote->Initialize();
Greg Clayton3af9ea52010-11-18 05:57:03 +00001208
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001209 // It is ok for us to set NULL as the logfile (this will disable any logging)
1210
1211 if (log_file != NULL)
1212 {
1213 DNBLogSetLogCallback(FileLogCallback, log_file);
1214 // If our log file was set, yet we have no log flags, log everything!
1215 if (log_flags == 0)
1216 log_flags = LOG_ALL | LOG_RNB_ALL;
1217
1218 DNBLogSetLogMask (log_flags);
1219 }
1220 else
1221 {
1222 // Enable DNB logging
1223 DNBLogSetLogCallback(ASLLogCallback, NULL);
1224 DNBLogSetLogMask (log_flags);
1225
1226 }
1227
1228 if (DNBLogEnabled())
1229 {
1230 for (i=0; i<argc; i++)
1231 DNBLogDebug("argv[%i] = %s", i, argv[i]);
1232 }
1233
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001234 // as long as we're dropping remotenub in as a replacement for gdbserver,
1235 // explicitly note that this is not gdbserver.
1236
1237 RNBLogSTDOUT ("%s-%g %sfor %s.\n",
1238 DEBUGSERVER_PROGRAM_NAME,
1239 DEBUGSERVER_VERSION_NUM,
1240 compile_options.c_str(),
1241 RNB_ARCH);
1242
Greg Clayton00fe87b2013-12-05 22:58:22 +00001243 std::string host;
1244 int port = INT32_MAX;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001245 char str[PATH_MAX];
Greg Clayton23f59502012-07-17 03:23:13 +00001246 str[0] = '\0';
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001247
1248 if (g_lockdown_opt == 0 && g_applist_opt == 0)
1249 {
1250 // Make sure we at least have port
1251 if (argc < 1)
1252 {
1253 show_usage_and_exit (1);
1254 }
1255 // accept 'localhost:' prefix on port number
1256
Greg Clayton00fe87b2013-12-05 22:58:22 +00001257 int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &port);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001258 if (items_scanned == 2)
1259 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001260 host = str;
1261 DNBLogDebug("host = '%s' port = %i", host.c_str(), port);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001262 }
1263 else
1264 {
Greg Claytonfd238892013-06-06 22:44:19 +00001265 // No hostname means "localhost"
Greg Clayton00fe87b2013-12-05 22:58:22 +00001266 int items_scanned = ::sscanf (argv[0], "%i", &port);
Greg Claytonfd238892013-06-06 22:44:19 +00001267 if (items_scanned == 1)
1268 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001269 host = "localhost";
1270 DNBLogDebug("host = '%s' port = %i", host.c_str(), port);
Greg Claytonfd238892013-06-06 22:44:19 +00001271 }
1272 else if (argv[0][0] == '/')
1273 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001274 port = INT32_MAX;
Greg Claytonfd238892013-06-06 22:44:19 +00001275 strncpy(str, argv[0], sizeof(str));
1276 }
1277 else
1278 {
1279 show_usage_and_exit (2);
1280 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001281 }
1282
1283 // We just used the 'host:port' or the '/path/file' arg...
1284 argc--;
1285 argv++;
1286
1287 }
1288
1289 // If we know we're waiting to attach, we don't need any of this other info.
Greg Clayton7a5388b2011-03-20 04:57:14 +00001290 if (start_mode != eRNBRunLoopModeInferiorAttaching &&
1291 start_mode != eRNBRunLoopModePlatformMode)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001292 {
1293 if (argc == 0 || g_lockdown_opt)
1294 {
1295 if (g_lockdown_opt != 0)
1296 {
1297 // Work around for SIGPIPE crashes due to posix_spawn issue.
1298 // We have to close STDOUT and STDERR, else the first time we
1299 // try and do any, we get SIGPIPE and die as posix_spawn is
1300 // doing bad things with our file descriptors at the moment.
1301 int null = open("/dev/null", O_RDWR);
1302 dup2(null, STDOUT_FILENO);
1303 dup2(null, STDERR_FILENO);
1304 }
1305 else if (g_applist_opt != 0)
1306 {
1307 // List all applications we are able to see
1308 std::string applist_plist;
1309 int err = ListApplications(applist_plist, false, false);
1310 if (err == 0)
1311 {
1312 fputs (applist_plist.c_str(), stdout);
1313 }
1314 else
1315 {
1316 RNBLogSTDERR ("error: ListApplications returned error %i\n", err);
1317 }
1318 // Exit with appropriate error if we were asked to list the applications
1319 // with no other args were given (and we weren't trying to do this over
1320 // lockdown)
1321 return err;
1322 }
1323
1324 DNBLogDebug("Get args from remote protocol...");
1325 start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
1326 }
1327 else
1328 {
1329 start_mode = eRNBRunLoopModeInferiorLaunching;
1330 // Fill in the argv array in the context from the rest of our args.
1331 // Skip the name of this executable and the port number
1332 for (int i = 0; i < argc; i++)
1333 {
1334 DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]);
1335 ctx.PushArgument (argv[i]);
1336 }
1337 }
1338 }
1339
1340 if (start_mode == eRNBRunLoopModeExit)
1341 return -1;
1342
1343 RNBRunLoopMode mode = start_mode;
1344 char err_str[1024] = {'\0'};
1345
1346 while (mode != eRNBRunLoopModeExit)
1347 {
1348 switch (mode)
1349 {
1350 case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
Jason Molenda42999a42012-02-22 02:18:59 +00001351#ifdef WITH_LOCKDOWN
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001352 if (g_lockdown_opt)
1353 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001354 if (!remote->Comm().IsConnected())
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001355 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001356 if (remote->Comm().ConnectToService () != rnb_success)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001357 {
1358 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
1359 mode = eRNBRunLoopModeExit;
1360 }
1361 else if (g_applist_opt != 0)
1362 {
1363 // List all applications we are able to see
1364 std::string applist_plist;
1365 if (ListApplications(applist_plist, false, false) == 0)
1366 {
1367 DNBLogDebug("Task list: %s", applist_plist.c_str());
1368
Greg Clayton6779606a2011-01-22 23:43:18 +00001369 remote->Comm().Write(applist_plist.c_str(), applist_plist.size());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001370 // Issue a read that will never yield any data until the other side
1371 // closes the socket so this process doesn't just exit and cause the
1372 // socket to close prematurely on the other end and cause data loss.
1373 std::string buf;
Greg Clayton6779606a2011-01-22 23:43:18 +00001374 remote->Comm().Read(buf);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001375 }
Greg Clayton6779606a2011-01-22 23:43:18 +00001376 remote->Comm().Disconnect(false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001377 mode = eRNBRunLoopModeExit;
1378 break;
1379 }
1380 else
1381 {
1382 // Start watching for remote packets
Greg Clayton6779606a2011-01-22 23:43:18 +00001383 remote->StartReadRemoteDataThread();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001384 }
1385 }
1386 }
1387 else
1388#endif
Greg Clayton00fe87b2013-12-05 22:58:22 +00001389 if (port != INT32_MAX)
Greg Clayton7a5388b2011-03-20 04:57:14 +00001390 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001391 if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str()))
Greg Clayton7a5388b2011-03-20 04:57:14 +00001392 mode = eRNBRunLoopModeExit;
1393 }
1394 else if (str[0] == '/')
1395 {
1396 if (remote->Comm().OpenFile (str))
1397 mode = eRNBRunLoopModeExit;
1398 }
1399
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001400 if (mode != eRNBRunLoopModeExit)
1401 {
1402 RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
1403
Greg Clayton6779606a2011-01-22 23:43:18 +00001404 mode = RNBRunLoopGetStartModeFromRemote (remote);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001405 }
1406 break;
1407
1408 case eRNBRunLoopModeInferiorAttaching:
1409 if (!waitfor_pid_name.empty())
1410 {
1411 // Set our end wait time if we are using a waitfor-duration
1412 // option that may have been specified
1413 struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1414 if (waitfor_duration != 0)
1415 {
1416 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1417 timeout_ptr = &attach_timeout_abstime;
1418 }
1419 nub_launch_flavor_t launch_flavor = g_launch_flavor;
1420 if (launch_flavor == eLaunchFlavorDefault)
1421 {
1422 // Our default launch method is posix spawn
1423 launch_flavor = eLaunchFlavorPosixSpawn;
1424
Jason Molenda42999a42012-02-22 02:18:59 +00001425#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001426 // Check if we have an app bundle, if so launch using SpringBoard.
1427 if (waitfor_pid_name.find (".app") != std::string::npos)
1428 {
1429 launch_flavor = eLaunchFlavorSpringBoard;
1430 }
1431#endif
1432 }
1433
1434 ctx.SetLaunchFlavor(launch_flavor);
Jim Inghamcd16df92012-07-20 21:37:13 +00001435 bool ignore_existing = false;
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001436 RNBLogSTDOUT ("Waiting to attach to process %s...\n", waitfor_pid_name.c_str());
Jim Inghamcd16df92012-07-20 21:37:13 +00001437 nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, ignore_existing, timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001438 g_pid = pid;
1439
1440 if (pid == INVALID_NUB_PROCESS)
1441 {
1442 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1443 if (err_str[0])
1444 ctx.LaunchStatus().SetErrorString(err_str);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001445 RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s\n", waitfor_pid_name.c_str(), err_str);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001446 mode = eRNBRunLoopModeExit;
1447 }
1448 else
1449 {
1450 ctx.SetProcessID(pid);
1451 mode = eRNBRunLoopModeInferiorExecuting;
1452 }
1453 }
1454 else if (attach_pid != INVALID_NUB_PROCESS)
1455 {
1456
1457 RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid);
1458 nub_process_t attached_pid;
Greg Clayton6779606a2011-01-22 23:43:18 +00001459 mode = RNBRunLoopLaunchAttaching (remote, attach_pid, attached_pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001460 if (mode != eRNBRunLoopModeInferiorExecuting)
1461 {
1462 const char *error_str = remote->Context().LaunchStatus().AsString();
1463 RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
1464 mode = eRNBRunLoopModeExit;
1465 }
1466 }
1467 else if (!attach_pid_name.empty ())
1468 {
1469 struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1470 if (waitfor_duration != 0)
1471 {
1472 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1473 timeout_ptr = &attach_timeout_abstime;
1474 }
1475
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001476 RNBLogSTDOUT ("Attaching to process %s...\n", attach_pid_name.c_str());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001477 nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str));
1478 g_pid = pid;
1479 if (pid == INVALID_NUB_PROCESS)
1480 {
1481 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1482 if (err_str[0])
1483 ctx.LaunchStatus().SetErrorString(err_str);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001484 RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s\n", waitfor_pid_name.c_str(), err_str);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001485 mode = eRNBRunLoopModeExit;
1486 }
1487 else
1488 {
1489 ctx.SetProcessID(pid);
1490 mode = eRNBRunLoopModeInferiorExecuting;
1491 }
1492
1493 }
1494 else
1495 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001496 RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001497 mode = eRNBRunLoopModeExit;
1498 }
1499
1500 if (mode != eRNBRunLoopModeExit)
1501 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001502 if (port != INT32_MAX)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001503 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001504 if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str()))
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001505 mode = eRNBRunLoopModeExit;
1506 }
1507 else if (str[0] == '/')
1508 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001509 if (remote->Comm().OpenFile (str))
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001510 mode = eRNBRunLoopModeExit;
1511 }
1512 if (mode != eRNBRunLoopModeExit)
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001513 RNBLogSTDOUT ("Waiting for debugger instructions for process %d.\n", attach_pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001514 }
1515 break;
1516
1517 case eRNBRunLoopModeInferiorLaunching:
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001518 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001519 mode = RNBRunLoopLaunchInferior (remote,
Greg Clayton71337622011-02-24 22:24:29 +00001520 ctx.GetSTDINPath(),
1521 ctx.GetSTDOUTPath(),
1522 ctx.GetSTDERRPath(),
Greg Clayton6779606a2011-01-22 23:43:18 +00001523 no_stdio);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001524
Greg Clayton6779606a2011-01-22 23:43:18 +00001525 if (mode == eRNBRunLoopModeInferiorExecuting)
1526 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001527 if (port != INT32_MAX)
Greg Clayton6779606a2011-01-22 23:43:18 +00001528 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001529 if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str()))
Greg Clayton6779606a2011-01-22 23:43:18 +00001530 mode = eRNBRunLoopModeExit;
1531 }
1532 else if (str[0] == '/')
1533 {
1534 if (remote->Comm().OpenFile (str))
1535 mode = eRNBRunLoopModeExit;
1536 }
1537
1538 if (mode != eRNBRunLoopModeExit)
Jim Ingham5689a212014-02-25 19:57:47 +00001539 {
1540 const char *proc_name = "<unknown>";
1541 if (ctx.ArgumentCount() > 0)
1542 proc_name = ctx.ArgumentAtIndex(0);
1543 RNBLogSTDOUT ("Got a connection, launched process %s (pid = %d).\n", proc_name, ctx.ProcessID());
1544 }
Greg Clayton6779606a2011-01-22 23:43:18 +00001545 }
1546 else
1547 {
1548 const char *error_str = remote->Context().LaunchStatus().AsString();
Jason Molenda0b2dbe02012-11-01 02:02:59 +00001549 RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv_sub_zero, error_str ? error_str : "unknown error.");
Greg Clayton6779606a2011-01-22 23:43:18 +00001550 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001551 }
1552 break;
1553
1554 case eRNBRunLoopModeInferiorExecuting:
Greg Clayton6779606a2011-01-22 23:43:18 +00001555 mode = RNBRunLoopInferiorExecuting(remote);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001556 break;
1557
Greg Clayton7a5388b2011-03-20 04:57:14 +00001558 case eRNBRunLoopModePlatformMode:
Greg Clayton00fe87b2013-12-05 22:58:22 +00001559 if (port != INT32_MAX)
Greg Clayton7a5388b2011-03-20 04:57:14 +00001560 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001561 if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str()))
Greg Clayton7a5388b2011-03-20 04:57:14 +00001562 mode = eRNBRunLoopModeExit;
1563 }
1564 else if (str[0] == '/')
1565 {
1566 if (remote->Comm().OpenFile (str))
1567 mode = eRNBRunLoopModeExit;
1568 }
1569
1570 if (mode != eRNBRunLoopModeExit)
1571 mode = RNBRunLoopPlatform (remote);
1572 break;
1573
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001574 default:
1575 mode = eRNBRunLoopModeExit;
1576 case eRNBRunLoopModeExit:
1577 break;
1578 }
1579 }
1580
Greg Clayton6779606a2011-01-22 23:43:18 +00001581 remote->StopReadRemoteDataThread ();
1582 remote->Context().SetProcessID(INVALID_NUB_PROCESS);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001583 RNBLogSTDOUT ("Exiting.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001584
1585 return 0;
1586}