1 /*
2  *  libdebugserver.cpp
3  *  debugserver
4  *
5  *  Copyright 2008-2012 Apple Inc. All rights reserved.
6  *
7  */
8 
9 #include <sys/socket.h>
10 #include <sys/types.h>
11 #include <errno.h>
12 #include <getopt.h>
13 #include <netinet/in.h>
14 #include <sys/select.h>
15 #include <sys/sysctl.h>
16 
17 #include "DNB.h"
18 #include "DNBLog.h"
19 #include "DNBTimer.h"
20 #include "PseudoTerminal.h"
21 #include "RNBContext.h"
22 #include "RNBServices.h"
23 #include "RNBSocket.h"
24 #include "RNBRemote.h"
25 #include "SysSignal.h"
26 
27 //----------------------------------------------------------------------
28 // Run loop modes which determine which run loop function will be called
29 //----------------------------------------------------------------------
30 typedef enum
31 {
32     eRNBRunLoopModeInvalid = 0,
33     eRNBRunLoopModeGetStartModeFromRemoteProtocol,
34     eRNBRunLoopModeInferiorExecuting,
35     eRNBRunLoopModeExit
36 } RNBRunLoopMode;
37 
38 
39 //----------------------------------------------------------------------
40 // Global Variables
41 //----------------------------------------------------------------------
42 RNBRemoteSP g_remoteSP;
43 int g_disable_aslr = 0;
44 int g_isatty = 0;
45 
46 #define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
47 #define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0)
48 
49 
50 //----------------------------------------------------------------------
51 // Get our program path and arguments from the remote connection.
52 // We will need to start up the remote connection without a PID, get the
53 // arguments, wait for the new process to finish launching and hit its
54 // entry point,  and then return the run loop mode that should come next.
55 //----------------------------------------------------------------------
56 RNBRunLoopMode
57 RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP)
58 {
59     std::string packet;
60 
61     if (remoteSP.get() != NULL)
62     {
63         RNBRemote* remote = remoteSP.get();
64         RNBContext& ctx = remote->Context();
65         uint32_t event_mask = RNBContext::event_read_packet_available;
66 
67         // Spin waiting to get the A packet.
68         while (1)
69         {
70             DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask);
71             nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
72             DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events);
73 
74             if (set_events & RNBContext::event_read_packet_available)
75             {
76                 rnb_err_t err = rnb_err;
77                 RNBRemote::PacketEnum type;
78 
79                 err = remote->HandleReceivedPacket (&type);
80 
81                 // check if we tried to attach to a process
82                 if (type == RNBRemote::vattach || type == RNBRemote::vattachwait)
83                 {
84                     if (err == rnb_success)
85                         return eRNBRunLoopModeInferiorExecuting;
86                     else
87                     {
88                         RNBLogSTDERR ("error: attach failed.");
89                         return eRNBRunLoopModeExit;
90                     }
91                 }
92 
93 
94                 if (err == rnb_success)
95                 {
96                     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Got success...",__FUNCTION__);
97 					continue;
98 				}
99 				else if (err == rnb_not_connected)
100                 {
101                     RNBLogSTDERR ("error: connection lost.");
102                     return eRNBRunLoopModeExit;
103                 }
104                 else
105                 {
106                     // a catch all for any other gdb remote packets that failed
107                     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__);
108                     continue;
109                 }
110 
111                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
112             }
113             else
114             {
115                 DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__);
116                 return eRNBRunLoopModeExit;
117             }
118         }
119     }
120     return eRNBRunLoopModeExit;
121 }
122 
123 
124 //----------------------------------------------------------------------
125 // Watch for signals:
126 // SIGINT: so we can halt our inferior. (disabled for now)
127 // SIGPIPE: in case our child process dies
128 //----------------------------------------------------------------------
129 nub_process_t g_pid;
130 int g_sigpipe_received = 0;
131 void
132 signal_handler(int signo)
133 {
134     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo));
135 
136     switch (signo)
137     {
138 			//  case SIGINT:
139 			//      DNBProcessKill (g_pid, signo);
140 			//      break;
141 
142 		case SIGPIPE:
143 			g_sigpipe_received = 1;
144 			break;
145     }
146 }
147 
148 // Return the new run loop mode based off of the current process state
149 RNBRunLoopMode
150 HandleProcessStateChange (RNBRemoteSP &remote, bool initialize)
151 {
152     RNBContext& ctx = remote->Context();
153     nub_process_t pid = ctx.ProcessID();
154 
155     if (pid == INVALID_NUB_PROCESS)
156     {
157         DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__);
158         return eRNBRunLoopModeExit;
159     }
160     nub_state_t pid_state = DNBProcessGetState (pid);
161 
162     DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i)  pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state));
163 
164     switch (pid_state)
165     {
166 		case eStateInvalid:
167 		case eStateUnloaded:
168 			// Something bad happened
169 			return eRNBRunLoopModeExit;
170 			break;
171 
172 		case eStateAttaching:
173 		case eStateLaunching:
174 			return eRNBRunLoopModeInferiorExecuting;
175 
176 		case eStateSuspended:
177 		case eStateCrashed:
178 		case eStateStopped:
179 			if (initialize == false)
180 			{
181 				// Compare the last stop count to our current notion of a stop count
182 				// to make sure we don't notify more than once for a given stop.
183 				nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
184 				bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid));
185 				if (pid_stop_count_changed)
186 				{
187 					remote->FlushSTDIO();
188 
189 					if (ctx.GetProcessStopCount() == 1)
190 					{
191 						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);
192 					}
193 					else
194 					{
195 
196 						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);
197 						remote->NotifyThatProcessStopped ();
198 					}
199 				}
200 				else
201 				{
202 					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);
203 				}
204 			}
205 			return eRNBRunLoopModeInferiorExecuting;
206 
207 		case eStateStepping:
208 		case eStateRunning:
209 			return eRNBRunLoopModeInferiorExecuting;
210 
211 		case eStateExited:
212 			remote->HandlePacket_last_signal(NULL);
213 			return eRNBRunLoopModeExit;
214 		case eStateDetached:
215             return eRNBRunLoopModeExit;
216 
217     }
218 
219     // Catch all...
220     return eRNBRunLoopModeExit;
221 }
222 // This function handles the case where our inferior program is stopped and
223 // we are waiting for gdb remote protocol packets. When a packet occurs that
224 // makes the inferior run, we need to leave this function with a new state
225 // as the return code.
226 RNBRunLoopMode
227 RNBRunLoopInferiorExecuting (RNBRemoteSP &remote)
228 {
229     DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
230     RNBContext& ctx = remote->Context();
231 
232     // Init our mode and set 'is_running' based on the current process state
233     RNBRunLoopMode mode = HandleProcessStateChange (remote, true);
234 
235     while (ctx.ProcessID() != INVALID_NUB_PROCESS)
236     {
237 
238         std::string set_events_str;
239         uint32_t event_mask = ctx.NormalEventBits();
240 
241         if (!ctx.ProcessStateRunning())
242         {
243             // Clear the stdio bits if we are not running so we don't send any async packets
244             event_mask &= ~RNBContext::event_proc_stdio_available;
245         }
246 
247         // We want to make sure we consume all process state changes and have
248         // whomever is notifying us to wait for us to reset the event bit before
249         // continuing.
250         //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
251 
252         DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask);
253         nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
254         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));
255 
256         if (set_events)
257         {
258             if ((set_events & RNBContext::event_proc_thread_exiting) ||
259                 (set_events & RNBContext::event_proc_stdio_available))
260             {
261                 remote->FlushSTDIO();
262             }
263 
264             if (set_events & RNBContext::event_read_packet_available)
265             {
266                 // handleReceivedPacket will take care of resetting the
267                 // event_read_packet_available events when there are no more...
268                 set_events ^= RNBContext::event_read_packet_available;
269 
270                 if (ctx.ProcessStateRunning())
271                 {
272                     if (remote->HandleAsyncPacket() == rnb_not_connected)
273                     {
274                         // TODO: connect again? Exit?
275                     }
276                 }
277                 else
278                 {
279                     if (remote->HandleReceivedPacket() == rnb_not_connected)
280                     {
281                         // TODO: connect again? Exit?
282                     }
283                 }
284             }
285 
286             if (set_events & RNBContext::event_proc_state_changed)
287             {
288                 mode = HandleProcessStateChange (remote, false);
289                 ctx.Events().ResetEvents(RNBContext::event_proc_state_changed);
290                 set_events ^= RNBContext::event_proc_state_changed;
291             }
292 
293             if (set_events & RNBContext::event_proc_thread_exiting)
294             {
295                 mode = eRNBRunLoopModeExit;
296             }
297 
298             if (set_events & RNBContext::event_read_thread_exiting)
299             {
300                 // Out remote packet receiving thread exited, exit for now.
301                 if (ctx.HasValidProcessID())
302                 {
303                     // TODO: We should add code that will leave the current process
304                     // in its current state and listen for another connection...
305                     if (ctx.ProcessStateRunning())
306                     {
307                         DNBProcessKill (ctx.ProcessID(), SIGINT);
308                     }
309                 }
310                 mode = eRNBRunLoopModeExit;
311             }
312         }
313 
314         // Reset all event bits that weren't reset for now...
315         if (set_events != 0)
316 			ctx.Events().ResetEvents(set_events);
317 
318         if (mode != eRNBRunLoopModeInferiorExecuting)
319 			break;
320     }
321 
322     return mode;
323 }
324 
325 void
326 ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args)
327 {
328 #if 0
329 	vprintf(format, args);
330 #endif
331 }
332 
333 extern "C" int
334 debug_server_main(int fd)
335 {
336 #if 1
337 	g_isatty = 0;
338 #else
339 	g_isatty = ::isatty (STDIN_FILENO);
340 
341 	DNBLogSetDebug(1);
342 	DNBLogSetVerbose(1);
343 	DNBLogSetLogMask(-1);
344 	DNBLogSetLogCallback(ASLLogCallback, NULL);
345 #endif
346 
347     signal (SIGPIPE, signal_handler);
348 
349     g_remoteSP.reset (new RNBRemote);
350 
351     RNBRemote *remote = g_remoteSP.get();
352     if (remote == NULL)
353     {
354         RNBLogSTDERR ("error: failed to create a remote connection class\n");
355         return -1;
356     }
357 
358 
359     RNBRunLoopMode mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
360 
361     while (mode != eRNBRunLoopModeExit)
362     {
363         switch (mode)
364         {
365 			case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
366 				if (g_remoteSP->Comm().useFD(fd) == rnb_success) {
367 					RNBLogSTDOUT("Starting remote data thread.\n");
368 					g_remoteSP->StartReadRemoteDataThread();
369 
370 					RNBLogSTDOUT("Waiting for start mode from remote.\n");
371 					mode = RNBRunLoopGetStartModeFromRemote(g_remoteSP);
372 				}
373 				else
374 				{
375 					mode = eRNBRunLoopModeExit;
376 				}
377 				break;
378 
379 			case eRNBRunLoopModeInferiorExecuting:
380 				mode = RNBRunLoopInferiorExecuting(g_remoteSP);
381 				break;
382 
383 			default:
384 				mode = eRNBRunLoopModeExit;
385 				break;
386 
387 			case eRNBRunLoopModeExit:
388 				break;
389         }
390     }
391 
392     g_remoteSP->StopReadRemoteDataThread ();
393     g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS);
394 
395     return 0;
396 }
397