xref: /qemu/gdbstub/user.c (revision 6971998e)
1ae7467b1SAlex Bennée /*
2ae7467b1SAlex Bennée  * gdbstub user-mode helper routines.
3ae7467b1SAlex Bennée  *
4ae7467b1SAlex Bennée  * We know for user-mode we are using TCG so we can call stuff directly.
5ae7467b1SAlex Bennée  *
69455762fSAlex Bennée  * Copyright (c) 2003-2005 Fabrice Bellard
7ae7467b1SAlex Bennée  * Copyright (c) 2022 Linaro Ltd
8ae7467b1SAlex Bennée  *
99455762fSAlex Bennée  * SPDX-License-Identifier: LGPL-2.0+
10ae7467b1SAlex Bennée  */
11ae7467b1SAlex Bennée 
12ae7467b1SAlex Bennée #include "qemu/osdep.h"
13046f143cSIlya Leoshkevich #include "qemu/bitops.h"
14d96bf49bSAlex Bennée #include "qemu/cutils.h"
15d96bf49bSAlex Bennée #include "qemu/sockets.h"
16d96bf49bSAlex Bennée #include "exec/hwaddr.h"
17d96bf49bSAlex Bennée #include "exec/tb-flush.h"
18ae7467b1SAlex Bennée #include "exec/gdbstub.h"
19c566080cSAlex Bennée #include "gdbstub/syscalls.h"
20d96bf49bSAlex Bennée #include "gdbstub/user.h"
21ae7467b1SAlex Bennée #include "hw/core/cpu.h"
22d96bf49bSAlex Bennée #include "trace.h"
23ae7467b1SAlex Bennée #include "internals.h"
24ae7467b1SAlex Bennée 
25046f143cSIlya Leoshkevich #define GDB_NR_SYSCALLS 1024
26046f143cSIlya Leoshkevich typedef unsigned long GDBSyscallsMask[BITS_TO_LONGS(GDB_NR_SYSCALLS)];
27046f143cSIlya Leoshkevich 
28d547e711SIlya Leoshkevich /*
29d547e711SIlya Leoshkevich  * Forked child talks to its parent in order to let GDB enforce the
30d547e711SIlya Leoshkevich  * follow-fork-mode. This happens inside a start_exclusive() section, so that
31d547e711SIlya Leoshkevich  * the other threads, which may be forking too, do not interfere. The
32d547e711SIlya Leoshkevich  * implementation relies on GDB not sending $vCont until it has detached
33d547e711SIlya Leoshkevich  * either from the parent (follow-fork-mode child) or from the child
34d547e711SIlya Leoshkevich  * (follow-fork-mode parent).
35d547e711SIlya Leoshkevich  *
36d547e711SIlya Leoshkevich  * The parent and the child share the GDB socket; at any given time only one
37d547e711SIlya Leoshkevich  * of them is allowed to use it, as is reflected in the respective fork_state.
38d547e711SIlya Leoshkevich  * This is negotiated via the fork_sockets pair as a reaction to $Hg.
39d547e711SIlya Leoshkevich  *
40d547e711SIlya Leoshkevich  * Below is a short summary of the possible state transitions:
41d547e711SIlya Leoshkevich  *
42d547e711SIlya Leoshkevich  *     ENABLED                     : Terminal state.
43d547e711SIlya Leoshkevich  *     DISABLED                    : Terminal state.
44d547e711SIlya Leoshkevich  *     ACTIVE                      : Parent initial state.
45d547e711SIlya Leoshkevich  *     INACTIVE                    : Child initial state.
46d547e711SIlya Leoshkevich  *     ACTIVE       -> DEACTIVATING: On $Hg.
47d547e711SIlya Leoshkevich  *     ACTIVE       -> ENABLING    : On $D.
48d547e711SIlya Leoshkevich  *     ACTIVE       -> DISABLING   : On $D.
49d547e711SIlya Leoshkevich  *     ACTIVE       -> DISABLED    : On communication error.
50d547e711SIlya Leoshkevich  *     DEACTIVATING -> INACTIVE    : On gdb_read_byte() return.
51d547e711SIlya Leoshkevich  *     DEACTIVATING -> DISABLED    : On communication error.
52d547e711SIlya Leoshkevich  *     INACTIVE     -> ACTIVE      : On $Hg in the peer.
53d547e711SIlya Leoshkevich  *     INACTIVE     -> ENABLE      : On $D in the peer.
54d547e711SIlya Leoshkevich  *     INACTIVE     -> DISABLE     : On $D in the peer.
55d547e711SIlya Leoshkevich  *     INACTIVE     -> DISABLED    : On communication error.
56d547e711SIlya Leoshkevich  *     ENABLING     -> ENABLED     : On gdb_read_byte() return.
57d547e711SIlya Leoshkevich  *     ENABLING     -> DISABLED    : On communication error.
58d547e711SIlya Leoshkevich  *     DISABLING    -> DISABLED    : On gdb_read_byte() return.
59d547e711SIlya Leoshkevich  */
60d547e711SIlya Leoshkevich enum GDBForkState {
61d547e711SIlya Leoshkevich     /* Fully owning the GDB socket. */
62d547e711SIlya Leoshkevich     GDB_FORK_ENABLED,
63d547e711SIlya Leoshkevich     /* Working with the GDB socket; the peer is inactive. */
64d547e711SIlya Leoshkevich     GDB_FORK_ACTIVE,
65d547e711SIlya Leoshkevich     /* Handing off the GDB socket to the peer. */
66d547e711SIlya Leoshkevich     GDB_FORK_DEACTIVATING,
67d547e711SIlya Leoshkevich     /* The peer is working with the GDB socket. */
68d547e711SIlya Leoshkevich     GDB_FORK_INACTIVE,
69d547e711SIlya Leoshkevich     /* Asking the peer to close its GDB socket fd. */
70d547e711SIlya Leoshkevich     GDB_FORK_ENABLING,
71d547e711SIlya Leoshkevich     /* Asking the peer to take over, closing our GDB socket fd. */
72d547e711SIlya Leoshkevich     GDB_FORK_DISABLING,
73d547e711SIlya Leoshkevich     /* The peer has taken over, our GDB socket fd is closed. */
74d547e711SIlya Leoshkevich     GDB_FORK_DISABLED,
75d547e711SIlya Leoshkevich };
76d547e711SIlya Leoshkevich 
77d547e711SIlya Leoshkevich enum GDBForkMessage {
78d547e711SIlya Leoshkevich     GDB_FORK_ACTIVATE = 'a',
79d547e711SIlya Leoshkevich     GDB_FORK_ENABLE = 'e',
80d547e711SIlya Leoshkevich     GDB_FORK_DISABLE = 'd',
81d547e711SIlya Leoshkevich };
82d547e711SIlya Leoshkevich 
83d96bf49bSAlex Bennée /* User-mode specific state */
84d96bf49bSAlex Bennée typedef struct {
85d96bf49bSAlex Bennée     int fd;
86d96bf49bSAlex Bennée     char *socket_path;
87d96bf49bSAlex Bennée     int running_state;
88046f143cSIlya Leoshkevich     /*
89046f143cSIlya Leoshkevich      * Store syscalls mask without memory allocation in order to avoid
90046f143cSIlya Leoshkevich      * implementing synchronization.
91046f143cSIlya Leoshkevich      */
92046f143cSIlya Leoshkevich     bool catch_all_syscalls;
93046f143cSIlya Leoshkevich     GDBSyscallsMask catch_syscalls_mask;
94d547e711SIlya Leoshkevich     bool fork_events;
95d547e711SIlya Leoshkevich     enum GDBForkState fork_state;
96d547e711SIlya Leoshkevich     int fork_sockets[2];
97d547e711SIlya Leoshkevich     pid_t fork_peer_pid, fork_peer_tid;
98f84e313eSGustavo Romero     uint8_t siginfo[MAX_SIGINFO_LENGTH];
99f84e313eSGustavo Romero     unsigned long siginfo_len;
100d96bf49bSAlex Bennée } GDBUserState;
101d96bf49bSAlex Bennée 
102d96bf49bSAlex Bennée static GDBUserState gdbserver_user_state;
103d96bf49bSAlex Bennée 
gdb_get_char(void)104d96bf49bSAlex Bennée int gdb_get_char(void)
105d96bf49bSAlex Bennée {
106d96bf49bSAlex Bennée     uint8_t ch;
107d96bf49bSAlex Bennée     int ret;
108d96bf49bSAlex Bennée 
109d96bf49bSAlex Bennée     for (;;) {
110d96bf49bSAlex Bennée         ret = recv(gdbserver_user_state.fd, &ch, 1, 0);
111d96bf49bSAlex Bennée         if (ret < 0) {
112d96bf49bSAlex Bennée             if (errno == ECONNRESET) {
113d96bf49bSAlex Bennée                 gdbserver_user_state.fd = -1;
114d96bf49bSAlex Bennée             }
115d96bf49bSAlex Bennée             if (errno != EINTR) {
116d96bf49bSAlex Bennée                 return -1;
117d96bf49bSAlex Bennée             }
118d96bf49bSAlex Bennée         } else if (ret == 0) {
119d96bf49bSAlex Bennée             close(gdbserver_user_state.fd);
120d96bf49bSAlex Bennée             gdbserver_user_state.fd = -1;
121d96bf49bSAlex Bennée             return -1;
122d96bf49bSAlex Bennée         } else {
123d96bf49bSAlex Bennée             break;
124d96bf49bSAlex Bennée         }
125d96bf49bSAlex Bennée     }
126d96bf49bSAlex Bennée     return ch;
127d96bf49bSAlex Bennée }
128d96bf49bSAlex Bennée 
gdb_got_immediate_ack(void)129a7e0f9bdSAlex Bennée bool gdb_got_immediate_ack(void)
130a7e0f9bdSAlex Bennée {
131a7e0f9bdSAlex Bennée     int i;
132a7e0f9bdSAlex Bennée 
133a7e0f9bdSAlex Bennée     i = gdb_get_char();
134a7e0f9bdSAlex Bennée     if (i < 0) {
135a7e0f9bdSAlex Bennée         /* no response, continue anyway */
136a7e0f9bdSAlex Bennée         return true;
137a7e0f9bdSAlex Bennée     }
138a7e0f9bdSAlex Bennée 
139a7e0f9bdSAlex Bennée     if (i == '+') {
140a7e0f9bdSAlex Bennée         /* received correctly, continue */
141a7e0f9bdSAlex Bennée         return true;
142a7e0f9bdSAlex Bennée     }
143a7e0f9bdSAlex Bennée 
144a7e0f9bdSAlex Bennée     /* anything else, including '-' then try again */
145a7e0f9bdSAlex Bennée     return false;
146a7e0f9bdSAlex Bennée }
147a7e0f9bdSAlex Bennée 
gdb_put_buffer(const uint8_t * buf,int len)148d96bf49bSAlex Bennée void gdb_put_buffer(const uint8_t *buf, int len)
149d96bf49bSAlex Bennée {
150d96bf49bSAlex Bennée     int ret;
151d96bf49bSAlex Bennée 
152d96bf49bSAlex Bennée     while (len > 0) {
153d96bf49bSAlex Bennée         ret = send(gdbserver_user_state.fd, buf, len, 0);
154d96bf49bSAlex Bennée         if (ret < 0) {
155d96bf49bSAlex Bennée             if (errno != EINTR) {
156d96bf49bSAlex Bennée                 return;
157d96bf49bSAlex Bennée             }
158d96bf49bSAlex Bennée         } else {
159d96bf49bSAlex Bennée             buf += ret;
160d96bf49bSAlex Bennée             len -= ret;
161d96bf49bSAlex Bennée         }
162d96bf49bSAlex Bennée     }
163d96bf49bSAlex Bennée }
164d96bf49bSAlex Bennée 
165d96bf49bSAlex Bennée /* Tell the remote gdb that the process has exited.  */
gdb_exit(int code)166d96bf49bSAlex Bennée void gdb_exit(int code)
167d96bf49bSAlex Bennée {
168d96bf49bSAlex Bennée     char buf[4];
169d96bf49bSAlex Bennée 
170d96bf49bSAlex Bennée     if (!gdbserver_state.init) {
171d96bf49bSAlex Bennée         return;
172d96bf49bSAlex Bennée     }
173d96bf49bSAlex Bennée     if (gdbserver_user_state.socket_path) {
174d96bf49bSAlex Bennée         unlink(gdbserver_user_state.socket_path);
175d96bf49bSAlex Bennée     }
176d96bf49bSAlex Bennée     if (gdbserver_user_state.fd < 0) {
177d96bf49bSAlex Bennée         return;
178d96bf49bSAlex Bennée     }
179d96bf49bSAlex Bennée 
180d96bf49bSAlex Bennée     trace_gdbstub_op_exiting((uint8_t)code);
181d96bf49bSAlex Bennée 
18275837005SMatheus Tavares Bernardino     if (gdbserver_state.allow_stop_reply) {
183d96bf49bSAlex Bennée         snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
184d96bf49bSAlex Bennée         gdb_put_packet(buf);
18575837005SMatheus Tavares Bernardino         gdbserver_state.allow_stop_reply = false;
18675837005SMatheus Tavares Bernardino     }
187e216256aSClément Chigot 
188e216256aSClément Chigot }
189e216256aSClément Chigot 
gdb_qemu_exit(int code)190e216256aSClément Chigot void gdb_qemu_exit(int code)
191e216256aSClément Chigot {
192e216256aSClément Chigot     exit(code);
193d96bf49bSAlex Bennée }
194d96bf49bSAlex Bennée 
gdb_handlesig(CPUState * cpu,int sig,const char * reason,void * siginfo,int siginfo_len)195f84e313eSGustavo Romero int gdb_handlesig(CPUState *cpu, int sig, const char *reason, void *siginfo,
196f84e313eSGustavo Romero                   int siginfo_len)
197d96bf49bSAlex Bennée {
198d96bf49bSAlex Bennée     char buf[256];
199d96bf49bSAlex Bennée     int n;
200d96bf49bSAlex Bennée 
201d96bf49bSAlex Bennée     if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
202d96bf49bSAlex Bennée         return sig;
203d96bf49bSAlex Bennée     }
204d96bf49bSAlex Bennée 
205f84e313eSGustavo Romero     if (siginfo) {
206f84e313eSGustavo Romero         /*
207f84e313eSGustavo Romero          * Save target-specific siginfo.
208f84e313eSGustavo Romero          *
209f84e313eSGustavo Romero          * siginfo size, i.e. siginfo_len, is asserted at compile-time to fit in
210f84e313eSGustavo Romero          * gdbserver_user_state.siginfo, usually in the source file calling
211f84e313eSGustavo Romero          * gdb_handlesig. See, for instance, {linux,bsd}-user/signal.c.
212f84e313eSGustavo Romero          */
213f84e313eSGustavo Romero         memcpy(gdbserver_user_state.siginfo, siginfo, siginfo_len);
214f84e313eSGustavo Romero         gdbserver_user_state.siginfo_len = siginfo_len;
215f84e313eSGustavo Romero     }
216f84e313eSGustavo Romero 
217d96bf49bSAlex Bennée     /* disable single step if it was enabled */
218d96bf49bSAlex Bennée     cpu_single_step(cpu, 0);
219d96bf49bSAlex Bennée     tb_flush(cpu);
220d96bf49bSAlex Bennée 
221d96bf49bSAlex Bennée     if (sig != 0) {
222d96bf49bSAlex Bennée         gdb_set_stop_cpu(cpu);
22375837005SMatheus Tavares Bernardino         if (gdbserver_state.allow_stop_reply) {
224d96bf49bSAlex Bennée             g_string_printf(gdbserver_state.str_buf,
225d96bf49bSAlex Bennée                             "T%02xthread:", gdb_target_signal_to_gdb(sig));
226d96bf49bSAlex Bennée             gdb_append_thread_id(cpu, gdbserver_state.str_buf);
227d96bf49bSAlex Bennée             g_string_append_c(gdbserver_state.str_buf, ';');
2288b7fcb8eSIlya Leoshkevich             if (reason) {
2298b7fcb8eSIlya Leoshkevich                 g_string_append(gdbserver_state.str_buf, reason);
2308b7fcb8eSIlya Leoshkevich             }
231d96bf49bSAlex Bennée             gdb_put_strbuf();
23275837005SMatheus Tavares Bernardino             gdbserver_state.allow_stop_reply = false;
23375837005SMatheus Tavares Bernardino         }
234d96bf49bSAlex Bennée     }
235d96bf49bSAlex Bennée     /*
236d96bf49bSAlex Bennée      * gdb_put_packet() might have detected that the peer terminated the
237d96bf49bSAlex Bennée      * connection.
238d96bf49bSAlex Bennée      */
239d96bf49bSAlex Bennée     if (gdbserver_user_state.fd < 0) {
240d96bf49bSAlex Bennée         return sig;
241d96bf49bSAlex Bennée     }
242d96bf49bSAlex Bennée 
243d96bf49bSAlex Bennée     sig = 0;
244d96bf49bSAlex Bennée     gdbserver_state.state = RS_IDLE;
245d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 0;
246d96bf49bSAlex Bennée     while (gdbserver_user_state.running_state == 0) {
247d96bf49bSAlex Bennée         n = read(gdbserver_user_state.fd, buf, 256);
248d96bf49bSAlex Bennée         if (n > 0) {
249d96bf49bSAlex Bennée             int i;
250d96bf49bSAlex Bennée 
251d96bf49bSAlex Bennée             for (i = 0; i < n; i++) {
252d96bf49bSAlex Bennée                 gdb_read_byte(buf[i]);
253d96bf49bSAlex Bennée             }
254d96bf49bSAlex Bennée         } else {
255d96bf49bSAlex Bennée             /*
256d96bf49bSAlex Bennée              * XXX: Connection closed.  Should probably wait for another
257d96bf49bSAlex Bennée              * connection before continuing.
258d96bf49bSAlex Bennée              */
259d96bf49bSAlex Bennée             if (n == 0) {
260d96bf49bSAlex Bennée                 close(gdbserver_user_state.fd);
261d96bf49bSAlex Bennée             }
262d96bf49bSAlex Bennée             gdbserver_user_state.fd = -1;
263d96bf49bSAlex Bennée             return sig;
264d96bf49bSAlex Bennée         }
265d96bf49bSAlex Bennée     }
266d96bf49bSAlex Bennée     sig = gdbserver_state.signal;
267d96bf49bSAlex Bennée     gdbserver_state.signal = 0;
268d96bf49bSAlex Bennée     return sig;
269d96bf49bSAlex Bennée }
270d96bf49bSAlex Bennée 
271d96bf49bSAlex Bennée /* Tell the remote gdb that the process has exited due to SIG.  */
gdb_signalled(CPUArchState * env,int sig)272d96bf49bSAlex Bennée void gdb_signalled(CPUArchState *env, int sig)
273d96bf49bSAlex Bennée {
274d96bf49bSAlex Bennée     char buf[4];
275d96bf49bSAlex Bennée 
27675837005SMatheus Tavares Bernardino     if (!gdbserver_state.init || gdbserver_user_state.fd < 0 ||
27775837005SMatheus Tavares Bernardino         !gdbserver_state.allow_stop_reply) {
278d96bf49bSAlex Bennée         return;
279d96bf49bSAlex Bennée     }
280d96bf49bSAlex Bennée 
281d96bf49bSAlex Bennée     snprintf(buf, sizeof(buf), "X%02x", gdb_target_signal_to_gdb(sig));
282d96bf49bSAlex Bennée     gdb_put_packet(buf);
28375837005SMatheus Tavares Bernardino     gdbserver_state.allow_stop_reply = false;
284d96bf49bSAlex Bennée }
285d96bf49bSAlex Bennée 
gdb_accept_init(int fd)286d96bf49bSAlex Bennée static void gdb_accept_init(int fd)
287d96bf49bSAlex Bennée {
288d96bf49bSAlex Bennée     gdb_init_gdbserver_state();
289d96bf49bSAlex Bennée     gdb_create_default_process(&gdbserver_state);
290d96bf49bSAlex Bennée     gdbserver_state.processes[0].attached = true;
291d96bf49bSAlex Bennée     gdbserver_state.c_cpu = gdb_first_attached_cpu();
292d96bf49bSAlex Bennée     gdbserver_state.g_cpu = gdbserver_state.c_cpu;
293d96bf49bSAlex Bennée     gdbserver_user_state.fd = fd;
294d96bf49bSAlex Bennée }
295d96bf49bSAlex Bennée 
gdb_accept_socket(int gdb_fd)296d96bf49bSAlex Bennée static bool gdb_accept_socket(int gdb_fd)
297d96bf49bSAlex Bennée {
298d96bf49bSAlex Bennée     int fd;
299d96bf49bSAlex Bennée 
300d96bf49bSAlex Bennée     for (;;) {
301d96bf49bSAlex Bennée         fd = accept(gdb_fd, NULL, NULL);
302d96bf49bSAlex Bennée         if (fd < 0 && errno != EINTR) {
303d96bf49bSAlex Bennée             perror("accept socket");
304d96bf49bSAlex Bennée             return false;
305d96bf49bSAlex Bennée         } else if (fd >= 0) {
306d96bf49bSAlex Bennée             qemu_set_cloexec(fd);
307d96bf49bSAlex Bennée             break;
308d96bf49bSAlex Bennée         }
309d96bf49bSAlex Bennée     }
310d96bf49bSAlex Bennée 
311d96bf49bSAlex Bennée     gdb_accept_init(fd);
312d96bf49bSAlex Bennée     return true;
313d96bf49bSAlex Bennée }
314d96bf49bSAlex Bennée 
gdbserver_open_socket(const char * path)315d96bf49bSAlex Bennée static int gdbserver_open_socket(const char *path)
316d96bf49bSAlex Bennée {
317d96bf49bSAlex Bennée     struct sockaddr_un sockaddr = {};
318d96bf49bSAlex Bennée     int fd, ret;
319d96bf49bSAlex Bennée 
320d96bf49bSAlex Bennée     fd = socket(AF_UNIX, SOCK_STREAM, 0);
321d96bf49bSAlex Bennée     if (fd < 0) {
322d96bf49bSAlex Bennée         perror("create socket");
323d96bf49bSAlex Bennée         return -1;
324d96bf49bSAlex Bennée     }
325d96bf49bSAlex Bennée 
326d96bf49bSAlex Bennée     sockaddr.sun_family = AF_UNIX;
327d96bf49bSAlex Bennée     pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path);
328d96bf49bSAlex Bennée     ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
329d96bf49bSAlex Bennée     if (ret < 0) {
330d96bf49bSAlex Bennée         perror("bind socket");
331d96bf49bSAlex Bennée         close(fd);
332d96bf49bSAlex Bennée         return -1;
333d96bf49bSAlex Bennée     }
334d96bf49bSAlex Bennée     ret = listen(fd, 1);
335d96bf49bSAlex Bennée     if (ret < 0) {
336d96bf49bSAlex Bennée         perror("listen socket");
337d96bf49bSAlex Bennée         close(fd);
338d96bf49bSAlex Bennée         return -1;
339d96bf49bSAlex Bennée     }
340d96bf49bSAlex Bennée 
341d96bf49bSAlex Bennée     return fd;
342d96bf49bSAlex Bennée }
343d96bf49bSAlex Bennée 
gdb_accept_tcp(int gdb_fd)344d96bf49bSAlex Bennée static bool gdb_accept_tcp(int gdb_fd)
345d96bf49bSAlex Bennée {
346d96bf49bSAlex Bennée     struct sockaddr_in sockaddr = {};
347d96bf49bSAlex Bennée     socklen_t len;
348d96bf49bSAlex Bennée     int fd;
349d96bf49bSAlex Bennée 
350d96bf49bSAlex Bennée     for (;;) {
351d96bf49bSAlex Bennée         len = sizeof(sockaddr);
352d96bf49bSAlex Bennée         fd = accept(gdb_fd, (struct sockaddr *)&sockaddr, &len);
353d96bf49bSAlex Bennée         if (fd < 0 && errno != EINTR) {
354d96bf49bSAlex Bennée             perror("accept");
355d96bf49bSAlex Bennée             return false;
356d96bf49bSAlex Bennée         } else if (fd >= 0) {
357d96bf49bSAlex Bennée             qemu_set_cloexec(fd);
358d96bf49bSAlex Bennée             break;
359d96bf49bSAlex Bennée         }
360d96bf49bSAlex Bennée     }
361d96bf49bSAlex Bennée 
362d96bf49bSAlex Bennée     /* set short latency */
363d96bf49bSAlex Bennée     if (socket_set_nodelay(fd)) {
364d96bf49bSAlex Bennée         perror("setsockopt");
365d96bf49bSAlex Bennée         close(fd);
366d96bf49bSAlex Bennée         return false;
367d96bf49bSAlex Bennée     }
368d96bf49bSAlex Bennée 
369d96bf49bSAlex Bennée     gdb_accept_init(fd);
370d96bf49bSAlex Bennée     return true;
371d96bf49bSAlex Bennée }
372d96bf49bSAlex Bennée 
gdbserver_open_port(int port)373d96bf49bSAlex Bennée static int gdbserver_open_port(int port)
374d96bf49bSAlex Bennée {
375d96bf49bSAlex Bennée     struct sockaddr_in sockaddr;
376d96bf49bSAlex Bennée     int fd, ret;
377d96bf49bSAlex Bennée 
378d96bf49bSAlex Bennée     fd = socket(PF_INET, SOCK_STREAM, 0);
379d96bf49bSAlex Bennée     if (fd < 0) {
380d96bf49bSAlex Bennée         perror("socket");
381d96bf49bSAlex Bennée         return -1;
382d96bf49bSAlex Bennée     }
383d96bf49bSAlex Bennée     qemu_set_cloexec(fd);
384d96bf49bSAlex Bennée 
385d96bf49bSAlex Bennée     socket_set_fast_reuse(fd);
386d96bf49bSAlex Bennée 
387d96bf49bSAlex Bennée     sockaddr.sin_family = AF_INET;
388d96bf49bSAlex Bennée     sockaddr.sin_port = htons(port);
389d96bf49bSAlex Bennée     sockaddr.sin_addr.s_addr = 0;
390d96bf49bSAlex Bennée     ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
391d96bf49bSAlex Bennée     if (ret < 0) {
392d96bf49bSAlex Bennée         perror("bind");
393d96bf49bSAlex Bennée         close(fd);
394d96bf49bSAlex Bennée         return -1;
395d96bf49bSAlex Bennée     }
396d96bf49bSAlex Bennée     ret = listen(fd, 1);
397d96bf49bSAlex Bennée     if (ret < 0) {
398d96bf49bSAlex Bennée         perror("listen");
399d96bf49bSAlex Bennée         close(fd);
400d96bf49bSAlex Bennée         return -1;
401d96bf49bSAlex Bennée     }
402d96bf49bSAlex Bennée 
403d96bf49bSAlex Bennée     return fd;
404d96bf49bSAlex Bennée }
405d96bf49bSAlex Bennée 
gdbserver_start(const char * port_or_path)406d96bf49bSAlex Bennée int gdbserver_start(const char *port_or_path)
407d96bf49bSAlex Bennée {
408d96bf49bSAlex Bennée     int port = g_ascii_strtoull(port_or_path, NULL, 10);
409d96bf49bSAlex Bennée     int gdb_fd;
410d96bf49bSAlex Bennée 
411d96bf49bSAlex Bennée     if (port > 0) {
412d96bf49bSAlex Bennée         gdb_fd = gdbserver_open_port(port);
413d96bf49bSAlex Bennée     } else {
414d96bf49bSAlex Bennée         gdb_fd = gdbserver_open_socket(port_or_path);
415d96bf49bSAlex Bennée     }
416d96bf49bSAlex Bennée 
417d96bf49bSAlex Bennée     if (gdb_fd < 0) {
418d96bf49bSAlex Bennée         return -1;
419d96bf49bSAlex Bennée     }
420d96bf49bSAlex Bennée 
421d96bf49bSAlex Bennée     if (port > 0 && gdb_accept_tcp(gdb_fd)) {
422d96bf49bSAlex Bennée         return 0;
423d96bf49bSAlex Bennée     } else if (gdb_accept_socket(gdb_fd)) {
424d96bf49bSAlex Bennée         gdbserver_user_state.socket_path = g_strdup(port_or_path);
425d96bf49bSAlex Bennée         return 0;
426d96bf49bSAlex Bennée     }
427d96bf49bSAlex Bennée 
428d96bf49bSAlex Bennée     /* gone wrong */
429d96bf49bSAlex Bennée     close(gdb_fd);
430d96bf49bSAlex Bennée     return -1;
431d96bf49bSAlex Bennée }
432d96bf49bSAlex Bennée 
gdbserver_fork_start(void)4333d6ed98dSIlya Leoshkevich void gdbserver_fork_start(void)
4343d6ed98dSIlya Leoshkevich {
435d547e711SIlya Leoshkevich     if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
436d547e711SIlya Leoshkevich         return;
437d547e711SIlya Leoshkevich     }
438d547e711SIlya Leoshkevich     if (!gdbserver_user_state.fork_events ||
439d547e711SIlya Leoshkevich             qemu_socketpair(AF_UNIX, SOCK_STREAM, 0,
440d547e711SIlya Leoshkevich                             gdbserver_user_state.fork_sockets) < 0) {
441d547e711SIlya Leoshkevich         gdbserver_user_state.fork_state = GDB_FORK_DISABLED;
442d547e711SIlya Leoshkevich         return;
443d547e711SIlya Leoshkevich     }
444d547e711SIlya Leoshkevich     gdbserver_user_state.fork_state = GDB_FORK_INACTIVE;
445d547e711SIlya Leoshkevich     gdbserver_user_state.fork_peer_pid = getpid();
446d547e711SIlya Leoshkevich     gdbserver_user_state.fork_peer_tid = qemu_get_thread_id();
4473d6ed98dSIlya Leoshkevich }
4483d6ed98dSIlya Leoshkevich 
disable_gdbstub(CPUState * thread_cpu)4491ea96f1dSIlya Leoshkevich static void disable_gdbstub(CPUState *thread_cpu)
4501ea96f1dSIlya Leoshkevich {
4511ea96f1dSIlya Leoshkevich     CPUState *cpu;
4521ea96f1dSIlya Leoshkevich 
4531ea96f1dSIlya Leoshkevich     close(gdbserver_user_state.fd);
4541ea96f1dSIlya Leoshkevich     gdbserver_user_state.fd = -1;
4551ea96f1dSIlya Leoshkevich     CPU_FOREACH(cpu) {
4561ea96f1dSIlya Leoshkevich         cpu_breakpoint_remove_all(cpu, BP_GDB);
4571ea96f1dSIlya Leoshkevich         /* no cpu_watchpoint_remove_all for user-mode */
4581ea96f1dSIlya Leoshkevich         cpu_single_step(cpu, 0);
4591ea96f1dSIlya Leoshkevich     }
4601ea96f1dSIlya Leoshkevich     tb_flush(thread_cpu);
4611ea96f1dSIlya Leoshkevich }
4621ea96f1dSIlya Leoshkevich 
gdbserver_fork_end(CPUState * cpu,pid_t pid)4636604b057SIlya Leoshkevich void gdbserver_fork_end(CPUState *cpu, pid_t pid)
464d96bf49bSAlex Bennée {
465d547e711SIlya Leoshkevich     char b;
466d547e711SIlya Leoshkevich     int fd;
467d547e711SIlya Leoshkevich 
468d547e711SIlya Leoshkevich     if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
469d96bf49bSAlex Bennée         return;
470d96bf49bSAlex Bennée     }
471d547e711SIlya Leoshkevich 
472d547e711SIlya Leoshkevich     if (pid == -1) {
473d547e711SIlya Leoshkevich         if (gdbserver_user_state.fork_state != GDB_FORK_DISABLED) {
474d547e711SIlya Leoshkevich             g_assert(gdbserver_user_state.fork_state == GDB_FORK_INACTIVE);
475d547e711SIlya Leoshkevich             close(gdbserver_user_state.fork_sockets[0]);
476d547e711SIlya Leoshkevich             close(gdbserver_user_state.fork_sockets[1]);
477d547e711SIlya Leoshkevich         }
478d547e711SIlya Leoshkevich         return;
479d547e711SIlya Leoshkevich     }
480d547e711SIlya Leoshkevich 
481d547e711SIlya Leoshkevich     if (gdbserver_user_state.fork_state == GDB_FORK_DISABLED) {
482d547e711SIlya Leoshkevich         if (pid == 0) {
4831ea96f1dSIlya Leoshkevich             disable_gdbstub(cpu);
484d96bf49bSAlex Bennée         }
485d547e711SIlya Leoshkevich         return;
486d547e711SIlya Leoshkevich     }
487d547e711SIlya Leoshkevich 
488d547e711SIlya Leoshkevich     if (pid == 0) {
489d547e711SIlya Leoshkevich         close(gdbserver_user_state.fork_sockets[0]);
490d547e711SIlya Leoshkevich         fd = gdbserver_user_state.fork_sockets[1];
491d547e711SIlya Leoshkevich         g_assert(gdbserver_state.process_num == 1);
492d547e711SIlya Leoshkevich         g_assert(gdbserver_state.processes[0].pid ==
493d547e711SIlya Leoshkevich                      gdbserver_user_state.fork_peer_pid);
494d547e711SIlya Leoshkevich         g_assert(gdbserver_state.processes[0].attached);
495d547e711SIlya Leoshkevich         gdbserver_state.processes[0].pid = getpid();
496d547e711SIlya Leoshkevich     } else {
497d547e711SIlya Leoshkevich         close(gdbserver_user_state.fork_sockets[1]);
498d547e711SIlya Leoshkevich         fd = gdbserver_user_state.fork_sockets[0];
499d547e711SIlya Leoshkevich         gdbserver_user_state.fork_state = GDB_FORK_ACTIVE;
500d547e711SIlya Leoshkevich         gdbserver_user_state.fork_peer_pid = pid;
501d547e711SIlya Leoshkevich         gdbserver_user_state.fork_peer_tid = pid;
502d547e711SIlya Leoshkevich 
503d547e711SIlya Leoshkevich         if (!gdbserver_state.allow_stop_reply) {
504d547e711SIlya Leoshkevich             goto fail;
505d547e711SIlya Leoshkevich         }
506d547e711SIlya Leoshkevich         g_string_printf(gdbserver_state.str_buf,
507d547e711SIlya Leoshkevich                         "T%02xfork:p%02x.%02x;thread:p%02x.%02x;",
508d547e711SIlya Leoshkevich                         gdb_target_signal_to_gdb(gdb_target_sigtrap()),
509d547e711SIlya Leoshkevich                         pid, pid, (int)getpid(), qemu_get_thread_id());
510d547e711SIlya Leoshkevich         gdb_put_strbuf();
511d547e711SIlya Leoshkevich     }
512d547e711SIlya Leoshkevich 
513d547e711SIlya Leoshkevich     gdbserver_state.state = RS_IDLE;
514d547e711SIlya Leoshkevich     gdbserver_state.allow_stop_reply = false;
515d547e711SIlya Leoshkevich     gdbserver_user_state.running_state = 0;
516d547e711SIlya Leoshkevich     for (;;) {
517d547e711SIlya Leoshkevich         switch (gdbserver_user_state.fork_state) {
518d547e711SIlya Leoshkevich         case GDB_FORK_ENABLED:
519d547e711SIlya Leoshkevich             if (gdbserver_user_state.running_state) {
5206971998eSIlya Leoshkevich                 close(fd);
521d547e711SIlya Leoshkevich                 return;
522d547e711SIlya Leoshkevich             }
523d547e711SIlya Leoshkevich             QEMU_FALLTHROUGH;
524d547e711SIlya Leoshkevich         case GDB_FORK_ACTIVE:
525d547e711SIlya Leoshkevich             if (read(gdbserver_user_state.fd, &b, 1) != 1) {
526d547e711SIlya Leoshkevich                 goto fail;
527d547e711SIlya Leoshkevich             }
528d547e711SIlya Leoshkevich             gdb_read_byte(b);
529d547e711SIlya Leoshkevich             break;
530d547e711SIlya Leoshkevich         case GDB_FORK_DEACTIVATING:
531d547e711SIlya Leoshkevich             b = GDB_FORK_ACTIVATE;
532d547e711SIlya Leoshkevich             if (write(fd, &b, 1) != 1) {
533d547e711SIlya Leoshkevich                 goto fail;
534d547e711SIlya Leoshkevich             }
535d547e711SIlya Leoshkevich             gdbserver_user_state.fork_state = GDB_FORK_INACTIVE;
536d547e711SIlya Leoshkevich             break;
537d547e711SIlya Leoshkevich         case GDB_FORK_INACTIVE:
538d547e711SIlya Leoshkevich             if (read(fd, &b, 1) != 1) {
539d547e711SIlya Leoshkevich                 goto fail;
540d547e711SIlya Leoshkevich             }
541d547e711SIlya Leoshkevich             switch (b) {
542d547e711SIlya Leoshkevich             case GDB_FORK_ACTIVATE:
543d547e711SIlya Leoshkevich                 gdbserver_user_state.fork_state = GDB_FORK_ACTIVE;
544d547e711SIlya Leoshkevich                 break;
545d547e711SIlya Leoshkevich             case GDB_FORK_ENABLE:
546d547e711SIlya Leoshkevich                 gdbserver_user_state.fork_state = GDB_FORK_ENABLED;
547d547e711SIlya Leoshkevich                 break;
548d547e711SIlya Leoshkevich             case GDB_FORK_DISABLE:
549d547e711SIlya Leoshkevich                 gdbserver_user_state.fork_state = GDB_FORK_DISABLED;
550d547e711SIlya Leoshkevich                 break;
551d547e711SIlya Leoshkevich             default:
552d547e711SIlya Leoshkevich                 g_assert_not_reached();
553d547e711SIlya Leoshkevich             }
554d547e711SIlya Leoshkevich             break;
555d547e711SIlya Leoshkevich         case GDB_FORK_ENABLING:
556d547e711SIlya Leoshkevich             b = GDB_FORK_DISABLE;
557d547e711SIlya Leoshkevich             if (write(fd, &b, 1) != 1) {
558d547e711SIlya Leoshkevich                 goto fail;
559d547e711SIlya Leoshkevich             }
560d547e711SIlya Leoshkevich             gdbserver_user_state.fork_state = GDB_FORK_ENABLED;
561d547e711SIlya Leoshkevich             break;
562d547e711SIlya Leoshkevich         case GDB_FORK_DISABLING:
563d547e711SIlya Leoshkevich             b = GDB_FORK_ENABLE;
564d547e711SIlya Leoshkevich             if (write(fd, &b, 1) != 1) {
565d547e711SIlya Leoshkevich                 goto fail;
566d547e711SIlya Leoshkevich             }
567d547e711SIlya Leoshkevich             gdbserver_user_state.fork_state = GDB_FORK_DISABLED;
568d547e711SIlya Leoshkevich             break;
569d547e711SIlya Leoshkevich         case GDB_FORK_DISABLED:
570d547e711SIlya Leoshkevich             close(fd);
571d547e711SIlya Leoshkevich             disable_gdbstub(cpu);
572d547e711SIlya Leoshkevich             return;
573d547e711SIlya Leoshkevich         default:
574d547e711SIlya Leoshkevich             g_assert_not_reached();
575d547e711SIlya Leoshkevich         }
576d547e711SIlya Leoshkevich     }
577d547e711SIlya Leoshkevich 
578d547e711SIlya Leoshkevich fail:
579d547e711SIlya Leoshkevich     close(fd);
580d547e711SIlya Leoshkevich     if (pid == 0) {
581d547e711SIlya Leoshkevich         disable_gdbstub(cpu);
582d547e711SIlya Leoshkevich     }
583d547e711SIlya Leoshkevich }
584d96bf49bSAlex Bennée 
gdb_handle_query_supported_user(const char * gdb_supported)5856d923112SIlya Leoshkevich void gdb_handle_query_supported_user(const char *gdb_supported)
5866d923112SIlya Leoshkevich {
587d547e711SIlya Leoshkevich     if (strstr(gdb_supported, "fork-events+")) {
588d547e711SIlya Leoshkevich         gdbserver_user_state.fork_events = true;
589d547e711SIlya Leoshkevich     }
590d547e711SIlya Leoshkevich     g_string_append(gdbserver_state.str_buf, ";fork-events+");
5916d923112SIlya Leoshkevich }
5926d923112SIlya Leoshkevich 
gdb_handle_set_thread_user(uint32_t pid,uint32_t tid)593e454f2feSIlya Leoshkevich bool gdb_handle_set_thread_user(uint32_t pid, uint32_t tid)
594e454f2feSIlya Leoshkevich {
595d547e711SIlya Leoshkevich     if (gdbserver_user_state.fork_state == GDB_FORK_ACTIVE &&
596d547e711SIlya Leoshkevich             pid == gdbserver_user_state.fork_peer_pid &&
597d547e711SIlya Leoshkevich             tid == gdbserver_user_state.fork_peer_tid) {
598d547e711SIlya Leoshkevich         gdbserver_user_state.fork_state = GDB_FORK_DEACTIVATING;
599d547e711SIlya Leoshkevich         gdb_put_packet("OK");
600d547e711SIlya Leoshkevich         return true;
601d547e711SIlya Leoshkevich     }
602e454f2feSIlya Leoshkevich     return false;
603e454f2feSIlya Leoshkevich }
604e454f2feSIlya Leoshkevich 
gdb_handle_detach_user(uint32_t pid)605539cb4ecSIlya Leoshkevich bool gdb_handle_detach_user(uint32_t pid)
606539cb4ecSIlya Leoshkevich {
607d547e711SIlya Leoshkevich     bool enable;
608d547e711SIlya Leoshkevich 
609d547e711SIlya Leoshkevich     if (gdbserver_user_state.fork_state == GDB_FORK_ACTIVE) {
610d547e711SIlya Leoshkevich         enable = pid == gdbserver_user_state.fork_peer_pid;
611d547e711SIlya Leoshkevich         if (enable || pid == getpid()) {
612d547e711SIlya Leoshkevich             gdbserver_user_state.fork_state = enable ? GDB_FORK_ENABLING :
613d547e711SIlya Leoshkevich                                                        GDB_FORK_DISABLING;
614d547e711SIlya Leoshkevich             gdb_put_packet("OK");
615d547e711SIlya Leoshkevich             return true;
616d547e711SIlya Leoshkevich         }
617d547e711SIlya Leoshkevich     }
618539cb4ecSIlya Leoshkevich     return false;
619539cb4ecSIlya Leoshkevich }
620539cb4ecSIlya Leoshkevich 
621d96bf49bSAlex Bennée /*
622d96bf49bSAlex Bennée  * Execution state helpers
623d96bf49bSAlex Bennée  */
624d96bf49bSAlex Bennée 
gdb_handle_query_attached(GArray * params,void * user_ctx)6258a2025b3SAlex Bennée void gdb_handle_query_attached(GArray *params, void *user_ctx)
6268a2025b3SAlex Bennée {
6278a2025b3SAlex Bennée     gdb_put_packet("0");
6288a2025b3SAlex Bennée }
6298a2025b3SAlex Bennée 
gdb_continue(void)630d96bf49bSAlex Bennée void gdb_continue(void)
631d96bf49bSAlex Bennée {
632d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 1;
633d96bf49bSAlex Bennée     trace_gdbstub_op_continue();
634d96bf49bSAlex Bennée }
635d96bf49bSAlex Bennée 
636d96bf49bSAlex Bennée /*
637d96bf49bSAlex Bennée  * Resume execution, for user-mode emulation it's equivalent to
638d96bf49bSAlex Bennée  * gdb_continue.
639d96bf49bSAlex Bennée  */
gdb_continue_partial(char * newstates)640d96bf49bSAlex Bennée int gdb_continue_partial(char *newstates)
641d96bf49bSAlex Bennée {
642d96bf49bSAlex Bennée     CPUState *cpu;
643d96bf49bSAlex Bennée     int res = 0;
644d96bf49bSAlex Bennée     /*
645d96bf49bSAlex Bennée      * This is not exactly accurate, but it's an improvement compared to the
646d96bf49bSAlex Bennée      * previous situation, where only one CPU would be single-stepped.
647d96bf49bSAlex Bennée      */
648d96bf49bSAlex Bennée     CPU_FOREACH(cpu) {
649d96bf49bSAlex Bennée         if (newstates[cpu->cpu_index] == 's') {
650d96bf49bSAlex Bennée             trace_gdbstub_op_stepping(cpu->cpu_index);
651d96bf49bSAlex Bennée             cpu_single_step(cpu, gdbserver_state.sstep_flags);
652d96bf49bSAlex Bennée         }
653d96bf49bSAlex Bennée     }
654d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 1;
655d96bf49bSAlex Bennée     return res;
656d96bf49bSAlex Bennée }
657d96bf49bSAlex Bennée 
658d96bf49bSAlex Bennée /*
659589a5867SAlex Bennée  * Memory access helpers
660589a5867SAlex Bennée  */
gdb_target_memory_rw_debug(CPUState * cpu,hwaddr addr,uint8_t * buf,int len,bool is_write)661589a5867SAlex Bennée int gdb_target_memory_rw_debug(CPUState *cpu, hwaddr addr,
662589a5867SAlex Bennée                                uint8_t *buf, int len, bool is_write)
663589a5867SAlex Bennée {
664589a5867SAlex Bennée     CPUClass *cc;
665589a5867SAlex Bennée 
666589a5867SAlex Bennée     cc = CPU_GET_CLASS(cpu);
667589a5867SAlex Bennée     if (cc->memory_rw_debug) {
668589a5867SAlex Bennée         return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
669589a5867SAlex Bennée     }
670589a5867SAlex Bennée     return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
671589a5867SAlex Bennée }
672589a5867SAlex Bennée 
673589a5867SAlex Bennée /*
6747ea0c33dSAlex Bennée  * cpu helpers
6757ea0c33dSAlex Bennée  */
6767ea0c33dSAlex Bennée 
gdb_get_max_cpus(void)6777ea0c33dSAlex Bennée unsigned int gdb_get_max_cpus(void)
6787ea0c33dSAlex Bennée {
6797ea0c33dSAlex Bennée     CPUState *cpu;
6807ea0c33dSAlex Bennée     unsigned int max_cpus = 1;
6817ea0c33dSAlex Bennée 
6827ea0c33dSAlex Bennée     CPU_FOREACH(cpu) {
6837ea0c33dSAlex Bennée         max_cpus = max_cpus <= cpu->cpu_index ? cpu->cpu_index + 1 : max_cpus;
6847ea0c33dSAlex Bennée     }
6857ea0c33dSAlex Bennée 
6867ea0c33dSAlex Bennée     return max_cpus;
6877ea0c33dSAlex Bennée }
6887ea0c33dSAlex Bennée 
689505601d5SAlex Bennée /* replay not supported for user-mode */
gdb_can_reverse(void)690505601d5SAlex Bennée bool gdb_can_reverse(void)
691505601d5SAlex Bennée {
692505601d5SAlex Bennée     return false;
693505601d5SAlex Bennée }
6947ea0c33dSAlex Bennée 
6957ea0c33dSAlex Bennée /*
696d96bf49bSAlex Bennée  * Break/Watch point helpers
697d96bf49bSAlex Bennée  */
698d96bf49bSAlex Bennée 
gdb_supports_guest_debug(void)699a48e7d9eSAlex Bennée bool gdb_supports_guest_debug(void)
700a48e7d9eSAlex Bennée {
701a48e7d9eSAlex Bennée     /* user-mode == TCG == supported */
702a48e7d9eSAlex Bennée     return true;
703a48e7d9eSAlex Bennée }
704a48e7d9eSAlex Bennée 
gdb_breakpoint_insert(CPUState * cs,int type,vaddr addr,vaddr len)70555b5b8e9SPhilippe Mathieu-Daudé int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len)
706ae7467b1SAlex Bennée {
707ae7467b1SAlex Bennée     CPUState *cpu;
708ae7467b1SAlex Bennée     int err = 0;
709ae7467b1SAlex Bennée 
710ae7467b1SAlex Bennée     switch (type) {
711ae7467b1SAlex Bennée     case GDB_BREAKPOINT_SW:
712ae7467b1SAlex Bennée     case GDB_BREAKPOINT_HW:
713ae7467b1SAlex Bennée         CPU_FOREACH(cpu) {
714ae7467b1SAlex Bennée             err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL);
715ae7467b1SAlex Bennée             if (err) {
716ae7467b1SAlex Bennée                 break;
717ae7467b1SAlex Bennée             }
718ae7467b1SAlex Bennée         }
719ae7467b1SAlex Bennée         return err;
720ae7467b1SAlex Bennée     default:
721ae7467b1SAlex Bennée         /* user-mode doesn't support watchpoints */
722ae7467b1SAlex Bennée         return -ENOSYS;
723ae7467b1SAlex Bennée     }
724ae7467b1SAlex Bennée }
725ae7467b1SAlex Bennée 
gdb_breakpoint_remove(CPUState * cs,int type,vaddr addr,vaddr len)72655b5b8e9SPhilippe Mathieu-Daudé int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len)
727ae7467b1SAlex Bennée {
728ae7467b1SAlex Bennée     CPUState *cpu;
729ae7467b1SAlex Bennée     int err = 0;
730ae7467b1SAlex Bennée 
731ae7467b1SAlex Bennée     switch (type) {
732ae7467b1SAlex Bennée     case GDB_BREAKPOINT_SW:
733ae7467b1SAlex Bennée     case GDB_BREAKPOINT_HW:
734ae7467b1SAlex Bennée         CPU_FOREACH(cpu) {
735ae7467b1SAlex Bennée             err = cpu_breakpoint_remove(cpu, addr, BP_GDB);
736ae7467b1SAlex Bennée             if (err) {
737ae7467b1SAlex Bennée                 break;
738ae7467b1SAlex Bennée             }
739ae7467b1SAlex Bennée         }
740ae7467b1SAlex Bennée         return err;
741ae7467b1SAlex Bennée     default:
742ae7467b1SAlex Bennée         /* user-mode doesn't support watchpoints */
743ae7467b1SAlex Bennée         return -ENOSYS;
744ae7467b1SAlex Bennée     }
745ae7467b1SAlex Bennée }
746ae7467b1SAlex Bennée 
gdb_breakpoint_remove_all(CPUState * cs)747ae7467b1SAlex Bennée void gdb_breakpoint_remove_all(CPUState *cs)
748ae7467b1SAlex Bennée {
749ae7467b1SAlex Bennée     cpu_breakpoint_remove_all(cs, BP_GDB);
750ae7467b1SAlex Bennée }
751131f387dSAlex Bennée 
752131f387dSAlex Bennée /*
753131f387dSAlex Bennée  * For user-mode syscall support we send the system call immediately
754131f387dSAlex Bennée  * and then return control to gdb for it to process the syscall request.
755131f387dSAlex Bennée  * Since the protocol requires that gdb hands control back to us
756131f387dSAlex Bennée  * using a "here are the results" F packet, we don't need to check
757131f387dSAlex Bennée  * gdb_handlesig's return value (which is the signal to deliver if
758131f387dSAlex Bennée  * execution was resumed via a continue packet).
759131f387dSAlex Bennée  */
gdb_syscall_handling(const char * syscall_packet)760131f387dSAlex Bennée void gdb_syscall_handling(const char *syscall_packet)
761131f387dSAlex Bennée {
762131f387dSAlex Bennée     gdb_put_packet(syscall_packet);
763f84e313eSGustavo Romero     gdb_handlesig(gdbserver_state.c_cpu, 0, NULL, NULL, 0);
764131f387dSAlex Bennée }
7650a0d87c9SIlya Leoshkevich 
should_catch_syscall(int num)766046f143cSIlya Leoshkevich static bool should_catch_syscall(int num)
767046f143cSIlya Leoshkevich {
768046f143cSIlya Leoshkevich     if (gdbserver_user_state.catch_all_syscalls) {
769046f143cSIlya Leoshkevich         return true;
770046f143cSIlya Leoshkevich     }
771046f143cSIlya Leoshkevich     if (num < 0 || num >= GDB_NR_SYSCALLS) {
772046f143cSIlya Leoshkevich         return false;
773046f143cSIlya Leoshkevich     }
774046f143cSIlya Leoshkevich     return test_bit(num, gdbserver_user_state.catch_syscalls_mask);
775046f143cSIlya Leoshkevich }
776046f143cSIlya Leoshkevich 
gdb_syscall_entry(CPUState * cs,int num)7770a0d87c9SIlya Leoshkevich void gdb_syscall_entry(CPUState *cs, int num)
7780a0d87c9SIlya Leoshkevich {
779046f143cSIlya Leoshkevich     if (should_catch_syscall(num)) {
780046f143cSIlya Leoshkevich         g_autofree char *reason = g_strdup_printf("syscall_entry:%x;", num);
781f84e313eSGustavo Romero         gdb_handlesig(cs, gdb_target_sigtrap(), reason, NULL, 0);
782046f143cSIlya Leoshkevich     }
7830a0d87c9SIlya Leoshkevich }
7840a0d87c9SIlya Leoshkevich 
gdb_syscall_return(CPUState * cs,int num)7850a0d87c9SIlya Leoshkevich void gdb_syscall_return(CPUState *cs, int num)
7860a0d87c9SIlya Leoshkevich {
787046f143cSIlya Leoshkevich     if (should_catch_syscall(num)) {
788046f143cSIlya Leoshkevich         g_autofree char *reason = g_strdup_printf("syscall_return:%x;", num);
789f84e313eSGustavo Romero         gdb_handlesig(cs, gdb_target_sigtrap(), reason, NULL, 0);
790046f143cSIlya Leoshkevich     }
791046f143cSIlya Leoshkevich }
792046f143cSIlya Leoshkevich 
gdb_handle_set_catch_syscalls(GArray * params,void * user_ctx)793046f143cSIlya Leoshkevich void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx)
794046f143cSIlya Leoshkevich {
795046f143cSIlya Leoshkevich     const char *param = get_param(params, 0)->data;
796046f143cSIlya Leoshkevich     GDBSyscallsMask catch_syscalls_mask;
797046f143cSIlya Leoshkevich     bool catch_all_syscalls;
798046f143cSIlya Leoshkevich     unsigned int num;
799046f143cSIlya Leoshkevich     const char *p;
800046f143cSIlya Leoshkevich 
801046f143cSIlya Leoshkevich     /* "0" means not catching any syscalls. */
802046f143cSIlya Leoshkevich     if (strcmp(param, "0") == 0) {
803046f143cSIlya Leoshkevich         gdbserver_user_state.catch_all_syscalls = false;
804046f143cSIlya Leoshkevich         memset(gdbserver_user_state.catch_syscalls_mask, 0,
805046f143cSIlya Leoshkevich                sizeof(gdbserver_user_state.catch_syscalls_mask));
806046f143cSIlya Leoshkevich         gdb_put_packet("OK");
807046f143cSIlya Leoshkevich         return;
808046f143cSIlya Leoshkevich     }
809046f143cSIlya Leoshkevich 
810046f143cSIlya Leoshkevich     /* "1" means catching all syscalls. */
811046f143cSIlya Leoshkevich     if (strcmp(param, "1") == 0) {
812046f143cSIlya Leoshkevich         gdbserver_user_state.catch_all_syscalls = true;
813046f143cSIlya Leoshkevich         gdb_put_packet("OK");
814046f143cSIlya Leoshkevich         return;
815046f143cSIlya Leoshkevich     }
816046f143cSIlya Leoshkevich 
817046f143cSIlya Leoshkevich     /*
818046f143cSIlya Leoshkevich      * "1;..." means catching only the specified syscalls.
819046f143cSIlya Leoshkevich      * The syscall list must not be empty.
820046f143cSIlya Leoshkevich      */
821046f143cSIlya Leoshkevich     if (param[0] == '1' && param[1] == ';') {
822046f143cSIlya Leoshkevich         catch_all_syscalls = false;
823046f143cSIlya Leoshkevich         memset(catch_syscalls_mask, 0, sizeof(catch_syscalls_mask));
824046f143cSIlya Leoshkevich         for (p = &param[2];; p++) {
825046f143cSIlya Leoshkevich             if (qemu_strtoui(p, &p, 16, &num) || (*p && *p != ';')) {
826046f143cSIlya Leoshkevich                 goto err;
827046f143cSIlya Leoshkevich             }
828046f143cSIlya Leoshkevich             if (num >= GDB_NR_SYSCALLS) {
829046f143cSIlya Leoshkevich                 /*
830046f143cSIlya Leoshkevich                  * Fall back to reporting all syscalls. Reporting extra
831046f143cSIlya Leoshkevich                  * syscalls is inefficient, but the spec explicitly allows it.
832046f143cSIlya Leoshkevich                  * Keep parsing in case there is a syntax error ahead.
833046f143cSIlya Leoshkevich                  */
834046f143cSIlya Leoshkevich                 catch_all_syscalls = true;
835046f143cSIlya Leoshkevich             } else {
836046f143cSIlya Leoshkevich                 set_bit(num, catch_syscalls_mask);
837046f143cSIlya Leoshkevich             }
838046f143cSIlya Leoshkevich             if (!*p) {
839046f143cSIlya Leoshkevich                 break;
840046f143cSIlya Leoshkevich             }
841046f143cSIlya Leoshkevich         }
842046f143cSIlya Leoshkevich         gdbserver_user_state.catch_all_syscalls = catch_all_syscalls;
843046f143cSIlya Leoshkevich         if (!catch_all_syscalls) {
844046f143cSIlya Leoshkevich             memcpy(gdbserver_user_state.catch_syscalls_mask,
845046f143cSIlya Leoshkevich                    catch_syscalls_mask, sizeof(catch_syscalls_mask));
846046f143cSIlya Leoshkevich         }
847046f143cSIlya Leoshkevich         gdb_put_packet("OK");
848046f143cSIlya Leoshkevich         return;
849046f143cSIlya Leoshkevich     }
850046f143cSIlya Leoshkevich 
851046f143cSIlya Leoshkevich err:
852046f143cSIlya Leoshkevich     gdb_put_packet("E00");
8530a0d87c9SIlya Leoshkevich }
8549ae5801dSGustavo Romero 
gdb_handle_query_xfer_siginfo(GArray * params,void * user_ctx)8559ae5801dSGustavo Romero void gdb_handle_query_xfer_siginfo(GArray *params, void *user_ctx)
8569ae5801dSGustavo Romero {
8579ae5801dSGustavo Romero     unsigned long offset, len;
8589ae5801dSGustavo Romero     uint8_t *siginfo_offset;
8599ae5801dSGustavo Romero 
8609ae5801dSGustavo Romero     offset = get_param(params, 0)->val_ul;
8619ae5801dSGustavo Romero     len = get_param(params, 1)->val_ul;
8629ae5801dSGustavo Romero 
8639ae5801dSGustavo Romero     if (offset + len > gdbserver_user_state.siginfo_len) {
8649ae5801dSGustavo Romero         /* Invalid offset and/or requested length. */
8659ae5801dSGustavo Romero         gdb_put_packet("E01");
8669ae5801dSGustavo Romero         return;
8679ae5801dSGustavo Romero     }
8689ae5801dSGustavo Romero 
8699ae5801dSGustavo Romero     siginfo_offset = (uint8_t *)gdbserver_user_state.siginfo + offset;
8709ae5801dSGustavo Romero 
8719ae5801dSGustavo Romero     /* Reply */
8729ae5801dSGustavo Romero     g_string_assign(gdbserver_state.str_buf, "l");
8739ae5801dSGustavo Romero     gdb_memtox(gdbserver_state.str_buf, (const char *)siginfo_offset, len);
8749ae5801dSGustavo Romero     gdb_put_packet_binary(gdbserver_state.str_buf->str,
8759ae5801dSGustavo Romero                           gdbserver_state.str_buf->len, true);
8769ae5801dSGustavo Romero }
877