xref: /qemu/gdbstub/user.c (revision d547e711)
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 
28*d547e711SIlya Leoshkevich /*
29*d547e711SIlya Leoshkevich  * Forked child talks to its parent in order to let GDB enforce the
30*d547e711SIlya Leoshkevich  * follow-fork-mode. This happens inside a start_exclusive() section, so that
31*d547e711SIlya Leoshkevich  * the other threads, which may be forking too, do not interfere. The
32*d547e711SIlya Leoshkevich  * implementation relies on GDB not sending $vCont until it has detached
33*d547e711SIlya Leoshkevich  * either from the parent (follow-fork-mode child) or from the child
34*d547e711SIlya Leoshkevich  * (follow-fork-mode parent).
35*d547e711SIlya Leoshkevich  *
36*d547e711SIlya Leoshkevich  * The parent and the child share the GDB socket; at any given time only one
37*d547e711SIlya Leoshkevich  * of them is allowed to use it, as is reflected in the respective fork_state.
38*d547e711SIlya Leoshkevich  * This is negotiated via the fork_sockets pair as a reaction to $Hg.
39*d547e711SIlya Leoshkevich  *
40*d547e711SIlya Leoshkevich  * Below is a short summary of the possible state transitions:
41*d547e711SIlya Leoshkevich  *
42*d547e711SIlya Leoshkevich  *     ENABLED                     : Terminal state.
43*d547e711SIlya Leoshkevich  *     DISABLED                    : Terminal state.
44*d547e711SIlya Leoshkevich  *     ACTIVE                      : Parent initial state.
45*d547e711SIlya Leoshkevich  *     INACTIVE                    : Child initial state.
46*d547e711SIlya Leoshkevich  *     ACTIVE       -> DEACTIVATING: On $Hg.
47*d547e711SIlya Leoshkevich  *     ACTIVE       -> ENABLING    : On $D.
48*d547e711SIlya Leoshkevich  *     ACTIVE       -> DISABLING   : On $D.
49*d547e711SIlya Leoshkevich  *     ACTIVE       -> DISABLED    : On communication error.
50*d547e711SIlya Leoshkevich  *     DEACTIVATING -> INACTIVE    : On gdb_read_byte() return.
51*d547e711SIlya Leoshkevich  *     DEACTIVATING -> DISABLED    : On communication error.
52*d547e711SIlya Leoshkevich  *     INACTIVE     -> ACTIVE      : On $Hg in the peer.
53*d547e711SIlya Leoshkevich  *     INACTIVE     -> ENABLE      : On $D in the peer.
54*d547e711SIlya Leoshkevich  *     INACTIVE     -> DISABLE     : On $D in the peer.
55*d547e711SIlya Leoshkevich  *     INACTIVE     -> DISABLED    : On communication error.
56*d547e711SIlya Leoshkevich  *     ENABLING     -> ENABLED     : On gdb_read_byte() return.
57*d547e711SIlya Leoshkevich  *     ENABLING     -> DISABLED    : On communication error.
58*d547e711SIlya Leoshkevich  *     DISABLING    -> DISABLED    : On gdb_read_byte() return.
59*d547e711SIlya Leoshkevich  */
60*d547e711SIlya Leoshkevich enum GDBForkState {
61*d547e711SIlya Leoshkevich     /* Fully owning the GDB socket. */
62*d547e711SIlya Leoshkevich     GDB_FORK_ENABLED,
63*d547e711SIlya Leoshkevich     /* Working with the GDB socket; the peer is inactive. */
64*d547e711SIlya Leoshkevich     GDB_FORK_ACTIVE,
65*d547e711SIlya Leoshkevich     /* Handing off the GDB socket to the peer. */
66*d547e711SIlya Leoshkevich     GDB_FORK_DEACTIVATING,
67*d547e711SIlya Leoshkevich     /* The peer is working with the GDB socket. */
68*d547e711SIlya Leoshkevich     GDB_FORK_INACTIVE,
69*d547e711SIlya Leoshkevich     /* Asking the peer to close its GDB socket fd. */
70*d547e711SIlya Leoshkevich     GDB_FORK_ENABLING,
71*d547e711SIlya Leoshkevich     /* Asking the peer to take over, closing our GDB socket fd. */
72*d547e711SIlya Leoshkevich     GDB_FORK_DISABLING,
73*d547e711SIlya Leoshkevich     /* The peer has taken over, our GDB socket fd is closed. */
74*d547e711SIlya Leoshkevich     GDB_FORK_DISABLED,
75*d547e711SIlya Leoshkevich };
76*d547e711SIlya Leoshkevich 
77*d547e711SIlya Leoshkevich enum GDBForkMessage {
78*d547e711SIlya Leoshkevich     GDB_FORK_ACTIVATE = 'a',
79*d547e711SIlya Leoshkevich     GDB_FORK_ENABLE = 'e',
80*d547e711SIlya Leoshkevich     GDB_FORK_DISABLE = 'd',
81*d547e711SIlya Leoshkevich };
82*d547e711SIlya 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;
94*d547e711SIlya Leoshkevich     bool fork_events;
95*d547e711SIlya Leoshkevich     enum GDBForkState fork_state;
96*d547e711SIlya Leoshkevich     int fork_sockets[2];
97*d547e711SIlya Leoshkevich     pid_t fork_peer_pid, fork_peer_tid;
98d96bf49bSAlex Bennée } GDBUserState;
99d96bf49bSAlex Bennée 
100d96bf49bSAlex Bennée static GDBUserState gdbserver_user_state;
101d96bf49bSAlex Bennée 
102d96bf49bSAlex Bennée int gdb_get_char(void)
103d96bf49bSAlex Bennée {
104d96bf49bSAlex Bennée     uint8_t ch;
105d96bf49bSAlex Bennée     int ret;
106d96bf49bSAlex Bennée 
107d96bf49bSAlex Bennée     for (;;) {
108d96bf49bSAlex Bennée         ret = recv(gdbserver_user_state.fd, &ch, 1, 0);
109d96bf49bSAlex Bennée         if (ret < 0) {
110d96bf49bSAlex Bennée             if (errno == ECONNRESET) {
111d96bf49bSAlex Bennée                 gdbserver_user_state.fd = -1;
112d96bf49bSAlex Bennée             }
113d96bf49bSAlex Bennée             if (errno != EINTR) {
114d96bf49bSAlex Bennée                 return -1;
115d96bf49bSAlex Bennée             }
116d96bf49bSAlex Bennée         } else if (ret == 0) {
117d96bf49bSAlex Bennée             close(gdbserver_user_state.fd);
118d96bf49bSAlex Bennée             gdbserver_user_state.fd = -1;
119d96bf49bSAlex Bennée             return -1;
120d96bf49bSAlex Bennée         } else {
121d96bf49bSAlex Bennée             break;
122d96bf49bSAlex Bennée         }
123d96bf49bSAlex Bennée     }
124d96bf49bSAlex Bennée     return ch;
125d96bf49bSAlex Bennée }
126d96bf49bSAlex Bennée 
127a7e0f9bdSAlex Bennée bool gdb_got_immediate_ack(void)
128a7e0f9bdSAlex Bennée {
129a7e0f9bdSAlex Bennée     int i;
130a7e0f9bdSAlex Bennée 
131a7e0f9bdSAlex Bennée     i = gdb_get_char();
132a7e0f9bdSAlex Bennée     if (i < 0) {
133a7e0f9bdSAlex Bennée         /* no response, continue anyway */
134a7e0f9bdSAlex Bennée         return true;
135a7e0f9bdSAlex Bennée     }
136a7e0f9bdSAlex Bennée 
137a7e0f9bdSAlex Bennée     if (i == '+') {
138a7e0f9bdSAlex Bennée         /* received correctly, continue */
139a7e0f9bdSAlex Bennée         return true;
140a7e0f9bdSAlex Bennée     }
141a7e0f9bdSAlex Bennée 
142a7e0f9bdSAlex Bennée     /* anything else, including '-' then try again */
143a7e0f9bdSAlex Bennée     return false;
144a7e0f9bdSAlex Bennée }
145a7e0f9bdSAlex Bennée 
146d96bf49bSAlex Bennée void gdb_put_buffer(const uint8_t *buf, int len)
147d96bf49bSAlex Bennée {
148d96bf49bSAlex Bennée     int ret;
149d96bf49bSAlex Bennée 
150d96bf49bSAlex Bennée     while (len > 0) {
151d96bf49bSAlex Bennée         ret = send(gdbserver_user_state.fd, buf, len, 0);
152d96bf49bSAlex Bennée         if (ret < 0) {
153d96bf49bSAlex Bennée             if (errno != EINTR) {
154d96bf49bSAlex Bennée                 return;
155d96bf49bSAlex Bennée             }
156d96bf49bSAlex Bennée         } else {
157d96bf49bSAlex Bennée             buf += ret;
158d96bf49bSAlex Bennée             len -= ret;
159d96bf49bSAlex Bennée         }
160d96bf49bSAlex Bennée     }
161d96bf49bSAlex Bennée }
162d96bf49bSAlex Bennée 
163d96bf49bSAlex Bennée /* Tell the remote gdb that the process has exited.  */
164d96bf49bSAlex Bennée void gdb_exit(int code)
165d96bf49bSAlex Bennée {
166d96bf49bSAlex Bennée     char buf[4];
167d96bf49bSAlex Bennée 
168d96bf49bSAlex Bennée     if (!gdbserver_state.init) {
169d96bf49bSAlex Bennée         return;
170d96bf49bSAlex Bennée     }
171d96bf49bSAlex Bennée     if (gdbserver_user_state.socket_path) {
172d96bf49bSAlex Bennée         unlink(gdbserver_user_state.socket_path);
173d96bf49bSAlex Bennée     }
174d96bf49bSAlex Bennée     if (gdbserver_user_state.fd < 0) {
175d96bf49bSAlex Bennée         return;
176d96bf49bSAlex Bennée     }
177d96bf49bSAlex Bennée 
178d96bf49bSAlex Bennée     trace_gdbstub_op_exiting((uint8_t)code);
179d96bf49bSAlex Bennée 
18075837005SMatheus Tavares Bernardino     if (gdbserver_state.allow_stop_reply) {
181d96bf49bSAlex Bennée         snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
182d96bf49bSAlex Bennée         gdb_put_packet(buf);
18375837005SMatheus Tavares Bernardino         gdbserver_state.allow_stop_reply = false;
18475837005SMatheus Tavares Bernardino     }
185e216256aSClément Chigot 
186e216256aSClément Chigot }
187e216256aSClément Chigot 
188e216256aSClément Chigot void gdb_qemu_exit(int code)
189e216256aSClément Chigot {
190e216256aSClément Chigot     exit(code);
191d96bf49bSAlex Bennée }
192d96bf49bSAlex Bennée 
1938b7fcb8eSIlya Leoshkevich int gdb_handlesig_reason(CPUState *cpu, int sig, const char *reason)
194d96bf49bSAlex Bennée {
195d96bf49bSAlex Bennée     char buf[256];
196d96bf49bSAlex Bennée     int n;
197d96bf49bSAlex Bennée 
198d96bf49bSAlex Bennée     if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
199d96bf49bSAlex Bennée         return sig;
200d96bf49bSAlex Bennée     }
201d96bf49bSAlex Bennée 
202d96bf49bSAlex Bennée     /* disable single step if it was enabled */
203d96bf49bSAlex Bennée     cpu_single_step(cpu, 0);
204d96bf49bSAlex Bennée     tb_flush(cpu);
205d96bf49bSAlex Bennée 
206d96bf49bSAlex Bennée     if (sig != 0) {
207d96bf49bSAlex Bennée         gdb_set_stop_cpu(cpu);
20875837005SMatheus Tavares Bernardino         if (gdbserver_state.allow_stop_reply) {
209d96bf49bSAlex Bennée             g_string_printf(gdbserver_state.str_buf,
210d96bf49bSAlex Bennée                             "T%02xthread:", gdb_target_signal_to_gdb(sig));
211d96bf49bSAlex Bennée             gdb_append_thread_id(cpu, gdbserver_state.str_buf);
212d96bf49bSAlex Bennée             g_string_append_c(gdbserver_state.str_buf, ';');
2138b7fcb8eSIlya Leoshkevich             if (reason) {
2148b7fcb8eSIlya Leoshkevich                 g_string_append(gdbserver_state.str_buf, reason);
2158b7fcb8eSIlya Leoshkevich             }
216d96bf49bSAlex Bennée             gdb_put_strbuf();
21775837005SMatheus Tavares Bernardino             gdbserver_state.allow_stop_reply = false;
21875837005SMatheus Tavares Bernardino         }
219d96bf49bSAlex Bennée     }
220d96bf49bSAlex Bennée     /*
221d96bf49bSAlex Bennée      * gdb_put_packet() might have detected that the peer terminated the
222d96bf49bSAlex Bennée      * connection.
223d96bf49bSAlex Bennée      */
224d96bf49bSAlex Bennée     if (gdbserver_user_state.fd < 0) {
225d96bf49bSAlex Bennée         return sig;
226d96bf49bSAlex Bennée     }
227d96bf49bSAlex Bennée 
228d96bf49bSAlex Bennée     sig = 0;
229d96bf49bSAlex Bennée     gdbserver_state.state = RS_IDLE;
230d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 0;
231d96bf49bSAlex Bennée     while (gdbserver_user_state.running_state == 0) {
232d96bf49bSAlex Bennée         n = read(gdbserver_user_state.fd, buf, 256);
233d96bf49bSAlex Bennée         if (n > 0) {
234d96bf49bSAlex Bennée             int i;
235d96bf49bSAlex Bennée 
236d96bf49bSAlex Bennée             for (i = 0; i < n; i++) {
237d96bf49bSAlex Bennée                 gdb_read_byte(buf[i]);
238d96bf49bSAlex Bennée             }
239d96bf49bSAlex Bennée         } else {
240d96bf49bSAlex Bennée             /*
241d96bf49bSAlex Bennée              * XXX: Connection closed.  Should probably wait for another
242d96bf49bSAlex Bennée              * connection before continuing.
243d96bf49bSAlex Bennée              */
244d96bf49bSAlex Bennée             if (n == 0) {
245d96bf49bSAlex Bennée                 close(gdbserver_user_state.fd);
246d96bf49bSAlex Bennée             }
247d96bf49bSAlex Bennée             gdbserver_user_state.fd = -1;
248d96bf49bSAlex Bennée             return sig;
249d96bf49bSAlex Bennée         }
250d96bf49bSAlex Bennée     }
251d96bf49bSAlex Bennée     sig = gdbserver_state.signal;
252d96bf49bSAlex Bennée     gdbserver_state.signal = 0;
253d96bf49bSAlex Bennée     return sig;
254d96bf49bSAlex Bennée }
255d96bf49bSAlex Bennée 
256d96bf49bSAlex Bennée /* Tell the remote gdb that the process has exited due to SIG.  */
257d96bf49bSAlex Bennée void gdb_signalled(CPUArchState *env, int sig)
258d96bf49bSAlex Bennée {
259d96bf49bSAlex Bennée     char buf[4];
260d96bf49bSAlex Bennée 
26175837005SMatheus Tavares Bernardino     if (!gdbserver_state.init || gdbserver_user_state.fd < 0 ||
26275837005SMatheus Tavares Bernardino         !gdbserver_state.allow_stop_reply) {
263d96bf49bSAlex Bennée         return;
264d96bf49bSAlex Bennée     }
265d96bf49bSAlex Bennée 
266d96bf49bSAlex Bennée     snprintf(buf, sizeof(buf), "X%02x", gdb_target_signal_to_gdb(sig));
267d96bf49bSAlex Bennée     gdb_put_packet(buf);
26875837005SMatheus Tavares Bernardino     gdbserver_state.allow_stop_reply = false;
269d96bf49bSAlex Bennée }
270d96bf49bSAlex Bennée 
271d96bf49bSAlex Bennée static void gdb_accept_init(int fd)
272d96bf49bSAlex Bennée {
273d96bf49bSAlex Bennée     gdb_init_gdbserver_state();
274d96bf49bSAlex Bennée     gdb_create_default_process(&gdbserver_state);
275d96bf49bSAlex Bennée     gdbserver_state.processes[0].attached = true;
276d96bf49bSAlex Bennée     gdbserver_state.c_cpu = gdb_first_attached_cpu();
277d96bf49bSAlex Bennée     gdbserver_state.g_cpu = gdbserver_state.c_cpu;
278d96bf49bSAlex Bennée     gdbserver_user_state.fd = fd;
279d96bf49bSAlex Bennée }
280d96bf49bSAlex Bennée 
281d96bf49bSAlex Bennée static bool gdb_accept_socket(int gdb_fd)
282d96bf49bSAlex Bennée {
283d96bf49bSAlex Bennée     int fd;
284d96bf49bSAlex Bennée 
285d96bf49bSAlex Bennée     for (;;) {
286d96bf49bSAlex Bennée         fd = accept(gdb_fd, NULL, NULL);
287d96bf49bSAlex Bennée         if (fd < 0 && errno != EINTR) {
288d96bf49bSAlex Bennée             perror("accept socket");
289d96bf49bSAlex Bennée             return false;
290d96bf49bSAlex Bennée         } else if (fd >= 0) {
291d96bf49bSAlex Bennée             qemu_set_cloexec(fd);
292d96bf49bSAlex Bennée             break;
293d96bf49bSAlex Bennée         }
294d96bf49bSAlex Bennée     }
295d96bf49bSAlex Bennée 
296d96bf49bSAlex Bennée     gdb_accept_init(fd);
297d96bf49bSAlex Bennée     return true;
298d96bf49bSAlex Bennée }
299d96bf49bSAlex Bennée 
300d96bf49bSAlex Bennée static int gdbserver_open_socket(const char *path)
301d96bf49bSAlex Bennée {
302d96bf49bSAlex Bennée     struct sockaddr_un sockaddr = {};
303d96bf49bSAlex Bennée     int fd, ret;
304d96bf49bSAlex Bennée 
305d96bf49bSAlex Bennée     fd = socket(AF_UNIX, SOCK_STREAM, 0);
306d96bf49bSAlex Bennée     if (fd < 0) {
307d96bf49bSAlex Bennée         perror("create socket");
308d96bf49bSAlex Bennée         return -1;
309d96bf49bSAlex Bennée     }
310d96bf49bSAlex Bennée 
311d96bf49bSAlex Bennée     sockaddr.sun_family = AF_UNIX;
312d96bf49bSAlex Bennée     pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path);
313d96bf49bSAlex Bennée     ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
314d96bf49bSAlex Bennée     if (ret < 0) {
315d96bf49bSAlex Bennée         perror("bind socket");
316d96bf49bSAlex Bennée         close(fd);
317d96bf49bSAlex Bennée         return -1;
318d96bf49bSAlex Bennée     }
319d96bf49bSAlex Bennée     ret = listen(fd, 1);
320d96bf49bSAlex Bennée     if (ret < 0) {
321d96bf49bSAlex Bennée         perror("listen socket");
322d96bf49bSAlex Bennée         close(fd);
323d96bf49bSAlex Bennée         return -1;
324d96bf49bSAlex Bennée     }
325d96bf49bSAlex Bennée 
326d96bf49bSAlex Bennée     return fd;
327d96bf49bSAlex Bennée }
328d96bf49bSAlex Bennée 
329d96bf49bSAlex Bennée static bool gdb_accept_tcp(int gdb_fd)
330d96bf49bSAlex Bennée {
331d96bf49bSAlex Bennée     struct sockaddr_in sockaddr = {};
332d96bf49bSAlex Bennée     socklen_t len;
333d96bf49bSAlex Bennée     int fd;
334d96bf49bSAlex Bennée 
335d96bf49bSAlex Bennée     for (;;) {
336d96bf49bSAlex Bennée         len = sizeof(sockaddr);
337d96bf49bSAlex Bennée         fd = accept(gdb_fd, (struct sockaddr *)&sockaddr, &len);
338d96bf49bSAlex Bennée         if (fd < 0 && errno != EINTR) {
339d96bf49bSAlex Bennée             perror("accept");
340d96bf49bSAlex Bennée             return false;
341d96bf49bSAlex Bennée         } else if (fd >= 0) {
342d96bf49bSAlex Bennée             qemu_set_cloexec(fd);
343d96bf49bSAlex Bennée             break;
344d96bf49bSAlex Bennée         }
345d96bf49bSAlex Bennée     }
346d96bf49bSAlex Bennée 
347d96bf49bSAlex Bennée     /* set short latency */
348d96bf49bSAlex Bennée     if (socket_set_nodelay(fd)) {
349d96bf49bSAlex Bennée         perror("setsockopt");
350d96bf49bSAlex Bennée         close(fd);
351d96bf49bSAlex Bennée         return false;
352d96bf49bSAlex Bennée     }
353d96bf49bSAlex Bennée 
354d96bf49bSAlex Bennée     gdb_accept_init(fd);
355d96bf49bSAlex Bennée     return true;
356d96bf49bSAlex Bennée }
357d96bf49bSAlex Bennée 
358d96bf49bSAlex Bennée static int gdbserver_open_port(int port)
359d96bf49bSAlex Bennée {
360d96bf49bSAlex Bennée     struct sockaddr_in sockaddr;
361d96bf49bSAlex Bennée     int fd, ret;
362d96bf49bSAlex Bennée 
363d96bf49bSAlex Bennée     fd = socket(PF_INET, SOCK_STREAM, 0);
364d96bf49bSAlex Bennée     if (fd < 0) {
365d96bf49bSAlex Bennée         perror("socket");
366d96bf49bSAlex Bennée         return -1;
367d96bf49bSAlex Bennée     }
368d96bf49bSAlex Bennée     qemu_set_cloexec(fd);
369d96bf49bSAlex Bennée 
370d96bf49bSAlex Bennée     socket_set_fast_reuse(fd);
371d96bf49bSAlex Bennée 
372d96bf49bSAlex Bennée     sockaddr.sin_family = AF_INET;
373d96bf49bSAlex Bennée     sockaddr.sin_port = htons(port);
374d96bf49bSAlex Bennée     sockaddr.sin_addr.s_addr = 0;
375d96bf49bSAlex Bennée     ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
376d96bf49bSAlex Bennée     if (ret < 0) {
377d96bf49bSAlex Bennée         perror("bind");
378d96bf49bSAlex Bennée         close(fd);
379d96bf49bSAlex Bennée         return -1;
380d96bf49bSAlex Bennée     }
381d96bf49bSAlex Bennée     ret = listen(fd, 1);
382d96bf49bSAlex Bennée     if (ret < 0) {
383d96bf49bSAlex Bennée         perror("listen");
384d96bf49bSAlex Bennée         close(fd);
385d96bf49bSAlex Bennée         return -1;
386d96bf49bSAlex Bennée     }
387d96bf49bSAlex Bennée 
388d96bf49bSAlex Bennée     return fd;
389d96bf49bSAlex Bennée }
390d96bf49bSAlex Bennée 
391d96bf49bSAlex Bennée int gdbserver_start(const char *port_or_path)
392d96bf49bSAlex Bennée {
393d96bf49bSAlex Bennée     int port = g_ascii_strtoull(port_or_path, NULL, 10);
394d96bf49bSAlex Bennée     int gdb_fd;
395d96bf49bSAlex Bennée 
396d96bf49bSAlex Bennée     if (port > 0) {
397d96bf49bSAlex Bennée         gdb_fd = gdbserver_open_port(port);
398d96bf49bSAlex Bennée     } else {
399d96bf49bSAlex Bennée         gdb_fd = gdbserver_open_socket(port_or_path);
400d96bf49bSAlex Bennée     }
401d96bf49bSAlex Bennée 
402d96bf49bSAlex Bennée     if (gdb_fd < 0) {
403d96bf49bSAlex Bennée         return -1;
404d96bf49bSAlex Bennée     }
405d96bf49bSAlex Bennée 
406d96bf49bSAlex Bennée     if (port > 0 && gdb_accept_tcp(gdb_fd)) {
407d96bf49bSAlex Bennée         return 0;
408d96bf49bSAlex Bennée     } else if (gdb_accept_socket(gdb_fd)) {
409d96bf49bSAlex Bennée         gdbserver_user_state.socket_path = g_strdup(port_or_path);
410d96bf49bSAlex Bennée         return 0;
411d96bf49bSAlex Bennée     }
412d96bf49bSAlex Bennée 
413d96bf49bSAlex Bennée     /* gone wrong */
414d96bf49bSAlex Bennée     close(gdb_fd);
415d96bf49bSAlex Bennée     return -1;
416d96bf49bSAlex Bennée }
417d96bf49bSAlex Bennée 
4183d6ed98dSIlya Leoshkevich void gdbserver_fork_start(void)
4193d6ed98dSIlya Leoshkevich {
420*d547e711SIlya Leoshkevich     if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
421*d547e711SIlya Leoshkevich         return;
422*d547e711SIlya Leoshkevich     }
423*d547e711SIlya Leoshkevich     if (!gdbserver_user_state.fork_events ||
424*d547e711SIlya Leoshkevich             qemu_socketpair(AF_UNIX, SOCK_STREAM, 0,
425*d547e711SIlya Leoshkevich                             gdbserver_user_state.fork_sockets) < 0) {
426*d547e711SIlya Leoshkevich         gdbserver_user_state.fork_state = GDB_FORK_DISABLED;
427*d547e711SIlya Leoshkevich         return;
428*d547e711SIlya Leoshkevich     }
429*d547e711SIlya Leoshkevich     gdbserver_user_state.fork_state = GDB_FORK_INACTIVE;
430*d547e711SIlya Leoshkevich     gdbserver_user_state.fork_peer_pid = getpid();
431*d547e711SIlya Leoshkevich     gdbserver_user_state.fork_peer_tid = qemu_get_thread_id();
4323d6ed98dSIlya Leoshkevich }
4333d6ed98dSIlya Leoshkevich 
4341ea96f1dSIlya Leoshkevich static void disable_gdbstub(CPUState *thread_cpu)
4351ea96f1dSIlya Leoshkevich {
4361ea96f1dSIlya Leoshkevich     CPUState *cpu;
4371ea96f1dSIlya Leoshkevich 
4381ea96f1dSIlya Leoshkevich     close(gdbserver_user_state.fd);
4391ea96f1dSIlya Leoshkevich     gdbserver_user_state.fd = -1;
4401ea96f1dSIlya Leoshkevich     CPU_FOREACH(cpu) {
4411ea96f1dSIlya Leoshkevich         cpu_breakpoint_remove_all(cpu, BP_GDB);
4421ea96f1dSIlya Leoshkevich         /* no cpu_watchpoint_remove_all for user-mode */
4431ea96f1dSIlya Leoshkevich         cpu_single_step(cpu, 0);
4441ea96f1dSIlya Leoshkevich     }
4451ea96f1dSIlya Leoshkevich     tb_flush(thread_cpu);
4461ea96f1dSIlya Leoshkevich }
4471ea96f1dSIlya Leoshkevich 
4486604b057SIlya Leoshkevich void gdbserver_fork_end(CPUState *cpu, pid_t pid)
449d96bf49bSAlex Bennée {
450*d547e711SIlya Leoshkevich     char b;
451*d547e711SIlya Leoshkevich     int fd;
452*d547e711SIlya Leoshkevich 
453*d547e711SIlya Leoshkevich     if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
454d96bf49bSAlex Bennée         return;
455d96bf49bSAlex Bennée     }
456*d547e711SIlya Leoshkevich 
457*d547e711SIlya Leoshkevich     if (pid == -1) {
458*d547e711SIlya Leoshkevich         if (gdbserver_user_state.fork_state != GDB_FORK_DISABLED) {
459*d547e711SIlya Leoshkevich             g_assert(gdbserver_user_state.fork_state == GDB_FORK_INACTIVE);
460*d547e711SIlya Leoshkevich             close(gdbserver_user_state.fork_sockets[0]);
461*d547e711SIlya Leoshkevich             close(gdbserver_user_state.fork_sockets[1]);
462*d547e711SIlya Leoshkevich         }
463*d547e711SIlya Leoshkevich         return;
464*d547e711SIlya Leoshkevich     }
465*d547e711SIlya Leoshkevich 
466*d547e711SIlya Leoshkevich     if (gdbserver_user_state.fork_state == GDB_FORK_DISABLED) {
467*d547e711SIlya Leoshkevich         if (pid == 0) {
4681ea96f1dSIlya Leoshkevich             disable_gdbstub(cpu);
469d96bf49bSAlex Bennée         }
470*d547e711SIlya Leoshkevich         return;
471*d547e711SIlya Leoshkevich     }
472*d547e711SIlya Leoshkevich 
473*d547e711SIlya Leoshkevich     if (pid == 0) {
474*d547e711SIlya Leoshkevich         close(gdbserver_user_state.fork_sockets[0]);
475*d547e711SIlya Leoshkevich         fd = gdbserver_user_state.fork_sockets[1];
476*d547e711SIlya Leoshkevich         g_assert(gdbserver_state.process_num == 1);
477*d547e711SIlya Leoshkevich         g_assert(gdbserver_state.processes[0].pid ==
478*d547e711SIlya Leoshkevich                      gdbserver_user_state.fork_peer_pid);
479*d547e711SIlya Leoshkevich         g_assert(gdbserver_state.processes[0].attached);
480*d547e711SIlya Leoshkevich         gdbserver_state.processes[0].pid = getpid();
481*d547e711SIlya Leoshkevich     } else {
482*d547e711SIlya Leoshkevich         close(gdbserver_user_state.fork_sockets[1]);
483*d547e711SIlya Leoshkevich         fd = gdbserver_user_state.fork_sockets[0];
484*d547e711SIlya Leoshkevich         gdbserver_user_state.fork_state = GDB_FORK_ACTIVE;
485*d547e711SIlya Leoshkevich         gdbserver_user_state.fork_peer_pid = pid;
486*d547e711SIlya Leoshkevich         gdbserver_user_state.fork_peer_tid = pid;
487*d547e711SIlya Leoshkevich 
488*d547e711SIlya Leoshkevich         if (!gdbserver_state.allow_stop_reply) {
489*d547e711SIlya Leoshkevich             goto fail;
490*d547e711SIlya Leoshkevich         }
491*d547e711SIlya Leoshkevich         g_string_printf(gdbserver_state.str_buf,
492*d547e711SIlya Leoshkevich                         "T%02xfork:p%02x.%02x;thread:p%02x.%02x;",
493*d547e711SIlya Leoshkevich                         gdb_target_signal_to_gdb(gdb_target_sigtrap()),
494*d547e711SIlya Leoshkevich                         pid, pid, (int)getpid(), qemu_get_thread_id());
495*d547e711SIlya Leoshkevich         gdb_put_strbuf();
496*d547e711SIlya Leoshkevich     }
497*d547e711SIlya Leoshkevich 
498*d547e711SIlya Leoshkevich     gdbserver_state.state = RS_IDLE;
499*d547e711SIlya Leoshkevich     gdbserver_state.allow_stop_reply = false;
500*d547e711SIlya Leoshkevich     gdbserver_user_state.running_state = 0;
501*d547e711SIlya Leoshkevich     for (;;) {
502*d547e711SIlya Leoshkevich         switch (gdbserver_user_state.fork_state) {
503*d547e711SIlya Leoshkevich         case GDB_FORK_ENABLED:
504*d547e711SIlya Leoshkevich             if (gdbserver_user_state.running_state) {
505*d547e711SIlya Leoshkevich                 return;
506*d547e711SIlya Leoshkevich             }
507*d547e711SIlya Leoshkevich             QEMU_FALLTHROUGH;
508*d547e711SIlya Leoshkevich         case GDB_FORK_ACTIVE:
509*d547e711SIlya Leoshkevich             if (read(gdbserver_user_state.fd, &b, 1) != 1) {
510*d547e711SIlya Leoshkevich                 goto fail;
511*d547e711SIlya Leoshkevich             }
512*d547e711SIlya Leoshkevich             gdb_read_byte(b);
513*d547e711SIlya Leoshkevich             break;
514*d547e711SIlya Leoshkevich         case GDB_FORK_DEACTIVATING:
515*d547e711SIlya Leoshkevich             b = GDB_FORK_ACTIVATE;
516*d547e711SIlya Leoshkevich             if (write(fd, &b, 1) != 1) {
517*d547e711SIlya Leoshkevich                 goto fail;
518*d547e711SIlya Leoshkevich             }
519*d547e711SIlya Leoshkevich             gdbserver_user_state.fork_state = GDB_FORK_INACTIVE;
520*d547e711SIlya Leoshkevich             break;
521*d547e711SIlya Leoshkevich         case GDB_FORK_INACTIVE:
522*d547e711SIlya Leoshkevich             if (read(fd, &b, 1) != 1) {
523*d547e711SIlya Leoshkevich                 goto fail;
524*d547e711SIlya Leoshkevich             }
525*d547e711SIlya Leoshkevich             switch (b) {
526*d547e711SIlya Leoshkevich             case GDB_FORK_ACTIVATE:
527*d547e711SIlya Leoshkevich                 gdbserver_user_state.fork_state = GDB_FORK_ACTIVE;
528*d547e711SIlya Leoshkevich                 break;
529*d547e711SIlya Leoshkevich             case GDB_FORK_ENABLE:
530*d547e711SIlya Leoshkevich                 close(fd);
531*d547e711SIlya Leoshkevich                 gdbserver_user_state.fork_state = GDB_FORK_ENABLED;
532*d547e711SIlya Leoshkevich                 break;
533*d547e711SIlya Leoshkevich             case GDB_FORK_DISABLE:
534*d547e711SIlya Leoshkevich                 gdbserver_user_state.fork_state = GDB_FORK_DISABLED;
535*d547e711SIlya Leoshkevich                 break;
536*d547e711SIlya Leoshkevich             default:
537*d547e711SIlya Leoshkevich                 g_assert_not_reached();
538*d547e711SIlya Leoshkevich             }
539*d547e711SIlya Leoshkevich             break;
540*d547e711SIlya Leoshkevich         case GDB_FORK_ENABLING:
541*d547e711SIlya Leoshkevich             b = GDB_FORK_DISABLE;
542*d547e711SIlya Leoshkevich             if (write(fd, &b, 1) != 1) {
543*d547e711SIlya Leoshkevich                 goto fail;
544*d547e711SIlya Leoshkevich             }
545*d547e711SIlya Leoshkevich             close(fd);
546*d547e711SIlya Leoshkevich             gdbserver_user_state.fork_state = GDB_FORK_ENABLED;
547*d547e711SIlya Leoshkevich             break;
548*d547e711SIlya Leoshkevich         case GDB_FORK_DISABLING:
549*d547e711SIlya Leoshkevich             b = GDB_FORK_ENABLE;
550*d547e711SIlya Leoshkevich             if (write(fd, &b, 1) != 1) {
551*d547e711SIlya Leoshkevich                 goto fail;
552*d547e711SIlya Leoshkevich             }
553*d547e711SIlya Leoshkevich             gdbserver_user_state.fork_state = GDB_FORK_DISABLED;
554*d547e711SIlya Leoshkevich             break;
555*d547e711SIlya Leoshkevich         case GDB_FORK_DISABLED:
556*d547e711SIlya Leoshkevich             close(fd);
557*d547e711SIlya Leoshkevich             disable_gdbstub(cpu);
558*d547e711SIlya Leoshkevich             return;
559*d547e711SIlya Leoshkevich         default:
560*d547e711SIlya Leoshkevich             g_assert_not_reached();
561*d547e711SIlya Leoshkevich         }
562*d547e711SIlya Leoshkevich     }
563*d547e711SIlya Leoshkevich 
564*d547e711SIlya Leoshkevich fail:
565*d547e711SIlya Leoshkevich     close(fd);
566*d547e711SIlya Leoshkevich     if (pid == 0) {
567*d547e711SIlya Leoshkevich         disable_gdbstub(cpu);
568*d547e711SIlya Leoshkevich     }
569*d547e711SIlya Leoshkevich }
570d96bf49bSAlex Bennée 
5716d923112SIlya Leoshkevich void gdb_handle_query_supported_user(const char *gdb_supported)
5726d923112SIlya Leoshkevich {
573*d547e711SIlya Leoshkevich     if (strstr(gdb_supported, "fork-events+")) {
574*d547e711SIlya Leoshkevich         gdbserver_user_state.fork_events = true;
575*d547e711SIlya Leoshkevich     }
576*d547e711SIlya Leoshkevich     g_string_append(gdbserver_state.str_buf, ";fork-events+");
5776d923112SIlya Leoshkevich }
5786d923112SIlya Leoshkevich 
579e454f2feSIlya Leoshkevich bool gdb_handle_set_thread_user(uint32_t pid, uint32_t tid)
580e454f2feSIlya Leoshkevich {
581*d547e711SIlya Leoshkevich     if (gdbserver_user_state.fork_state == GDB_FORK_ACTIVE &&
582*d547e711SIlya Leoshkevich             pid == gdbserver_user_state.fork_peer_pid &&
583*d547e711SIlya Leoshkevich             tid == gdbserver_user_state.fork_peer_tid) {
584*d547e711SIlya Leoshkevich         gdbserver_user_state.fork_state = GDB_FORK_DEACTIVATING;
585*d547e711SIlya Leoshkevich         gdb_put_packet("OK");
586*d547e711SIlya Leoshkevich         return true;
587*d547e711SIlya Leoshkevich     }
588e454f2feSIlya Leoshkevich     return false;
589e454f2feSIlya Leoshkevich }
590e454f2feSIlya Leoshkevich 
591539cb4ecSIlya Leoshkevich bool gdb_handle_detach_user(uint32_t pid)
592539cb4ecSIlya Leoshkevich {
593*d547e711SIlya Leoshkevich     bool enable;
594*d547e711SIlya Leoshkevich 
595*d547e711SIlya Leoshkevich     if (gdbserver_user_state.fork_state == GDB_FORK_ACTIVE) {
596*d547e711SIlya Leoshkevich         enable = pid == gdbserver_user_state.fork_peer_pid;
597*d547e711SIlya Leoshkevich         if (enable || pid == getpid()) {
598*d547e711SIlya Leoshkevich             gdbserver_user_state.fork_state = enable ? GDB_FORK_ENABLING :
599*d547e711SIlya Leoshkevich                                                        GDB_FORK_DISABLING;
600*d547e711SIlya Leoshkevich             gdb_put_packet("OK");
601*d547e711SIlya Leoshkevich             return true;
602*d547e711SIlya Leoshkevich         }
603*d547e711SIlya Leoshkevich     }
604539cb4ecSIlya Leoshkevich     return false;
605539cb4ecSIlya Leoshkevich }
606539cb4ecSIlya Leoshkevich 
607d96bf49bSAlex Bennée /*
608d96bf49bSAlex Bennée  * Execution state helpers
609d96bf49bSAlex Bennée  */
610d96bf49bSAlex Bennée 
6118a2025b3SAlex Bennée void gdb_handle_query_attached(GArray *params, void *user_ctx)
6128a2025b3SAlex Bennée {
6138a2025b3SAlex Bennée     gdb_put_packet("0");
6148a2025b3SAlex Bennée }
6158a2025b3SAlex Bennée 
616d96bf49bSAlex Bennée void gdb_continue(void)
617d96bf49bSAlex Bennée {
618d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 1;
619d96bf49bSAlex Bennée     trace_gdbstub_op_continue();
620d96bf49bSAlex Bennée }
621d96bf49bSAlex Bennée 
622d96bf49bSAlex Bennée /*
623d96bf49bSAlex Bennée  * Resume execution, for user-mode emulation it's equivalent to
624d96bf49bSAlex Bennée  * gdb_continue.
625d96bf49bSAlex Bennée  */
626d96bf49bSAlex Bennée int gdb_continue_partial(char *newstates)
627d96bf49bSAlex Bennée {
628d96bf49bSAlex Bennée     CPUState *cpu;
629d96bf49bSAlex Bennée     int res = 0;
630d96bf49bSAlex Bennée     /*
631d96bf49bSAlex Bennée      * This is not exactly accurate, but it's an improvement compared to the
632d96bf49bSAlex Bennée      * previous situation, where only one CPU would be single-stepped.
633d96bf49bSAlex Bennée      */
634d96bf49bSAlex Bennée     CPU_FOREACH(cpu) {
635d96bf49bSAlex Bennée         if (newstates[cpu->cpu_index] == 's') {
636d96bf49bSAlex Bennée             trace_gdbstub_op_stepping(cpu->cpu_index);
637d96bf49bSAlex Bennée             cpu_single_step(cpu, gdbserver_state.sstep_flags);
638d96bf49bSAlex Bennée         }
639d96bf49bSAlex Bennée     }
640d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 1;
641d96bf49bSAlex Bennée     return res;
642d96bf49bSAlex Bennée }
643d96bf49bSAlex Bennée 
644d96bf49bSAlex Bennée /*
645589a5867SAlex Bennée  * Memory access helpers
646589a5867SAlex Bennée  */
647589a5867SAlex Bennée int gdb_target_memory_rw_debug(CPUState *cpu, hwaddr addr,
648589a5867SAlex Bennée                                uint8_t *buf, int len, bool is_write)
649589a5867SAlex Bennée {
650589a5867SAlex Bennée     CPUClass *cc;
651589a5867SAlex Bennée 
652589a5867SAlex Bennée     cc = CPU_GET_CLASS(cpu);
653589a5867SAlex Bennée     if (cc->memory_rw_debug) {
654589a5867SAlex Bennée         return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
655589a5867SAlex Bennée     }
656589a5867SAlex Bennée     return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
657589a5867SAlex Bennée }
658589a5867SAlex Bennée 
659589a5867SAlex Bennée /*
6607ea0c33dSAlex Bennée  * cpu helpers
6617ea0c33dSAlex Bennée  */
6627ea0c33dSAlex Bennée 
6637ea0c33dSAlex Bennée unsigned int gdb_get_max_cpus(void)
6647ea0c33dSAlex Bennée {
6657ea0c33dSAlex Bennée     CPUState *cpu;
6667ea0c33dSAlex Bennée     unsigned int max_cpus = 1;
6677ea0c33dSAlex Bennée 
6687ea0c33dSAlex Bennée     CPU_FOREACH(cpu) {
6697ea0c33dSAlex Bennée         max_cpus = max_cpus <= cpu->cpu_index ? cpu->cpu_index + 1 : max_cpus;
6707ea0c33dSAlex Bennée     }
6717ea0c33dSAlex Bennée 
6727ea0c33dSAlex Bennée     return max_cpus;
6737ea0c33dSAlex Bennée }
6747ea0c33dSAlex Bennée 
675505601d5SAlex Bennée /* replay not supported for user-mode */
676505601d5SAlex Bennée bool gdb_can_reverse(void)
677505601d5SAlex Bennée {
678505601d5SAlex Bennée     return false;
679505601d5SAlex Bennée }
6807ea0c33dSAlex Bennée 
6817ea0c33dSAlex Bennée /*
682d96bf49bSAlex Bennée  * Break/Watch point helpers
683d96bf49bSAlex Bennée  */
684d96bf49bSAlex Bennée 
685a48e7d9eSAlex Bennée bool gdb_supports_guest_debug(void)
686a48e7d9eSAlex Bennée {
687a48e7d9eSAlex Bennée     /* user-mode == TCG == supported */
688a48e7d9eSAlex Bennée     return true;
689a48e7d9eSAlex Bennée }
690a48e7d9eSAlex Bennée 
69155b5b8e9SPhilippe Mathieu-Daudé int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len)
692ae7467b1SAlex Bennée {
693ae7467b1SAlex Bennée     CPUState *cpu;
694ae7467b1SAlex Bennée     int err = 0;
695ae7467b1SAlex Bennée 
696ae7467b1SAlex Bennée     switch (type) {
697ae7467b1SAlex Bennée     case GDB_BREAKPOINT_SW:
698ae7467b1SAlex Bennée     case GDB_BREAKPOINT_HW:
699ae7467b1SAlex Bennée         CPU_FOREACH(cpu) {
700ae7467b1SAlex Bennée             err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL);
701ae7467b1SAlex Bennée             if (err) {
702ae7467b1SAlex Bennée                 break;
703ae7467b1SAlex Bennée             }
704ae7467b1SAlex Bennée         }
705ae7467b1SAlex Bennée         return err;
706ae7467b1SAlex Bennée     default:
707ae7467b1SAlex Bennée         /* user-mode doesn't support watchpoints */
708ae7467b1SAlex Bennée         return -ENOSYS;
709ae7467b1SAlex Bennée     }
710ae7467b1SAlex Bennée }
711ae7467b1SAlex Bennée 
71255b5b8e9SPhilippe Mathieu-Daudé int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len)
713ae7467b1SAlex Bennée {
714ae7467b1SAlex Bennée     CPUState *cpu;
715ae7467b1SAlex Bennée     int err = 0;
716ae7467b1SAlex Bennée 
717ae7467b1SAlex Bennée     switch (type) {
718ae7467b1SAlex Bennée     case GDB_BREAKPOINT_SW:
719ae7467b1SAlex Bennée     case GDB_BREAKPOINT_HW:
720ae7467b1SAlex Bennée         CPU_FOREACH(cpu) {
721ae7467b1SAlex Bennée             err = cpu_breakpoint_remove(cpu, addr, BP_GDB);
722ae7467b1SAlex Bennée             if (err) {
723ae7467b1SAlex Bennée                 break;
724ae7467b1SAlex Bennée             }
725ae7467b1SAlex Bennée         }
726ae7467b1SAlex Bennée         return err;
727ae7467b1SAlex Bennée     default:
728ae7467b1SAlex Bennée         /* user-mode doesn't support watchpoints */
729ae7467b1SAlex Bennée         return -ENOSYS;
730ae7467b1SAlex Bennée     }
731ae7467b1SAlex Bennée }
732ae7467b1SAlex Bennée 
733ae7467b1SAlex Bennée void gdb_breakpoint_remove_all(CPUState *cs)
734ae7467b1SAlex Bennée {
735ae7467b1SAlex Bennée     cpu_breakpoint_remove_all(cs, BP_GDB);
736ae7467b1SAlex Bennée }
737131f387dSAlex Bennée 
738131f387dSAlex Bennée /*
739131f387dSAlex Bennée  * For user-mode syscall support we send the system call immediately
740131f387dSAlex Bennée  * and then return control to gdb for it to process the syscall request.
741131f387dSAlex Bennée  * Since the protocol requires that gdb hands control back to us
742131f387dSAlex Bennée  * using a "here are the results" F packet, we don't need to check
743131f387dSAlex Bennée  * gdb_handlesig's return value (which is the signal to deliver if
744131f387dSAlex Bennée  * execution was resumed via a continue packet).
745131f387dSAlex Bennée  */
746131f387dSAlex Bennée void gdb_syscall_handling(const char *syscall_packet)
747131f387dSAlex Bennée {
748131f387dSAlex Bennée     gdb_put_packet(syscall_packet);
749131f387dSAlex Bennée     gdb_handlesig(gdbserver_state.c_cpu, 0);
750131f387dSAlex Bennée }
7510a0d87c9SIlya Leoshkevich 
752046f143cSIlya Leoshkevich static bool should_catch_syscall(int num)
753046f143cSIlya Leoshkevich {
754046f143cSIlya Leoshkevich     if (gdbserver_user_state.catch_all_syscalls) {
755046f143cSIlya Leoshkevich         return true;
756046f143cSIlya Leoshkevich     }
757046f143cSIlya Leoshkevich     if (num < 0 || num >= GDB_NR_SYSCALLS) {
758046f143cSIlya Leoshkevich         return false;
759046f143cSIlya Leoshkevich     }
760046f143cSIlya Leoshkevich     return test_bit(num, gdbserver_user_state.catch_syscalls_mask);
761046f143cSIlya Leoshkevich }
762046f143cSIlya Leoshkevich 
7630a0d87c9SIlya Leoshkevich void gdb_syscall_entry(CPUState *cs, int num)
7640a0d87c9SIlya Leoshkevich {
765046f143cSIlya Leoshkevich     if (should_catch_syscall(num)) {
766046f143cSIlya Leoshkevich         g_autofree char *reason = g_strdup_printf("syscall_entry:%x;", num);
767046f143cSIlya Leoshkevich         gdb_handlesig_reason(cs, gdb_target_sigtrap(), reason);
768046f143cSIlya Leoshkevich     }
7690a0d87c9SIlya Leoshkevich }
7700a0d87c9SIlya Leoshkevich 
7710a0d87c9SIlya Leoshkevich void gdb_syscall_return(CPUState *cs, int num)
7720a0d87c9SIlya Leoshkevich {
773046f143cSIlya Leoshkevich     if (should_catch_syscall(num)) {
774046f143cSIlya Leoshkevich         g_autofree char *reason = g_strdup_printf("syscall_return:%x;", num);
775046f143cSIlya Leoshkevich         gdb_handlesig_reason(cs, gdb_target_sigtrap(), reason);
776046f143cSIlya Leoshkevich     }
777046f143cSIlya Leoshkevich }
778046f143cSIlya Leoshkevich 
779046f143cSIlya Leoshkevich void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx)
780046f143cSIlya Leoshkevich {
781046f143cSIlya Leoshkevich     const char *param = get_param(params, 0)->data;
782046f143cSIlya Leoshkevich     GDBSyscallsMask catch_syscalls_mask;
783046f143cSIlya Leoshkevich     bool catch_all_syscalls;
784046f143cSIlya Leoshkevich     unsigned int num;
785046f143cSIlya Leoshkevich     const char *p;
786046f143cSIlya Leoshkevich 
787046f143cSIlya Leoshkevich     /* "0" means not catching any syscalls. */
788046f143cSIlya Leoshkevich     if (strcmp(param, "0") == 0) {
789046f143cSIlya Leoshkevich         gdbserver_user_state.catch_all_syscalls = false;
790046f143cSIlya Leoshkevich         memset(gdbserver_user_state.catch_syscalls_mask, 0,
791046f143cSIlya Leoshkevich                sizeof(gdbserver_user_state.catch_syscalls_mask));
792046f143cSIlya Leoshkevich         gdb_put_packet("OK");
793046f143cSIlya Leoshkevich         return;
794046f143cSIlya Leoshkevich     }
795046f143cSIlya Leoshkevich 
796046f143cSIlya Leoshkevich     /* "1" means catching all syscalls. */
797046f143cSIlya Leoshkevich     if (strcmp(param, "1") == 0) {
798046f143cSIlya Leoshkevich         gdbserver_user_state.catch_all_syscalls = true;
799046f143cSIlya Leoshkevich         gdb_put_packet("OK");
800046f143cSIlya Leoshkevich         return;
801046f143cSIlya Leoshkevich     }
802046f143cSIlya Leoshkevich 
803046f143cSIlya Leoshkevich     /*
804046f143cSIlya Leoshkevich      * "1;..." means catching only the specified syscalls.
805046f143cSIlya Leoshkevich      * The syscall list must not be empty.
806046f143cSIlya Leoshkevich      */
807046f143cSIlya Leoshkevich     if (param[0] == '1' && param[1] == ';') {
808046f143cSIlya Leoshkevich         catch_all_syscalls = false;
809046f143cSIlya Leoshkevich         memset(catch_syscalls_mask, 0, sizeof(catch_syscalls_mask));
810046f143cSIlya Leoshkevich         for (p = &param[2];; p++) {
811046f143cSIlya Leoshkevich             if (qemu_strtoui(p, &p, 16, &num) || (*p && *p != ';')) {
812046f143cSIlya Leoshkevich                 goto err;
813046f143cSIlya Leoshkevich             }
814046f143cSIlya Leoshkevich             if (num >= GDB_NR_SYSCALLS) {
815046f143cSIlya Leoshkevich                 /*
816046f143cSIlya Leoshkevich                  * Fall back to reporting all syscalls. Reporting extra
817046f143cSIlya Leoshkevich                  * syscalls is inefficient, but the spec explicitly allows it.
818046f143cSIlya Leoshkevich                  * Keep parsing in case there is a syntax error ahead.
819046f143cSIlya Leoshkevich                  */
820046f143cSIlya Leoshkevich                 catch_all_syscalls = true;
821046f143cSIlya Leoshkevich             } else {
822046f143cSIlya Leoshkevich                 set_bit(num, catch_syscalls_mask);
823046f143cSIlya Leoshkevich             }
824046f143cSIlya Leoshkevich             if (!*p) {
825046f143cSIlya Leoshkevich                 break;
826046f143cSIlya Leoshkevich             }
827046f143cSIlya Leoshkevich         }
828046f143cSIlya Leoshkevich         gdbserver_user_state.catch_all_syscalls = catch_all_syscalls;
829046f143cSIlya Leoshkevich         if (!catch_all_syscalls) {
830046f143cSIlya Leoshkevich             memcpy(gdbserver_user_state.catch_syscalls_mask,
831046f143cSIlya Leoshkevich                    catch_syscalls_mask, sizeof(catch_syscalls_mask));
832046f143cSIlya Leoshkevich         }
833046f143cSIlya Leoshkevich         gdb_put_packet("OK");
834046f143cSIlya Leoshkevich         return;
835046f143cSIlya Leoshkevich     }
836046f143cSIlya Leoshkevich 
837046f143cSIlya Leoshkevich err:
838046f143cSIlya Leoshkevich     gdb_put_packet("E00");
8390a0d87c9SIlya Leoshkevich }
840