1061da546Spatrick //===-- libdebugserver.cpp --------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9*be691f3bSpatrick #include <cerrno>
10061da546Spatrick #include <getopt.h>
11061da546Spatrick #include <netinet/in.h>
12061da546Spatrick #include <sys/select.h>
13061da546Spatrick #include <sys/socket.h>
14061da546Spatrick #include <sys/sysctl.h>
15061da546Spatrick #include <sys/types.h>
16061da546Spatrick
17061da546Spatrick #include <memory>
18061da546Spatrick
19061da546Spatrick #include "DNB.h"
20061da546Spatrick #include "DNBLog.h"
21061da546Spatrick #include "DNBTimer.h"
22061da546Spatrick #include "PseudoTerminal.h"
23061da546Spatrick #include "RNBContext.h"
24061da546Spatrick #include "RNBRemote.h"
25061da546Spatrick #include "RNBServices.h"
26061da546Spatrick #include "RNBSocket.h"
27061da546Spatrick #include "SysSignal.h"
28061da546Spatrick
29061da546Spatrick // Run loop modes which determine which run loop function will be called
30061da546Spatrick enum RNBRunLoopMode {
31061da546Spatrick eRNBRunLoopModeInvalid = 0,
32061da546Spatrick eRNBRunLoopModeGetStartModeFromRemoteProtocol,
33061da546Spatrick eRNBRunLoopModeInferiorExecuting,
34061da546Spatrick eRNBRunLoopModeExit
35061da546Spatrick };
36061da546Spatrick
37061da546Spatrick // Global Variables
38061da546Spatrick RNBRemoteSP g_remoteSP;
39061da546Spatrick int g_disable_aslr = 0;
40061da546Spatrick int g_isatty = 0;
41061da546Spatrick
42061da546Spatrick #define RNBLogSTDOUT(fmt, ...) \
43061da546Spatrick do { \
44061da546Spatrick if (g_isatty) { \
45061da546Spatrick fprintf(stdout, fmt, ##__VA_ARGS__); \
46061da546Spatrick } else { \
47061da546Spatrick _DNBLog(0, fmt, ##__VA_ARGS__); \
48061da546Spatrick } \
49061da546Spatrick } while (0)
50061da546Spatrick #define RNBLogSTDERR(fmt, ...) \
51061da546Spatrick do { \
52061da546Spatrick if (g_isatty) { \
53061da546Spatrick fprintf(stderr, fmt, ##__VA_ARGS__); \
54061da546Spatrick } else { \
55061da546Spatrick _DNBLog(0, fmt, ##__VA_ARGS__); \
56061da546Spatrick } \
57061da546Spatrick } while (0)
58061da546Spatrick
59061da546Spatrick // Get our program path and arguments from the remote connection.
60061da546Spatrick // We will need to start up the remote connection without a PID, get the
61061da546Spatrick // arguments, wait for the new process to finish launching and hit its
62061da546Spatrick // entry point, and then return the run loop mode that should come next.
RNBRunLoopGetStartModeFromRemote(RNBRemoteSP & remoteSP)63061da546Spatrick RNBRunLoopMode RNBRunLoopGetStartModeFromRemote(RNBRemoteSP &remoteSP) {
64061da546Spatrick std::string packet;
65061da546Spatrick
66061da546Spatrick if (remoteSP.get() != NULL) {
67061da546Spatrick RNBRemote *remote = remoteSP.get();
68061da546Spatrick RNBContext &ctx = remote->Context();
69061da546Spatrick uint32_t event_mask = RNBContext::event_read_packet_available;
70061da546Spatrick
71061da546Spatrick // Spin waiting to get the A packet.
72061da546Spatrick while (true) {
73061da546Spatrick DNBLogThreadedIf(LOG_RNB_MAX,
74061da546Spatrick "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",
75061da546Spatrick __FUNCTION__, event_mask);
76061da546Spatrick nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
77061da546Spatrick DNBLogThreadedIf(LOG_RNB_MAX,
78061da546Spatrick "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x",
79061da546Spatrick __FUNCTION__, event_mask, set_events);
80061da546Spatrick
81061da546Spatrick if (set_events & RNBContext::event_read_packet_available) {
82061da546Spatrick rnb_err_t err = rnb_err;
83061da546Spatrick RNBRemote::PacketEnum type;
84061da546Spatrick
85061da546Spatrick err = remote->HandleReceivedPacket(&type);
86061da546Spatrick
87061da546Spatrick // check if we tried to attach to a process
88061da546Spatrick if (type == RNBRemote::vattach || type == RNBRemote::vattachwait) {
89061da546Spatrick if (err == rnb_success)
90061da546Spatrick return eRNBRunLoopModeInferiorExecuting;
91061da546Spatrick else {
92061da546Spatrick RNBLogSTDERR("error: attach failed.");
93061da546Spatrick return eRNBRunLoopModeExit;
94061da546Spatrick }
95061da546Spatrick }
96061da546Spatrick
97061da546Spatrick if (err == rnb_success) {
98061da546Spatrick DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Got success...", __FUNCTION__);
99061da546Spatrick continue;
100061da546Spatrick } else if (err == rnb_not_connected) {
101061da546Spatrick RNBLogSTDERR("error: connection lost.");
102061da546Spatrick return eRNBRunLoopModeExit;
103061da546Spatrick } else {
104061da546Spatrick // a catch all for any other gdb remote packets that failed
105061da546Spatrick DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Error getting packet.",
106061da546Spatrick __FUNCTION__);
107061da546Spatrick continue;
108061da546Spatrick }
109061da546Spatrick
110061da546Spatrick DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
111061da546Spatrick } else {
112061da546Spatrick DNBLogThreadedIf(LOG_RNB_MINIMAL,
113061da546Spatrick "%s Connection closed before getting \"A\" packet.",
114061da546Spatrick __FUNCTION__);
115061da546Spatrick return eRNBRunLoopModeExit;
116061da546Spatrick }
117061da546Spatrick }
118061da546Spatrick }
119061da546Spatrick return eRNBRunLoopModeExit;
120061da546Spatrick }
121061da546Spatrick
122061da546Spatrick // Watch for signals:
123061da546Spatrick // SIGINT: so we can halt our inferior. (disabled for now)
124061da546Spatrick // SIGPIPE: in case our child process dies
125061da546Spatrick nub_process_t g_pid;
126061da546Spatrick int g_sigpipe_received = 0;
signal_handler(int signo)127061da546Spatrick void signal_handler(int signo) {
128061da546Spatrick DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__,
129061da546Spatrick SysSignal::Name(signo));
130061da546Spatrick
131061da546Spatrick switch (signo) {
132061da546Spatrick // case SIGINT:
133061da546Spatrick // DNBProcessKill (g_pid, signo);
134061da546Spatrick // break;
135061da546Spatrick
136061da546Spatrick case SIGPIPE:
137061da546Spatrick g_sigpipe_received = 1;
138061da546Spatrick break;
139061da546Spatrick }
140061da546Spatrick }
141061da546Spatrick
142061da546Spatrick // Return the new run loop mode based off of the current process state
HandleProcessStateChange(RNBRemoteSP & remote,bool initialize)143061da546Spatrick RNBRunLoopMode HandleProcessStateChange(RNBRemoteSP &remote, bool initialize) {
144061da546Spatrick RNBContext &ctx = remote->Context();
145061da546Spatrick nub_process_t pid = ctx.ProcessID();
146061da546Spatrick
147061da546Spatrick if (pid == INVALID_NUB_PROCESS) {
148061da546Spatrick DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...",
149061da546Spatrick __FUNCTION__);
150061da546Spatrick return eRNBRunLoopModeExit;
151061da546Spatrick }
152061da546Spatrick nub_state_t pid_state = DNBProcessGetState(pid);
153061da546Spatrick
154061da546Spatrick DNBLogThreadedIf(LOG_RNB_MINIMAL,
155061da546Spatrick "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__,
156061da546Spatrick (int)initialize, DNBStateAsString(pid_state));
157061da546Spatrick
158061da546Spatrick switch (pid_state) {
159061da546Spatrick case eStateInvalid:
160061da546Spatrick case eStateUnloaded:
161061da546Spatrick // Something bad happened
162061da546Spatrick return eRNBRunLoopModeExit;
163061da546Spatrick break;
164061da546Spatrick
165061da546Spatrick case eStateAttaching:
166061da546Spatrick case eStateLaunching:
167061da546Spatrick return eRNBRunLoopModeInferiorExecuting;
168061da546Spatrick
169061da546Spatrick case eStateSuspended:
170061da546Spatrick case eStateCrashed:
171061da546Spatrick case eStateStopped:
172061da546Spatrick if (!initialize) {
173061da546Spatrick // Compare the last stop count to our current notion of a stop count
174061da546Spatrick // to make sure we don't notify more than once for a given stop.
175061da546Spatrick nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount();
176061da546Spatrick bool pid_stop_count_changed =
177061da546Spatrick ctx.SetProcessStopCount(DNBProcessGetStopCount(pid));
178061da546Spatrick if (pid_stop_count_changed) {
179061da546Spatrick remote->FlushSTDIO();
180061da546Spatrick
181061da546Spatrick if (ctx.GetProcessStopCount() == 1) {
182061da546Spatrick DNBLogThreadedIf(
183061da546Spatrick LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s "
184061da546Spatrick "pid_stop_count %zu (old %zu)) Notify??? no, "
185061da546Spatrick "first stop...",
186061da546Spatrick __FUNCTION__, (int)initialize, DNBStateAsString(pid_state),
187061da546Spatrick ctx.GetProcessStopCount(), prev_pid_stop_count);
188061da546Spatrick } else {
189061da546Spatrick
190061da546Spatrick DNBLogThreadedIf(
191061da546Spatrick LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s "
192061da546Spatrick "pid_stop_count %zu (old %zu)) Notify??? YES!!!",
193061da546Spatrick __FUNCTION__, (int)initialize, DNBStateAsString(pid_state),
194061da546Spatrick ctx.GetProcessStopCount(), prev_pid_stop_count);
195061da546Spatrick remote->NotifyThatProcessStopped();
196061da546Spatrick }
197061da546Spatrick } else {
198061da546Spatrick DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) "
199061da546Spatrick "pid_state = %s pid_stop_count %zu "
200061da546Spatrick "(old %zu)) Notify??? skipping...",
201061da546Spatrick __FUNCTION__, (int)initialize,
202061da546Spatrick DNBStateAsString(pid_state), ctx.GetProcessStopCount(),
203061da546Spatrick prev_pid_stop_count);
204061da546Spatrick }
205061da546Spatrick }
206061da546Spatrick return eRNBRunLoopModeInferiorExecuting;
207061da546Spatrick
208061da546Spatrick case eStateStepping:
209061da546Spatrick case eStateRunning:
210061da546Spatrick return eRNBRunLoopModeInferiorExecuting;
211061da546Spatrick
212061da546Spatrick case eStateExited:
213061da546Spatrick remote->HandlePacket_last_signal(NULL);
214061da546Spatrick return eRNBRunLoopModeExit;
215061da546Spatrick case eStateDetached:
216061da546Spatrick return eRNBRunLoopModeExit;
217061da546Spatrick }
218061da546Spatrick
219061da546Spatrick // Catch all...
220061da546Spatrick return eRNBRunLoopModeExit;
221061da546Spatrick }
222061da546Spatrick // This function handles the case where our inferior program is stopped and
223061da546Spatrick // we are waiting for gdb remote protocol packets. When a packet occurs that
224061da546Spatrick // makes the inferior run, we need to leave this function with a new state
225061da546Spatrick // as the return code.
RNBRunLoopInferiorExecuting(RNBRemoteSP & remote)226061da546Spatrick RNBRunLoopMode RNBRunLoopInferiorExecuting(RNBRemoteSP &remote) {
227061da546Spatrick DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s", __FUNCTION__);
228061da546Spatrick RNBContext &ctx = remote->Context();
229061da546Spatrick
230061da546Spatrick // Init our mode and set 'is_running' based on the current process state
231061da546Spatrick RNBRunLoopMode mode = HandleProcessStateChange(remote, true);
232061da546Spatrick
233061da546Spatrick while (ctx.ProcessID() != INVALID_NUB_PROCESS) {
234061da546Spatrick
235061da546Spatrick std::string set_events_str;
236061da546Spatrick uint32_t event_mask = ctx.NormalEventBits();
237061da546Spatrick
238061da546Spatrick if (!ctx.ProcessStateRunning()) {
239061da546Spatrick // Clear the stdio bits if we are not running so we don't send any async
240061da546Spatrick // packets
241061da546Spatrick event_mask &= ~RNBContext::event_proc_stdio_available;
242061da546Spatrick }
243061da546Spatrick
244061da546Spatrick // We want to make sure we consume all process state changes and have
245061da546Spatrick // whomever is notifying us to wait for us to reset the event bit before
246061da546Spatrick // continuing.
247061da546Spatrick // ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
248061da546Spatrick
249061da546Spatrick DNBLogThreadedIf(LOG_RNB_EVENTS,
250061da546Spatrick "%s ctx.Events().WaitForSetEvents(0x%08x) ...",
251061da546Spatrick __FUNCTION__, event_mask);
252061da546Spatrick nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask);
253061da546Spatrick DNBLogThreadedIf(LOG_RNB_EVENTS,
254061da546Spatrick "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)",
255061da546Spatrick __FUNCTION__, event_mask, set_events,
256061da546Spatrick ctx.EventsAsString(set_events, set_events_str));
257061da546Spatrick
258061da546Spatrick if (set_events) {
259061da546Spatrick if ((set_events & RNBContext::event_proc_thread_exiting) ||
260061da546Spatrick (set_events & RNBContext::event_proc_stdio_available)) {
261061da546Spatrick remote->FlushSTDIO();
262061da546Spatrick }
263061da546Spatrick
264061da546Spatrick if (set_events & RNBContext::event_read_packet_available) {
265061da546Spatrick // handleReceivedPacket will take care of resetting the
266061da546Spatrick // event_read_packet_available events when there are no more...
267061da546Spatrick set_events ^= RNBContext::event_read_packet_available;
268061da546Spatrick
269061da546Spatrick if (ctx.ProcessStateRunning()) {
270061da546Spatrick if (remote->HandleAsyncPacket() == rnb_not_connected) {
271061da546Spatrick // TODO: connect again? Exit?
272061da546Spatrick }
273061da546Spatrick } else {
274061da546Spatrick if (remote->HandleReceivedPacket() == rnb_not_connected) {
275061da546Spatrick // TODO: connect again? Exit?
276061da546Spatrick }
277061da546Spatrick }
278061da546Spatrick }
279061da546Spatrick
280061da546Spatrick if (set_events & RNBContext::event_proc_state_changed) {
281061da546Spatrick mode = HandleProcessStateChange(remote, false);
282061da546Spatrick ctx.Events().ResetEvents(RNBContext::event_proc_state_changed);
283061da546Spatrick set_events ^= RNBContext::event_proc_state_changed;
284061da546Spatrick }
285061da546Spatrick
286061da546Spatrick if (set_events & RNBContext::event_proc_thread_exiting) {
287061da546Spatrick mode = eRNBRunLoopModeExit;
288061da546Spatrick }
289061da546Spatrick
290061da546Spatrick if (set_events & RNBContext::event_read_thread_exiting) {
291061da546Spatrick // Out remote packet receiving thread exited, exit for now.
292061da546Spatrick if (ctx.HasValidProcessID()) {
293061da546Spatrick // TODO: We should add code that will leave the current process
294061da546Spatrick // in its current state and listen for another connection...
295061da546Spatrick if (ctx.ProcessStateRunning()) {
296061da546Spatrick DNBProcessKill(ctx.ProcessID());
297061da546Spatrick }
298061da546Spatrick }
299061da546Spatrick mode = eRNBRunLoopModeExit;
300061da546Spatrick }
301061da546Spatrick }
302061da546Spatrick
303061da546Spatrick // Reset all event bits that weren't reset for now...
304061da546Spatrick if (set_events != 0)
305061da546Spatrick ctx.Events().ResetEvents(set_events);
306061da546Spatrick
307061da546Spatrick if (mode != eRNBRunLoopModeInferiorExecuting)
308061da546Spatrick break;
309061da546Spatrick }
310061da546Spatrick
311061da546Spatrick return mode;
312061da546Spatrick }
313061da546Spatrick
ASLLogCallback(void * baton,uint32_t flags,const char * format,va_list args)314061da546Spatrick void ASLLogCallback(void *baton, uint32_t flags, const char *format,
315061da546Spatrick va_list args) {
316061da546Spatrick #if 0
317061da546Spatrick vprintf(format, args);
318061da546Spatrick #endif
319061da546Spatrick }
320061da546Spatrick
debug_server_main(int fd)321061da546Spatrick extern "C" int debug_server_main(int fd) {
322061da546Spatrick #if 1
323061da546Spatrick g_isatty = 0;
324061da546Spatrick #else
325061da546Spatrick g_isatty = ::isatty(STDIN_FILENO);
326061da546Spatrick
327061da546Spatrick DNBLogSetDebug(1);
328061da546Spatrick DNBLogSetVerbose(1);
329061da546Spatrick DNBLogSetLogMask(-1);
330061da546Spatrick DNBLogSetLogCallback(ASLLogCallback, NULL);
331061da546Spatrick #endif
332061da546Spatrick
333061da546Spatrick signal(SIGPIPE, signal_handler);
334061da546Spatrick
335061da546Spatrick g_remoteSP = std::make_shared<RNBRemote>();
336061da546Spatrick
337061da546Spatrick RNBRemote *remote = g_remoteSP.get();
338061da546Spatrick if (remote == NULL) {
339061da546Spatrick RNBLogSTDERR("error: failed to create a remote connection class\n");
340061da546Spatrick return -1;
341061da546Spatrick }
342061da546Spatrick
343061da546Spatrick RNBRunLoopMode mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol;
344061da546Spatrick
345061da546Spatrick while (mode != eRNBRunLoopModeExit) {
346061da546Spatrick switch (mode) {
347061da546Spatrick case eRNBRunLoopModeGetStartModeFromRemoteProtocol:
348061da546Spatrick if (g_remoteSP->Comm().useFD(fd) == rnb_success) {
349061da546Spatrick RNBLogSTDOUT("Starting remote data thread.\n");
350061da546Spatrick g_remoteSP->StartReadRemoteDataThread();
351061da546Spatrick
352061da546Spatrick RNBLogSTDOUT("Waiting for start mode from remote.\n");
353061da546Spatrick mode = RNBRunLoopGetStartModeFromRemote(g_remoteSP);
354061da546Spatrick } else {
355061da546Spatrick mode = eRNBRunLoopModeExit;
356061da546Spatrick }
357061da546Spatrick break;
358061da546Spatrick
359061da546Spatrick case eRNBRunLoopModeInferiorExecuting:
360061da546Spatrick mode = RNBRunLoopInferiorExecuting(g_remoteSP);
361061da546Spatrick break;
362061da546Spatrick
363061da546Spatrick default:
364061da546Spatrick mode = eRNBRunLoopModeExit;
365061da546Spatrick break;
366061da546Spatrick
367061da546Spatrick case eRNBRunLoopModeExit:
368061da546Spatrick break;
369061da546Spatrick }
370061da546Spatrick }
371061da546Spatrick
372061da546Spatrick g_remoteSP->StopReadRemoteDataThread();
373061da546Spatrick g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS);
374061da546Spatrick
375061da546Spatrick return 0;
376061da546Spatrick }
377