blob: a22f046771d939e3a4faf6450e3a2a094f249b29 [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>
Jason Molenda3f661e02015-07-07 04:15:43 +000030extern "C" int proc_set_wakemon_params(pid_t, int, int); // <libproc_internal.h> SPI
Jason Molenda36a216e2014-07-24 01:36:24 +000031#endif
32
Chris Lattner30fdc8d2010-06-08 16:52:24 +000033#include "CFString.h"
34#include "DNB.h"
35#include "DNBLog.h"
36#include "DNBTimer.h"
37#include "PseudoTerminal.h"
38#include "RNBContext.h"
39#include "RNBServices.h"
40#include "RNBSocket.h"
41#include "RNBRemote.h"
42#include "SysSignal.h"
43
44// Global PID in case we get a signal and need to stop the process...
45nub_process_t g_pid = INVALID_NUB_PROCESS;
46
47//----------------------------------------------------------------------
48// Run loop modes which determine which run loop function will be called
49//----------------------------------------------------------------------
50typedef enum
51{
52 eRNBRunLoopModeInvalid = 0,
53 eRNBRunLoopModeGetStartModeFromRemoteProtocol,
54 eRNBRunLoopModeInferiorAttaching,
55 eRNBRunLoopModeInferiorLaunching,
56 eRNBRunLoopModeInferiorExecuting,
Greg Clayton7a5388b2011-03-20 04:57:14 +000057 eRNBRunLoopModePlatformMode,
Chris Lattner30fdc8d2010-06-08 16:52:24 +000058 eRNBRunLoopModeExit
59} RNBRunLoopMode;
60
61
62//----------------------------------------------------------------------
63// Global Variables
64//----------------------------------------------------------------------
65RNBRemoteSP g_remoteSP;
66static int g_lockdown_opt = 0;
67static int g_applist_opt = 0;
68static nub_launch_flavor_t g_launch_flavor = eLaunchFlavorDefault;
Greg Clayton6f35f5c2010-09-09 06:32:46 +000069int g_disable_aslr = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000070
71int g_isatty = 0;
Jim Ingham5689a212014-02-25 19:57:47 +000072bool g_detach_on_error = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000073
74#define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
75#define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
76
77//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +000078// Get our program path and arguments from the remote connection.
79// We will need to start up the remote connection without a PID, get the
80// arguments, wait for the new process to finish launching and hit its
81// entry point, and then return the run loop mode that should come next.
82//----------------------------------------------------------------------
83RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +000084RNBRunLoopGetStartModeFromRemote (RNBRemote* remote)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000085{
86 std::string packet;
87
Greg Clayton6779606a2011-01-22 23:43:18 +000088 if (remote)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000089 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +000090 RNBContext& ctx = remote->Context();
Greg Clayton71337622011-02-24 22:24:29 +000091 uint32_t event_mask = RNBContext::event_read_packet_available |
92 RNBContext::event_read_thread_exiting;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000093
94 // Spin waiting to get the A packet.
95 while (1)
96 {
97 DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask);
98 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
99 DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events);
100
Greg Clayton71337622011-02-24 22:24:29 +0000101 if (set_events & RNBContext::event_read_thread_exiting)
102 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000103 RNBLogSTDERR ("error: packet read thread exited.\n");
Greg Clayton71337622011-02-24 22:24:29 +0000104 return eRNBRunLoopModeExit;
105 }
106
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000107 if (set_events & RNBContext::event_read_packet_available)
108 {
109 rnb_err_t err = rnb_err;
110 RNBRemote::PacketEnum type;
111
112 err = remote->HandleReceivedPacket (&type);
113
114 // check if we tried to attach to a process
Jim Inghamcd16df92012-07-20 21:37:13 +0000115 if (type == RNBRemote::vattach || type == RNBRemote::vattachwait || type == RNBRemote::vattachorwait)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000116 {
117 if (err == rnb_success)
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000118 {
119 RNBLogSTDOUT ("Attach succeeded, ready to debug.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000120 return eRNBRunLoopModeInferiorExecuting;
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000121 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000122 else
123 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000124 RNBLogSTDERR ("error: attach failed.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000125 return eRNBRunLoopModeExit;
126 }
127 }
128
129 if (err == rnb_success)
130 {
131 // If we got our arguments we are ready to launch using the arguments
132 // and any environment variables we received.
133 if (type == RNBRemote::set_argv)
134 {
135 return eRNBRunLoopModeInferiorLaunching;
136 }
137 }
138 else if (err == rnb_not_connected)
139 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +0000140 RNBLogSTDERR ("error: connection lost.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000141 return eRNBRunLoopModeExit;
142 }
143 else
144 {
145 // a catch all for any other gdb remote packets that failed
146 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__);
147 continue;
148 }
149
150 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
151 }
152 else
153 {
154 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__);
155 return eRNBRunLoopModeExit;
156 }
157 }
158 }
159 return eRNBRunLoopModeExit;
160}
161
162
163//----------------------------------------------------------------------
164// This run loop mode will wait for the process to launch and hit its
165// entry point. It will currently ignore all events except for the
166// process state changed event, where it watches for the process stopped
167// or crash process state.
168//----------------------------------------------------------------------
169RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000170RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char *stdout_path, const char *stderr_path, bool no_stdio)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000171{
172 RNBContext& ctx = remote->Context();
173
174 // The Process stuff takes a c array, the RNBContext has a vector...
175 // So make up a c array.
176
177 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, ctx.ArgumentAtIndex(0));
178
179 size_t inferior_argc = ctx.ArgumentCount();
180 // Initialize inferior_argv with inferior_argc + 1 NULLs
181 std::vector<const char *> inferior_argv(inferior_argc + 1, NULL);
182
183 size_t i;
184 for (i = 0; i < inferior_argc; i++)
185 inferior_argv[i] = ctx.ArgumentAtIndex(i);
186
187 // Pass the environment array the same way:
188
189 size_t inferior_envc = ctx.EnvironmentCount();
190 // Initialize inferior_argv with inferior_argc + 1 NULLs
191 std::vector<const char *> inferior_envp(inferior_envc + 1, NULL);
192
193 for (i = 0; i < inferior_envc; i++)
194 inferior_envp[i] = ctx.EnvironmentAtIndex(i);
195
196 // Our launch type hasn't been set to anything concrete, so we need to
197 // figure our how we are going to launch automatically.
198
199 nub_launch_flavor_t launch_flavor = g_launch_flavor;
200 if (launch_flavor == eLaunchFlavorDefault)
201 {
202 // Our default launch method is posix spawn
203 launch_flavor = eLaunchFlavorPosixSpawn;
204
Jason Molendac611a742015-10-23 02:49:51 +0000205#if defined WITH_FBS
206 // Check if we have an app bundle, if so launch using BackBoard Services.
207 if (strstr(inferior_argv[0], ".app"))
208 {
209 launch_flavor = eLaunchFlavorFBS;
210 }
211#elif defined WITH_BKS
Jason Molendaa3329782014-03-29 18:54:20 +0000212 // Check if we have an app bundle, if so launch using BackBoard Services.
213 if (strstr(inferior_argv[0], ".app"))
214 {
215 launch_flavor = eLaunchFlavorBKS;
216 }
217#elif defined WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000218 // Check if we have an app bundle, if so launch using SpringBoard.
219 if (strstr(inferior_argv[0], ".app"))
220 {
221 launch_flavor = eLaunchFlavorSpringBoard;
222 }
223#endif
224 }
225
226 ctx.SetLaunchFlavor(launch_flavor);
227 char resolved_path[PATH_MAX];
228
229 // If we fail to resolve the path to our executable, then just use what we
230 // were given and hope for the best
231 if ( !DNBResolveExecutablePath (inferior_argv[0], resolved_path, sizeof(resolved_path)) )
232 ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path));
233
234 char launch_err_str[PATH_MAX];
235 launch_err_str[0] = '\0';
Johnny Chen725269a2011-02-26 01:36:13 +0000236 const char * cwd = (ctx.GetWorkingDirPath() != NULL ? ctx.GetWorkingDirPath()
237 : ctx.GetWorkingDirectory());
Jason Molendaa3329782014-03-29 18:54:20 +0000238 const char *process_event = ctx.GetProcessEvent();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000239 nub_process_t pid = DNBProcessLaunch (resolved_path,
240 &inferior_argv[0],
241 &inferior_envp[0],
Johnny Chen725269a2011-02-26 01:36:13 +0000242 cwd,
Greg Clayton6779606a2011-01-22 23:43:18 +0000243 stdin_path,
244 stdout_path,
245 stderr_path,
Caroline Ticef8da8632010-12-03 18:46:09 +0000246 no_stdio,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000247 launch_flavor,
Greg Claytonf681b942010-08-31 18:35:14 +0000248 g_disable_aslr,
Jason Molendaa3329782014-03-29 18:54:20 +0000249 process_event,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000250 launch_err_str,
251 sizeof(launch_err_str));
252
253 g_pid = pid;
254
Jason Molenda4e0c94b2011-07-08 00:00:32 +0000255 if (pid == INVALID_NUB_PROCESS && strlen (launch_err_str) > 0)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000256 {
Greg Clayton3382c2c2010-07-30 23:14:42 +0000257 DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, launch_err_str);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000258 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
259 ctx.LaunchStatus().SetErrorString(launch_err_str);
260 }
Jason Molenda4e0c94b2011-07-08 00:00:32 +0000261 else if (pid == INVALID_NUB_PROCESS)
262 {
263 DNBLogThreaded ("%s DNBProcessLaunch() failed to launch process, unknown failure", __FUNCTION__);
264 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
Jim Inghamcfae0b22015-03-04 21:28:55 +0000265 ctx.LaunchStatus().SetErrorString("<unknown failure>");
Jason Molenda4e0c94b2011-07-08 00:00:32 +0000266 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000267 else
Greg Clayton71337622011-02-24 22:24:29 +0000268 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000269 ctx.LaunchStatus().Clear();
Greg Clayton71337622011-02-24 22:24:29 +0000270 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000271
272 if (remote->Comm().IsConnected())
273 {
274 // It we are connected already, the next thing gdb will do is ask
275 // whether the launch succeeded, and if not, whether there is an
276 // error code. So we need to fetch one packet from gdb before we wait
277 // on the stop from the target.
278
279 uint32_t event_mask = RNBContext::event_read_packet_available;
280 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
281
282 if (set_events & RNBContext::event_read_packet_available)
283 {
284 rnb_err_t err = rnb_err;
285 RNBRemote::PacketEnum type;
286
287 err = remote->HandleReceivedPacket (&type);
288
289 if (err != rnb_success)
290 {
291 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__);
292 return eRNBRunLoopModeExit;
293 }
294 if (type != RNBRemote::query_launch_success)
295 {
296 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__);
297 }
298 }
299 }
300
301 while (pid != INVALID_NUB_PROCESS)
302 {
303 // Wait for process to start up and hit entry point
304 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid);
305 nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL);
306 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events);
307
308 if (set_events == 0)
309 {
310 pid = INVALID_NUB_PROCESS;
311 g_pid = pid;
312 }
313 else
314 {
315 if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
316 {
317 nub_state_t pid_state = DNBProcessGetState (pid);
318 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
319
320 switch (pid_state)
321 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000322 case eStateInvalid:
323 case eStateUnloaded:
324 case eStateAttaching:
325 case eStateLaunching:
326 case eStateSuspended:
327 break; // Ignore
328
329 case eStateRunning:
330 case eStateStepping:
331 // Still waiting to stop at entry point...
332 break;
333
334 case eStateStopped:
335 case eStateCrashed:
336 ctx.SetProcessID(pid);
337 return eRNBRunLoopModeInferiorExecuting;
338
339 case eStateDetached:
340 case eStateExited:
341 pid = INVALID_NUB_PROCESS;
342 g_pid = pid;
343 return eRNBRunLoopModeExit;
344 }
345 }
346
347 DNBProcessResetEvents(pid, set_events);
348 }
349 }
350
351 return eRNBRunLoopModeExit;
352}
353
354
355//----------------------------------------------------------------------
356// This run loop mode will wait for the process to launch and hit its
357// entry point. It will currently ignore all events except for the
358// process state changed event, where it watches for the process stopped
359// or crash process state.
360//----------------------------------------------------------------------
361RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000362RNBRunLoopLaunchAttaching (RNBRemote *remote, nub_process_t attach_pid, nub_process_t& pid)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000363{
364 RNBContext& ctx = remote->Context();
365
366 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid);
367 char err_str[1024];
368 pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str));
369 g_pid = pid;
370
371 if (pid == INVALID_NUB_PROCESS)
372 {
373 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
374 if (err_str[0])
375 ctx.LaunchStatus().SetErrorString(err_str);
376 return eRNBRunLoopModeExit;
377 }
378 else
379 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000380 ctx.SetProcessID(pid);
381 return eRNBRunLoopModeInferiorExecuting;
382 }
383}
384
385//----------------------------------------------------------------------
386// Watch for signals:
387// SIGINT: so we can halt our inferior. (disabled for now)
388// SIGPIPE: in case our child process dies
389//----------------------------------------------------------------------
390int g_sigint_received = 0;
391int g_sigpipe_received = 0;
392void
393signal_handler(int signo)
394{
395 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo));
396
397 switch (signo)
398 {
399 case SIGINT:
400 g_sigint_received++;
401 if (g_pid != INVALID_NUB_PROCESS)
402 {
403 // Only send a SIGINT once...
404 if (g_sigint_received == 1)
405 {
406 switch (DNBProcessGetState (g_pid))
407 {
408 case eStateRunning:
409 case eStateStepping:
410 DNBProcessSignal (g_pid, SIGSTOP);
411 return;
Greg Clayton95bf0fd2011-04-01 00:29:43 +0000412 default:
413 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000414 }
415 }
416 }
417 exit (SIGINT);
418 break;
419
420 case SIGPIPE:
421 g_sigpipe_received = 1;
422 break;
423 }
424}
425
426// Return the new run loop mode based off of the current process state
427RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000428HandleProcessStateChange (RNBRemote *remote, bool initialize)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000429{
430 RNBContext& ctx = remote->Context();
431 nub_process_t pid = ctx.ProcessID();
432
433 if (pid == INVALID_NUB_PROCESS)
434 {
435 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
436 return eRNBRunLoopModeExit;
437 }
438 nub_state_t pid_state = DNBProcessGetState (pid);
439
440 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state));
441
442 switch (pid_state)
443 {
444 case eStateInvalid:
445 case eStateUnloaded:
446 // Something bad happened
447 return eRNBRunLoopModeExit;
448 break;
449
450 case eStateAttaching:
451 case eStateLaunching:
452 return eRNBRunLoopModeInferiorExecuting;
453
454 case eStateSuspended:
455 case eStateCrashed:
456 case eStateStopped:
457 // If we stop due to a signal, so clear the fact that we got a SIGINT
458 // so we can stop ourselves again (but only while our inferior
459 // process is running..)
460 g_sigint_received = 0;
461 if (initialize == false)
462 {
463 // Compare the last stop count to our current notion of a stop count
464 // to make sure we don't notify more than once for a given stop.
465 nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
466 bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid));
467 if (pid_stop_count_changed)
468 {
469 remote->FlushSTDIO();
470
471 if (ctx.GetProcessStopCount() == 1)
472 {
Greg Clayton43e0af02012-09-18 18:04:04 +0000473 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 +0000474 }
475 else
476 {
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??? YES!!!", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), (uint64_t)ctx.GetProcessStopCount(), (uint64_t)prev_pid_stop_count);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000479 remote->NotifyThatProcessStopped ();
480 }
481 }
482 else
483 {
Greg Clayton43e0af02012-09-18 18:04:04 +0000484 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 +0000485 }
486 }
487 return eRNBRunLoopModeInferiorExecuting;
488
489 case eStateStepping:
490 case eStateRunning:
491 return eRNBRunLoopModeInferiorExecuting;
492
493 case eStateExited:
494 remote->HandlePacket_last_signal(NULL);
Greg Clayton95bf0fd2011-04-01 00:29:43 +0000495 case eStateDetached:
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000496 return eRNBRunLoopModeExit;
497
498 }
499
500 // Catch all...
501 return eRNBRunLoopModeExit;
502}
503// This function handles the case where our inferior program is stopped and
504// we are waiting for gdb remote protocol packets. When a packet occurs that
505// makes the inferior run, we need to leave this function with a new state
506// as the return code.
507RNBRunLoopMode
Greg Clayton6779606a2011-01-22 23:43:18 +0000508RNBRunLoopInferiorExecuting (RNBRemote *remote)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000509{
510 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
511 RNBContext& ctx = remote->Context();
512
513 // Init our mode and set 'is_running' based on the current process state
514 RNBRunLoopMode mode = HandleProcessStateChange (remote, true);
515
516 while (ctx.ProcessID() != INVALID_NUB_PROCESS)
517 {
518
519 std::string set_events_str;
520 uint32_t event_mask = ctx.NormalEventBits();
521
522 if (!ctx.ProcessStateRunning())
523 {
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000524 // Clear some bits if we are not running so we don't send any async packets
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000525 event_mask &= ~RNBContext::event_proc_stdio_available;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000526 event_mask &= ~RNBContext::event_proc_profile_data;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000527 }
528
529 // We want to make sure we consume all process state changes and have
530 // whomever is notifying us to wait for us to reset the event bit before
531 // continuing.
532 //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
533
534 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
535 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
536 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));
537
538 if (set_events)
539 {
540 if ((set_events & RNBContext::event_proc_thread_exiting) ||
541 (set_events & RNBContext::event_proc_stdio_available))
542 {
543 remote->FlushSTDIO();
544 }
545
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000546 if (set_events & RNBContext::event_proc_profile_data)
547 {
548 remote->SendAsyncProfileData();
549 }
550
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000551 if (set_events & RNBContext::event_read_packet_available)
552 {
553 // handleReceivedPacket will take care of resetting the
554 // event_read_packet_available events when there are no more...
555 set_events ^= RNBContext::event_read_packet_available;
556
557 if (ctx.ProcessStateRunning())
558 {
559 if (remote->HandleAsyncPacket() == rnb_not_connected)
560 {
561 // TODO: connect again? Exit?
562 }
563 }
564 else
565 {
566 if (remote->HandleReceivedPacket() == rnb_not_connected)
567 {
568 // TODO: connect again? Exit?
569 }
570 }
571 }
572
573 if (set_events & RNBContext::event_proc_state_changed)
574 {
575 mode = HandleProcessStateChange (remote, false);
576 ctx.Events().ResetEvents(RNBContext::event_proc_state_changed);
577 set_events ^= RNBContext::event_proc_state_changed;
578 }
579
580 if (set_events & RNBContext::event_proc_thread_exiting)
581 {
582 mode = eRNBRunLoopModeExit;
583 }
584
585 if (set_events & RNBContext::event_read_thread_exiting)
586 {
587 // Out remote packet receiving thread exited, exit for now.
588 if (ctx.HasValidProcessID())
589 {
590 // TODO: We should add code that will leave the current process
591 // in its current state and listen for another connection...
592 if (ctx.ProcessStateRunning())
593 {
Jim Ingham58813182014-02-25 04:53:13 +0000594 if (ctx.GetDetachOnError())
595 {
596 DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process.");
597 DNBProcessDetach (ctx.ProcessID());
598 }
599 else
600 {
601 DNBLog ("debugserver's event read thread is exiting, killing the inferior process.");
602 DNBProcessKill (ctx.ProcessID());
603 }
604 }
605 else
606 {
607 if (ctx.GetDetachOnError())
608 {
609 DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process.");
610 DNBProcessDetach (ctx.ProcessID());
611 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000612 }
613 }
614 mode = eRNBRunLoopModeExit;
615 }
616 }
617
618 // Reset all event bits that weren't reset for now...
619 if (set_events != 0)
620 ctx.Events().ResetEvents(set_events);
621
622 if (mode != eRNBRunLoopModeInferiorExecuting)
623 break;
624 }
625
626 return mode;
627}
628
629
Greg Clayton7a5388b2011-03-20 04:57:14 +0000630RNBRunLoopMode
631RNBRunLoopPlatform (RNBRemote *remote)
632{
633 RNBRunLoopMode mode = eRNBRunLoopModePlatformMode;
634 RNBContext& ctx = remote->Context();
635
636 while (mode == eRNBRunLoopModePlatformMode)
637 {
638 std::string set_events_str;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000639 const uint32_t event_mask = RNBContext::event_read_packet_available |
Greg Clayton7a5388b2011-03-20 04:57:14 +0000640 RNBContext::event_read_thread_exiting;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000641
Greg Clayton7a5388b2011-03-20 04:57:14 +0000642 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
643 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
644 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));
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000645
Greg Clayton7a5388b2011-03-20 04:57:14 +0000646 if (set_events)
647 {
648 if (set_events & RNBContext::event_read_packet_available)
649 {
650 if (remote->HandleReceivedPacket() == rnb_not_connected)
651 mode = eRNBRunLoopModeExit;
652 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000653
Greg Clayton7a5388b2011-03-20 04:57:14 +0000654 if (set_events & RNBContext::event_read_thread_exiting)
655 {
656 mode = eRNBRunLoopModeExit;
657 }
658 ctx.Events().ResetEvents(set_events);
659 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000660 }
Greg Clayton7a5388b2011-03-20 04:57:14 +0000661 return eRNBRunLoopModeExit;
662}
663
Greg Claytonc93068b2013-12-10 19:36:45 +0000664//----------------------------------------------------------------------
665// Convenience function to set up the remote listening port
666// Returns 1 for success 0 for failure.
667//----------------------------------------------------------------------
668
669static void
670PortWasBoundCallbackUnixSocket (const void *baton, in_port_t port)
671{
672 //::printf ("PortWasBoundCallbackUnixSocket (baton = %p, port = %u)\n", baton, port);
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000673
Greg Claytonc93068b2013-12-10 19:36:45 +0000674 const char *unix_socket_name = (const char *)baton;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000675
Greg Claytonc93068b2013-12-10 19:36:45 +0000676 if (unix_socket_name && unix_socket_name[0])
677 {
678 // We were given a unix socket name to use to communicate the port
679 // that we ended up binding to back to our parent process
680 struct sockaddr_un saddr_un;
681 int s = ::socket (AF_UNIX, SOCK_STREAM, 0);
682 if (s < 0)
683 {
684 perror("error: socket (AF_UNIX, SOCK_STREAM, 0)");
685 exit(1);
686 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000687
Greg Claytonc93068b2013-12-10 19:36:45 +0000688 saddr_un.sun_family = AF_UNIX;
689 ::strncpy(saddr_un.sun_path, unix_socket_name, sizeof(saddr_un.sun_path) - 1);
690 saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
691 saddr_un.sun_len = SUN_LEN (&saddr_un);
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000692
Greg Claytonee2ed522015-03-09 19:45:23 +0000693 if (::connect (s, (struct sockaddr *)&saddr_un, static_cast<socklen_t>(SUN_LEN (&saddr_un))) < 0)
Greg Claytonc93068b2013-12-10 19:36:45 +0000694 {
695 perror("error: connect (socket, &saddr_un, saddr_un_len)");
696 exit(1);
697 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000698
Greg Claytonc93068b2013-12-10 19:36:45 +0000699 //::printf ("connect () sucess!!\n");
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000700
701
Greg Claytonc93068b2013-12-10 19:36:45 +0000702 // We were able to connect to the socket, now write our PID so whomever
703 // launched us will know this process's ID
704 RNBLogSTDOUT ("Listening to port %i...\n", port);
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000705
Greg Claytonc93068b2013-12-10 19:36:45 +0000706 char pid_str[64];
707 const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%u", port);
Greg Claytonee2ed522015-03-09 19:45:23 +0000708 const ssize_t bytes_sent = ::send (s, pid_str, pid_str_len, 0);
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000709
Greg Claytonc93068b2013-12-10 19:36:45 +0000710 if (pid_str_len != bytes_sent)
711 {
712 perror("error: send (s, pid_str, pid_str_len, 0)");
713 exit (1);
714 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000715
Greg Claytonc93068b2013-12-10 19:36:45 +0000716 //::printf ("send () sucess!!\n");
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000717
Greg Claytonc93068b2013-12-10 19:36:45 +0000718 // We are done with the socket
719 close (s);
720 }
721}
722
Greg Clayton8b82f082011-04-12 05:54:46 +0000723static void
Greg Claytond6299802013-12-06 17:46:35 +0000724PortWasBoundCallbackNamedPipe (const void *baton, uint16_t port)
Greg Clayton8b82f082011-04-12 05:54:46 +0000725{
Greg Clayton91a9b2472013-12-04 19:19:12 +0000726 const char *named_pipe = (const char *)baton;
727 if (named_pipe && named_pipe[0])
Greg Clayton8b82f082011-04-12 05:54:46 +0000728 {
Greg Clayton91a9b2472013-12-04 19:19:12 +0000729 int fd = ::open(named_pipe, O_WRONLY);
730 if (fd > -1)
Greg Clayton8b82f082011-04-12 05:54:46 +0000731 {
Greg Clayton91a9b2472013-12-04 19:19:12 +0000732 char port_str[64];
733 const ssize_t port_str_len = ::snprintf (port_str, sizeof(port_str), "%u", port);
734 // Write the port number as a C string with the NULL terminator
735 ::write (fd, port_str, port_str_len + 1);
736 close (fd);
Greg Clayton8b82f082011-04-12 05:54:46 +0000737 }
Greg Clayton8b82f082011-04-12 05:54:46 +0000738 }
739}
740
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000741static int
Greg Claytonc93068b2013-12-10 19:36:45 +0000742ConnectRemote (RNBRemote *remote,
743 const char *host,
744 int port,
745 bool reverse_connect,
746 const char *named_pipe_path,
747 const char *unix_socket_name)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000748{
Greg Clayton6779606a2011-01-22 23:43:18 +0000749 if (!remote->Comm().IsConnected())
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000750 {
Greg Clayton00fe87b2013-12-05 22:58:22 +0000751 if (reverse_connect)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000752 {
Greg Clayton00fe87b2013-12-05 22:58:22 +0000753 if (port == 0)
754 {
755 DNBLogThreaded("error: invalid port supplied for reverse connection: %i.\n", port);
756 return 0;
757 }
758 if (remote->Comm().Connect(host, port) != rnb_success)
759 {
760 DNBLogThreaded("Failed to reverse connect to %s:%i.\n", host, port);
761 return 0;
762 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000763 }
764 else
765 {
Greg Clayton00fe87b2013-12-05 22:58:22 +0000766 if (port != 0)
Greg Clayton16810922014-02-27 19:38:18 +0000767 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 +0000768 if (unix_socket_name && unix_socket_name[0])
Greg Clayton00fe87b2013-12-05 22:58:22 +0000769 {
Greg Claytonc93068b2013-12-10 19:36:45 +0000770 if (remote->Comm().Listen(host, port, PortWasBoundCallbackUnixSocket, unix_socket_name) != rnb_success)
771 {
772 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
773 return 0;
774 }
775 }
776 else
777 {
778 if (remote->Comm().Listen(host, port, PortWasBoundCallbackNamedPipe, named_pipe_path) != rnb_success)
779 {
780 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
781 return 0;
782 }
Greg Clayton00fe87b2013-12-05 22:58:22 +0000783 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000784 }
Greg Clayton00fe87b2013-12-05 22:58:22 +0000785 remote->StartReadRemoteDataThread();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000786 }
787 return 1;
788}
789
790//----------------------------------------------------------------------
791// ASL Logging callback that can be registered with DNBLogSetLogCallback
792//----------------------------------------------------------------------
793void
794ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
795{
796 if (format == NULL)
797 return;
798 static aslmsg g_aslmsg = NULL;
799 if (g_aslmsg == NULL)
800 {
801 g_aslmsg = ::asl_new (ASL_TYPE_MSG);
802 char asl_key_sender[PATH_MAX];
Todd Fialac3ec3372014-03-13 18:30:04 +0000803 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 +0000804 ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
805 }
806
807 int asl_level;
808 if (flags & DNBLOG_FLAG_FATAL) asl_level = ASL_LEVEL_CRIT;
809 else if (flags & DNBLOG_FLAG_ERROR) asl_level = ASL_LEVEL_ERR;
810 else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING;
811 else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO;
812 else asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG;
813
814 ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
815}
816
817//----------------------------------------------------------------------
818// FILE based Logging callback that can be registered with
819// DNBLogSetLogCallback
820//----------------------------------------------------------------------
821void
822FileLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
823{
824 if (baton == NULL || format == NULL)
825 return;
826
Greg Clayton7301d392016-05-02 22:53:08 +0000827 ::vfprintf((FILE *)baton, format, args);
828 ::fprintf((FILE *)baton, "\n");
829 ::fflush((FILE *)baton);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000830}
831
832
833void
834show_usage_and_exit (int exit_code)
835{
836 RNBLogSTDERR ("Usage:\n %s host:port [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
837 RNBLogSTDERR (" %s /path/file [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
838 RNBLogSTDERR (" %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
839 RNBLogSTDERR (" %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
840 RNBLogSTDERR (" %s host:port --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
841 RNBLogSTDERR (" %s /path/file --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
842 exit (exit_code);
843}
844
845
846//----------------------------------------------------------------------
Greg Claytonb7ad58a2013-04-04 20:35:24 +0000847// option descriptors for getopt_long_only()
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000848//----------------------------------------------------------------------
849static struct option g_long_options[] =
850{
851 { "attach", required_argument, NULL, 'a' },
Greg Clayton3af9ea52010-11-18 05:57:03 +0000852 { "arch", required_argument, NULL, 'A' },
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000853 { "debug", no_argument, NULL, 'g' },
Jim Ingham5689a212014-02-25 19:57:47 +0000854 { "kill-on-error", no_argument, NULL, 'K' },
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000855 { "verbose", no_argument, NULL, 'v' },
856 { "lockdown", no_argument, &g_lockdown_opt, 1 }, // short option "-k"
857 { "applist", no_argument, &g_applist_opt, 1 }, // short option "-t"
858 { "log-file", required_argument, NULL, 'l' },
859 { "log-flags", required_argument, NULL, 'f' },
860 { "launch", required_argument, NULL, 'x' }, // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
861 { "waitfor", required_argument, NULL, 'w' }, // Wait for a process whose name starts with ARG
862 { "waitfor-interval", required_argument, NULL, 'i' }, // Time in usecs to wait between sampling the pid list when waiting for a process by name
863 { "waitfor-duration", required_argument, NULL, 'd' }, // The time in seconds to wait for a process to show up by name
864 { "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 +0000865 { "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)
866 { "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 +0000867 { "stdout-path", required_argument, NULL, 'O' }, // Set the STDOUT path to be used when launching applications (only if debugserver launches the process)
868 { "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 +0000869 { "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)
870 { "setsid", no_argument, NULL, 'S' }, // call setsid() to make debugserver run in its own session
Greg Claytonf681b942010-08-31 18:35:14 +0000871 { "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
Greg Claytonbd82a5d2011-01-23 05:56:20 +0000872 { "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 +0000873 { "platform", required_argument, NULL, 'p' }, // Put this executable into a remote platform mode
Greg Claytonc93068b2013-12-10 19:36:45 +0000874 { "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 +0000875 { "named-pipe", required_argument, NULL, 'P' },
Greg Clayton00fe87b2013-12-05 22:58:22 +0000876 { "reverse-connect", no_argument, NULL, 'R' },
Greg Claytonce1843b2014-06-18 18:26:50 +0000877 { "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")
878 { "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 +0000879 { NULL, 0, NULL, 0 }
880};
881
882
883//----------------------------------------------------------------------
884// main
885//----------------------------------------------------------------------
886int
887main (int argc, char *argv[])
888{
Greg Clayton0e14c042016-02-09 21:20:17 +0000889 // If debugserver is launched with DYLD_INSERT_LIBRARIES, unset it so we
890 // don't spawn child processes with this enabled.
891 unsetenv("DYLD_INSERT_LIBRARIES");
892
Jason Molenda0b2dbe02012-11-01 02:02:59 +0000893 const char *argv_sub_zero = argv[0]; // save a copy of argv[0] for error reporting post-launch
894
Jason Molenda36a216e2014-07-24 01:36:24 +0000895#if defined (__APPLE__)
896 pthread_setname_np ("main thread");
897#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
898 struct sched_param thread_param;
899 int thread_sched_policy;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000900 if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0)
Jason Molenda36a216e2014-07-24 01:36:24 +0000901 {
902 thread_param.sched_priority = 47;
903 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
904 }
Jason Molenda3f661e02015-07-07 04:15:43 +0000905
906 ::proc_set_wakemon_params (getpid(), 500, 0); // Allow up to 500 wakeups/sec to avoid EXC_RESOURCE for normal use.
Jason Molenda36a216e2014-07-24 01:36:24 +0000907#endif
908#endif
909
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000910 g_isatty = ::isatty (STDIN_FILENO);
911
912 // ::printf ("uid=%u euid=%u gid=%u egid=%u\n",
913 // getuid(),
914 // geteuid(),
915 // getgid(),
916 // getegid());
917
918
919 // signal (SIGINT, signal_handler);
920 signal (SIGPIPE, signal_handler);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000921 signal (SIGHUP, signal_handler);
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000922
Jason Molendaa3329782014-03-29 18:54:20 +0000923 // We're always sitting in waitpid or kevent waiting on our target process' death,
924 // we don't need no stinking SIGCHLD's...
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000925
Jason Molendaa3329782014-03-29 18:54:20 +0000926 sigset_t sigset;
927 sigemptyset(&sigset);
928 sigaddset(&sigset, SIGCHLD);
929 sigprocmask(SIG_BLOCK, &sigset, NULL);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000930
Greg Clayton71337622011-02-24 22:24:29 +0000931 g_remoteSP.reset (new RNBRemote ());
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000932
933
Greg Clayton71337622011-02-24 22:24:29 +0000934 RNBRemote *remote = g_remoteSP.get();
935 if (remote == NULL)
936 {
937 RNBLogSTDERR ("error: failed to create a remote connection class\n");
938 return -1;
939 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000940
Greg Clayton71337622011-02-24 22:24:29 +0000941 RNBContext& ctx = remote->Context();
942
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000943 int i;
944 int attach_pid = INVALID_NUB_PROCESS;
945
946 FILE* log_file = NULL;
947 uint32_t log_flags = 0;
948 // Parse our options
949 int ch;
950 int long_option_index = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000951 int debug = 0;
952 std::string compile_options;
953 std::string waitfor_pid_name; // Wait for a process that starts with this name
954 std::string attach_pid_name;
Greg Clayton3af9ea52010-11-18 05:57:03 +0000955 std::string arch_name;
Greg Clayton8b82f082011-04-12 05:54:46 +0000956 std::string working_dir; // The new working directory to use for the inferior
Greg Claytonc93068b2013-12-10 19:36:45 +0000957 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 +0000958 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 +0000959 useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
960 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 +0000961 bool no_stdio = false;
Greg Clayton00fe87b2013-12-05 22:58:22 +0000962 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 +0000963
964#if !defined (DNBLOG_ENABLED)
965 compile_options += "(no-logging) ";
966#endif
967
968 RNBRunLoopMode start_mode = eRNBRunLoopModeExit;
969
Greg Clayton8d400e172011-05-23 18:04:09 +0000970 char short_options[512];
971 uint32_t short_options_idx = 0;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000972
Greg Clayton8d400e172011-05-23 18:04:09 +0000973 // Handle the two case that don't have short options in g_long_options
974 short_options[short_options_idx++] = 'k';
975 short_options[short_options_idx++] = 't';
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000976
Greg Clayton8d400e172011-05-23 18:04:09 +0000977 for (i=0; g_long_options[i].name != NULL; ++i)
978 {
979 if (isalpha(g_long_options[i].val))
980 {
981 short_options[short_options_idx++] = g_long_options[i].val;
982 switch (g_long_options[i].has_arg)
983 {
984 default:
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000985 case no_argument:
Greg Clayton8d400e172011-05-23 18:04:09 +0000986 break;
987
988 case optional_argument:
989 short_options[short_options_idx++] = ':';
990 // Fall through to required_argument case below...
991 case required_argument:
992 short_options[short_options_idx++] = ':';
993 break;
994 }
995 }
996 }
997 // NULL terminate the short option string.
998 short_options[short_options_idx++] = '\0';
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000999
Greg Claytond4724cf2013-11-22 18:55:04 +00001000#if __GLIBC__
1001 optind = 0;
1002#else
1003 optreset = 1;
1004 optind = 1;
1005#endif
1006
Greg Claytonb7ad58a2013-04-04 20:35:24 +00001007 while ((ch = getopt_long_only(argc, argv, short_options, g_long_options, &long_option_index)) != -1)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001008 {
1009 DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
1010 ch, (uint8_t)ch,
1011 g_long_options[long_option_index].name,
1012 g_long_options[long_option_index].has_arg ? '=' : ' ',
1013 optarg ? optarg : "");
1014 switch (ch)
1015 {
1016 case 0: // Any optional that auto set themselves will return 0
1017 break;
1018
Greg Clayton3af9ea52010-11-18 05:57:03 +00001019 case 'A':
1020 if (optarg && optarg[0])
1021 arch_name.assign(optarg);
1022 break;
1023
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001024 case 'a':
1025 if (optarg && optarg[0])
1026 {
1027 if (isdigit(optarg[0]))
1028 {
1029 char *end = NULL;
Greg Claytonee2ed522015-03-09 19:45:23 +00001030 attach_pid = static_cast<int>(strtoul(optarg, &end, 0));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001031 if (end == NULL || *end != '\0')
1032 {
1033 RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg);
1034 exit (4);
1035 }
1036 }
1037 else
1038 {
1039 attach_pid_name = optarg;
1040 }
1041 start_mode = eRNBRunLoopModeInferiorAttaching;
1042 }
1043 break;
1044
1045 // --waitfor=NAME
1046 case 'w':
1047 if (optarg && optarg[0])
1048 {
1049 waitfor_pid_name = optarg;
1050 start_mode = eRNBRunLoopModeInferiorAttaching;
1051 }
1052 break;
1053
1054 // --waitfor-interval=USEC
1055 case 'i':
1056 if (optarg && optarg[0])
1057 {
1058 char *end = NULL;
Greg Claytonee2ed522015-03-09 19:45:23 +00001059 waitfor_interval = static_cast<useconds_t>(strtoul(optarg, &end, 0));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001060 if (end == NULL || *end != '\0')
1061 {
1062 RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
1063 exit (6);
1064 }
1065 }
1066 break;
1067
1068 // --waitfor-duration=SEC
1069 case 'd':
1070 if (optarg && optarg[0])
1071 {
1072 char *end = NULL;
Greg Claytonee2ed522015-03-09 19:45:23 +00001073 waitfor_duration = static_cast<useconds_t>(strtoul(optarg, &end, 0));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001074 if (end == NULL || *end != '\0')
1075 {
1076 RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
1077 exit (7);
1078 }
1079 }
1080 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001081
Jim Ingham5689a212014-02-25 19:57:47 +00001082 case 'K':
1083 g_detach_on_error = false;
Jim Ingham78591722016-02-10 01:33:58 +00001084 break;
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001085 case 'W':
Greg Clayton6779606a2011-01-22 23:43:18 +00001086 if (optarg && optarg[0])
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001087 working_dir.assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001088 break;
1089
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001090 case 'x':
1091 if (optarg && optarg[0])
1092 {
1093 if (strcasecmp(optarg, "auto") == 0)
1094 g_launch_flavor = eLaunchFlavorDefault;
1095 else if (strcasestr(optarg, "posix") == optarg)
1096 g_launch_flavor = eLaunchFlavorPosixSpawn;
1097 else if (strcasestr(optarg, "fork") == optarg)
1098 g_launch_flavor = eLaunchFlavorForkExec;
Jason Molenda42999a42012-02-22 02:18:59 +00001099#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001100 else if (strcasestr(optarg, "spring") == optarg)
1101 g_launch_flavor = eLaunchFlavorSpringBoard;
1102#endif
Jason Molendaa3329782014-03-29 18:54:20 +00001103#ifdef WITH_BKS
1104 else if (strcasestr(optarg, "backboard") == optarg)
1105 g_launch_flavor = eLaunchFlavorBKS;
1106#endif
Jason Molendac611a742015-10-23 02:49:51 +00001107#ifdef WITH_FBS
1108 else if (strcasestr(optarg, "frontboard") == optarg)
1109 g_launch_flavor = eLaunchFlavorFBS;
1110#endif
Jason Molendaa3329782014-03-29 18:54:20 +00001111
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001112 else
1113 {
1114 RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
1115 RNBLogSTDERR ("Valid values TYPE are:\n");
Jason Molendaa3329782014-03-29 18:54:20 +00001116 RNBLogSTDERR (" auto Auto-detect the best launch method to use.\n");
1117 RNBLogSTDERR (" posix Launch the executable using posix_spawn.\n");
1118 RNBLogSTDERR (" fork Launch the executable using fork and exec.\n");
Jason Molenda42999a42012-02-22 02:18:59 +00001119#ifdef WITH_SPRINGBOARD
Jason Molendaa3329782014-03-29 18:54:20 +00001120 RNBLogSTDERR (" spring Launch the executable through Springboard.\n");
1121#endif
1122#ifdef WITH_BKS
1123 RNBLogSTDERR (" backboard Launch the executable through BackBoard Services.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001124#endif
Jason Molendac611a742015-10-23 02:49:51 +00001125#ifdef WITH_FBS
1126 RNBLogSTDERR (" frontboard Launch the executable through FrontBoard Services.\n");
1127#endif
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001128 exit (5);
1129 }
1130 }
1131 break;
1132
1133 case 'l': // Set Log File
1134 if (optarg && optarg[0])
1135 {
1136 if (strcasecmp(optarg, "stdout") == 0)
1137 log_file = stdout;
1138 else if (strcasecmp(optarg, "stderr") == 0)
1139 log_file = stderr;
1140 else
Jim Inghamc530be62011-01-24 03:46:59 +00001141 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001142 log_file = fopen(optarg, "w");
Jim Inghamc530be62011-01-24 03:46:59 +00001143 if (log_file != NULL)
1144 setlinebuf(log_file);
1145 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001146
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001147 if (log_file == NULL)
1148 {
1149 const char *errno_str = strerror(errno);
1150 RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
1151 }
1152 }
1153 break;
1154
1155 case 'f': // Log Flags
1156 if (optarg && optarg[0])
Greg Claytonee2ed522015-03-09 19:45:23 +00001157 log_flags = static_cast<uint32_t>(strtoul(optarg, NULL, 0));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001158 break;
1159
1160 case 'g':
1161 debug = 1;
Johnny Chen2fe7dd42011-08-10 23:01:39 +00001162 DNBLogSetDebug(debug);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001163 break;
1164
1165 case 't':
1166 g_applist_opt = 1;
1167 break;
1168
1169 case 'k':
1170 g_lockdown_opt = 1;
1171 break;
1172
1173 case 'r':
Greg Clayton85480022013-11-09 00:33:46 +00001174 // Do nothing, native regs is the default these days
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001175 break;
1176
Greg Clayton00fe87b2013-12-05 22:58:22 +00001177 case 'R':
1178 reverse_connect = true;
1179 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001180 case 'v':
1181 DNBLogSetVerbose(1);
1182 break;
1183
1184 case 's':
Greg Clayton71337622011-02-24 22:24:29 +00001185 ctx.GetSTDIN().assign(optarg);
1186 ctx.GetSTDOUT().assign(optarg);
1187 ctx.GetSTDERR().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001188 break;
1189
1190 case 'I':
Greg Clayton71337622011-02-24 22:24:29 +00001191 ctx.GetSTDIN().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001192 break;
1193
1194 case 'O':
Greg Clayton71337622011-02-24 22:24:29 +00001195 ctx.GetSTDOUT().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001196 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001197
Greg Clayton6779606a2011-01-22 23:43:18 +00001198 case 'E':
Greg Clayton71337622011-02-24 22:24:29 +00001199 ctx.GetSTDERR().assign(optarg);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001200 break;
1201
Caroline Ticef8da8632010-12-03 18:46:09 +00001202 case 'n':
1203 no_stdio = true;
1204 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001205
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001206 case 'S':
1207 // Put debugserver into a new session. Terminals group processes
1208 // into sessions and when a special terminal key sequences
1209 // (like control+c) are typed they can cause signals to go out to
1210 // all processes in a session. Using this --setsid (-S) option
1211 // will cause debugserver to run in its own sessions and be free
1212 // from such issues.
1213 //
1214 // This is useful when debugserver is spawned from a command
1215 // line application that uses debugserver to do the debugging,
1216 // yet that application doesn't want debugserver receiving the
1217 // signals sent to the session (i.e. dying when anyone hits ^C).
1218 setsid();
1219 break;
Greg Claytonf681b942010-08-31 18:35:14 +00001220 case 'D':
1221 g_disable_aslr = 1;
1222 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001223
Greg Clayton7a5388b2011-03-20 04:57:14 +00001224 case 'p':
1225 start_mode = eRNBRunLoopModePlatformMode;
1226 break;
Greg Clayton8b82f082011-04-12 05:54:46 +00001227
Greg Claytonc93068b2013-12-10 19:36:45 +00001228 case 'u':
1229 unix_socket_name.assign (optarg);
1230 break;
1231
Greg Clayton91a9b2472013-12-04 19:19:12 +00001232 case 'P':
1233 named_pipe_path.assign (optarg);
Greg Clayton8b82f082011-04-12 05:54:46 +00001234 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001235
Greg Claytonce1843b2014-06-18 18:26:50 +00001236 case 'e':
1237 // Pass a single specified environment variable down to the process that gets launched
1238 remote->Context().PushEnvironment(optarg);
1239 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001240
Greg Claytonce1843b2014-06-18 18:26:50 +00001241 case 'F':
1242 // Pass the current environment down to the process that gets launched
1243 {
1244 char **host_env = *_NSGetEnviron();
1245 char *env_entry;
1246 size_t i;
1247 for (i=0; (env_entry = host_env[i]) != NULL; ++i)
1248 remote->Context().PushEnvironment(env_entry);
1249 }
1250 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001251 }
1252 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001253
Greg Clayton3af9ea52010-11-18 05:57:03 +00001254 if (arch_name.empty())
1255 {
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001256#if defined (__arm__)
Greg Clayton3af9ea52010-11-18 05:57:03 +00001257 arch_name.assign ("arm");
1258#endif
1259 }
Greg Clayton3c144382010-12-01 22:45:40 +00001260 else
1261 {
1262 DNBSetArchitecture (arch_name.c_str());
1263 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001264
Greg Clayton71337622011-02-24 22:24:29 +00001265// if (arch_name.empty())
1266// {
1267// fprintf(stderr, "error: no architecture was specified\n");
1268// exit (8);
1269// }
Greg Claytonb7ad58a2013-04-04 20:35:24 +00001270 // Skip any options we consumed with getopt_long_only
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001271 argc -= optind;
1272 argv += optind;
1273
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001274
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001275 if (!working_dir.empty())
Greg Clayton6779606a2011-01-22 23:43:18 +00001276 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001277 if (remote->Context().SetWorkingDirectory (working_dir.c_str()) == false)
Greg Clayton6779606a2011-01-22 23:43:18 +00001278 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001279 RNBLogSTDERR ("error: working directory doesn't exist '%s'.\n", working_dir.c_str());
Greg Clayton6779606a2011-01-22 23:43:18 +00001280 exit (8);
1281 }
1282 }
1283
Jim Ingham58813182014-02-25 04:53:13 +00001284 remote->Context().SetDetachOnError(g_detach_on_error);
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001285
Greg Clayton6779606a2011-01-22 23:43:18 +00001286 remote->Initialize();
Greg Clayton3af9ea52010-11-18 05:57:03 +00001287
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001288 // It is ok for us to set NULL as the logfile (this will disable any logging)
1289
1290 if (log_file != NULL)
1291 {
1292 DNBLogSetLogCallback(FileLogCallback, log_file);
1293 // If our log file was set, yet we have no log flags, log everything!
1294 if (log_flags == 0)
1295 log_flags = LOG_ALL | LOG_RNB_ALL;
1296
1297 DNBLogSetLogMask (log_flags);
1298 }
1299 else
1300 {
1301 // Enable DNB logging
1302 DNBLogSetLogCallback(ASLLogCallback, NULL);
1303 DNBLogSetLogMask (log_flags);
1304
1305 }
1306
1307 if (DNBLogEnabled())
1308 {
1309 for (i=0; i<argc; i++)
1310 DNBLogDebug("argv[%i] = %s", i, argv[i]);
1311 }
1312
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001313 // as long as we're dropping remotenub in as a replacement for gdbserver,
1314 // explicitly note that this is not gdbserver.
1315
Todd Fialac3ec3372014-03-13 18:30:04 +00001316 RNBLogSTDOUT ("%s-%s %sfor %s.\n",
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001317 DEBUGSERVER_PROGRAM_NAME,
Todd Fialac3ec3372014-03-13 18:30:04 +00001318 DEBUGSERVER_VERSION_STR,
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001319 compile_options.c_str(),
1320 RNB_ARCH);
1321
Greg Clayton00fe87b2013-12-05 22:58:22 +00001322 std::string host;
1323 int port = INT32_MAX;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001324 char str[PATH_MAX];
Greg Clayton23f59502012-07-17 03:23:13 +00001325 str[0] = '\0';
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001326
1327 if (g_lockdown_opt == 0 && g_applist_opt == 0)
1328 {
1329 // Make sure we at least have port
1330 if (argc < 1)
1331 {
1332 show_usage_and_exit (1);
1333 }
1334 // accept 'localhost:' prefix on port number
1335
Greg Clayton00fe87b2013-12-05 22:58:22 +00001336 int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &port);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001337 if (items_scanned == 2)
1338 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001339 host = str;
1340 DNBLogDebug("host = '%s' port = %i", host.c_str(), port);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001341 }
1342 else
1343 {
Greg Claytonfd238892013-06-06 22:44:19 +00001344 // No hostname means "localhost"
Greg Clayton00fe87b2013-12-05 22:58:22 +00001345 int items_scanned = ::sscanf (argv[0], "%i", &port);
Greg Claytonfd238892013-06-06 22:44:19 +00001346 if (items_scanned == 1)
1347 {
Greg Clayton16810922014-02-27 19:38:18 +00001348 host = "127.0.0.1";
Greg Clayton00fe87b2013-12-05 22:58:22 +00001349 DNBLogDebug("host = '%s' port = %i", host.c_str(), port);
Greg Claytonfd238892013-06-06 22:44:19 +00001350 }
1351 else if (argv[0][0] == '/')
1352 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001353 port = INT32_MAX;
Greg Claytonfd238892013-06-06 22:44:19 +00001354 strncpy(str, argv[0], sizeof(str));
1355 }
1356 else
1357 {
1358 show_usage_and_exit (2);
1359 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001360 }
1361
1362 // We just used the 'host:port' or the '/path/file' arg...
1363 argc--;
1364 argv++;
1365
1366 }
1367
1368 // If we know we're waiting to attach, we don't need any of this other info.
Greg Clayton7a5388b2011-03-20 04:57:14 +00001369 if (start_mode != eRNBRunLoopModeInferiorAttaching &&
1370 start_mode != eRNBRunLoopModePlatformMode)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001371 {
1372 if (argc == 0 || g_lockdown_opt)
1373 {
1374 if (g_lockdown_opt != 0)
1375 {
1376 // Work around for SIGPIPE crashes due to posix_spawn issue.
1377 // We have to close STDOUT and STDERR, else the first time we
1378 // try and do any, we get SIGPIPE and die as posix_spawn is
1379 // doing bad things with our file descriptors at the moment.
1380 int null = open("/dev/null", O_RDWR);
1381 dup2(null, STDOUT_FILENO);
1382 dup2(null, STDERR_FILENO);
1383 }
1384 else if (g_applist_opt != 0)
1385 {
1386 // List all applications we are able to see
1387 std::string applist_plist;
1388 int err = ListApplications(applist_plist, false, false);
1389 if (err == 0)
1390 {
1391 fputs (applist_plist.c_str(), stdout);
1392 }
1393 else
1394 {
1395 RNBLogSTDERR ("error: ListApplications returned error %i\n", err);
1396 }
1397 // Exit with appropriate error if we were asked to list the applications
1398 // with no other args were given (and we weren't trying to do this over
1399 // lockdown)
1400 return err;
1401 }
1402
1403 DNBLogDebug("Get args from remote protocol...");
1404 start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
1405 }
1406 else
1407 {
1408 start_mode = eRNBRunLoopModeInferiorLaunching;
1409 // Fill in the argv array in the context from the rest of our args.
1410 // Skip the name of this executable and the port number
1411 for (int i = 0; i < argc; i++)
1412 {
1413 DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]);
1414 ctx.PushArgument (argv[i]);
1415 }
1416 }
1417 }
1418
1419 if (start_mode == eRNBRunLoopModeExit)
1420 return -1;
1421
1422 RNBRunLoopMode mode = start_mode;
1423 char err_str[1024] = {'\0'};
1424
1425 while (mode != eRNBRunLoopModeExit)
1426 {
1427 switch (mode)
1428 {
1429 case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
Jason Molenda42999a42012-02-22 02:18:59 +00001430#ifdef WITH_LOCKDOWN
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001431 if (g_lockdown_opt)
1432 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001433 if (!remote->Comm().IsConnected())
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001434 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001435 if (remote->Comm().ConnectToService () != rnb_success)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001436 {
1437 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
1438 mode = eRNBRunLoopModeExit;
1439 }
1440 else if (g_applist_opt != 0)
1441 {
1442 // List all applications we are able to see
1443 std::string applist_plist;
1444 if (ListApplications(applist_plist, false, false) == 0)
1445 {
1446 DNBLogDebug("Task list: %s", applist_plist.c_str());
1447
Greg Clayton6779606a2011-01-22 23:43:18 +00001448 remote->Comm().Write(applist_plist.c_str(), applist_plist.size());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001449 // Issue a read that will never yield any data until the other side
1450 // closes the socket so this process doesn't just exit and cause the
1451 // socket to close prematurely on the other end and cause data loss.
1452 std::string buf;
Greg Clayton6779606a2011-01-22 23:43:18 +00001453 remote->Comm().Read(buf);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001454 }
Greg Clayton6779606a2011-01-22 23:43:18 +00001455 remote->Comm().Disconnect(false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001456 mode = eRNBRunLoopModeExit;
1457 break;
1458 }
1459 else
1460 {
1461 // Start watching for remote packets
Greg Clayton6779606a2011-01-22 23:43:18 +00001462 remote->StartReadRemoteDataThread();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001463 }
1464 }
1465 }
1466 else
1467#endif
Greg Clayton00fe87b2013-12-05 22:58:22 +00001468 if (port != INT32_MAX)
Greg Clayton7a5388b2011-03-20 04:57:14 +00001469 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001470 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 +00001471 mode = eRNBRunLoopModeExit;
1472 }
1473 else if (str[0] == '/')
1474 {
1475 if (remote->Comm().OpenFile (str))
1476 mode = eRNBRunLoopModeExit;
1477 }
1478
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001479 if (mode != eRNBRunLoopModeExit)
1480 {
1481 RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
1482
Greg Clayton6779606a2011-01-22 23:43:18 +00001483 mode = RNBRunLoopGetStartModeFromRemote (remote);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001484 }
1485 break;
1486
1487 case eRNBRunLoopModeInferiorAttaching:
1488 if (!waitfor_pid_name.empty())
1489 {
1490 // Set our end wait time if we are using a waitfor-duration
1491 // option that may have been specified
1492 struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1493 if (waitfor_duration != 0)
1494 {
1495 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1496 timeout_ptr = &attach_timeout_abstime;
1497 }
1498 nub_launch_flavor_t launch_flavor = g_launch_flavor;
1499 if (launch_flavor == eLaunchFlavorDefault)
1500 {
1501 // Our default launch method is posix spawn
1502 launch_flavor = eLaunchFlavorPosixSpawn;
1503
Jason Molendac611a742015-10-23 02:49:51 +00001504#if defined WITH_FBS
1505 // Check if we have an app bundle, if so launch using SpringBoard.
1506 if (waitfor_pid_name.find (".app") != std::string::npos)
1507 {
1508 launch_flavor = eLaunchFlavorFBS;
1509 }
1510#elif defined WITH_BKS
Jason Molendaa3329782014-03-29 18:54:20 +00001511 // Check if we have an app bundle, if so launch using SpringBoard.
1512 if (waitfor_pid_name.find (".app") != std::string::npos)
1513 {
1514 launch_flavor = eLaunchFlavorBKS;
1515 }
1516#elif defined WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001517 // Check if we have an app bundle, if so launch using SpringBoard.
1518 if (waitfor_pid_name.find (".app") != std::string::npos)
1519 {
1520 launch_flavor = eLaunchFlavorSpringBoard;
1521 }
1522#endif
1523 }
1524
1525 ctx.SetLaunchFlavor(launch_flavor);
Jim Inghamcd16df92012-07-20 21:37:13 +00001526 bool ignore_existing = false;
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001527 RNBLogSTDOUT ("Waiting to attach to process %s...\n", waitfor_pid_name.c_str());
Jim Inghamcd16df92012-07-20 21:37:13 +00001528 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 +00001529 g_pid = pid;
1530
1531 if (pid == INVALID_NUB_PROCESS)
1532 {
1533 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1534 if (err_str[0])
1535 ctx.LaunchStatus().SetErrorString(err_str);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001536 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 +00001537 mode = eRNBRunLoopModeExit;
1538 }
1539 else
1540 {
1541 ctx.SetProcessID(pid);
1542 mode = eRNBRunLoopModeInferiorExecuting;
1543 }
1544 }
1545 else if (attach_pid != INVALID_NUB_PROCESS)
1546 {
1547
1548 RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid);
1549 nub_process_t attached_pid;
Greg Clayton6779606a2011-01-22 23:43:18 +00001550 mode = RNBRunLoopLaunchAttaching (remote, attach_pid, attached_pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001551 if (mode != eRNBRunLoopModeInferiorExecuting)
1552 {
1553 const char *error_str = remote->Context().LaunchStatus().AsString();
1554 RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
1555 mode = eRNBRunLoopModeExit;
1556 }
1557 }
1558 else if (!attach_pid_name.empty ())
1559 {
1560 struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1561 if (waitfor_duration != 0)
1562 {
1563 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1564 timeout_ptr = &attach_timeout_abstime;
1565 }
1566
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001567 RNBLogSTDOUT ("Attaching to process %s...\n", attach_pid_name.c_str());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001568 nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str));
1569 g_pid = pid;
1570 if (pid == INVALID_NUB_PROCESS)
1571 {
1572 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1573 if (err_str[0])
1574 ctx.LaunchStatus().SetErrorString(err_str);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001575 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 +00001576 mode = eRNBRunLoopModeExit;
1577 }
1578 else
1579 {
1580 ctx.SetProcessID(pid);
1581 mode = eRNBRunLoopModeInferiorExecuting;
1582 }
1583
1584 }
1585 else
1586 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001587 RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001588 mode = eRNBRunLoopModeExit;
1589 }
1590
1591 if (mode != eRNBRunLoopModeExit)
1592 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001593 if (port != INT32_MAX)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001594 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001595 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 +00001596 mode = eRNBRunLoopModeExit;
1597 }
1598 else if (str[0] == '/')
1599 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001600 if (remote->Comm().OpenFile (str))
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001601 mode = eRNBRunLoopModeExit;
1602 }
1603 if (mode != eRNBRunLoopModeExit)
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001604 RNBLogSTDOUT ("Waiting for debugger instructions for process %d.\n", attach_pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001605 }
1606 break;
1607
1608 case eRNBRunLoopModeInferiorLaunching:
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001609 {
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001610 mode = RNBRunLoopLaunchInferior (remote,
Greg Clayton71337622011-02-24 22:24:29 +00001611 ctx.GetSTDINPath(),
1612 ctx.GetSTDOUTPath(),
1613 ctx.GetSTDERRPath(),
Greg Clayton6779606a2011-01-22 23:43:18 +00001614 no_stdio);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001615
Greg Clayton6779606a2011-01-22 23:43:18 +00001616 if (mode == eRNBRunLoopModeInferiorExecuting)
1617 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001618 if (port != INT32_MAX)
Greg Clayton6779606a2011-01-22 23:43:18 +00001619 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001620 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 +00001621 mode = eRNBRunLoopModeExit;
1622 }
1623 else if (str[0] == '/')
1624 {
1625 if (remote->Comm().OpenFile (str))
1626 mode = eRNBRunLoopModeExit;
1627 }
1628
1629 if (mode != eRNBRunLoopModeExit)
Jim Ingham5689a212014-02-25 19:57:47 +00001630 {
1631 const char *proc_name = "<unknown>";
1632 if (ctx.ArgumentCount() > 0)
1633 proc_name = ctx.ArgumentAtIndex(0);
1634 RNBLogSTDOUT ("Got a connection, launched process %s (pid = %d).\n", proc_name, ctx.ProcessID());
1635 }
Greg Clayton6779606a2011-01-22 23:43:18 +00001636 }
1637 else
1638 {
1639 const char *error_str = remote->Context().LaunchStatus().AsString();
Jason Molenda0b2dbe02012-11-01 02:02:59 +00001640 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 +00001641 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001642 }
1643 break;
1644
1645 case eRNBRunLoopModeInferiorExecuting:
Greg Clayton6779606a2011-01-22 23:43:18 +00001646 mode = RNBRunLoopInferiorExecuting(remote);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001647 break;
1648
Greg Clayton7a5388b2011-03-20 04:57:14 +00001649 case eRNBRunLoopModePlatformMode:
Greg Clayton00fe87b2013-12-05 22:58:22 +00001650 if (port != INT32_MAX)
Greg Clayton7a5388b2011-03-20 04:57:14 +00001651 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001652 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 +00001653 mode = eRNBRunLoopModeExit;
1654 }
1655 else if (str[0] == '/')
1656 {
1657 if (remote->Comm().OpenFile (str))
1658 mode = eRNBRunLoopModeExit;
1659 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001660
Greg Clayton7a5388b2011-03-20 04:57:14 +00001661 if (mode != eRNBRunLoopModeExit)
1662 mode = RNBRunLoopPlatform (remote);
1663 break;
1664
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001665 default:
1666 mode = eRNBRunLoopModeExit;
1667 case eRNBRunLoopModeExit:
1668 break;
1669 }
1670 }
1671
Greg Clayton6779606a2011-01-22 23:43:18 +00001672 remote->StopReadRemoteDataThread ();
1673 remote->Context().SetProcessID(INVALID_NUB_PROCESS);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001674 RNBLogSTDOUT ("Exiting.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001675
1676 return 0;
1677}