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