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