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