blob: f7696acfb99bc0df07d529e87dc3a17e23ddf8fc [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>
20
21#include "CFString.h"
22#include "DNB.h"
23#include "DNBLog.h"
24#include "DNBTimer.h"
25#include "PseudoTerminal.h"
26#include "RNBContext.h"
27#include "RNBServices.h"
28#include "RNBSocket.h"
29#include "RNBRemote.h"
30#include "SysSignal.h"
31
32// Global PID in case we get a signal and need to stop the process...
33nub_process_t g_pid = INVALID_NUB_PROCESS;
34
35//----------------------------------------------------------------------
36// Run loop modes which determine which run loop function will be called
37//----------------------------------------------------------------------
38typedef enum
39{
40 eRNBRunLoopModeInvalid = 0,
41 eRNBRunLoopModeGetStartModeFromRemoteProtocol,
42 eRNBRunLoopModeInferiorAttaching,
43 eRNBRunLoopModeInferiorLaunching,
44 eRNBRunLoopModeInferiorExecuting,
45 eRNBRunLoopModeExit
46} RNBRunLoopMode;
47
48
49//----------------------------------------------------------------------
50// Global Variables
51//----------------------------------------------------------------------
52RNBRemoteSP g_remoteSP;
53static int g_lockdown_opt = 0;
54static int g_applist_opt = 0;
55static nub_launch_flavor_t g_launch_flavor = eLaunchFlavorDefault;
Greg Clayton6f35f5c2010-09-09 06:32:46 +000056int g_disable_aslr = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000057
58int g_isatty = 0;
59
60#define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
61#define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
62
63//----------------------------------------------------------------------
64// Run Loop function prototypes
65//----------------------------------------------------------------------
66RNBRunLoopMode RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remote);
67RNBRunLoopMode RNBRunLoopInferiorExecuting (RNBRemoteSP &remote);
68
69
70//----------------------------------------------------------------------
71// Get our program path and arguments from the remote connection.
72// We will need to start up the remote connection without a PID, get the
73// arguments, wait for the new process to finish launching and hit its
74// entry point, and then return the run loop mode that should come next.
75//----------------------------------------------------------------------
76RNBRunLoopMode
77RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP)
78{
79 std::string packet;
80
81 if (remoteSP.get() != NULL)
82 {
83 RNBRemote* remote = remoteSP.get();
84 RNBContext& ctx = remote->Context();
85 uint32_t event_mask = RNBContext::event_read_packet_available;
86
87 // Spin waiting to get the A packet.
88 while (1)
89 {
90 DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask);
91 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
92 DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events);
93
94 if (set_events & RNBContext::event_read_packet_available)
95 {
96 rnb_err_t err = rnb_err;
97 RNBRemote::PacketEnum type;
98
99 err = remote->HandleReceivedPacket (&type);
100
101 // check if we tried to attach to a process
102 if (type == RNBRemote::vattach || type == RNBRemote::vattachwait)
103 {
104 if (err == rnb_success)
105 return eRNBRunLoopModeInferiorExecuting;
106 else
107 {
108 RNBLogSTDERR ("error: attach failed.");
109 return eRNBRunLoopModeExit;
110 }
111 }
112
113 if (err == rnb_success)
114 {
115 // If we got our arguments we are ready to launch using the arguments
116 // and any environment variables we received.
117 if (type == RNBRemote::set_argv)
118 {
119 return eRNBRunLoopModeInferiorLaunching;
120 }
121 }
122 else if (err == rnb_not_connected)
123 {
124 RNBLogSTDERR ("error: connection lost.");
125 return eRNBRunLoopModeExit;
126 }
127 else
128 {
129 // a catch all for any other gdb remote packets that failed
130 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__);
131 continue;
132 }
133
134 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
135 }
136 else
137 {
138 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__);
139 return eRNBRunLoopModeExit;
140 }
141 }
142 }
143 return eRNBRunLoopModeExit;
144}
145
146
147//----------------------------------------------------------------------
148// This run loop mode will wait for the process to launch and hit its
149// entry point. It will currently ignore all events except for the
150// process state changed event, where it watches for the process stopped
151// or crash process state.
152//----------------------------------------------------------------------
153RNBRunLoopMode
154RNBRunLoopLaunchInferior (RNBRemoteSP &remote, const char *stdio_path)
155{
156 RNBContext& ctx = remote->Context();
157
158 // The Process stuff takes a c array, the RNBContext has a vector...
159 // So make up a c array.
160
161 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, ctx.ArgumentAtIndex(0));
162
163 size_t inferior_argc = ctx.ArgumentCount();
164 // Initialize inferior_argv with inferior_argc + 1 NULLs
165 std::vector<const char *> inferior_argv(inferior_argc + 1, NULL);
166
167 size_t i;
168 for (i = 0; i < inferior_argc; i++)
169 inferior_argv[i] = ctx.ArgumentAtIndex(i);
170
171 // Pass the environment array the same way:
172
173 size_t inferior_envc = ctx.EnvironmentCount();
174 // Initialize inferior_argv with inferior_argc + 1 NULLs
175 std::vector<const char *> inferior_envp(inferior_envc + 1, NULL);
176
177 for (i = 0; i < inferior_envc; i++)
178 inferior_envp[i] = ctx.EnvironmentAtIndex(i);
179
180 // Our launch type hasn't been set to anything concrete, so we need to
181 // figure our how we are going to launch automatically.
182
183 nub_launch_flavor_t launch_flavor = g_launch_flavor;
184 if (launch_flavor == eLaunchFlavorDefault)
185 {
186 // Our default launch method is posix spawn
187 launch_flavor = eLaunchFlavorPosixSpawn;
188
189#if defined (__arm__)
190 // Check if we have an app bundle, if so launch using SpringBoard.
191 if (strstr(inferior_argv[0], ".app"))
192 {
193 launch_flavor = eLaunchFlavorSpringBoard;
194 }
195#endif
196 }
197
198 ctx.SetLaunchFlavor(launch_flavor);
199 char resolved_path[PATH_MAX];
200
201 // If we fail to resolve the path to our executable, then just use what we
202 // were given and hope for the best
203 if ( !DNBResolveExecutablePath (inferior_argv[0], resolved_path, sizeof(resolved_path)) )
204 ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path));
205
206 char launch_err_str[PATH_MAX];
207 launch_err_str[0] = '\0';
208 nub_process_t pid = DNBProcessLaunch (resolved_path,
209 &inferior_argv[0],
210 &inferior_envp[0],
211 stdio_path,
212 launch_flavor,
Greg Claytonf681b942010-08-31 18:35:14 +0000213 g_disable_aslr,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000214 launch_err_str,
215 sizeof(launch_err_str));
216
217 g_pid = pid;
218
219 if (pid == INVALID_NUB_PROCESS && strlen(launch_err_str) > 0)
220 {
Greg Clayton3382c2c2010-07-30 23:14:42 +0000221 DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, launch_err_str);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000222 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
223 ctx.LaunchStatus().SetErrorString(launch_err_str);
224 }
225 else
226 ctx.LaunchStatus().Clear();
227
228 if (remote->Comm().IsConnected())
229 {
230 // It we are connected already, the next thing gdb will do is ask
231 // whether the launch succeeded, and if not, whether there is an
232 // error code. So we need to fetch one packet from gdb before we wait
233 // on the stop from the target.
234
235 uint32_t event_mask = RNBContext::event_read_packet_available;
236 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
237
238 if (set_events & RNBContext::event_read_packet_available)
239 {
240 rnb_err_t err = rnb_err;
241 RNBRemote::PacketEnum type;
242
243 err = remote->HandleReceivedPacket (&type);
244
245 if (err != rnb_success)
246 {
247 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__);
248 return eRNBRunLoopModeExit;
249 }
250 if (type != RNBRemote::query_launch_success)
251 {
252 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__);
253 }
254 }
255 }
256
257 while (pid != INVALID_NUB_PROCESS)
258 {
259 // Wait for process to start up and hit entry point
260 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid);
261 nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL);
262 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events);
263
264 if (set_events == 0)
265 {
266 pid = INVALID_NUB_PROCESS;
267 g_pid = pid;
268 }
269 else
270 {
271 if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
272 {
273 nub_state_t pid_state = DNBProcessGetState (pid);
274 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
275
276 switch (pid_state)
277 {
278 default:
279 case eStateInvalid:
280 case eStateUnloaded:
281 case eStateAttaching:
282 case eStateLaunching:
283 case eStateSuspended:
284 break; // Ignore
285
286 case eStateRunning:
287 case eStateStepping:
288 // Still waiting to stop at entry point...
289 break;
290
291 case eStateStopped:
292 case eStateCrashed:
293 ctx.SetProcessID(pid);
294 return eRNBRunLoopModeInferiorExecuting;
295
296 case eStateDetached:
297 case eStateExited:
298 pid = INVALID_NUB_PROCESS;
299 g_pid = pid;
300 return eRNBRunLoopModeExit;
301 }
302 }
303
304 DNBProcessResetEvents(pid, set_events);
305 }
306 }
307
308 return eRNBRunLoopModeExit;
309}
310
311
312//----------------------------------------------------------------------
313// This run loop mode will wait for the process to launch and hit its
314// entry point. It will currently ignore all events except for the
315// process state changed event, where it watches for the process stopped
316// or crash process state.
317//----------------------------------------------------------------------
318RNBRunLoopMode
319RNBRunLoopLaunchAttaching (RNBRemoteSP &remote, nub_process_t attach_pid, nub_process_t& pid)
320{
321 RNBContext& ctx = remote->Context();
322
323 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid);
324 char err_str[1024];
325 pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str));
326 g_pid = pid;
327
328 if (pid == INVALID_NUB_PROCESS)
329 {
330 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
331 if (err_str[0])
332 ctx.LaunchStatus().SetErrorString(err_str);
333 return eRNBRunLoopModeExit;
334 }
335 else
336 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000337 ctx.SetProcessID(pid);
338 return eRNBRunLoopModeInferiorExecuting;
339 }
340}
341
342//----------------------------------------------------------------------
343// Watch for signals:
344// SIGINT: so we can halt our inferior. (disabled for now)
345// SIGPIPE: in case our child process dies
346//----------------------------------------------------------------------
347int g_sigint_received = 0;
348int g_sigpipe_received = 0;
349void
350signal_handler(int signo)
351{
352 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo));
353
354 switch (signo)
355 {
356 case SIGINT:
357 g_sigint_received++;
358 if (g_pid != INVALID_NUB_PROCESS)
359 {
360 // Only send a SIGINT once...
361 if (g_sigint_received == 1)
362 {
363 switch (DNBProcessGetState (g_pid))
364 {
365 case eStateRunning:
366 case eStateStepping:
367 DNBProcessSignal (g_pid, SIGSTOP);
368 return;
369 }
370 }
371 }
372 exit (SIGINT);
373 break;
374
375 case SIGPIPE:
376 g_sigpipe_received = 1;
377 break;
378 }
379}
380
381// Return the new run loop mode based off of the current process state
382RNBRunLoopMode
383HandleProcessStateChange (RNBRemoteSP &remote, bool initialize)
384{
385 RNBContext& ctx = remote->Context();
386 nub_process_t pid = ctx.ProcessID();
387
388 if (pid == INVALID_NUB_PROCESS)
389 {
390 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
391 return eRNBRunLoopModeExit;
392 }
393 nub_state_t pid_state = DNBProcessGetState (pid);
394
395 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state));
396
397 switch (pid_state)
398 {
399 case eStateInvalid:
400 case eStateUnloaded:
401 // Something bad happened
402 return eRNBRunLoopModeExit;
403 break;
404
405 case eStateAttaching:
406 case eStateLaunching:
407 return eRNBRunLoopModeInferiorExecuting;
408
409 case eStateSuspended:
410 case eStateCrashed:
411 case eStateStopped:
412 // If we stop due to a signal, so clear the fact that we got a SIGINT
413 // so we can stop ourselves again (but only while our inferior
414 // process is running..)
415 g_sigint_received = 0;
416 if (initialize == false)
417 {
418 // Compare the last stop count to our current notion of a stop count
419 // to make sure we don't notify more than once for a given stop.
420 nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
421 bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid));
422 if (pid_stop_count_changed)
423 {
424 remote->FlushSTDIO();
425
426 if (ctx.GetProcessStopCount() == 1)
427 {
428 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
429 }
430 else
431 {
432
433 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? YES!!!", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
434 remote->NotifyThatProcessStopped ();
435 }
436 }
437 else
438 {
439 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %u (old %u)) Notify??? skipping...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count);
440 }
441 }
442 return eRNBRunLoopModeInferiorExecuting;
443
444 case eStateStepping:
445 case eStateRunning:
446 return eRNBRunLoopModeInferiorExecuting;
447
448 case eStateExited:
449 remote->HandlePacket_last_signal(NULL);
450 return eRNBRunLoopModeExit;
451
452 }
453
454 // Catch all...
455 return eRNBRunLoopModeExit;
456}
457// This function handles the case where our inferior program is stopped and
458// we are waiting for gdb remote protocol packets. When a packet occurs that
459// makes the inferior run, we need to leave this function with a new state
460// as the return code.
461RNBRunLoopMode
462RNBRunLoopInferiorExecuting (RNBRemoteSP &remote)
463{
464 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
465 RNBContext& ctx = remote->Context();
466
467 // Init our mode and set 'is_running' based on the current process state
468 RNBRunLoopMode mode = HandleProcessStateChange (remote, true);
469
470 while (ctx.ProcessID() != INVALID_NUB_PROCESS)
471 {
472
473 std::string set_events_str;
474 uint32_t event_mask = ctx.NormalEventBits();
475
476 if (!ctx.ProcessStateRunning())
477 {
478 // Clear the stdio bits if we are not running so we don't send any async packets
479 event_mask &= ~RNBContext::event_proc_stdio_available;
480 }
481
482 // We want to make sure we consume all process state changes and have
483 // whomever is notifying us to wait for us to reset the event bit before
484 // continuing.
485 //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
486
487 DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
488 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
489 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));
490
491 if (set_events)
492 {
493 if ((set_events & RNBContext::event_proc_thread_exiting) ||
494 (set_events & RNBContext::event_proc_stdio_available))
495 {
496 remote->FlushSTDIO();
497 }
498
499 if (set_events & RNBContext::event_read_packet_available)
500 {
501 // handleReceivedPacket will take care of resetting the
502 // event_read_packet_available events when there are no more...
503 set_events ^= RNBContext::event_read_packet_available;
504
505 if (ctx.ProcessStateRunning())
506 {
507 if (remote->HandleAsyncPacket() == rnb_not_connected)
508 {
509 // TODO: connect again? Exit?
510 }
511 }
512 else
513 {
514 if (remote->HandleReceivedPacket() == rnb_not_connected)
515 {
516 // TODO: connect again? Exit?
517 }
518 }
519 }
520
521 if (set_events & RNBContext::event_proc_state_changed)
522 {
523 mode = HandleProcessStateChange (remote, false);
524 ctx.Events().ResetEvents(RNBContext::event_proc_state_changed);
525 set_events ^= RNBContext::event_proc_state_changed;
526 }
527
528 if (set_events & RNBContext::event_proc_thread_exiting)
529 {
530 mode = eRNBRunLoopModeExit;
531 }
532
533 if (set_events & RNBContext::event_read_thread_exiting)
534 {
535 // Out remote packet receiving thread exited, exit for now.
536 if (ctx.HasValidProcessID())
537 {
538 // TODO: We should add code that will leave the current process
539 // in its current state and listen for another connection...
540 if (ctx.ProcessStateRunning())
541 {
542 DNBProcessKill (ctx.ProcessID());
543 }
544 }
545 mode = eRNBRunLoopModeExit;
546 }
547 }
548
549 // Reset all event bits that weren't reset for now...
550 if (set_events != 0)
551 ctx.Events().ResetEvents(set_events);
552
553 if (mode != eRNBRunLoopModeInferiorExecuting)
554 break;
555 }
556
557 return mode;
558}
559
560
561//----------------------------------------------------------------------
562// Convenience function to set up the remote listening port
563// Returns 1 for success 0 for failure.
564//----------------------------------------------------------------------
565
566static int
567StartListening (RNBRemoteSP remoteSP, int listen_port)
568{
569 if (!remoteSP->Comm().IsConnected())
570 {
571 RNBLogSTDOUT ("Listening to port %i...\n", listen_port);
572 if (remoteSP->Comm().Listen(listen_port) != rnb_success)
573 {
574 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
575 return 0;
576 }
577 else
578 {
579 remoteSP->StartReadRemoteDataThread();
580 }
581 }
582 return 1;
583}
584
585//----------------------------------------------------------------------
586// ASL Logging callback that can be registered with DNBLogSetLogCallback
587//----------------------------------------------------------------------
588void
589ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
590{
591 if (format == NULL)
592 return;
593 static aslmsg g_aslmsg = NULL;
594 if (g_aslmsg == NULL)
595 {
596 g_aslmsg = ::asl_new (ASL_TYPE_MSG);
597 char asl_key_sender[PATH_MAX];
598 snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.%s-%g", DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_NUM);
599 ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
600 }
601
602 int asl_level;
603 if (flags & DNBLOG_FLAG_FATAL) asl_level = ASL_LEVEL_CRIT;
604 else if (flags & DNBLOG_FLAG_ERROR) asl_level = ASL_LEVEL_ERR;
605 else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING;
606 else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO;
607 else asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG;
608
609 ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
610}
611
612//----------------------------------------------------------------------
613// FILE based Logging callback that can be registered with
614// DNBLogSetLogCallback
615//----------------------------------------------------------------------
616void
617FileLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
618{
619 if (baton == NULL || format == NULL)
620 return;
621
622 ::vfprintf ((FILE *)baton, format, args);
623 ::fprintf ((FILE *)baton, "\n");
624}
625
626
627void
628show_usage_and_exit (int exit_code)
629{
630 RNBLogSTDERR ("Usage:\n %s host:port [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
631 RNBLogSTDERR (" %s /path/file [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME);
632 RNBLogSTDERR (" %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
633 RNBLogSTDERR (" %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME);
634 RNBLogSTDERR (" %s host:port --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
635 RNBLogSTDERR (" %s /path/file --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME);
636 exit (exit_code);
637}
638
639
640//----------------------------------------------------------------------
641// option descriptors for getopt_long()
642//----------------------------------------------------------------------
643static struct option g_long_options[] =
644{
645 { "attach", required_argument, NULL, 'a' },
Greg Clayton3af9ea52010-11-18 05:57:03 +0000646 { "arch", required_argument, NULL, 'A' },
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000647 { "debug", no_argument, NULL, 'g' },
648 { "verbose", no_argument, NULL, 'v' },
649 { "lockdown", no_argument, &g_lockdown_opt, 1 }, // short option "-k"
650 { "applist", no_argument, &g_applist_opt, 1 }, // short option "-t"
651 { "log-file", required_argument, NULL, 'l' },
652 { "log-flags", required_argument, NULL, 'f' },
653 { "launch", required_argument, NULL, 'x' }, // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only)
654 { "waitfor", required_argument, NULL, 'w' }, // Wait for a process whose name starts with ARG
655 { "waitfor-interval", required_argument, NULL, 'i' }, // Time in usecs to wait between sampling the pid list when waiting for a process by name
656 { "waitfor-duration", required_argument, NULL, 'd' }, // The time in seconds to wait for a process to show up by name
657 { "native-regs", no_argument, NULL, 'r' }, // Specify to use the native registers instead of the gdb defaults for the architecture.
658 { "stdio-path", required_argument, NULL, 's' }, // Set the STDIO path to be used when launching applications
659 { "setsid", no_argument, NULL, 'S' }, // call setsid() to make debugserver run in its own sessions
Greg Claytonf681b942010-08-31 18:35:14 +0000660 { "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000661 { NULL, 0, NULL, 0 }
662};
663
664
665//----------------------------------------------------------------------
666// main
667//----------------------------------------------------------------------
668int
669main (int argc, char *argv[])
670{
671 g_isatty = ::isatty (STDIN_FILENO);
672
673 // ::printf ("uid=%u euid=%u gid=%u egid=%u\n",
674 // getuid(),
675 // geteuid(),
676 // getgid(),
677 // getegid());
678
679
680 // signal (SIGINT, signal_handler);
681 signal (SIGPIPE, signal_handler);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000682 signal (SIGHUP, signal_handler);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000683
684 int i;
685 int attach_pid = INVALID_NUB_PROCESS;
686
687 FILE* log_file = NULL;
688 uint32_t log_flags = 0;
689 // Parse our options
690 int ch;
691 int long_option_index = 0;
692 int use_native_registers = 0;
693 int debug = 0;
694 std::string compile_options;
695 std::string waitfor_pid_name; // Wait for a process that starts with this name
696 std::string attach_pid_name;
697 std::string stdio_path;
Greg Clayton3af9ea52010-11-18 05:57:03 +0000698 std::string arch_name;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000699 useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
700 useconds_t waitfor_duration = 0; // Time in seconds to wait for a process by name, 0 means wait forever.
701
702#if !defined (DNBLOG_ENABLED)
703 compile_options += "(no-logging) ";
704#endif
705
706 RNBRunLoopMode start_mode = eRNBRunLoopModeExit;
707
Greg Clayton3af9ea52010-11-18 05:57:03 +0000708 while ((ch = getopt_long(argc, argv, "a:A:d:gi:vktl:f:w:x:rs:", g_long_options, &long_option_index)) != -1)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000709 {
710 DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n",
711 ch, (uint8_t)ch,
712 g_long_options[long_option_index].name,
713 g_long_options[long_option_index].has_arg ? '=' : ' ',
714 optarg ? optarg : "");
715 switch (ch)
716 {
717 case 0: // Any optional that auto set themselves will return 0
718 break;
719
Greg Clayton3af9ea52010-11-18 05:57:03 +0000720 case 'A':
721 if (optarg && optarg[0])
722 arch_name.assign(optarg);
723 break;
724
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000725 case 'a':
726 if (optarg && optarg[0])
727 {
728 if (isdigit(optarg[0]))
729 {
730 char *end = NULL;
731 attach_pid = strtoul(optarg, &end, 0);
732 if (end == NULL || *end != '\0')
733 {
734 RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg);
735 exit (4);
736 }
737 }
738 else
739 {
740 attach_pid_name = optarg;
741 }
742 start_mode = eRNBRunLoopModeInferiorAttaching;
743 }
744 break;
745
746 // --waitfor=NAME
747 case 'w':
748 if (optarg && optarg[0])
749 {
750 waitfor_pid_name = optarg;
751 start_mode = eRNBRunLoopModeInferiorAttaching;
752 }
753 break;
754
755 // --waitfor-interval=USEC
756 case 'i':
757 if (optarg && optarg[0])
758 {
759 char *end = NULL;
760 waitfor_interval = strtoul(optarg, &end, 0);
761 if (end == NULL || *end != '\0')
762 {
763 RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg);
764 exit (6);
765 }
766 }
767 break;
768
769 // --waitfor-duration=SEC
770 case 'd':
771 if (optarg && optarg[0])
772 {
773 char *end = NULL;
774 waitfor_duration = strtoul(optarg, &end, 0);
775 if (end == NULL || *end != '\0')
776 {
777 RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg);
778 exit (7);
779 }
780 }
781 break;
782
783 case 'x':
784 if (optarg && optarg[0])
785 {
786 if (strcasecmp(optarg, "auto") == 0)
787 g_launch_flavor = eLaunchFlavorDefault;
788 else if (strcasestr(optarg, "posix") == optarg)
789 g_launch_flavor = eLaunchFlavorPosixSpawn;
790 else if (strcasestr(optarg, "fork") == optarg)
791 g_launch_flavor = eLaunchFlavorForkExec;
792#if defined (__arm__)
793 else if (strcasestr(optarg, "spring") == optarg)
794 g_launch_flavor = eLaunchFlavorSpringBoard;
795#endif
796 else
797 {
798 RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg);
799 RNBLogSTDERR ("Valid values TYPE are:\n");
800 RNBLogSTDERR (" auto Auto-detect the best launch method to use.\n");
801 RNBLogSTDERR (" posix Launch the executable using posix_spawn.\n");
802 RNBLogSTDERR (" fork Launch the executable using fork and exec.\n");
803#if defined (__arm__)
804 RNBLogSTDERR (" spring Launch the executable through Springboard.\n");
805#endif
806 exit (5);
807 }
808 }
809 break;
810
811 case 'l': // Set Log File
812 if (optarg && optarg[0])
813 {
814 if (strcasecmp(optarg, "stdout") == 0)
815 log_file = stdout;
816 else if (strcasecmp(optarg, "stderr") == 0)
817 log_file = stderr;
818 else
819 log_file = fopen(optarg, "w+");
820
821 if (log_file == NULL)
822 {
823 const char *errno_str = strerror(errno);
824 RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error");
825 }
826 }
827 break;
828
829 case 'f': // Log Flags
830 if (optarg && optarg[0])
831 log_flags = strtoul(optarg, NULL, 0);
832 break;
833
834 case 'g':
835 debug = 1;
836 DNBLogSetDebug(1);
837 break;
838
839 case 't':
840 g_applist_opt = 1;
841 break;
842
843 case 'k':
844 g_lockdown_opt = 1;
845 break;
846
847 case 'r':
848 use_native_registers = 1;
849 break;
850
851 case 'v':
852 DNBLogSetVerbose(1);
853 break;
854
855 case 's':
856 stdio_path = optarg;
857 break;
858
859 case 'S':
860 // Put debugserver into a new session. Terminals group processes
861 // into sessions and when a special terminal key sequences
862 // (like control+c) are typed they can cause signals to go out to
863 // all processes in a session. Using this --setsid (-S) option
864 // will cause debugserver to run in its own sessions and be free
865 // from such issues.
866 //
867 // This is useful when debugserver is spawned from a command
868 // line application that uses debugserver to do the debugging,
869 // yet that application doesn't want debugserver receiving the
870 // signals sent to the session (i.e. dying when anyone hits ^C).
871 setsid();
872 break;
Greg Claytonf681b942010-08-31 18:35:14 +0000873 case 'D':
874 g_disable_aslr = 1;
875 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000876 }
877 }
Greg Clayton3af9ea52010-11-18 05:57:03 +0000878
879 if (arch_name.empty())
880 {
881#if defined (__i386__)
882 arch_name.assign ("i386");
883#elif defined (__x86_64__)
884 arch_name.assign ("x86_64");
885#elif defined (__arm__)
886 arch_name.assign ("arm");
887#endif
888 }
Greg Clayton3c144382010-12-01 22:45:40 +0000889 else
890 {
891 DNBSetArchitecture (arch_name.c_str());
892 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000893
Greg Clayton3af9ea52010-11-18 05:57:03 +0000894 if (arch_name.empty())
895 {
896 fprintf(stderr, "error: no architecture was specified\n");
897 exit (8);
898 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000899 // Skip any options we consumed with getopt_long
900 argc -= optind;
901 argv += optind;
902
Greg Clayton3af9ea52010-11-18 05:57:03 +0000903 g_remoteSP.reset (new RNBRemote (use_native_registers, arch_name.c_str()));
Greg Clayton3c144382010-12-01 22:45:40 +0000904
905
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000906
907 RNBRemote *remote = g_remoteSP.get();
908 if (remote == NULL)
909 {
910 RNBLogSTDERR ("error: failed to create a remote connection class\n");
911 return -1;
912 }
913
Greg Clayton3af9ea52010-11-18 05:57:03 +0000914 g_remoteSP->Initialize();
915
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000916 RNBContext& ctx = remote->Context();
917
918
919 // It is ok for us to set NULL as the logfile (this will disable any logging)
920
921 if (log_file != NULL)
922 {
923 DNBLogSetLogCallback(FileLogCallback, log_file);
924 // If our log file was set, yet we have no log flags, log everything!
925 if (log_flags == 0)
926 log_flags = LOG_ALL | LOG_RNB_ALL;
927
928 DNBLogSetLogMask (log_flags);
929 }
930 else
931 {
932 // Enable DNB logging
933 DNBLogSetLogCallback(ASLLogCallback, NULL);
934 DNBLogSetLogMask (log_flags);
935
936 }
937
938 if (DNBLogEnabled())
939 {
940 for (i=0; i<argc; i++)
941 DNBLogDebug("argv[%i] = %s", i, argv[i]);
942 }
943
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000944 // as long as we're dropping remotenub in as a replacement for gdbserver,
945 // explicitly note that this is not gdbserver.
946
947 RNBLogSTDOUT ("%s-%g %sfor %s.\n",
948 DEBUGSERVER_PROGRAM_NAME,
949 DEBUGSERVER_VERSION_NUM,
950 compile_options.c_str(),
951 RNB_ARCH);
952
953 int listen_port = INT32_MAX;
954 char str[PATH_MAX];
955
956 if (g_lockdown_opt == 0 && g_applist_opt == 0)
957 {
958 // Make sure we at least have port
959 if (argc < 1)
960 {
961 show_usage_and_exit (1);
962 }
963 // accept 'localhost:' prefix on port number
964
965 int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &listen_port);
966 if (items_scanned == 2)
967 {
968 DNBLogDebug("host = '%s' port = %i", str, listen_port);
969 }
970 else if (argv[0][0] == '/')
971 {
972 listen_port = INT32_MAX;
973 strncpy(str, argv[0], sizeof(str));
974 }
975 else
976 {
977 show_usage_and_exit (2);
978 }
979
980 // We just used the 'host:port' or the '/path/file' arg...
981 argc--;
982 argv++;
983
984 }
985
986 // If we know we're waiting to attach, we don't need any of this other info.
987 if (start_mode != eRNBRunLoopModeInferiorAttaching)
988 {
989 if (argc == 0 || g_lockdown_opt)
990 {
991 if (g_lockdown_opt != 0)
992 {
993 // Work around for SIGPIPE crashes due to posix_spawn issue.
994 // We have to close STDOUT and STDERR, else the first time we
995 // try and do any, we get SIGPIPE and die as posix_spawn is
996 // doing bad things with our file descriptors at the moment.
997 int null = open("/dev/null", O_RDWR);
998 dup2(null, STDOUT_FILENO);
999 dup2(null, STDERR_FILENO);
1000 }
1001 else if (g_applist_opt != 0)
1002 {
1003 // List all applications we are able to see
1004 std::string applist_plist;
1005 int err = ListApplications(applist_plist, false, false);
1006 if (err == 0)
1007 {
1008 fputs (applist_plist.c_str(), stdout);
1009 }
1010 else
1011 {
1012 RNBLogSTDERR ("error: ListApplications returned error %i\n", err);
1013 }
1014 // Exit with appropriate error if we were asked to list the applications
1015 // with no other args were given (and we weren't trying to do this over
1016 // lockdown)
1017 return err;
1018 }
1019
1020 DNBLogDebug("Get args from remote protocol...");
1021 start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
1022 }
1023 else
1024 {
1025 start_mode = eRNBRunLoopModeInferiorLaunching;
1026 // Fill in the argv array in the context from the rest of our args.
1027 // Skip the name of this executable and the port number
1028 for (int i = 0; i < argc; i++)
1029 {
1030 DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]);
1031 ctx.PushArgument (argv[i]);
1032 }
1033 }
1034 }
1035
1036 if (start_mode == eRNBRunLoopModeExit)
1037 return -1;
1038
1039 RNBRunLoopMode mode = start_mode;
1040 char err_str[1024] = {'\0'};
1041
1042 while (mode != eRNBRunLoopModeExit)
1043 {
1044 switch (mode)
1045 {
1046 case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
1047#if defined (__arm__)
1048 if (g_lockdown_opt)
1049 {
1050 if (!g_remoteSP->Comm().IsConnected())
1051 {
1052 if (g_remoteSP->Comm().ConnectToService () != rnb_success)
1053 {
1054 RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
1055 mode = eRNBRunLoopModeExit;
1056 }
1057 else if (g_applist_opt != 0)
1058 {
1059 // List all applications we are able to see
1060 std::string applist_plist;
1061 if (ListApplications(applist_plist, false, false) == 0)
1062 {
1063 DNBLogDebug("Task list: %s", applist_plist.c_str());
1064
1065 g_remoteSP->Comm().Write(applist_plist.c_str(), applist_plist.size());
1066 // Issue a read that will never yield any data until the other side
1067 // closes the socket so this process doesn't just exit and cause the
1068 // socket to close prematurely on the other end and cause data loss.
1069 std::string buf;
1070 g_remoteSP->Comm().Read(buf);
1071 }
1072 g_remoteSP->Comm().Disconnect(false);
1073 mode = eRNBRunLoopModeExit;
1074 break;
1075 }
1076 else
1077 {
1078 // Start watching for remote packets
1079 g_remoteSP->StartReadRemoteDataThread();
1080 }
1081 }
1082 }
1083 else
1084#endif
1085 if (listen_port != INT32_MAX)
1086 {
1087 if (!StartListening (g_remoteSP, listen_port))
1088 mode = eRNBRunLoopModeExit;
1089 }
1090 else if (str[0] == '/')
1091 {
1092 if (g_remoteSP->Comm().OpenFile (str))
1093 mode = eRNBRunLoopModeExit;
1094 }
1095 if (mode != eRNBRunLoopModeExit)
1096 {
1097 RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n");
1098
1099 mode = RNBRunLoopGetStartModeFromRemote (g_remoteSP);
1100 }
1101 break;
1102
1103 case eRNBRunLoopModeInferiorAttaching:
1104 if (!waitfor_pid_name.empty())
1105 {
1106 // Set our end wait time if we are using a waitfor-duration
1107 // option that may have been specified
1108 struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1109 if (waitfor_duration != 0)
1110 {
1111 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1112 timeout_ptr = &attach_timeout_abstime;
1113 }
1114 nub_launch_flavor_t launch_flavor = g_launch_flavor;
1115 if (launch_flavor == eLaunchFlavorDefault)
1116 {
1117 // Our default launch method is posix spawn
1118 launch_flavor = eLaunchFlavorPosixSpawn;
1119
1120#if defined (__arm__)
1121 // Check if we have an app bundle, if so launch using SpringBoard.
1122 if (waitfor_pid_name.find (".app") != std::string::npos)
1123 {
1124 launch_flavor = eLaunchFlavorSpringBoard;
1125 }
1126#endif
1127 }
1128
1129 ctx.SetLaunchFlavor(launch_flavor);
1130
1131 nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
1132 g_pid = pid;
1133
1134 if (pid == INVALID_NUB_PROCESS)
1135 {
1136 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1137 if (err_str[0])
1138 ctx.LaunchStatus().SetErrorString(err_str);
1139 RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
1140 mode = eRNBRunLoopModeExit;
1141 }
1142 else
1143 {
1144 ctx.SetProcessID(pid);
1145 mode = eRNBRunLoopModeInferiorExecuting;
1146 }
1147 }
1148 else if (attach_pid != INVALID_NUB_PROCESS)
1149 {
1150
1151 RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid);
1152 nub_process_t attached_pid;
1153 mode = RNBRunLoopLaunchAttaching (g_remoteSP, attach_pid, attached_pid);
1154 if (mode != eRNBRunLoopModeInferiorExecuting)
1155 {
1156 const char *error_str = remote->Context().LaunchStatus().AsString();
1157 RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error.");
1158 mode = eRNBRunLoopModeExit;
1159 }
1160 }
1161 else if (!attach_pid_name.empty ())
1162 {
1163 struct timespec attach_timeout_abstime, *timeout_ptr = NULL;
1164 if (waitfor_duration != 0)
1165 {
1166 DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0);
1167 timeout_ptr = &attach_timeout_abstime;
1168 }
1169
1170 nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str));
1171 g_pid = pid;
1172 if (pid == INVALID_NUB_PROCESS)
1173 {
1174 ctx.LaunchStatus().SetError(-1, DNBError::Generic);
1175 if (err_str[0])
1176 ctx.LaunchStatus().SetErrorString(err_str);
1177 RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s", waitfor_pid_name.c_str(), err_str);
1178 mode = eRNBRunLoopModeExit;
1179 }
1180 else
1181 {
1182 ctx.SetProcessID(pid);
1183 mode = eRNBRunLoopModeInferiorExecuting;
1184 }
1185
1186 }
1187 else
1188 {
1189 RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.");
1190 mode = eRNBRunLoopModeExit;
1191 }
1192
1193 if (mode != eRNBRunLoopModeExit)
1194 {
1195 if (listen_port != INT32_MAX)
1196 {
1197 if (!StartListening (g_remoteSP, listen_port))
1198 mode = eRNBRunLoopModeExit;
1199 }
1200 else if (str[0] == '/')
1201 {
1202 if (g_remoteSP->Comm().OpenFile (str))
1203 mode = eRNBRunLoopModeExit;
1204 }
1205 if (mode != eRNBRunLoopModeExit)
1206 RNBLogSTDOUT ("Got a connection, waiting for debugger instructions for process %d.\n", attach_pid);
1207 }
1208 break;
1209
1210 case eRNBRunLoopModeInferiorLaunching:
1211 mode = RNBRunLoopLaunchInferior (g_remoteSP, stdio_path.empty() ? NULL : stdio_path.c_str());
1212
1213 if (mode == eRNBRunLoopModeInferiorExecuting)
1214 {
1215 if (listen_port != INT32_MAX)
1216 {
1217 if (!StartListening (g_remoteSP, listen_port))
1218 mode = eRNBRunLoopModeExit;
1219 }
1220 else if (str[0] == '/')
1221 {
1222 if (g_remoteSP->Comm().OpenFile (str))
1223 mode = eRNBRunLoopModeExit;
1224 }
1225
1226 if (mode != eRNBRunLoopModeExit)
1227 RNBLogSTDOUT ("Got a connection, waiting for debugger instructions.\n");
1228 }
1229 else
1230 {
1231 const char *error_str = remote->Context().LaunchStatus().AsString();
1232 RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv[0], error_str ? error_str : "unknown error.");
1233 }
1234 break;
1235
1236 case eRNBRunLoopModeInferiorExecuting:
1237 mode = RNBRunLoopInferiorExecuting(g_remoteSP);
1238 break;
1239
1240 default:
1241 mode = eRNBRunLoopModeExit;
1242 case eRNBRunLoopModeExit:
1243 break;
1244 }
1245 }
1246
1247 g_remoteSP->StopReadRemoteDataThread ();
1248 g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS);
1249
1250 return 0;
1251}