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