blob: c46d63d8b4279666844ef3eeb1fb8852f2239af1 [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>
Greg Claytonce1843b2014-06-18 18:26:50 +000026#include <crt_externs.h> // for _NSGetEnviron()
Chris Lattner30fdc8d2010-06-08 16:52:24 +000027
Jason Molenda36a216e2014-07-24 01:36:24 +000028#if defined (__APPLE__)
29#include <sched.h>
30#endif
31
Chris Lattner30fdc8d2010-06-08 16:52:24 +000032#include "CFString.h"
33#include "DNB.h"
34#include "DNBLog.h"
35#include "DNBTimer.h"
36#include "PseudoTerminal.h"
37#include "RNBContext.h"
38#include "RNBServices.h"
39#include "RNBSocket.h"
40#include "RNBRemote.h"
41#include "SysSignal.h"
42
43// Global PID in case we get a signal and need to stop the process...
44nub_process_t g_pid = INVALID_NUB_PROCESS;
45
46//----------------------------------------------------------------------
47// Run loop modes which determine which run loop function will be called
48//----------------------------------------------------------------------
49typedef enum
50{
51 eRNBRunLoopModeInvalid = 0,
52 eRNBRunLoopModeGetStartModeFromRemoteProtocol,
53 eRNBRunLoopModeInferiorAttaching,
54 eRNBRunLoopModeInferiorLaunching,
55 eRNBRunLoopModeInferiorExecuting,
Greg Clayton7a5388b2011-03-20 04:57:14 +000056 eRNBRunLoopModePlatformMode,
Chris Lattner30fdc8d2010-06-08 16:52:24 +000057 eRNBRunLoopModeExit
58} RNBRunLoopMode;
59
60
61//----------------------------------------------------------------------
62// Global Variables
63//----------------------------------------------------------------------
64RNBRemoteSP g_remoteSP;
65static int g_lockdown_opt = 0;
66static int g_applist_opt = 0;
67static nub_launch_flavor_t g_launch_flavor = eLaunchFlavorDefault;
Greg Clayton6f35f5c2010-09-09 06:32:46 +000068int g_disable_aslr = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000069
70int g_isatty = 0;
Jim Ingham5689a212014-02-25 19:57:47 +000071bool g_detach_on_error = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000072
73#define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
74#define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
75
76//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +000077// Get our program path and arguments from the remote connection.
78// We will need to start up the remote connection without a PID, get the
79// arguments, wait for the new process to finish launching and hit its
80// entry point, and then return the run loop mode that should come next.
81//----------------------------------------------------------------------
82RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +000083RNBRunLoopGetStartModeFromRemote (RNBRemote* remote)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000084{
85 std::string packet;
86
Greg Clayton6779606a2011-01-22 23:43:18 +000087 if (remote)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000088 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +000089 RNBContext& ctx = remote->Context();
Greg Clayton71337622011-02-24 22:24:29 +000090 uint32_t event_mask = RNBContext::event_read_packet_available |
91 RNBContext::event_read_thread_exiting;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000092
93 // Spin waiting to get the A packet.
94 while (1)
95 {
96 DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask);
97 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
98 DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events);
99
Greg Clayton71337622011-02-24 22:24:29 +0000100 if (set_events & RNBContext::event_read_thread_exiting)
101 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000102 RNBLogSTDERR ("error: packet read thread exited.\n");
Greg Clayton71337622011-02-24 22:24:29 +0000103 return eRNBRunLoopModeExit;
104 }
105
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000106 if (set_events & RNBContext::event_read_packet_available)
107 {
108 rnb_err_t err = rnb_err;
109 RNBRemote::PacketEnum type;
110
111 err = remote->HandleReceivedPacket (&type);
112
113 // check if we tried to attach to a process
Jim Inghamcd16df92012-07-20 21:37:13 +0000114 if (type == RNBRemote::vattach || type == RNBRemote::vattachwait || type == RNBRemote::vattachorwait)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000115 {
116 if (err == rnb_success)
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000117 {
118 RNBLogSTDOUT ("Attach succeeded, ready to debug.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000119 return eRNBRunLoopModeInferiorExecuting;
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000120 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000121 else
122 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000123 RNBLogSTDERR ("error: attach failed.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000124 return eRNBRunLoopModeExit;
125 }
126 }
127
128 if (err == rnb_success)
129 {
130 // If we got our arguments we are ready to launch using the arguments
131 // and any environment variables we received.
132 if (type == RNBRemote::set_argv)
133 {
134 return eRNBRunLoopModeInferiorLaunching;
135 }
136 }
137 else if (err == rnb_not_connected)
138 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000139 RNBLogSTDERR ("error: connection lost.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000140 return eRNBRunLoopModeExit;
141 }
142 else
143 {
144 // a catch all for any other gdb remote packets that failed
145 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__);
146 continue;
147 }
148
149 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
150 }
151 else
152 {
153 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__);
154 return eRNBRunLoopModeExit;
155 }
156 }
157 }
158 return eRNBRunLoopModeExit;
159}
160
161
162//----------------------------------------------------------------------
163// This run loop mode will wait for the process to launch and hit its
164// entry point. It will currently ignore all events except for the
165// process state changed event, where it watches for the process stopped
166// or crash process state.
167//----------------------------------------------------------------------
168RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000169RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char *stdout_path, const char *stderr_path, bool no_stdio)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000170{
171 RNBContext& ctx = remote->Context();
172
173 // The Process stuff takes a c array, the RNBContext has a vector...
174 // So make up a c array.
175
176 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, ctx.ArgumentAtIndex(0));
177
178 size_t inferior_argc = ctx.ArgumentCount();
179 // Initialize inferior_argv with inferior_argc + 1 NULLs
180 std::vector<const char *> inferior_argv(inferior_argc + 1, NULL);
181
182 size_t i;
183 for (i = 0; i < inferior_argc; i++)
184 inferior_argv[i] = ctx.ArgumentAtIndex(i);
185
186 // Pass the environment array the same way:
187
188 size_t inferior_envc = ctx.EnvironmentCount();
189 // Initialize inferior_argv with inferior_argc + 1 NULLs
190 std::vector<const char *> inferior_envp(inferior_envc + 1, NULL);
191
192 for (i = 0; i < inferior_envc; i++)
193 inferior_envp[i] = ctx.EnvironmentAtIndex(i);
194
195 // Our launch type hasn't been set to anything concrete, so we need to
196 // figure our how we are going to launch automatically.
197
198 nub_launch_flavor_t launch_flavor = g_launch_flavor;
199 if (launch_flavor == eLaunchFlavorDefault)
200 {
201 // Our default launch method is posix spawn
202 launch_flavor = eLaunchFlavorPosixSpawn;
203
Jason Molendaa3329782014-03-29 18:54:20 +0000204#if defined WITH_BKS
205 // Check if we have an app bundle, if so launch using BackBoard Services.
206 if (strstr(inferior_argv[0], ".app"))
207 {
208 launch_flavor = eLaunchFlavorBKS;
209 }
210#elif defined WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000211 // Check if we have an app bundle, if so launch using SpringBoard.
212 if (strstr(inferior_argv[0], ".app"))
213 {
214 launch_flavor = eLaunchFlavorSpringBoard;
215 }
216#endif
217 }
218
219 ctx.SetLaunchFlavor(launch_flavor);
220 char resolved_path[PATH_MAX];
221
222 // If we fail to resolve the path to our executable, then just use what we
223 // were given and hope for the best
224 if ( !DNBResolveExecutablePath (inferior_argv[0], resolved_path, sizeof(resolved_path)) )
225 ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path));
226
227 char launch_err_str[PATH_MAX];
228 launch_err_str[0] = '\0';
Johnny Chen725269a2011-02-26 01:36:13 +0000229 const char * cwd = (ctx.GetWorkingDirPath() != NULL ? ctx.GetWorkingDirPath()
230 : ctx.GetWorkingDirectory());
Jason Molendaa3329782014-03-29 18:54:20 +0000231 const char *process_event = ctx.GetProcessEvent();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000232 nub_process_t pid = DNBProcessLaunch (resolved_path,
233 &inferior_argv[0],
234 &inferior_envp[0],
Johnny Chen725269a2011-02-26 01:36:13 +0000235 cwd,
Greg Clayton6779606a2011-01-22 23:43:18 +0000236 stdin_path,
237 stdout_path,
238 stderr_path,
Caroline Ticef8da8632010-12-03 18:46:09 +0000239 no_stdio,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000240 launch_flavor,
Greg Claytonf681b942010-08-31 18:35:14 +0000241 g_disable_aslr,
Jason Molendaa3329782014-03-29 18:54:20 +0000242 process_event,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000243 launch_err_str,
244 sizeof(launch_err_str));
245
246 g_pid = pid;
247
Jason Molenda4e0c94b2011-07-08 00:00:32 +0000248 if (pid == INVALID_NUB_PROCESS && strlen (launch_err_str) > 0)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000249 {
Greg Clayton3382c2c2010-07-30 23:14:42 +0000250 DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, launch_err_str);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000251 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
252 ctx.LaunchStatus().SetErrorString(launch_err_str);
253 }
Jason Molenda4e0c94b2011-07-08 00:00:32 +0000254 else if (pid == INVALID_NUB_PROCESS)
255 {
256 DNBLogThreaded ("%s DNBProcessLaunch() failed to launch process, unknown failure", __FUNCTION__);
257 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
258 ctx.LaunchStatus().SetErrorString(launch_err_str);
259 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000260 else
Greg Clayton71337622011-02-24 22:24:29 +0000261 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000262 ctx.LaunchStatus().Clear();
Greg Clayton71337622011-02-24 22:24:29 +0000263 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000264
265 if (remote->Comm().IsConnected())
266 {
267 // It we are connected already, the next thing gdb will do is ask
268 // whether the launch succeeded, and if not, whether there is an
269 // error code. So we need to fetch one packet from gdb before we wait
270 // on the stop from the target.
271
272 uint32_t event_mask = RNBContext::event_read_packet_available;
273 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
274
275 if (set_events & RNBContext::event_read_packet_available)
276 {
277 rnb_err_t err = rnb_err;
278 RNBRemote::PacketEnum type;
279
280 err = remote->HandleReceivedPacket (&type);
281
282 if (err != rnb_success)
283 {
284 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__);
285 return eRNBRunLoopModeExit;
286 }
287 if (type != RNBRemote::query_launch_success)
288 {
289 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__);
290 }
291 }
292 }
293
294 while (pid != INVALID_NUB_PROCESS)
295 {
296 // Wait for process to start up and hit entry point
297 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid);
298 nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL);
299 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events);
300
301 if (set_events == 0)
302 {
303 pid = INVALID_NUB_PROCESS;
304 g_pid = pid;
305 }
306 else
307 {
308 if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
309 {
310 nub_state_t pid_state = DNBProcessGetState (pid);
311 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
312
313 switch (pid_state)
314 {
315 default:
316 case eStateInvalid:
317 case eStateUnloaded:
318 case eStateAttaching:
319 case eStateLaunching:
320 case eStateSuspended:
321 break; // Ignore
322
323 case eStateRunning:
324 case eStateStepping:
325 // Still waiting to stop at entry point...
326 break;
327
328 case eStateStopped:
329 case eStateCrashed:
330 ctx.SetProcessID(pid);
331 return eRNBRunLoopModeInferiorExecuting;
332
333 case eStateDetached:
334 case eStateExited:
335 pid = INVALID_NUB_PROCESS;
336 g_pid = pid;
337 return eRNBRunLoopModeExit;
338 }
339 }
340
341 DNBProcessResetEvents(pid, set_events);
342 }
343 }
344
345 return eRNBRunLoopModeExit;
346}
347
348
349//----------------------------------------------------------------------
350// This run loop mode will wait for the process to launch and hit its
351// entry point. It will currently ignore all events except for the
352// process state changed event, where it watches for the process stopped
353// or crash process state.
354//----------------------------------------------------------------------
355RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000356RNBRunLoopLaunchAttaching (RNBRemote *remote, nub_process_t attach_pid, nub_process_t& pid)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000357{
358 RNBContext& ctx = remote->Context();
359
360 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid);
361 char err_str[1024];
362 pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str));
363 g_pid = pid;
364
365 if (pid == INVALID_NUB_PROCESS)
366 {
367 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
368 if (err_str[0])
369 ctx.LaunchStatus().SetErrorString(err_str);
370 return eRNBRunLoopModeExit;
371 }
372 else
373 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000374 ctx.SetProcessID(pid);
375 return eRNBRunLoopModeInferiorExecuting;
376 }
377}
378
379//----------------------------------------------------------------------
380// Watch for signals:
381// SIGINT: so we can halt our inferior. (disabled for now)
382// SIGPIPE: in case our child process dies
383//----------------------------------------------------------------------
384int g_sigint_received = 0;
385int g_sigpipe_received = 0;
386void
387signal_handler(int signo)
388{
389 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo));
390
391 switch (signo)
392 {
393 case SIGINT:
394 g_sigint_received++;
395 if (g_pid != INVALID_NUB_PROCESS)
396 {
397 // Only send a SIGINT once...
398 if (g_sigint_received == 1)
399 {
400 switch (DNBProcessGetState (g_pid))
401 {
402 case eStateRunning:
403 case eStateStepping:
404 DNBProcessSignal (g_pid, SIGSTOP);
405 return;
Greg Clayton95bf0fd2011-04-01 00:29:43 +0000406 default:
407 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000408 }
409 }
410 }
411 exit (SIGINT);
412 break;
413
414 case SIGPIPE:
415 g_sigpipe_received = 1;
416 break;
417 }
418}
419
420// Return the new run loop mode based off of the current process state
421RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000422HandleProcessStateChange (RNBRemote *remote, bool initialize)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000423{
424 RNBContext& ctx = remote->Context();
425 nub_process_t pid = ctx.ProcessID();
426
427 if (pid == INVALID_NUB_PROCESS)
428 {
429 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
430 return eRNBRunLoopModeExit;
431 }
432 nub_state_t pid_state = DNBProcessGetState (pid);
433
434 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state));
435
436 switch (pid_state)
437 {
438 case eStateInvalid:
439 case eStateUnloaded:
440 // Something bad happened
441 return eRNBRunLoopModeExit;
442 break;
443
444 case eStateAttaching:
445 case eStateLaunching:
446 return eRNBRunLoopModeInferiorExecuting;
447
448 case eStateSuspended:
449 case eStateCrashed:
450 case eStateStopped:
451 // If we stop due to a signal, so clear the fact that we got a SIGINT
452 // so we can stop ourselves again (but only while our inferior
453 // process is running..)
454 g_sigint_received = 0;
455 if (initialize == false)
456 {
457 // Compare the last stop count to our current notion of a stop count
458 // to make sure we don't notify more than once for a given stop.
459 nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
460 bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid));
461 if (pid_stop_count_changed)
462 {
463 remote->FlushSTDIO();
464
465 if (ctx.GetProcessStopCount() == 1)
466 {
Greg Clayton43e0af02012-09-18 18:04:04 +0000467 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 +0000468 }
469 else
470 {
471
Greg Clayton43e0af02012-09-18 18:04:04 +0000472 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 +0000473 remote->NotifyThatProcessStopped ();
474 }
475 }
476 else
477 {
Greg Clayton43e0af02012-09-18 18:04:04 +0000478 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 +0000479 }
480 }
481 return eRNBRunLoopModeInferiorExecuting;
482
483 case eStateStepping:
484 case eStateRunning:
485 return eRNBRunLoopModeInferiorExecuting;
486
487 case eStateExited:
488 remote->HandlePacket_last_signal(NULL);
Greg Clayton95bf0fd2011-04-01 00:29:43 +0000489 case eStateDetached:
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000490 return eRNBRunLoopModeExit;
491
492 }
493
494 // Catch all...
495 return eRNBRunLoopModeExit;
496}
497// This function handles the case where our inferior program is stopped and
498// we are waiting for gdb remote protocol packets. When a packet occurs that
499// makes the inferior run, we need to leave this function with a new state
500// as the return code.
501RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000502RNBRunLoopInferiorExecuting (RNBRemote *remote)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000503{
504 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
505 RNBContext& ctx = remote->Context();
506
507 // Init our mode and set 'is_running' based on the current process state
508 RNBRunLoopMode mode = HandleProcessStateChange (remote, true);
509
510 while (ctx.ProcessID() != INVALID_NUB_PROCESS)
511 {
512
513 std::string set_events_str;
514 uint32_t event_mask = ctx.NormalEventBits();
515
516 if (!ctx.ProcessStateRunning())
517 {
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000518 // Clear some bits if we are not running so we don't send any async packets
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000519 event_mask &= ~RNBContext::event_proc_stdio_available;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000520 event_mask &= ~RNBContext::event_proc_profile_data;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000521 }
522
523 // We want to make sure we consume all process state changes and have
524 // whomever is notifying us to wait for us to reset the event bit before
525 // continuing.
526 //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
527
528 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
529 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
530 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));
531
532 if (set_events)
533 {
534 if ((set_events & RNBContext::event_proc_thread_exiting) ||
535 (set_events & RNBContext::event_proc_stdio_available))
536 {
537 remote->FlushSTDIO();
538 }
539
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000540 if (set_events & RNBContext::event_proc_profile_data)
541 {
542 remote->SendAsyncProfileData();
543 }
544
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000545 if (set_events & RNBContext::event_read_packet_available)
546 {
547 // handleReceivedPacket will take care of resetting the
548 // event_read_packet_available events when there are no more...
549 set_events ^= RNBContext::event_read_packet_available;
550
551 if (ctx.ProcessStateRunning())
552 {
553 if (remote->HandleAsyncPacket() == rnb_not_connected)
554 {
555 // TODO: connect again? Exit?
556 }
557 }
558 else
559 {
560 if (remote->HandleReceivedPacket() == rnb_not_connected)
561 {
562 // TODO: connect again? Exit?
563 }
564 }
565 }
566
567 if (set_events & RNBContext::event_proc_state_changed)
568 {
569 mode = HandleProcessStateChange (remote, false);
570 ctx.Events().ResetEvents(RNBContext::event_proc_state_changed);
571 set_events ^= RNBContext::event_proc_state_changed;
572 }
573
574 if (set_events & RNBContext::event_proc_thread_exiting)
575 {
576 mode = eRNBRunLoopModeExit;
577 }
578
579 if (set_events & RNBContext::event_read_thread_exiting)
580 {
581 // Out remote packet receiving thread exited, exit for now.
582 if (ctx.HasValidProcessID())
583 {
584 // TODO: We should add code that will leave the current process
585 // in its current state and listen for another connection...
586 if (ctx.ProcessStateRunning())
587 {
Jim Ingham58813182014-02-25 04:53:13 +0000588 if (ctx.GetDetachOnError())
589 {
590 DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process.");
591 DNBProcessDetach (ctx.ProcessID());
592 }
593 else
594 {
595 DNBLog ("debugserver's event read thread is exiting, killing the inferior process.");
596 DNBProcessKill (ctx.ProcessID());
597 }
598 }
599 else
600 {
601 if (ctx.GetDetachOnError())
602 {
603 DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process.");
604 DNBProcessDetach (ctx.ProcessID());
605 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000606 }
607 }
608 mode = eRNBRunLoopModeExit;
609 }
610 }
611
612 // Reset all event bits that weren't reset for now...
613 if (set_events != 0)
614 ctx.Events().ResetEvents(set_events);
615
616 if (mode != eRNBRunLoopModeInferiorExecuting)
617 break;
618 }
619
620 return mode;
621}
622
623
Greg Clayton7a5388b2011-03-20 04:57:14 +0000624RNBRunLoopMode
625RNBRunLoopPlatform (RNBRemote *remote)
626{
627 RNBRunLoopMode mode = eRNBRunLoopModePlatformMode;
628 RNBContext& ctx = remote->Context();
629
630 while (mode == eRNBRunLoopModePlatformMode)
631 {
632 std::string set_events_str;
633 const uint32_t event_mask = RNBContext::event_read_packet_available |
634 RNBContext::event_read_thread_exiting;
635
636 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
637 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
638 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));
639
640 if (set_events)
641 {
642 if (set_events & RNBContext::event_read_packet_available)
643 {
644 if (remote->HandleReceivedPacket() == rnb_not_connected)
645 mode = eRNBRunLoopModeExit;
646 }
647
648 if (set_events & RNBContext::event_read_thread_exiting)
649 {
650 mode = eRNBRunLoopModeExit;
651 }
652 ctx.Events().ResetEvents(set_events);
653 }
654 }
655 return eRNBRunLoopModeExit;
656}
657
Greg Claytonc93068b2013-12-10 19:36:45 +0000658//----------------------------------------------------------------------
659// Convenience function to set up the remote listening port
660// Returns 1 for success 0 for failure.
661//----------------------------------------------------------------------
662
663static void
664PortWasBoundCallbackUnixSocket (const void *baton, in_port_t port)
665{
666 //::printf ("PortWasBoundCallbackUnixSocket (baton = %p, port = %u)\n", baton, port);
667
668 const char *unix_socket_name = (const char *)baton;
669
670 if (unix_socket_name && unix_socket_name[0])
671 {
672 // We were given a unix socket name to use to communicate the port
673 // that we ended up binding to back to our parent process
674 struct sockaddr_un saddr_un;
675 int s = ::socket (AF_UNIX, SOCK_STREAM, 0);
676 if (s < 0)
677 {
678 perror("error: socket (AF_UNIX, SOCK_STREAM, 0)");
679 exit(1);
680 }
681
682 saddr_un.sun_family = AF_UNIX;
683 ::strncpy(saddr_un.sun_path, unix_socket_name, sizeof(saddr_un.sun_path) - 1);
684 saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
685 saddr_un.sun_len = SUN_LEN (&saddr_un);
686
687 if (::connect (s, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0)
688 {
689 perror("error: connect (socket, &saddr_un, saddr_un_len)");
690 exit(1);
691 }
692
693 //::printf ("connect () sucess!!\n");
694
695
696 // We were able to connect to the socket, now write our PID so whomever
697 // launched us will know this process's ID
698 RNBLogSTDOUT ("Listening to port %i...\n", port);
699
700 char pid_str[64];
701 const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%u", port);
702 const int bytes_sent = ::send (s, pid_str, pid_str_len, 0);
703
704 if (pid_str_len != bytes_sent)
705 {
706 perror("error: send (s, pid_str, pid_str_len, 0)");
707 exit (1);
708 }
709
710 //::printf ("send () sucess!!\n");
711
712 // We are done with the socket
713 close (s);
714 }
715}
716
Greg Clayton8b82f082011-04-12 05:54:46 +0000717static void
Greg Claytond6299802013-12-06 17:46:35 +0000718PortWasBoundCallbackNamedPipe (const void *baton, uint16_t port)
Greg Clayton8b82f082011-04-12 05:54:46 +0000719{
Greg Clayton91a9b2472013-12-04 19:19:12 +0000720 const char *named_pipe = (const char *)baton;
721 if (named_pipe && named_pipe[0])
Greg Clayton8b82f082011-04-12 05:54:46 +0000722 {
Greg Clayton91a9b2472013-12-04 19:19:12 +0000723 int fd = ::open(named_pipe, O_WRONLY);
724 if (fd > -1)
Greg Clayton8b82f082011-04-12 05:54:46 +0000725 {
Greg Clayton91a9b2472013-12-04 19:19:12 +0000726 char port_str[64];
727 const ssize_t port_str_len = ::snprintf (port_str, sizeof(port_str), "%u", port);
728 // Write the port number as a C string with the NULL terminator
729 ::write (fd, port_str, port_str_len + 1);
730 close (fd);
Greg Clayton8b82f082011-04-12 05:54:46 +0000731 }
Greg Clayton8b82f082011-04-12 05:54:46 +0000732 }
733}
734
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000735static int
Greg Claytonc93068b2013-12-10 19:36:45 +0000736ConnectRemote (RNBRemote *remote,
737 const char *host,
738 int port,
739 bool reverse_connect,
740 const char *named_pipe_path,
741 const char *unix_socket_name)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000742{
Greg Clayton6779606a2011-01-22 23:43:18 +0000743 if (!remote->Comm().IsConnected())
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000744 {
Greg Clayton00fe87b2013-12-05 22:58:22 +0000745 if (reverse_connect)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000746 {
Greg Clayton00fe87b2013-12-05 22:58:22 +0000747 if (port == 0)
748 {
749 DNBLogThreaded("error: invalid port supplied for reverse connection: %i.\n", port);
750 return 0;
751 }
752 if (remote->Comm().Connect(host, port) != rnb_success)
753 {
754 DNBLogThreaded("Failed to reverse connect to %s:%i.\n", host, port);
755 return 0;
756 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000757 }
758 else
759 {
Greg Clayton00fe87b2013-12-05 22:58:22 +0000760 if (port != 0)
Greg Clayton16810922014-02-27 19:38:18 +0000761 RNBLogSTDOUT ("Listening to port %i for a connection from %s...\n", port, host ? host : "127.0.0.1");
Greg Claytonc93068b2013-12-10 19:36:45 +0000762 if (unix_socket_name && unix_socket_name[0])
Greg Clayton00fe87b2013-12-05 22:58:22 +0000763 {
Greg Claytonc93068b2013-12-10 19:36:45 +0000764 if (remote->Comm().Listen(host, port, PortWasBoundCallbackUnixSocket, unix_socket_name) != rnb_success)
765 {
766 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
767 return 0;
768 }
769 }
770 else
771 {
772 if (remote->Comm().Listen(host, port, PortWasBoundCallbackNamedPipe, named_pipe_path) != rnb_success)
773 {
774 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
775 return 0;
776 }
Greg Clayton00fe87b2013-12-05 22:58:22 +0000777 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000778 }
Greg Clayton00fe87b2013-12-05 22:58:22 +0000779 remote->StartReadRemoteDataThread();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000780 }
781 return 1;
782}
783
784//----------------------------------------------------------------------
785// ASL Logging callback that can be registered with DNBLogSetLogCallback
786//----------------------------------------------------------------------
787void
788ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
789{
790 if (format == NULL)
791 return;
792 static aslmsg g_aslmsg = NULL;
793 if (g_aslmsg == NULL)
794 {
795 g_aslmsg = ::asl_new (ASL_TYPE_MSG);
796 char asl_key_sender[PATH_MAX];
Todd Fialac3ec3372014-03-13 18:30:04 +0000797 snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.%s-%s", DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_STR);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000798 ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
799 }
800
801 int asl_level;
802 if (flags & DNBLOG_FLAG_FATAL) asl_level = ASL_LEVEL_CRIT;
803 else if (flags & DNBLOG_FLAG_ERROR) asl_level = ASL_LEVEL_ERR;
804 else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING;
805 else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO;
806 else asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG;
807
808 ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
809}
810
811//----------------------------------------------------------------------
812// FILE based Logging callback that can be registered with
813// DNBLogSetLogCallback
814//----------------------------------------------------------------------
815void
816FileLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
817{
818 if (baton == NULL || format == NULL)
819 return;
820
821 ::vfprintf ((FILE *)baton, format, args);
822 ::fprintf ((FILE *)baton, "\n");
823}
824
825
826void
827show_usage_and_exit (int exit_code)
828{
829 RNBLogSTDERR ("Usage:\n %s host:port [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
830 RNBLogSTDERR (" %s /path/file [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
831 RNBLogSTDERR (" %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
832 RNBLogSTDERR (" %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
833 RNBLogSTDERR (" %s host:port --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
834 RNBLogSTDERR (" %s /path/file --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
835 exit (exit_code);
836}
837
838
839//----------------------------------------------------------------------
Greg Claytonb7ad58a2013-04-04 20:35:24 +0000840// option descriptors for getopt_long_only()
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000841//----------------------------------------------------------------------
842static struct option g_long_options[] =
843{
844 { "attach", required_argument, NULL, 'a' },
Greg Clayton3af9ea52010-11-18 05:57:03 +0000845 { "arch", required_argument, NULL, 'A' },
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000846 { "debug", no_argument, NULL, 'g' },
Jim Ingham5689a212014-02-25 19:57:47 +0000847 { "kill-on-error", no_argument, NULL, 'K' },
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000848 { "verbose", no_argument, NULL, 'v' },
849 { "lockdown", no_argument, &g_lockdown_opt, 1 }, // short option "-k"
850 { "applist", no_argument, &g_applist_opt, 1 }, // short option "-t"
851 { "log-file", required_argument, NULL, 'l' },
852 { "log-flags", required_argument, NULL, 'f' },
853 { "launch", required_argument, NULL, 'x' }, // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
854 { "waitfor", required_argument, NULL, 'w' }, // Wait for a process whose name starts with ARG
855 { "waitfor-interval", required_argument, NULL, 'i' }, // Time in usecs to wait between sampling the pid list when waiting for a process by name
856 { "waitfor-duration", required_argument, NULL, 'd' }, // The time in seconds to wait for a process to show up by name
857 { "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 +0000858 { "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)
859 { "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 +0000860 { "stdout-path", required_argument, NULL, 'O' }, // Set the STDOUT path to be used when launching applications (only if debugserver launches the process)
861 { "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 +0000862 { "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)
863 { "setsid", no_argument, NULL, 'S' }, // call setsid() to make debugserver run in its own session
Greg Claytonf681b942010-08-31 18:35:14 +0000864 { "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
Greg Claytonbd82a5d2011-01-23 05:56:20 +0000865 { "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 +0000866 { "platform", required_argument, NULL, 'p' }, // Put this executable into a remote platform mode
Greg Claytonc93068b2013-12-10 19:36:45 +0000867 { "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 +0000868 { "named-pipe", required_argument, NULL, 'P' },
Greg Clayton00fe87b2013-12-05 22:58:22 +0000869 { "reverse-connect", no_argument, NULL, 'R' },
Greg Claytonce1843b2014-06-18 18:26:50 +0000870 { "env", required_argument, NULL, 'e' }, // When debugserver launches the process, set a single environment entry as specified by the option value ("./debugserver -e FOO=1 -e BAR=2 localhost:1234 -- /bin/ls")
871 { "forward-env", no_argument, NULL, 'F' }, // When debugserver launches the process, forward debugserver's current environment variables to the child process ("./debugserver -F localhost:1234 -- /bin/ls"
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000872 { NULL, 0, NULL, 0 }
873};
874
875
876//----------------------------------------------------------------------
877// main
878//----------------------------------------------------------------------
879int
880main (int argc, char *argv[])
881{
Jason Molenda0b2dbe02012-11-01 02:02:59 +0000882 const char *argv_sub_zero = argv[0]; // save a copy of argv[0] for error reporting post-launch
883
Jason Molenda36a216e2014-07-24 01:36:24 +0000884#if defined (__APPLE__)
885 pthread_setname_np ("main thread");
886#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
887 struct sched_param thread_param;
888 int thread_sched_policy;
889 if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0)
890 {
891 thread_param.sched_priority = 47;
892 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
893 }
894#endif
895#endif
896
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000897 g_isatty = ::isatty (STDIN_FILENO);
898
899 // ::printf ("uid=%u euid=%u gid=%u egid=%u\n",
900 // getuid(),
901 // geteuid(),
902 // getgid(),
903 // getegid());
904
905
906 // signal (SIGINT, signal_handler);
907 signal (SIGPIPE, signal_handler);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000908 signal (SIGHUP, signal_handler);
Jason Molendaa3329782014-03-29 18:54:20 +0000909
910 // We're always sitting in waitpid or kevent waiting on our target process' death,
911 // we don't need no stinking SIGCHLD's...
912
913 sigset_t sigset;
914 sigemptyset(&sigset);
915 sigaddset(&sigset, SIGCHLD);
916 sigprocmask(SIG_BLOCK, &sigset, NULL);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000917
Greg Clayton71337622011-02-24 22:24:29 +0000918 g_remoteSP.reset (new RNBRemote ());
919
920
921 RNBRemote *remote = g_remoteSP.get();
922 if (remote == NULL)
923 {
924 RNBLogSTDERR ("error: failed to create a remote connection class\n");
925 return -1;
926 }
927
928 RNBContext& ctx = remote->Context();
929
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000930 int i;
931 int attach_pid = INVALID_NUB_PROCESS;
932
933 FILE* log_file = NULL;
934 uint32_t log_flags = 0;
935 // Parse our options
936 int ch;
937 int long_option_index = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000938 int debug = 0;
939 std::string compile_options;
940 std::string waitfor_pid_name; // Wait for a process that starts with this name
941 std::string attach_pid_name;
Greg Clayton3af9ea52010-11-18 05:57:03 +0000942 std::string arch_name;
Greg Clayton8b82f082011-04-12 05:54:46 +0000943 std::string working_dir; // The new working directory to use for the inferior
Greg Claytonc93068b2013-12-10 19:36:45 +0000944 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 +0000945 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 +0000946 useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
947 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 +0000948 bool no_stdio = false;
Greg Clayton00fe87b2013-12-05 22:58:22 +0000949 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 +0000950
951#if !defined (DNBLOG_ENABLED)
952 compile_options += "(no-logging) ";
953#endif
954
955 RNBRunLoopMode start_mode = eRNBRunLoopModeExit;
956
Greg Clayton8d400e172011-05-23 18:04:09 +0000957 char short_options[512];
958 uint32_t short_options_idx = 0;
959
960 // Handle the two case that don't have short options in g_long_options
961 short_options[short_options_idx++] = 'k';
962 short_options[short_options_idx++] = 't';
963
964 for (i=0; g_long_options[i].name != NULL; ++i)
965 {
966 if (isalpha(g_long_options[i].val))
967 {
968 short_options[short_options_idx++] = g_long_options[i].val;
969 switch (g_long_options[i].has_arg)
970 {
971 default:
972 case no_argument:
973 break;
974
975 case optional_argument:
976 short_options[short_options_idx++] = ':';
977 // Fall through to required_argument case below...
978 case required_argument:
979 short_options[short_options_idx++] = ':';
980 break;
981 }
982 }
983 }
984 // NULL terminate the short option string.
985 short_options[short_options_idx++] = '\0';
Greg Claytond4724cf2013-11-22 18:55:04 +0000986
987#if __GLIBC__
988 optind = 0;
989#else
990 optreset = 1;
991 optind = 1;
992#endif
993
Greg Claytonb7ad58a2013-04-04 20:35:24 +0000994 while ((ch = getopt_long_only(argc, argv, short_options, g_long_options, &long_option_index)) != -1)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000995 {
996 DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
997 ch, (uint8_t)ch,
998 g_long_options[long_option_index].name,
999 g_long_options[long_option_index].has_arg ? '=' : ' ',
1000 optarg ? optarg : "");
1001 switch (ch)
1002 {
1003 case 0: // Any optional that auto set themselves will return 0
1004 break;
1005
Greg Clayton3af9ea52010-11-18 05:57:03 +00001006 case 'A':
1007 if (optarg && optarg[0])
1008 arch_name.assign(optarg);
1009 break;
1010
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001011 case 'a':
1012 if (optarg && optarg[0])
1013 {
1014 if (isdigit(optarg[0]))
1015 {
1016 char *end = NULL;
1017 attach_pid = strtoul(optarg, &end, 0);
1018 if (end == NULL || *end != '\0')
1019 {
1020 RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg);
1021 exit (4);
1022 }
1023 }
1024 else
1025 {
1026 attach_pid_name = optarg;
1027 }
1028 start_mode = eRNBRunLoopModeInferiorAttaching;
1029 }
1030 break;
1031
1032 // --waitfor=NAME
1033 case 'w':
1034 if (optarg && optarg[0])
1035 {
1036 waitfor_pid_name = optarg;
1037 start_mode = eRNBRunLoopModeInferiorAttaching;
1038 }
1039 break;
1040
1041 // --waitfor-interval=USEC
1042 case 'i':
1043 if (optarg && optarg[0])
1044 {
1045 char *end = NULL;
1046 waitfor_interval = strtoul(optarg, &end, 0);
1047 if (end == NULL || *end != '\0')
1048 {
1049 RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
1050 exit (6);
1051 }
1052 }
1053 break;
1054
1055 // --waitfor-duration=SEC
1056 case 'd':
1057 if (optarg && optarg[0])
1058 {
1059 char *end = NULL;
1060 waitfor_duration = strtoul(optarg, &end, 0);
1061 if (end == NULL || *end != '\0')
1062 {
1063 RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
1064 exit (7);
1065 }
1066 }
1067 break;
Jim Ingham58813182014-02-25 04:53:13 +00001068
Jim Ingham5689a212014-02-25 19:57:47 +00001069 case 'K':
1070 g_detach_on_error = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001071
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001072 case 'W':
Greg Clayton6779606a2011-01-22 23:43:18 +00001073 if (optarg && optarg[0])
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001074 working_dir.assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001075 break;
1076
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001077 case 'x':
1078 if (optarg && optarg[0])
1079 {
1080 if (strcasecmp(optarg, "auto") == 0)
1081 g_launch_flavor = eLaunchFlavorDefault;
1082 else if (strcasestr(optarg, "posix") == optarg)
1083 g_launch_flavor = eLaunchFlavorPosixSpawn;
1084 else if (strcasestr(optarg, "fork") == optarg)
1085 g_launch_flavor = eLaunchFlavorForkExec;
Jason Molenda42999a42012-02-22 02:18:59 +00001086#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001087 else if (strcasestr(optarg, "spring") == optarg)
1088 g_launch_flavor = eLaunchFlavorSpringBoard;
1089#endif
Jason Molendaa3329782014-03-29 18:54:20 +00001090#ifdef WITH_BKS
1091 else if (strcasestr(optarg, "backboard") == optarg)
1092 g_launch_flavor = eLaunchFlavorBKS;
1093#endif
1094
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001095 else
1096 {
1097 RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
1098 RNBLogSTDERR ("Valid values TYPE are:\n");
Jason Molendaa3329782014-03-29 18:54:20 +00001099 RNBLogSTDERR (" auto Auto-detect the best launch method to use.\n");
1100 RNBLogSTDERR (" posix Launch the executable using posix_spawn.\n");
1101 RNBLogSTDERR (" fork Launch the executable using fork and exec.\n");
Jason Molenda42999a42012-02-22 02:18:59 +00001102#ifdef WITH_SPRINGBOARD
Jason Molendaa3329782014-03-29 18:54:20 +00001103 RNBLogSTDERR (" spring Launch the executable through Springboard.\n");
1104#endif
1105#ifdef WITH_BKS
1106 RNBLogSTDERR (" backboard Launch the executable through BackBoard Services.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001107#endif
1108 exit (5);
1109 }
1110 }
1111 break;
1112
1113 case 'l': // Set Log File
1114 if (optarg && optarg[0])
1115 {
1116 if (strcasecmp(optarg, "stdout") == 0)
1117 log_file = stdout;
1118 else if (strcasecmp(optarg, "stderr") == 0)
1119 log_file = stderr;
1120 else
Jim Inghamc530be62011-01-24 03:46:59 +00001121 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001122 log_file = fopen(optarg, "w");
Jim Inghamc530be62011-01-24 03:46:59 +00001123 if (log_file != NULL)
1124 setlinebuf(log_file);
1125 }
1126
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001127 if (log_file == NULL)
1128 {
1129 const char *errno_str = strerror(errno);
1130 RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
1131 }
1132 }
1133 break;
1134
1135 case 'f': // Log Flags
1136 if (optarg && optarg[0])
1137 log_flags = strtoul(optarg, NULL, 0);
1138 break;
1139
1140 case 'g':
1141 debug = 1;
Johnny Chen2fe7dd42011-08-10 23:01:39 +00001142 DNBLogSetDebug(debug);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001143 break;
1144
1145 case 't':
1146 g_applist_opt = 1;
1147 break;
1148
1149 case 'k':
1150 g_lockdown_opt = 1;
1151 break;
1152
1153 case 'r':
Greg Clayton85480022013-11-09 00:33:46 +00001154 // Do nothing, native regs is the default these days
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001155 break;
1156
Greg Clayton00fe87b2013-12-05 22:58:22 +00001157 case 'R':
1158 reverse_connect = true;
1159 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001160 case 'v':
1161 DNBLogSetVerbose(1);
1162 break;
1163
1164 case 's':
Greg Clayton71337622011-02-24 22:24:29 +00001165 ctx.GetSTDIN().assign(optarg);
1166 ctx.GetSTDOUT().assign(optarg);
1167 ctx.GetSTDERR().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001168 break;
1169
1170 case 'I':
Greg Clayton71337622011-02-24 22:24:29 +00001171 ctx.GetSTDIN().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001172 break;
1173
1174 case 'O':
Greg Clayton71337622011-02-24 22:24:29 +00001175 ctx.GetSTDOUT().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001176 break;
1177
1178 case 'E':
Greg Clayton71337622011-02-24 22:24:29 +00001179 ctx.GetSTDERR().assign(optarg);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001180 break;
1181
Caroline Ticef8da8632010-12-03 18:46:09 +00001182 case 'n':
1183 no_stdio = true;
1184 break;
1185
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001186 case 'S':
1187 // Put debugserver into a new session. Terminals group processes
1188 // into sessions and when a special terminal key sequences
1189 // (like control+c) are typed they can cause signals to go out to
1190 // all processes in a session. Using this --setsid (-S) option
1191 // will cause debugserver to run in its own sessions and be free
1192 // from such issues.
1193 //
1194 // This is useful when debugserver is spawned from a command
1195 // line application that uses debugserver to do the debugging,
1196 // yet that application doesn't want debugserver receiving the
1197 // signals sent to the session (i.e. dying when anyone hits ^C).
1198 setsid();
1199 break;
Greg Claytonf681b942010-08-31 18:35:14 +00001200 case 'D':
1201 g_disable_aslr = 1;
1202 break;
Greg Clayton7a5388b2011-03-20 04:57:14 +00001203
1204 case 'p':
1205 start_mode = eRNBRunLoopModePlatformMode;
1206 break;
Greg Clayton8b82f082011-04-12 05:54:46 +00001207
Greg Claytonc93068b2013-12-10 19:36:45 +00001208 case 'u':
1209 unix_socket_name.assign (optarg);
1210 break;
1211
Greg Clayton91a9b2472013-12-04 19:19:12 +00001212 case 'P':
1213 named_pipe_path.assign (optarg);
Greg Clayton8b82f082011-04-12 05:54:46 +00001214 break;
Greg Claytonc93068b2013-12-10 19:36:45 +00001215
Greg Claytonce1843b2014-06-18 18:26:50 +00001216 case 'e':
1217 // Pass a single specified environment variable down to the process that gets launched
1218 remote->Context().PushEnvironment(optarg);
1219 break;
1220
1221 case 'F':
1222 // Pass the current environment down to the process that gets launched
1223 {
1224 char **host_env = *_NSGetEnviron();
1225 char *env_entry;
1226 size_t i;
1227 for (i=0; (env_entry = host_env[i]) != NULL; ++i)
1228 remote->Context().PushEnvironment(env_entry);
1229 }
1230 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001231 }
1232 }
Greg Clayton3af9ea52010-11-18 05:57:03 +00001233
1234 if (arch_name.empty())
1235 {
Greg Clayton71337622011-02-24 22:24:29 +00001236#if defined (__arm__)
Greg Clayton3af9ea52010-11-18 05:57:03 +00001237 arch_name.assign ("arm");
1238#endif
1239 }
Greg Clayton3c144382010-12-01 22:45:40 +00001240 else
1241 {
1242 DNBSetArchitecture (arch_name.c_str());
1243 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001244
Greg Clayton71337622011-02-24 22:24:29 +00001245// if (arch_name.empty())
1246// {
1247// fprintf(stderr, "error: no architecture was specified\n");
1248// exit (8);
1249// }
Greg Claytonb7ad58a2013-04-04 20:35:24 +00001250 // Skip any options we consumed with getopt_long_only
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001251 argc -= optind;
1252 argv += optind;
1253
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001254
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001255 if (!working_dir.empty())
Greg Clayton6779606a2011-01-22 23:43:18 +00001256 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001257 if (remote->Context().SetWorkingDirectory (working_dir.c_str()) == false)
Greg Clayton6779606a2011-01-22 23:43:18 +00001258 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001259 RNBLogSTDERR ("error: working directory doesn't exist '%s'.\n", working_dir.c_str());
Greg Clayton6779606a2011-01-22 23:43:18 +00001260 exit (8);
1261 }
1262 }
1263
Jim Ingham58813182014-02-25 04:53:13 +00001264 remote->Context().SetDetachOnError(g_detach_on_error);
1265
Greg Clayton6779606a2011-01-22 23:43:18 +00001266 remote->Initialize();
Greg Clayton3af9ea52010-11-18 05:57:03 +00001267
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001268 // It is ok for us to set NULL as the logfile (this will disable any logging)
1269
1270 if (log_file != NULL)
1271 {
1272 DNBLogSetLogCallback(FileLogCallback, log_file);
1273 // If our log file was set, yet we have no log flags, log everything!
1274 if (log_flags == 0)
1275 log_flags = LOG_ALL | LOG_RNB_ALL;
1276
1277 DNBLogSetLogMask (log_flags);
1278 }
1279 else
1280 {
1281 // Enable DNB logging
1282 DNBLogSetLogCallback(ASLLogCallback, NULL);
1283 DNBLogSetLogMask (log_flags);
1284
1285 }
1286
1287 if (DNBLogEnabled())
1288 {
1289 for (i=0; i<argc; i++)
1290 DNBLogDebug("argv[%i] = %s", i, argv[i]);
1291 }
1292
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001293 // as long as we're dropping remotenub in as a replacement for gdbserver,
1294 // explicitly note that this is not gdbserver.
1295
Todd Fialac3ec3372014-03-13 18:30:04 +00001296 RNBLogSTDOUT ("%s-%s %sfor %s.\n",
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001297 DEBUGSERVER_PROGRAM_NAME,
Todd Fialac3ec3372014-03-13 18:30:04 +00001298 DEBUGSERVER_VERSION_STR,
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001299 compile_options.c_str(),
1300 RNB_ARCH);
1301
Greg Clayton00fe87b2013-12-05 22:58:22 +00001302 std::string host;
1303 int port = INT32_MAX;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001304 char str[PATH_MAX];
Greg Clayton23f59502012-07-17 03:23:13 +00001305 str[0] = '\0';
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001306
1307 if (g_lockdown_opt == 0 && g_applist_opt == 0)
1308 {
1309 // Make sure we at least have port
1310 if (argc < 1)
1311 {
1312 show_usage_and_exit (1);
1313 }
1314 // accept 'localhost:' prefix on port number
1315
Greg Clayton00fe87b2013-12-05 22:58:22 +00001316 int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &port);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001317 if (items_scanned == 2)
1318 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001319 host = str;
1320 DNBLogDebug("host = '%s' port = %i", host.c_str(), port);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001321 }
1322 else
1323 {
Greg Claytonfd238892013-06-06 22:44:19 +00001324 // No hostname means "localhost"
Greg Clayton00fe87b2013-12-05 22:58:22 +00001325 int items_scanned = ::sscanf (argv[0], "%i", &port);
Greg Claytonfd238892013-06-06 22:44:19 +00001326 if (items_scanned == 1)
1327 {
Greg Clayton16810922014-02-27 19:38:18 +00001328 host = "127.0.0.1";
Greg Clayton00fe87b2013-12-05 22:58:22 +00001329 DNBLogDebug("host = '%s' port = %i", host.c_str(), port);
Greg Claytonfd238892013-06-06 22:44:19 +00001330 }
1331 else if (argv[0][0] == '/')
1332 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001333 port = INT32_MAX;
Greg Claytonfd238892013-06-06 22:44:19 +00001334 strncpy(str, argv[0], sizeof(str));
1335 }
1336 else
1337 {
1338 show_usage_and_exit (2);
1339 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001340 }
1341
1342 // We just used the 'host:port' or the '/path/file' arg...
1343 argc--;
1344 argv++;
1345
1346 }
1347
1348 // If we know we're waiting to attach, we don't need any of this other info.
Greg Clayton7a5388b2011-03-20 04:57:14 +00001349 if (start_mode != eRNBRunLoopModeInferiorAttaching &&
1350 start_mode != eRNBRunLoopModePlatformMode)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001351 {
1352 if (argc == 0 || g_lockdown_opt)
1353 {
1354 if (g_lockdown_opt != 0)
1355 {
1356 // Work around for SIGPIPE crashes due to posix_spawn issue.
1357 // We have to close STDOUT and STDERR, else the first time we
1358 // try and do any, we get SIGPIPE and die as posix_spawn is
1359 // doing bad things with our file descriptors at the moment.
1360 int null = open("/dev/null", O_RDWR);
1361 dup2(null, STDOUT_FILENO);
1362 dup2(null, STDERR_FILENO);
1363 }
1364 else if (g_applist_opt != 0)
1365 {
1366 // List all applications we are able to see
1367 std::string applist_plist;
1368 int err = ListApplications(applist_plist, false, false);
1369 if (err == 0)
1370 {
1371 fputs (applist_plist.c_str(), stdout);
1372 }
1373 else
1374 {
1375 RNBLogSTDERR ("error: ListApplications returned error %i\n", err);
1376 }
1377 // Exit with appropriate error if we were asked to list the applications
1378 // with no other args were given (and we weren't trying to do this over
1379 // lockdown)
1380 return err;
1381 }
1382
1383 DNBLogDebug("Get args from remote protocol...");
1384 start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
1385 }
1386 else
1387 {
1388 start_mode = eRNBRunLoopModeInferiorLaunching;
1389 // Fill in the argv array in the context from the rest of our args.
1390 // Skip the name of this executable and the port number
1391 for (int i = 0; i < argc; i++)
1392 {
1393 DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]);
1394 ctx.PushArgument (argv[i]);
1395 }
1396 }
1397 }
1398
1399 if (start_mode == eRNBRunLoopModeExit)
1400 return -1;
1401
1402 RNBRunLoopMode mode = start_mode;
1403 char err_str[1024] = {'\0'};
1404
1405 while (mode != eRNBRunLoopModeExit)
1406 {
1407 switch (mode)
1408 {
1409 case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
Jason Molenda42999a42012-02-22 02:18:59 +00001410#ifdef WITH_LOCKDOWN
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001411 if (g_lockdown_opt)
1412 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001413 if (!remote->Comm().IsConnected())
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001414 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001415 if (remote->Comm().ConnectToService () != rnb_success)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001416 {
1417 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
1418 mode = eRNBRunLoopModeExit;
1419 }
1420 else if (g_applist_opt != 0)
1421 {
1422 // List all applications we are able to see
1423 std::string applist_plist;
1424 if (ListApplications(applist_plist, false, false) == 0)
1425 {
1426 DNBLogDebug("Task list: %s", applist_plist.c_str());
1427
Greg Clayton6779606a2011-01-22 23:43:18 +00001428 remote->Comm().Write(applist_plist.c_str(), applist_plist.size());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001429 // Issue a read that will never yield any data until the other side
1430 // closes the socket so this process doesn't just exit and cause the
1431 // socket to close prematurely on the other end and cause data loss.
1432 std::string buf;
Greg Clayton6779606a2011-01-22 23:43:18 +00001433 remote->Comm().Read(buf);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001434 }
Greg Clayton6779606a2011-01-22 23:43:18 +00001435 remote->Comm().Disconnect(false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001436 mode = eRNBRunLoopModeExit;
1437 break;
1438 }
1439 else
1440 {
1441 // Start watching for remote packets
Greg Clayton6779606a2011-01-22 23:43:18 +00001442 remote->StartReadRemoteDataThread();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001443 }
1444 }
1445 }
1446 else
1447#endif
Greg Clayton00fe87b2013-12-05 22:58:22 +00001448 if (port != INT32_MAX)
Greg Clayton7a5388b2011-03-20 04:57:14 +00001449 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001450 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 +00001451 mode = eRNBRunLoopModeExit;
1452 }
1453 else if (str[0] == '/')
1454 {
1455 if (remote->Comm().OpenFile (str))
1456 mode = eRNBRunLoopModeExit;
1457 }
1458
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001459 if (mode != eRNBRunLoopModeExit)
1460 {
1461 RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
1462
Greg Clayton6779606a2011-01-22 23:43:18 +00001463 mode = RNBRunLoopGetStartModeFromRemote (remote);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001464 }
1465 break;
1466
1467 case eRNBRunLoopModeInferiorAttaching:
1468 if (!waitfor_pid_name.empty())
1469 {
1470 // Set our end wait time if we are using a waitfor-duration
1471 // option that may have been specified
1472 struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1473 if (waitfor_duration != 0)
1474 {
1475 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1476 timeout_ptr = &attach_timeout_abstime;
1477 }
1478 nub_launch_flavor_t launch_flavor = g_launch_flavor;
1479 if (launch_flavor == eLaunchFlavorDefault)
1480 {
1481 // Our default launch method is posix spawn
1482 launch_flavor = eLaunchFlavorPosixSpawn;
1483
Jason Molendaa3329782014-03-29 18:54:20 +00001484#if defined WITH_BKS
1485 // Check if we have an app bundle, if so launch using SpringBoard.
1486 if (waitfor_pid_name.find (".app") != std::string::npos)
1487 {
1488 launch_flavor = eLaunchFlavorBKS;
1489 }
1490#elif defined WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001491 // Check if we have an app bundle, if so launch using SpringBoard.
1492 if (waitfor_pid_name.find (".app") != std::string::npos)
1493 {
1494 launch_flavor = eLaunchFlavorSpringBoard;
1495 }
1496#endif
1497 }
1498
1499 ctx.SetLaunchFlavor(launch_flavor);
Jim Inghamcd16df92012-07-20 21:37:13 +00001500 bool ignore_existing = false;
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001501 RNBLogSTDOUT ("Waiting to attach to process %s...\n", waitfor_pid_name.c_str());
Jim Inghamcd16df92012-07-20 21:37:13 +00001502 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 +00001503 g_pid = pid;
1504
1505 if (pid == INVALID_NUB_PROCESS)
1506 {
1507 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1508 if (err_str[0])
1509 ctx.LaunchStatus().SetErrorString(err_str);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001510 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 +00001511 mode = eRNBRunLoopModeExit;
1512 }
1513 else
1514 {
1515 ctx.SetProcessID(pid);
1516 mode = eRNBRunLoopModeInferiorExecuting;
1517 }
1518 }
1519 else if (attach_pid != INVALID_NUB_PROCESS)
1520 {
1521
1522 RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid);
1523 nub_process_t attached_pid;
Greg Clayton6779606a2011-01-22 23:43:18 +00001524 mode = RNBRunLoopLaunchAttaching (remote, attach_pid, attached_pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001525 if (mode != eRNBRunLoopModeInferiorExecuting)
1526 {
1527 const char *error_str = remote->Context().LaunchStatus().AsString();
1528 RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
1529 mode = eRNBRunLoopModeExit;
1530 }
1531 }
1532 else if (!attach_pid_name.empty ())
1533 {
1534 struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1535 if (waitfor_duration != 0)
1536 {
1537 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1538 timeout_ptr = &attach_timeout_abstime;
1539 }
1540
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001541 RNBLogSTDOUT ("Attaching to process %s...\n", attach_pid_name.c_str());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001542 nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str));
1543 g_pid = pid;
1544 if (pid == INVALID_NUB_PROCESS)
1545 {
1546 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1547 if (err_str[0])
1548 ctx.LaunchStatus().SetErrorString(err_str);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001549 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 +00001550 mode = eRNBRunLoopModeExit;
1551 }
1552 else
1553 {
1554 ctx.SetProcessID(pid);
1555 mode = eRNBRunLoopModeInferiorExecuting;
1556 }
1557
1558 }
1559 else
1560 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001561 RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001562 mode = eRNBRunLoopModeExit;
1563 }
1564
1565 if (mode != eRNBRunLoopModeExit)
1566 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001567 if (port != INT32_MAX)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001568 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001569 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 +00001570 mode = eRNBRunLoopModeExit;
1571 }
1572 else if (str[0] == '/')
1573 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001574 if (remote->Comm().OpenFile (str))
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001575 mode = eRNBRunLoopModeExit;
1576 }
1577 if (mode != eRNBRunLoopModeExit)
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001578 RNBLogSTDOUT ("Waiting for debugger instructions for process %d.\n", attach_pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001579 }
1580 break;
1581
1582 case eRNBRunLoopModeInferiorLaunching:
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001583 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001584 mode = RNBRunLoopLaunchInferior (remote,
Greg Clayton71337622011-02-24 22:24:29 +00001585 ctx.GetSTDINPath(),
1586 ctx.GetSTDOUTPath(),
1587 ctx.GetSTDERRPath(),
Greg Clayton6779606a2011-01-22 23:43:18 +00001588 no_stdio);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001589
Greg Clayton6779606a2011-01-22 23:43:18 +00001590 if (mode == eRNBRunLoopModeInferiorExecuting)
1591 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001592 if (port != INT32_MAX)
Greg Clayton6779606a2011-01-22 23:43:18 +00001593 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001594 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 +00001595 mode = eRNBRunLoopModeExit;
1596 }
1597 else if (str[0] == '/')
1598 {
1599 if (remote->Comm().OpenFile (str))
1600 mode = eRNBRunLoopModeExit;
1601 }
1602
1603 if (mode != eRNBRunLoopModeExit)
Jim Ingham5689a212014-02-25 19:57:47 +00001604 {
1605 const char *proc_name = "<unknown>";
1606 if (ctx.ArgumentCount() > 0)
1607 proc_name = ctx.ArgumentAtIndex(0);
1608 RNBLogSTDOUT ("Got a connection, launched process %s (pid = %d).\n", proc_name, ctx.ProcessID());
1609 }
Greg Clayton6779606a2011-01-22 23:43:18 +00001610 }
1611 else
1612 {
1613 const char *error_str = remote->Context().LaunchStatus().AsString();
Jason Molenda0b2dbe02012-11-01 02:02:59 +00001614 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 +00001615 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001616 }
1617 break;
1618
1619 case eRNBRunLoopModeInferiorExecuting:
Greg Clayton6779606a2011-01-22 23:43:18 +00001620 mode = RNBRunLoopInferiorExecuting(remote);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001621 break;
1622
Greg Clayton7a5388b2011-03-20 04:57:14 +00001623 case eRNBRunLoopModePlatformMode:
Greg Clayton00fe87b2013-12-05 22:58:22 +00001624 if (port != INT32_MAX)
Greg Clayton7a5388b2011-03-20 04:57:14 +00001625 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001626 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 +00001627 mode = eRNBRunLoopModeExit;
1628 }
1629 else if (str[0] == '/')
1630 {
1631 if (remote->Comm().OpenFile (str))
1632 mode = eRNBRunLoopModeExit;
1633 }
1634
1635 if (mode != eRNBRunLoopModeExit)
1636 mode = RNBRunLoopPlatform (remote);
1637 break;
1638
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001639 default:
1640 mode = eRNBRunLoopModeExit;
1641 case eRNBRunLoopModeExit:
1642 break;
1643 }
1644 }
1645
Greg Clayton6779606a2011-01-22 23:43:18 +00001646 remote->StopReadRemoteDataThread ();
1647 remote->Context().SetProcessID(INVALID_NUB_PROCESS);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001648 RNBLogSTDOUT ("Exiting.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001649
1650 return 0;
1651}