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