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