blob: 369a0a1c47d334a7251bbab0d4ea8abc6f72867e [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
827 ::vfprintf ((FILE *)baton, format, args);
828 ::fprintf ((FILE *)baton, "\n");
829}
830
831
832void
833show_usage_and_exit (int exit_code)
834{
835 RNBLogSTDERR ("Usage:\n %s host:port [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
836 RNBLogSTDERR (" %s /path/file [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
837 RNBLogSTDERR (" %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
838 RNBLogSTDERR (" %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
839 RNBLogSTDERR (" %s host:port --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
840 RNBLogSTDERR (" %s /path/file --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
841 exit (exit_code);
842}
843
844
845//----------------------------------------------------------------------
Greg Claytonb7ad58a2013-04-04 20:35:24 +0000846// option descriptors for getopt_long_only()
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000847//----------------------------------------------------------------------
848static struct option g_long_options[] =
849{
850 { "attach", required_argument, NULL, 'a' },
Greg Clayton3af9ea52010-11-18 05:57:03 +0000851 { "arch", required_argument, NULL, 'A' },
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000852 { "debug", no_argument, NULL, 'g' },
Jim Ingham5689a212014-02-25 19:57:47 +0000853 { "kill-on-error", no_argument, NULL, 'K' },
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000854 { "verbose", no_argument, NULL, 'v' },
855 { "lockdown", no_argument, &g_lockdown_opt, 1 }, // short option "-k"
856 { "applist", no_argument, &g_applist_opt, 1 }, // short option "-t"
857 { "log-file", required_argument, NULL, 'l' },
858 { "log-flags", required_argument, NULL, 'f' },
859 { "launch", required_argument, NULL, 'x' }, // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
860 { "waitfor", required_argument, NULL, 'w' }, // Wait for a process whose name starts with ARG
861 { "waitfor-interval", required_argument, NULL, 'i' }, // Time in usecs to wait between sampling the pid list when waiting for a process by name
862 { "waitfor-duration", required_argument, NULL, 'd' }, // The time in seconds to wait for a process to show up by name
863 { "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 +0000864 { "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)
865 { "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 +0000866 { "stdout-path", required_argument, NULL, 'O' }, // Set the STDOUT path to be used when launching applications (only if debugserver launches the process)
867 { "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 +0000868 { "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)
869 { "setsid", no_argument, NULL, 'S' }, // call setsid() to make debugserver run in its own session
Greg Claytonf681b942010-08-31 18:35:14 +0000870 { "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
Greg Claytonbd82a5d2011-01-23 05:56:20 +0000871 { "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 +0000872 { "platform", required_argument, NULL, 'p' }, // Put this executable into a remote platform mode
Greg Claytonc93068b2013-12-10 19:36:45 +0000873 { "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 +0000874 { "named-pipe", required_argument, NULL, 'P' },
Greg Clayton00fe87b2013-12-05 22:58:22 +0000875 { "reverse-connect", no_argument, NULL, 'R' },
Greg Claytonce1843b2014-06-18 18:26:50 +0000876 { "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")
877 { "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 +0000878 { NULL, 0, NULL, 0 }
879};
880
881
882//----------------------------------------------------------------------
883// main
884//----------------------------------------------------------------------
885int
886main (int argc, char *argv[])
887{
Greg Clayton0e14c042016-02-09 21:20:17 +0000888 // If debugserver is launched with DYLD_INSERT_LIBRARIES, unset it so we
889 // don't spawn child processes with this enabled.
890 unsetenv("DYLD_INSERT_LIBRARIES");
891
Jason Molenda0b2dbe02012-11-01 02:02:59 +0000892 const char *argv_sub_zero = argv[0]; // save a copy of argv[0] for error reporting post-launch
893
Jason Molenda36a216e2014-07-24 01:36:24 +0000894#if defined (__APPLE__)
895 pthread_setname_np ("main thread");
896#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
897 struct sched_param thread_param;
898 int thread_sched_policy;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000899 if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0)
Jason Molenda36a216e2014-07-24 01:36:24 +0000900 {
901 thread_param.sched_priority = 47;
902 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
903 }
Jason Molenda3f661e02015-07-07 04:15:43 +0000904
905 ::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 +0000906#endif
907#endif
908
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000909 g_isatty = ::isatty (STDIN_FILENO);
910
911 // ::printf ("uid=%u euid=%u gid=%u egid=%u\n",
912 // getuid(),
913 // geteuid(),
914 // getgid(),
915 // getegid());
916
917
918 // signal (SIGINT, signal_handler);
919 signal (SIGPIPE, signal_handler);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000920 signal (SIGHUP, signal_handler);
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000921
Jason Molendaa3329782014-03-29 18:54:20 +0000922 // We're always sitting in waitpid or kevent waiting on our target process' death,
923 // we don't need no stinking SIGCHLD's...
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000924
Jason Molendaa3329782014-03-29 18:54:20 +0000925 sigset_t sigset;
926 sigemptyset(&sigset);
927 sigaddset(&sigset, SIGCHLD);
928 sigprocmask(SIG_BLOCK, &sigset, NULL);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000929
Greg Clayton71337622011-02-24 22:24:29 +0000930 g_remoteSP.reset (new RNBRemote ());
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000931
932
Greg Clayton71337622011-02-24 22:24:29 +0000933 RNBRemote *remote = g_remoteSP.get();
934 if (remote == NULL)
935 {
936 RNBLogSTDERR ("error: failed to create a remote connection class\n");
937 return -1;
938 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000939
Greg Clayton71337622011-02-24 22:24:29 +0000940 RNBContext& ctx = remote->Context();
941
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000942 int i;
943 int attach_pid = INVALID_NUB_PROCESS;
944
945 FILE* log_file = NULL;
946 uint32_t log_flags = 0;
947 // Parse our options
948 int ch;
949 int long_option_index = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000950 int debug = 0;
951 std::string compile_options;
952 std::string waitfor_pid_name; // Wait for a process that starts with this name
953 std::string attach_pid_name;
Greg Clayton3af9ea52010-11-18 05:57:03 +0000954 std::string arch_name;
Greg Clayton8b82f082011-04-12 05:54:46 +0000955 std::string working_dir; // The new working directory to use for the inferior
Greg Claytonc93068b2013-12-10 19:36:45 +0000956 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 +0000957 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 +0000958 useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
959 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 +0000960 bool no_stdio = false;
Greg Clayton00fe87b2013-12-05 22:58:22 +0000961 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 +0000962
963#if !defined (DNBLOG_ENABLED)
964 compile_options += "(no-logging) ";
965#endif
966
967 RNBRunLoopMode start_mode = eRNBRunLoopModeExit;
968
Greg Clayton8d400e172011-05-23 18:04:09 +0000969 char short_options[512];
970 uint32_t short_options_idx = 0;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000971
Greg Clayton8d400e172011-05-23 18:04:09 +0000972 // Handle the two case that don't have short options in g_long_options
973 short_options[short_options_idx++] = 'k';
974 short_options[short_options_idx++] = 't';
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000975
Greg Clayton8d400e172011-05-23 18:04:09 +0000976 for (i=0; g_long_options[i].name != NULL; ++i)
977 {
978 if (isalpha(g_long_options[i].val))
979 {
980 short_options[short_options_idx++] = g_long_options[i].val;
981 switch (g_long_options[i].has_arg)
982 {
983 default:
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000984 case no_argument:
Greg Clayton8d400e172011-05-23 18:04:09 +0000985 break;
986
987 case optional_argument:
988 short_options[short_options_idx++] = ':';
989 // Fall through to required_argument case below...
990 case required_argument:
991 short_options[short_options_idx++] = ':';
992 break;
993 }
994 }
995 }
996 // NULL terminate the short option string.
997 short_options[short_options_idx++] = '\0';
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +0000998
Greg Claytond4724cf2013-11-22 18:55:04 +0000999#if __GLIBC__
1000 optind = 0;
1001#else
1002 optreset = 1;
1003 optind = 1;
1004#endif
1005
Greg Claytonb7ad58a2013-04-04 20:35:24 +00001006 while ((ch = getopt_long_only(argc, argv, short_options, g_long_options, &long_option_index)) != -1)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001007 {
1008 DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
1009 ch, (uint8_t)ch,
1010 g_long_options[long_option_index].name,
1011 g_long_options[long_option_index].has_arg ? '=' : ' ',
1012 optarg ? optarg : "");
1013 switch (ch)
1014 {
1015 case 0: // Any optional that auto set themselves will return 0
1016 break;
1017
Greg Clayton3af9ea52010-11-18 05:57:03 +00001018 case 'A':
1019 if (optarg && optarg[0])
1020 arch_name.assign(optarg);
1021 break;
1022
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001023 case 'a':
1024 if (optarg && optarg[0])
1025 {
1026 if (isdigit(optarg[0]))
1027 {
1028 char *end = NULL;
Greg Claytonee2ed522015-03-09 19:45:23 +00001029 attach_pid = static_cast<int>(strtoul(optarg, &end, 0));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001030 if (end == NULL || *end != '\0')
1031 {
1032 RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg);
1033 exit (4);
1034 }
1035 }
1036 else
1037 {
1038 attach_pid_name = optarg;
1039 }
1040 start_mode = eRNBRunLoopModeInferiorAttaching;
1041 }
1042 break;
1043
1044 // --waitfor=NAME
1045 case 'w':
1046 if (optarg && optarg[0])
1047 {
1048 waitfor_pid_name = optarg;
1049 start_mode = eRNBRunLoopModeInferiorAttaching;
1050 }
1051 break;
1052
1053 // --waitfor-interval=USEC
1054 case 'i':
1055 if (optarg && optarg[0])
1056 {
1057 char *end = NULL;
Greg Claytonee2ed522015-03-09 19:45:23 +00001058 waitfor_interval = static_cast<useconds_t>(strtoul(optarg, &end, 0));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001059 if (end == NULL || *end != '\0')
1060 {
1061 RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
1062 exit (6);
1063 }
1064 }
1065 break;
1066
1067 // --waitfor-duration=SEC
1068 case 'd':
1069 if (optarg && optarg[0])
1070 {
1071 char *end = NULL;
Greg Claytonee2ed522015-03-09 19:45:23 +00001072 waitfor_duration = static_cast<useconds_t>(strtoul(optarg, &end, 0));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001073 if (end == NULL || *end != '\0')
1074 {
1075 RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
1076 exit (7);
1077 }
1078 }
1079 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001080
Jim Ingham5689a212014-02-25 19:57:47 +00001081 case 'K':
1082 g_detach_on_error = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001083
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001084 case 'W':
Greg Clayton6779606a2011-01-22 23:43:18 +00001085 if (optarg && optarg[0])
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001086 working_dir.assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001087 break;
1088
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001089 case 'x':
1090 if (optarg && optarg[0])
1091 {
1092 if (strcasecmp(optarg, "auto") == 0)
1093 g_launch_flavor = eLaunchFlavorDefault;
1094 else if (strcasestr(optarg, "posix") == optarg)
1095 g_launch_flavor = eLaunchFlavorPosixSpawn;
1096 else if (strcasestr(optarg, "fork") == optarg)
1097 g_launch_flavor = eLaunchFlavorForkExec;
Jason Molenda42999a42012-02-22 02:18:59 +00001098#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001099 else if (strcasestr(optarg, "spring") == optarg)
1100 g_launch_flavor = eLaunchFlavorSpringBoard;
1101#endif
Jason Molendaa3329782014-03-29 18:54:20 +00001102#ifdef WITH_BKS
1103 else if (strcasestr(optarg, "backboard") == optarg)
1104 g_launch_flavor = eLaunchFlavorBKS;
1105#endif
Jason Molendac611a742015-10-23 02:49:51 +00001106#ifdef WITH_FBS
1107 else if (strcasestr(optarg, "frontboard") == optarg)
1108 g_launch_flavor = eLaunchFlavorFBS;
1109#endif
Jason Molendaa3329782014-03-29 18:54:20 +00001110
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001111 else
1112 {
1113 RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
1114 RNBLogSTDERR ("Valid values TYPE are:\n");
Jason Molendaa3329782014-03-29 18:54:20 +00001115 RNBLogSTDERR (" auto Auto-detect the best launch method to use.\n");
1116 RNBLogSTDERR (" posix Launch the executable using posix_spawn.\n");
1117 RNBLogSTDERR (" fork Launch the executable using fork and exec.\n");
Jason Molenda42999a42012-02-22 02:18:59 +00001118#ifdef WITH_SPRINGBOARD
Jason Molendaa3329782014-03-29 18:54:20 +00001119 RNBLogSTDERR (" spring Launch the executable through Springboard.\n");
1120#endif
1121#ifdef WITH_BKS
1122 RNBLogSTDERR (" backboard Launch the executable through BackBoard Services.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001123#endif
Jason Molendac611a742015-10-23 02:49:51 +00001124#ifdef WITH_FBS
1125 RNBLogSTDERR (" frontboard Launch the executable through FrontBoard Services.\n");
1126#endif
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001127 exit (5);
1128 }
1129 }
1130 break;
1131
1132 case 'l': // Set Log File
1133 if (optarg && optarg[0])
1134 {
1135 if (strcasecmp(optarg, "stdout") == 0)
1136 log_file = stdout;
1137 else if (strcasecmp(optarg, "stderr") == 0)
1138 log_file = stderr;
1139 else
Jim Inghamc530be62011-01-24 03:46:59 +00001140 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001141 log_file = fopen(optarg, "w");
Jim Inghamc530be62011-01-24 03:46:59 +00001142 if (log_file != NULL)
1143 setlinebuf(log_file);
1144 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001145
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001146 if (log_file == NULL)
1147 {
1148 const char *errno_str = strerror(errno);
1149 RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
1150 }
1151 }
1152 break;
1153
1154 case 'f': // Log Flags
1155 if (optarg && optarg[0])
Greg Claytonee2ed522015-03-09 19:45:23 +00001156 log_flags = static_cast<uint32_t>(strtoul(optarg, NULL, 0));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001157 break;
1158
1159 case 'g':
1160 debug = 1;
Johnny Chen2fe7dd42011-08-10 23:01:39 +00001161 DNBLogSetDebug(debug);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001162 break;
1163
1164 case 't':
1165 g_applist_opt = 1;
1166 break;
1167
1168 case 'k':
1169 g_lockdown_opt = 1;
1170 break;
1171
1172 case 'r':
Greg Clayton85480022013-11-09 00:33:46 +00001173 // Do nothing, native regs is the default these days
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001174 break;
1175
Greg Clayton00fe87b2013-12-05 22:58:22 +00001176 case 'R':
1177 reverse_connect = true;
1178 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001179 case 'v':
1180 DNBLogSetVerbose(1);
1181 break;
1182
1183 case 's':
Greg Clayton71337622011-02-24 22:24:29 +00001184 ctx.GetSTDIN().assign(optarg);
1185 ctx.GetSTDOUT().assign(optarg);
1186 ctx.GetSTDERR().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001187 break;
1188
1189 case 'I':
Greg Clayton71337622011-02-24 22:24:29 +00001190 ctx.GetSTDIN().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001191 break;
1192
1193 case 'O':
Greg Clayton71337622011-02-24 22:24:29 +00001194 ctx.GetSTDOUT().assign(optarg);
Greg Clayton6779606a2011-01-22 23:43:18 +00001195 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001196
Greg Clayton6779606a2011-01-22 23:43:18 +00001197 case 'E':
Greg Clayton71337622011-02-24 22:24:29 +00001198 ctx.GetSTDERR().assign(optarg);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001199 break;
1200
Caroline Ticef8da8632010-12-03 18:46:09 +00001201 case 'n':
1202 no_stdio = true;
1203 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001204
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001205 case 'S':
1206 // Put debugserver into a new session. Terminals group processes
1207 // into sessions and when a special terminal key sequences
1208 // (like control+c) are typed they can cause signals to go out to
1209 // all processes in a session. Using this --setsid (-S) option
1210 // will cause debugserver to run in its own sessions and be free
1211 // from such issues.
1212 //
1213 // This is useful when debugserver is spawned from a command
1214 // line application that uses debugserver to do the debugging,
1215 // yet that application doesn't want debugserver receiving the
1216 // signals sent to the session (i.e. dying when anyone hits ^C).
1217 setsid();
1218 break;
Greg Claytonf681b942010-08-31 18:35:14 +00001219 case 'D':
1220 g_disable_aslr = 1;
1221 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001222
Greg Clayton7a5388b2011-03-20 04:57:14 +00001223 case 'p':
1224 start_mode = eRNBRunLoopModePlatformMode;
1225 break;
Greg Clayton8b82f082011-04-12 05:54:46 +00001226
Greg Claytonc93068b2013-12-10 19:36:45 +00001227 case 'u':
1228 unix_socket_name.assign (optarg);
1229 break;
1230
Greg Clayton91a9b2472013-12-04 19:19:12 +00001231 case 'P':
1232 named_pipe_path.assign (optarg);
Greg Clayton8b82f082011-04-12 05:54:46 +00001233 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001234
Greg Claytonce1843b2014-06-18 18:26:50 +00001235 case 'e':
1236 // Pass a single specified environment variable down to the process that gets launched
1237 remote->Context().PushEnvironment(optarg);
1238 break;
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001239
Greg Claytonce1843b2014-06-18 18:26:50 +00001240 case 'F':
1241 // Pass the current environment down to the process that gets launched
1242 {
1243 char **host_env = *_NSGetEnviron();
1244 char *env_entry;
1245 size_t i;
1246 for (i=0; (env_entry = host_env[i]) != NULL; ++i)
1247 remote->Context().PushEnvironment(env_entry);
1248 }
1249 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001250 }
1251 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001252
Greg Clayton3af9ea52010-11-18 05:57:03 +00001253 if (arch_name.empty())
1254 {
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001255#if defined (__arm__)
Greg Clayton3af9ea52010-11-18 05:57:03 +00001256 arch_name.assign ("arm");
1257#endif
1258 }
Greg Clayton3c144382010-12-01 22:45:40 +00001259 else
1260 {
1261 DNBSetArchitecture (arch_name.c_str());
1262 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001263
Greg Clayton71337622011-02-24 22:24:29 +00001264// if (arch_name.empty())
1265// {
1266// fprintf(stderr, "error: no architecture was specified\n");
1267// exit (8);
1268// }
Greg Claytonb7ad58a2013-04-04 20:35:24 +00001269 // Skip any options we consumed with getopt_long_only
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001270 argc -= optind;
1271 argv += optind;
1272
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001273
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001274 if (!working_dir.empty())
Greg Clayton6779606a2011-01-22 23:43:18 +00001275 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001276 if (remote->Context().SetWorkingDirectory (working_dir.c_str()) == false)
Greg Clayton6779606a2011-01-22 23:43:18 +00001277 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001278 RNBLogSTDERR ("error: working directory doesn't exist '%s'.\n", working_dir.c_str());
Greg Clayton6779606a2011-01-22 23:43:18 +00001279 exit (8);
1280 }
1281 }
1282
Jim Ingham58813182014-02-25 04:53:13 +00001283 remote->Context().SetDetachOnError(g_detach_on_error);
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001284
Greg Clayton6779606a2011-01-22 23:43:18 +00001285 remote->Initialize();
Greg Clayton3af9ea52010-11-18 05:57:03 +00001286
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001287 // It is ok for us to set NULL as the logfile (this will disable any logging)
1288
1289 if (log_file != NULL)
1290 {
1291 DNBLogSetLogCallback(FileLogCallback, log_file);
1292 // If our log file was set, yet we have no log flags, log everything!
1293 if (log_flags == 0)
1294 log_flags = LOG_ALL | LOG_RNB_ALL;
1295
1296 DNBLogSetLogMask (log_flags);
1297 }
1298 else
1299 {
1300 // Enable DNB logging
1301 DNBLogSetLogCallback(ASLLogCallback, NULL);
1302 DNBLogSetLogMask (log_flags);
1303
1304 }
1305
1306 if (DNBLogEnabled())
1307 {
1308 for (i=0; i<argc; i++)
1309 DNBLogDebug("argv[%i] = %s", i, argv[i]);
1310 }
1311
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001312 // as long as we're dropping remotenub in as a replacement for gdbserver,
1313 // explicitly note that this is not gdbserver.
1314
Todd Fialac3ec3372014-03-13 18:30:04 +00001315 RNBLogSTDOUT ("%s-%s %sfor %s.\n",
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001316 DEBUGSERVER_PROGRAM_NAME,
Todd Fialac3ec3372014-03-13 18:30:04 +00001317 DEBUGSERVER_VERSION_STR,
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001318 compile_options.c_str(),
1319 RNB_ARCH);
1320
Greg Clayton00fe87b2013-12-05 22:58:22 +00001321 std::string host;
1322 int port = INT32_MAX;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001323 char str[PATH_MAX];
Greg Clayton23f59502012-07-17 03:23:13 +00001324 str[0] = '\0';
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001325
1326 if (g_lockdown_opt == 0 && g_applist_opt == 0)
1327 {
1328 // Make sure we at least have port
1329 if (argc < 1)
1330 {
1331 show_usage_and_exit (1);
1332 }
1333 // accept 'localhost:' prefix on port number
1334
Greg Clayton00fe87b2013-12-05 22:58:22 +00001335 int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &port);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001336 if (items_scanned == 2)
1337 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001338 host = str;
1339 DNBLogDebug("host = '%s' port = %i", host.c_str(), port);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001340 }
1341 else
1342 {
Greg Claytonfd238892013-06-06 22:44:19 +00001343 // No hostname means "localhost"
Greg Clayton00fe87b2013-12-05 22:58:22 +00001344 int items_scanned = ::sscanf (argv[0], "%i", &port);
Greg Claytonfd238892013-06-06 22:44:19 +00001345 if (items_scanned == 1)
1346 {
Greg Clayton16810922014-02-27 19:38:18 +00001347 host = "127.0.0.1";
Greg Clayton00fe87b2013-12-05 22:58:22 +00001348 DNBLogDebug("host = '%s' port = %i", host.c_str(), port);
Greg Claytonfd238892013-06-06 22:44:19 +00001349 }
1350 else if (argv[0][0] == '/')
1351 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001352 port = INT32_MAX;
Greg Claytonfd238892013-06-06 22:44:19 +00001353 strncpy(str, argv[0], sizeof(str));
1354 }
1355 else
1356 {
1357 show_usage_and_exit (2);
1358 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001359 }
1360
1361 // We just used the 'host:port' or the '/path/file' arg...
1362 argc--;
1363 argv++;
1364
1365 }
1366
1367 // If we know we're waiting to attach, we don't need any of this other info.
Greg Clayton7a5388b2011-03-20 04:57:14 +00001368 if (start_mode != eRNBRunLoopModeInferiorAttaching &&
1369 start_mode != eRNBRunLoopModePlatformMode)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001370 {
1371 if (argc == 0 || g_lockdown_opt)
1372 {
1373 if (g_lockdown_opt != 0)
1374 {
1375 // Work around for SIGPIPE crashes due to posix_spawn issue.
1376 // We have to close STDOUT and STDERR, else the first time we
1377 // try and do any, we get SIGPIPE and die as posix_spawn is
1378 // doing bad things with our file descriptors at the moment.
1379 int null = open("/dev/null", O_RDWR);
1380 dup2(null, STDOUT_FILENO);
1381 dup2(null, STDERR_FILENO);
1382 }
1383 else if (g_applist_opt != 0)
1384 {
1385 // List all applications we are able to see
1386 std::string applist_plist;
1387 int err = ListApplications(applist_plist, false, false);
1388 if (err == 0)
1389 {
1390 fputs (applist_plist.c_str(), stdout);
1391 }
1392 else
1393 {
1394 RNBLogSTDERR ("error: ListApplications returned error %i\n", err);
1395 }
1396 // Exit with appropriate error if we were asked to list the applications
1397 // with no other args were given (and we weren't trying to do this over
1398 // lockdown)
1399 return err;
1400 }
1401
1402 DNBLogDebug("Get args from remote protocol...");
1403 start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
1404 }
1405 else
1406 {
1407 start_mode = eRNBRunLoopModeInferiorLaunching;
1408 // Fill in the argv array in the context from the rest of our args.
1409 // Skip the name of this executable and the port number
1410 for (int i = 0; i < argc; i++)
1411 {
1412 DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]);
1413 ctx.PushArgument (argv[i]);
1414 }
1415 }
1416 }
1417
1418 if (start_mode == eRNBRunLoopModeExit)
1419 return -1;
1420
1421 RNBRunLoopMode mode = start_mode;
1422 char err_str[1024] = {'\0'};
1423
1424 while (mode != eRNBRunLoopModeExit)
1425 {
1426 switch (mode)
1427 {
1428 case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
Jason Molenda42999a42012-02-22 02:18:59 +00001429#ifdef WITH_LOCKDOWN
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001430 if (g_lockdown_opt)
1431 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001432 if (!remote->Comm().IsConnected())
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001433 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001434 if (remote->Comm().ConnectToService () != rnb_success)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001435 {
1436 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
1437 mode = eRNBRunLoopModeExit;
1438 }
1439 else if (g_applist_opt != 0)
1440 {
1441 // List all applications we are able to see
1442 std::string applist_plist;
1443 if (ListApplications(applist_plist, false, false) == 0)
1444 {
1445 DNBLogDebug("Task list: %s", applist_plist.c_str());
1446
Greg Clayton6779606a2011-01-22 23:43:18 +00001447 remote->Comm().Write(applist_plist.c_str(), applist_plist.size());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001448 // Issue a read that will never yield any data until the other side
1449 // closes the socket so this process doesn't just exit and cause the
1450 // socket to close prematurely on the other end and cause data loss.
1451 std::string buf;
Greg Clayton6779606a2011-01-22 23:43:18 +00001452 remote->Comm().Read(buf);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001453 }
Greg Clayton6779606a2011-01-22 23:43:18 +00001454 remote->Comm().Disconnect(false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001455 mode = eRNBRunLoopModeExit;
1456 break;
1457 }
1458 else
1459 {
1460 // Start watching for remote packets
Greg Clayton6779606a2011-01-22 23:43:18 +00001461 remote->StartReadRemoteDataThread();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001462 }
1463 }
1464 }
1465 else
1466#endif
Greg Clayton00fe87b2013-12-05 22:58:22 +00001467 if (port != INT32_MAX)
Greg Clayton7a5388b2011-03-20 04:57:14 +00001468 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001469 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 +00001470 mode = eRNBRunLoopModeExit;
1471 }
1472 else if (str[0] == '/')
1473 {
1474 if (remote->Comm().OpenFile (str))
1475 mode = eRNBRunLoopModeExit;
1476 }
1477
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001478 if (mode != eRNBRunLoopModeExit)
1479 {
1480 RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
1481
Greg Clayton6779606a2011-01-22 23:43:18 +00001482 mode = RNBRunLoopGetStartModeFromRemote (remote);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001483 }
1484 break;
1485
1486 case eRNBRunLoopModeInferiorAttaching:
1487 if (!waitfor_pid_name.empty())
1488 {
1489 // Set our end wait time if we are using a waitfor-duration
1490 // option that may have been specified
1491 struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1492 if (waitfor_duration != 0)
1493 {
1494 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1495 timeout_ptr = &attach_timeout_abstime;
1496 }
1497 nub_launch_flavor_t launch_flavor = g_launch_flavor;
1498 if (launch_flavor == eLaunchFlavorDefault)
1499 {
1500 // Our default launch method is posix spawn
1501 launch_flavor = eLaunchFlavorPosixSpawn;
1502
Jason Molendac611a742015-10-23 02:49:51 +00001503#if defined WITH_FBS
1504 // Check if we have an app bundle, if so launch using SpringBoard.
1505 if (waitfor_pid_name.find (".app") != std::string::npos)
1506 {
1507 launch_flavor = eLaunchFlavorFBS;
1508 }
1509#elif defined WITH_BKS
Jason Molendaa3329782014-03-29 18:54:20 +00001510 // Check if we have an app bundle, if so launch using SpringBoard.
1511 if (waitfor_pid_name.find (".app") != std::string::npos)
1512 {
1513 launch_flavor = eLaunchFlavorBKS;
1514 }
1515#elif defined WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001516 // Check if we have an app bundle, if so launch using SpringBoard.
1517 if (waitfor_pid_name.find (".app") != std::string::npos)
1518 {
1519 launch_flavor = eLaunchFlavorSpringBoard;
1520 }
1521#endif
1522 }
1523
1524 ctx.SetLaunchFlavor(launch_flavor);
Jim Inghamcd16df92012-07-20 21:37:13 +00001525 bool ignore_existing = false;
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001526 RNBLogSTDOUT ("Waiting to attach to process %s...\n", waitfor_pid_name.c_str());
Jim Inghamcd16df92012-07-20 21:37:13 +00001527 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 +00001528 g_pid = pid;
1529
1530 if (pid == INVALID_NUB_PROCESS)
1531 {
1532 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1533 if (err_str[0])
1534 ctx.LaunchStatus().SetErrorString(err_str);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001535 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 +00001536 mode = eRNBRunLoopModeExit;
1537 }
1538 else
1539 {
1540 ctx.SetProcessID(pid);
1541 mode = eRNBRunLoopModeInferiorExecuting;
1542 }
1543 }
1544 else if (attach_pid != INVALID_NUB_PROCESS)
1545 {
1546
1547 RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid);
1548 nub_process_t attached_pid;
Greg Clayton6779606a2011-01-22 23:43:18 +00001549 mode = RNBRunLoopLaunchAttaching (remote, attach_pid, attached_pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001550 if (mode != eRNBRunLoopModeInferiorExecuting)
1551 {
1552 const char *error_str = remote->Context().LaunchStatus().AsString();
1553 RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
1554 mode = eRNBRunLoopModeExit;
1555 }
1556 }
1557 else if (!attach_pid_name.empty ())
1558 {
1559 struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1560 if (waitfor_duration != 0)
1561 {
1562 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1563 timeout_ptr = &attach_timeout_abstime;
1564 }
1565
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001566 RNBLogSTDOUT ("Attaching to process %s...\n", attach_pid_name.c_str());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001567 nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str));
1568 g_pid = pid;
1569 if (pid == INVALID_NUB_PROCESS)
1570 {
1571 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1572 if (err_str[0])
1573 ctx.LaunchStatus().SetErrorString(err_str);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001574 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 +00001575 mode = eRNBRunLoopModeExit;
1576 }
1577 else
1578 {
1579 ctx.SetProcessID(pid);
1580 mode = eRNBRunLoopModeInferiorExecuting;
1581 }
1582
1583 }
1584 else
1585 {
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001586 RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001587 mode = eRNBRunLoopModeExit;
1588 }
1589
1590 if (mode != eRNBRunLoopModeExit)
1591 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001592 if (port != INT32_MAX)
Chris Lattner30fdc8d2010-06-08 16:52:24 +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()))
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001595 mode = eRNBRunLoopModeExit;
1596 }
1597 else if (str[0] == '/')
1598 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001599 if (remote->Comm().OpenFile (str))
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001600 mode = eRNBRunLoopModeExit;
1601 }
1602 if (mode != eRNBRunLoopModeExit)
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001603 RNBLogSTDOUT ("Waiting for debugger instructions for process %d.\n", attach_pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001604 }
1605 break;
1606
1607 case eRNBRunLoopModeInferiorLaunching:
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001608 {
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001609 mode = RNBRunLoopLaunchInferior (remote,
Greg Clayton71337622011-02-24 22:24:29 +00001610 ctx.GetSTDINPath(),
1611 ctx.GetSTDOUTPath(),
1612 ctx.GetSTDERRPath(),
Greg Clayton6779606a2011-01-22 23:43:18 +00001613 no_stdio);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001614
Greg Clayton6779606a2011-01-22 23:43:18 +00001615 if (mode == eRNBRunLoopModeInferiorExecuting)
1616 {
Greg Clayton00fe87b2013-12-05 22:58:22 +00001617 if (port != INT32_MAX)
Greg Clayton6779606a2011-01-22 23:43:18 +00001618 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001619 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 +00001620 mode = eRNBRunLoopModeExit;
1621 }
1622 else if (str[0] == '/')
1623 {
1624 if (remote->Comm().OpenFile (str))
1625 mode = eRNBRunLoopModeExit;
1626 }
1627
1628 if (mode != eRNBRunLoopModeExit)
Jim Ingham5689a212014-02-25 19:57:47 +00001629 {
1630 const char *proc_name = "<unknown>";
1631 if (ctx.ArgumentCount() > 0)
1632 proc_name = ctx.ArgumentAtIndex(0);
1633 RNBLogSTDOUT ("Got a connection, launched process %s (pid = %d).\n", proc_name, ctx.ProcessID());
1634 }
Greg Clayton6779606a2011-01-22 23:43:18 +00001635 }
1636 else
1637 {
1638 const char *error_str = remote->Context().LaunchStatus().AsString();
Jason Molenda0b2dbe02012-11-01 02:02:59 +00001639 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 +00001640 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001641 }
1642 break;
1643
1644 case eRNBRunLoopModeInferiorExecuting:
Greg Clayton6779606a2011-01-22 23:43:18 +00001645 mode = RNBRunLoopInferiorExecuting(remote);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001646 break;
1647
Greg Clayton7a5388b2011-03-20 04:57:14 +00001648 case eRNBRunLoopModePlatformMode:
Greg Clayton00fe87b2013-12-05 22:58:22 +00001649 if (port != INT32_MAX)
Greg Clayton7a5388b2011-03-20 04:57:14 +00001650 {
Greg Claytonc93068b2013-12-10 19:36:45 +00001651 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 +00001652 mode = eRNBRunLoopModeExit;
1653 }
1654 else if (str[0] == '/')
1655 {
1656 if (remote->Comm().OpenFile (str))
1657 mode = eRNBRunLoopModeExit;
1658 }
Ramkumar Ramachandrad5fa2262015-11-03 21:29:52 +00001659
Greg Clayton7a5388b2011-03-20 04:57:14 +00001660 if (mode != eRNBRunLoopModeExit)
1661 mode = RNBRunLoopPlatform (remote);
1662 break;
1663
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001664 default:
1665 mode = eRNBRunLoopModeExit;
1666 case eRNBRunLoopModeExit:
1667 break;
1668 }
1669 }
1670
Greg Clayton6779606a2011-01-22 23:43:18 +00001671 remote->StopReadRemoteDataThread ();
1672 remote->Context().SetProcessID(INVALID_NUB_PROCESS);
Jim Inghame2ff0ba2013-02-25 19:31:37 +00001673 RNBLogSTDOUT ("Exiting.\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001674
1675 return 0;
1676}