blob: 98e1f8d618d47af44274bce024ab0ab7dc500211 [file] [log] [blame]
Jason Molendabd2d88d2013-03-01 00:11:36 +00001//===-- libdebugserver.cpp --------------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Jason Molendabd2d88d2013-03-01 00:11:36 +00006//
7//===----------------------------------------------------------------------===//
Jason Molendad6760742013-02-28 04:25:38 +00008
Jason Molendad6760742013-02-28 04:25:38 +00009#include <errno.h>
10#include <getopt.h>
11#include <netinet/in.h>
12#include <sys/select.h>
Kate Stoneb9c1b512016-09-06 20:57:50 +000013#include <sys/socket.h>
Jason Molendad6760742013-02-28 04:25:38 +000014#include <sys/sysctl.h>
Kate Stoneb9c1b512016-09-06 20:57:50 +000015#include <sys/types.h>
Jason Molendad6760742013-02-28 04:25:38 +000016
17#include "DNB.h"
18#include "DNBLog.h"
19#include "DNBTimer.h"
20#include "PseudoTerminal.h"
21#include "RNBContext.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000022#include "RNBRemote.h"
Jason Molendad6760742013-02-28 04:25:38 +000023#include "RNBServices.h"
24#include "RNBSocket.h"
Jason Molendad6760742013-02-28 04:25:38 +000025#include "SysSignal.h"
26
27//----------------------------------------------------------------------
28// Run loop modes which determine which run loop function will be called
29//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000030typedef enum {
31 eRNBRunLoopModeInvalid = 0,
32 eRNBRunLoopModeGetStartModeFromRemoteProtocol,
33 eRNBRunLoopModeInferiorExecuting,
34 eRNBRunLoopModeExit
Jason Molendad6760742013-02-28 04:25:38 +000035} RNBRunLoopMode;
36
Jason Molendad6760742013-02-28 04:25:38 +000037//----------------------------------------------------------------------
38// Global Variables
39//----------------------------------------------------------------------
40RNBRemoteSP g_remoteSP;
41int g_disable_aslr = 0;
42int g_isatty = 0;
43
Kate Stoneb9c1b512016-09-06 20:57:50 +000044#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)
Jason Molendad6760742013-02-28 04:25:38 +000060
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//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000067RNBRunLoopMode RNBRunLoopGetStartModeFromRemote(RNBRemoteSP &remoteSP) {
68 std::string packet;
Jason Molendad6760742013-02-28 04:25:38 +000069
Kate Stoneb9c1b512016-09-06 20:57:50 +000070 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}
Jason Molendad6760742013-02-28 04:25:38 +0000125
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//----------------------------------------------------------------------
131nub_process_t g_pid;
132int g_sigpipe_received = 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000133void 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 }
Jason Molendad6760742013-02-28 04:25:38 +0000146}
147
148// Return the new run loop mode based off of the current process state
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149RNBRunLoopMode 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:
Jonas Devliegherea6682a42018-12-15 00:15:33 +0000178 if (!initialize) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000179 // 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 }
Jason Molendad6760742013-02-28 04:25:38 +0000211 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000212 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;
Jason Molendad6760742013-02-28 04:25:38 +0000227}
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.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000232RNBRunLoopMode 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;
Jason Molendad6760742013-02-28 04:25:38 +0000248 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000249
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;
Jason Molendad6760742013-02-28 04:25:38 +0000318}
319
Kate Stoneb9c1b512016-09-06 20:57:50 +0000320void ASLLogCallback(void *baton, uint32_t flags, const char *format,
321 va_list args) {
Jason Molendad6760742013-02-28 04:25:38 +0000322#if 0
323 vprintf(format, args);
324#endif
325}
326
Kate Stoneb9c1b512016-09-06 20:57:50 +0000327extern "C" int debug_server_main(int fd) {
Jason Molendad6760742013-02-28 04:25:38 +0000328#if 1
Kate Stoneb9c1b512016-09-06 20:57:50 +0000329 g_isatty = 0;
Jason Molendad6760742013-02-28 04:25:38 +0000330#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000331 g_isatty = ::isatty(STDIN_FILENO);
Jason Molendad6760742013-02-28 04:25:38 +0000332
Kate Stoneb9c1b512016-09-06 20:57:50 +0000333 DNBLogSetDebug(1);
334 DNBLogSetVerbose(1);
335 DNBLogSetLogMask(-1);
336 DNBLogSetLogCallback(ASLLogCallback, NULL);
Jason Molendad6760742013-02-28 04:25:38 +0000337#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000338
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;
Jason Molendad6760742013-02-28 04:25:38 +0000375 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000376 }
377
378 g_remoteSP->StopReadRemoteDataThread();
379 g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS);
380
381 return 0;
Jason Molendad6760742013-02-28 04:25:38 +0000382}