1 //===-- libdebugserver.cpp --------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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>
22 #include "PseudoTerminal.h"
23 #include "RNBContext.h"
24 #include "RNBRemote.h"
25 #include "RNBServices.h"
26 #include "RNBSocket.h"
27 #include "SysSignal.h"
29 // Run loop modes which determine which run loop function will be called
31 eRNBRunLoopModeInvalid
= 0,
32 eRNBRunLoopModeGetStartModeFromRemoteProtocol
,
33 eRNBRunLoopModeInferiorExecuting
,
38 RNBRemoteSP g_remoteSP
;
39 int g_disable_aslr
= 0;
42 #define RNBLogSTDOUT(fmt, ...) \
45 fprintf(stdout, fmt, ##__VA_ARGS__); \
47 _DNBLog(0, fmt, ##__VA_ARGS__); \
50 #define RNBLogSTDERR(fmt, ...) \
53 fprintf(stderr, fmt, ##__VA_ARGS__); \
55 _DNBLog(0, fmt, ##__VA_ARGS__); \
59 // Get our program path and arguments from the remote connection.
60 // We will need to start up the remote connection without a PID, get the
61 // arguments, wait for the new process to finish launching and hit its
62 // entry point, and then return the run loop mode that should come next.
63 RNBRunLoopMode
RNBRunLoopGetStartModeFromRemote(RNBRemoteSP
&remoteSP
) {
66 if (remoteSP
.get() != NULL
) {
67 RNBRemote
*remote
= remoteSP
.get();
68 RNBContext
&ctx
= remote
->Context();
69 uint32_t event_mask
= RNBContext::event_read_packet_available
;
71 // Spin waiting to get the A packet.
73 DNBLogThreadedIf(LOG_RNB_MAX
,
74 "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",
75 __FUNCTION__
, event_mask
);
76 nub_event_t set_events
= ctx
.Events().WaitForSetEvents(event_mask
);
77 DNBLogThreadedIf(LOG_RNB_MAX
,
78 "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x",
79 __FUNCTION__
, event_mask
, set_events
);
81 if (set_events
& RNBContext::event_read_packet_available
) {
82 rnb_err_t err
= rnb_err
;
83 RNBRemote::PacketEnum type
;
85 err
= remote
->HandleReceivedPacket(&type
);
87 // check if we tried to attach to a process
88 if (type
== RNBRemote::vattach
|| type
== RNBRemote::vattachwait
) {
89 if (err
== rnb_success
)
90 return eRNBRunLoopModeInferiorExecuting
;
92 RNBLogSTDERR("error: attach failed.");
93 return eRNBRunLoopModeExit
;
97 if (err
== rnb_success
) {
98 DNBLogThreadedIf(LOG_RNB_MINIMAL
, "%s Got success...", __FUNCTION__
);
100 } else if (err
== rnb_not_connected
) {
101 RNBLogSTDERR("error: connection lost.");
102 return eRNBRunLoopModeExit
;
104 // a catch all for any other gdb remote packets that failed
105 DNBLogThreadedIf(LOG_RNB_MINIMAL
, "%s Error getting packet.",
110 DNBLogThreadedIf(LOG_RNB_MINIMAL
, "#### %s", __FUNCTION__
);
112 DNBLogThreadedIf(LOG_RNB_MINIMAL
,
113 "%s Connection closed before getting \"A\" packet.",
115 return eRNBRunLoopModeExit
;
119 return eRNBRunLoopModeExit
;
122 // Watch for signals:
123 // SIGINT: so we can halt our inferior. (disabled for now)
124 // SIGPIPE: in case our child process dies
126 int g_sigpipe_received
= 0;
127 void signal_handler(int signo
) {
128 DNBLogThreadedIf(LOG_RNB_MINIMAL
, "%s (%s)", __FUNCTION__
,
129 SysSignal::Name(signo
));
133 // DNBProcessKill (g_pid, signo);
137 g_sigpipe_received
= 1;
142 // Return the new run loop mode based off of the current process state
143 RNBRunLoopMode
HandleProcessStateChange(RNBRemoteSP
&remote
, bool initialize
) {
144 RNBContext
&ctx
= remote
->Context();
145 nub_process_t pid
= ctx
.ProcessID();
147 if (pid
== INVALID_NUB_PROCESS
) {
148 DNBLogThreadedIf(LOG_RNB_MINIMAL
, "#### %s error: pid invalid, exiting...",
150 return eRNBRunLoopModeExit
;
152 nub_state_t pid_state
= DNBProcessGetState(pid
);
154 DNBLogThreadedIf(LOG_RNB_MINIMAL
,
155 "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__
,
156 (int)initialize
, DNBStateAsString(pid_state
));
161 // Something bad happened
162 return eRNBRunLoopModeExit
;
165 case eStateAttaching
:
166 case eStateLaunching
:
167 return eRNBRunLoopModeInferiorExecuting
;
169 case eStateSuspended
:
173 // Compare the last stop count to our current notion of a stop count
174 // to make sure we don't notify more than once for a given stop.
175 nub_size_t prev_pid_stop_count
= ctx
.GetProcessStopCount();
176 bool pid_stop_count_changed
=
177 ctx
.SetProcessStopCount(DNBProcessGetStopCount(pid
));
178 if (pid_stop_count_changed
) {
179 remote
->FlushSTDIO();
181 if (ctx
.GetProcessStopCount() == 1) {
183 LOG_RNB_MINIMAL
, "%s (&remote, initialize=%i) pid_state = %s "
184 "pid_stop_count %zu (old %zu)) Notify??? no, "
186 __FUNCTION__
, (int)initialize
, DNBStateAsString(pid_state
),
187 ctx
.GetProcessStopCount(), prev_pid_stop_count
);
191 LOG_RNB_MINIMAL
, "%s (&remote, initialize=%i) pid_state = %s "
192 "pid_stop_count %zu (old %zu)) Notify??? YES!!!",
193 __FUNCTION__
, (int)initialize
, DNBStateAsString(pid_state
),
194 ctx
.GetProcessStopCount(), prev_pid_stop_count
);
195 remote
->NotifyThatProcessStopped();
198 DNBLogThreadedIf(LOG_RNB_MINIMAL
, "%s (&remote, initialize=%i) "
199 "pid_state = %s pid_stop_count %zu "
200 "(old %zu)) Notify??? skipping...",
201 __FUNCTION__
, (int)initialize
,
202 DNBStateAsString(pid_state
), ctx
.GetProcessStopCount(),
203 prev_pid_stop_count
);
206 return eRNBRunLoopModeInferiorExecuting
;
210 return eRNBRunLoopModeInferiorExecuting
;
213 remote
->HandlePacket_last_signal(NULL
);
214 return eRNBRunLoopModeExit
;
216 return eRNBRunLoopModeExit
;
220 return eRNBRunLoopModeExit
;
222 // This function handles the case where our inferior program is stopped and
223 // we are waiting for gdb remote protocol packets. When a packet occurs that
224 // makes the inferior run, we need to leave this function with a new state
225 // as the return code.
226 RNBRunLoopMode
RNBRunLoopInferiorExecuting(RNBRemoteSP
&remote
) {
227 DNBLogThreadedIf(LOG_RNB_MINIMAL
, "#### %s", __FUNCTION__
);
228 RNBContext
&ctx
= remote
->Context();
230 // Init our mode and set 'is_running' based on the current process state
231 RNBRunLoopMode mode
= HandleProcessStateChange(remote
, true);
233 while (ctx
.ProcessID() != INVALID_NUB_PROCESS
) {
235 std::string set_events_str
;
236 uint32_t event_mask
= ctx
.NormalEventBits();
238 if (!ctx
.ProcessStateRunning()) {
239 // Clear the stdio bits if we are not running so we don't send any async
241 event_mask
&= ~RNBContext::event_proc_stdio_available
;
244 // We want to make sure we consume all process state changes and have
245 // whomever is notifying us to wait for us to reset the event bit before
247 // ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed);
249 DNBLogThreadedIf(LOG_RNB_EVENTS
,
250 "%s ctx.Events().WaitForSetEvents(0x%08x) ...",
251 __FUNCTION__
, event_mask
);
252 nub_event_t set_events
= ctx
.Events().WaitForSetEvents(event_mask
);
253 DNBLogThreadedIf(LOG_RNB_EVENTS
,
254 "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)",
255 __FUNCTION__
, event_mask
, set_events
,
256 ctx
.EventsAsString(set_events
, set_events_str
));
259 if ((set_events
& RNBContext::event_proc_thread_exiting
) ||
260 (set_events
& RNBContext::event_proc_stdio_available
)) {
261 remote
->FlushSTDIO();
264 if (set_events
& RNBContext::event_read_packet_available
) {
265 // handleReceivedPacket will take care of resetting the
266 // event_read_packet_available events when there are no more...
267 set_events
^= RNBContext::event_read_packet_available
;
269 if (ctx
.ProcessStateRunning()) {
270 if (remote
->HandleAsyncPacket() == rnb_not_connected
) {
271 // TODO: connect again? Exit?
274 if (remote
->HandleReceivedPacket() == rnb_not_connected
) {
275 // TODO: connect again? Exit?
280 if (set_events
& RNBContext::event_proc_state_changed
) {
281 mode
= HandleProcessStateChange(remote
, false);
282 ctx
.Events().ResetEvents(RNBContext::event_proc_state_changed
);
283 set_events
^= RNBContext::event_proc_state_changed
;
286 if (set_events
& RNBContext::event_proc_thread_exiting
) {
287 mode
= eRNBRunLoopModeExit
;
290 if (set_events
& RNBContext::event_read_thread_exiting
) {
291 // Out remote packet receiving thread exited, exit for now.
292 if (ctx
.HasValidProcessID()) {
293 // TODO: We should add code that will leave the current process
294 // in its current state and listen for another connection...
295 if (ctx
.ProcessStateRunning()) {
296 DNBProcessKill(ctx
.ProcessID());
299 mode
= eRNBRunLoopModeExit
;
303 // Reset all event bits that weren't reset for now...
305 ctx
.Events().ResetEvents(set_events
);
307 if (mode
!= eRNBRunLoopModeInferiorExecuting
)
314 void ASLLogCallback(void *baton
, uint32_t flags
, const char *format
,
317 vprintf(format
, args
);
321 extern "C" int debug_server_main(int fd
) {
325 g_isatty
= ::isatty(STDIN_FILENO
);
329 DNBLogSetLogMask(-1);
330 DNBLogSetLogCallback(ASLLogCallback
, NULL
);
333 signal(SIGPIPE
, signal_handler
);
335 g_remoteSP
= std::make_shared
<RNBRemote
>();
337 RNBRemote
*remote
= g_remoteSP
.get();
338 if (remote
== NULL
) {
339 RNBLogSTDERR("error: failed to create a remote connection class\n");
343 RNBRunLoopMode mode
= eRNBRunLoopModeGetStartModeFromRemoteProtocol
;
345 while (mode
!= eRNBRunLoopModeExit
) {
347 case eRNBRunLoopModeGetStartModeFromRemoteProtocol
:
348 if (g_remoteSP
->Comm().useFD(fd
) == rnb_success
) {
349 RNBLogSTDOUT("Starting remote data thread.\n");
350 g_remoteSP
->StartReadRemoteDataThread();
352 RNBLogSTDOUT("Waiting for start mode from remote.\n");
353 mode
= RNBRunLoopGetStartModeFromRemote(g_remoteSP
);
355 mode
= eRNBRunLoopModeExit
;
359 case eRNBRunLoopModeInferiorExecuting
:
360 mode
= RNBRunLoopInferiorExecuting(g_remoteSP
);
364 mode
= eRNBRunLoopModeExit
;
367 case eRNBRunLoopModeExit
:
372 g_remoteSP
->StopReadRemoteDataThread();
373 g_remoteSP
->Context().SetProcessID(INVALID_NUB_PROCESS
);