xref: /qemu/gdbstub/user.c (revision 6d923112)
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 
28d96bf49bSAlex Bennée /* User-mode specific state */
29d96bf49bSAlex Bennée typedef struct {
30d96bf49bSAlex Bennée     int fd;
31d96bf49bSAlex Bennée     char *socket_path;
32d96bf49bSAlex Bennée     int running_state;
33046f143cSIlya Leoshkevich     /*
34046f143cSIlya Leoshkevich      * Store syscalls mask without memory allocation in order to avoid
35046f143cSIlya Leoshkevich      * implementing synchronization.
36046f143cSIlya Leoshkevich      */
37046f143cSIlya Leoshkevich     bool catch_all_syscalls;
38046f143cSIlya Leoshkevich     GDBSyscallsMask catch_syscalls_mask;
39d96bf49bSAlex Bennée } GDBUserState;
40d96bf49bSAlex Bennée 
41d96bf49bSAlex Bennée static GDBUserState gdbserver_user_state;
42d96bf49bSAlex Bennée 
43d96bf49bSAlex Bennée int gdb_get_char(void)
44d96bf49bSAlex Bennée {
45d96bf49bSAlex Bennée     uint8_t ch;
46d96bf49bSAlex Bennée     int ret;
47d96bf49bSAlex Bennée 
48d96bf49bSAlex Bennée     for (;;) {
49d96bf49bSAlex Bennée         ret = recv(gdbserver_user_state.fd, &ch, 1, 0);
50d96bf49bSAlex Bennée         if (ret < 0) {
51d96bf49bSAlex Bennée             if (errno == ECONNRESET) {
52d96bf49bSAlex Bennée                 gdbserver_user_state.fd = -1;
53d96bf49bSAlex Bennée             }
54d96bf49bSAlex Bennée             if (errno != EINTR) {
55d96bf49bSAlex Bennée                 return -1;
56d96bf49bSAlex Bennée             }
57d96bf49bSAlex Bennée         } else if (ret == 0) {
58d96bf49bSAlex Bennée             close(gdbserver_user_state.fd);
59d96bf49bSAlex Bennée             gdbserver_user_state.fd = -1;
60d96bf49bSAlex Bennée             return -1;
61d96bf49bSAlex Bennée         } else {
62d96bf49bSAlex Bennée             break;
63d96bf49bSAlex Bennée         }
64d96bf49bSAlex Bennée     }
65d96bf49bSAlex Bennée     return ch;
66d96bf49bSAlex Bennée }
67d96bf49bSAlex Bennée 
68a7e0f9bdSAlex Bennée bool gdb_got_immediate_ack(void)
69a7e0f9bdSAlex Bennée {
70a7e0f9bdSAlex Bennée     int i;
71a7e0f9bdSAlex Bennée 
72a7e0f9bdSAlex Bennée     i = gdb_get_char();
73a7e0f9bdSAlex Bennée     if (i < 0) {
74a7e0f9bdSAlex Bennée         /* no response, continue anyway */
75a7e0f9bdSAlex Bennée         return true;
76a7e0f9bdSAlex Bennée     }
77a7e0f9bdSAlex Bennée 
78a7e0f9bdSAlex Bennée     if (i == '+') {
79a7e0f9bdSAlex Bennée         /* received correctly, continue */
80a7e0f9bdSAlex Bennée         return true;
81a7e0f9bdSAlex Bennée     }
82a7e0f9bdSAlex Bennée 
83a7e0f9bdSAlex Bennée     /* anything else, including '-' then try again */
84a7e0f9bdSAlex Bennée     return false;
85a7e0f9bdSAlex Bennée }
86a7e0f9bdSAlex Bennée 
87d96bf49bSAlex Bennée void gdb_put_buffer(const uint8_t *buf, int len)
88d96bf49bSAlex Bennée {
89d96bf49bSAlex Bennée     int ret;
90d96bf49bSAlex Bennée 
91d96bf49bSAlex Bennée     while (len > 0) {
92d96bf49bSAlex Bennée         ret = send(gdbserver_user_state.fd, buf, len, 0);
93d96bf49bSAlex Bennée         if (ret < 0) {
94d96bf49bSAlex Bennée             if (errno != EINTR) {
95d96bf49bSAlex Bennée                 return;
96d96bf49bSAlex Bennée             }
97d96bf49bSAlex Bennée         } else {
98d96bf49bSAlex Bennée             buf += ret;
99d96bf49bSAlex Bennée             len -= ret;
100d96bf49bSAlex Bennée         }
101d96bf49bSAlex Bennée     }
102d96bf49bSAlex Bennée }
103d96bf49bSAlex Bennée 
104d96bf49bSAlex Bennée /* Tell the remote gdb that the process has exited.  */
105d96bf49bSAlex Bennée void gdb_exit(int code)
106d96bf49bSAlex Bennée {
107d96bf49bSAlex Bennée     char buf[4];
108d96bf49bSAlex Bennée 
109d96bf49bSAlex Bennée     if (!gdbserver_state.init) {
110d96bf49bSAlex Bennée         return;
111d96bf49bSAlex Bennée     }
112d96bf49bSAlex Bennée     if (gdbserver_user_state.socket_path) {
113d96bf49bSAlex Bennée         unlink(gdbserver_user_state.socket_path);
114d96bf49bSAlex Bennée     }
115d96bf49bSAlex Bennée     if (gdbserver_user_state.fd < 0) {
116d96bf49bSAlex Bennée         return;
117d96bf49bSAlex Bennée     }
118d96bf49bSAlex Bennée 
119d96bf49bSAlex Bennée     trace_gdbstub_op_exiting((uint8_t)code);
120d96bf49bSAlex Bennée 
12175837005SMatheus Tavares Bernardino     if (gdbserver_state.allow_stop_reply) {
122d96bf49bSAlex Bennée         snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
123d96bf49bSAlex Bennée         gdb_put_packet(buf);
12475837005SMatheus Tavares Bernardino         gdbserver_state.allow_stop_reply = false;
12575837005SMatheus Tavares Bernardino     }
126e216256aSClément Chigot 
127e216256aSClément Chigot }
128e216256aSClément Chigot 
129e216256aSClément Chigot void gdb_qemu_exit(int code)
130e216256aSClément Chigot {
131e216256aSClément Chigot     exit(code);
132d96bf49bSAlex Bennée }
133d96bf49bSAlex Bennée 
1348b7fcb8eSIlya Leoshkevich int gdb_handlesig_reason(CPUState *cpu, int sig, const char *reason)
135d96bf49bSAlex Bennée {
136d96bf49bSAlex Bennée     char buf[256];
137d96bf49bSAlex Bennée     int n;
138d96bf49bSAlex Bennée 
139d96bf49bSAlex Bennée     if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
140d96bf49bSAlex Bennée         return sig;
141d96bf49bSAlex Bennée     }
142d96bf49bSAlex Bennée 
143d96bf49bSAlex Bennée     /* disable single step if it was enabled */
144d96bf49bSAlex Bennée     cpu_single_step(cpu, 0);
145d96bf49bSAlex Bennée     tb_flush(cpu);
146d96bf49bSAlex Bennée 
147d96bf49bSAlex Bennée     if (sig != 0) {
148d96bf49bSAlex Bennée         gdb_set_stop_cpu(cpu);
14975837005SMatheus Tavares Bernardino         if (gdbserver_state.allow_stop_reply) {
150d96bf49bSAlex Bennée             g_string_printf(gdbserver_state.str_buf,
151d96bf49bSAlex Bennée                             "T%02xthread:", gdb_target_signal_to_gdb(sig));
152d96bf49bSAlex Bennée             gdb_append_thread_id(cpu, gdbserver_state.str_buf);
153d96bf49bSAlex Bennée             g_string_append_c(gdbserver_state.str_buf, ';');
1548b7fcb8eSIlya Leoshkevich             if (reason) {
1558b7fcb8eSIlya Leoshkevich                 g_string_append(gdbserver_state.str_buf, reason);
1568b7fcb8eSIlya Leoshkevich             }
157d96bf49bSAlex Bennée             gdb_put_strbuf();
15875837005SMatheus Tavares Bernardino             gdbserver_state.allow_stop_reply = false;
15975837005SMatheus Tavares Bernardino         }
160d96bf49bSAlex Bennée     }
161d96bf49bSAlex Bennée     /*
162d96bf49bSAlex Bennée      * gdb_put_packet() might have detected that the peer terminated the
163d96bf49bSAlex Bennée      * connection.
164d96bf49bSAlex Bennée      */
165d96bf49bSAlex Bennée     if (gdbserver_user_state.fd < 0) {
166d96bf49bSAlex Bennée         return sig;
167d96bf49bSAlex Bennée     }
168d96bf49bSAlex Bennée 
169d96bf49bSAlex Bennée     sig = 0;
170d96bf49bSAlex Bennée     gdbserver_state.state = RS_IDLE;
171d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 0;
172d96bf49bSAlex Bennée     while (gdbserver_user_state.running_state == 0) {
173d96bf49bSAlex Bennée         n = read(gdbserver_user_state.fd, buf, 256);
174d96bf49bSAlex Bennée         if (n > 0) {
175d96bf49bSAlex Bennée             int i;
176d96bf49bSAlex Bennée 
177d96bf49bSAlex Bennée             for (i = 0; i < n; i++) {
178d96bf49bSAlex Bennée                 gdb_read_byte(buf[i]);
179d96bf49bSAlex Bennée             }
180d96bf49bSAlex Bennée         } else {
181d96bf49bSAlex Bennée             /*
182d96bf49bSAlex Bennée              * XXX: Connection closed.  Should probably wait for another
183d96bf49bSAlex Bennée              * connection before continuing.
184d96bf49bSAlex Bennée              */
185d96bf49bSAlex Bennée             if (n == 0) {
186d96bf49bSAlex Bennée                 close(gdbserver_user_state.fd);
187d96bf49bSAlex Bennée             }
188d96bf49bSAlex Bennée             gdbserver_user_state.fd = -1;
189d96bf49bSAlex Bennée             return sig;
190d96bf49bSAlex Bennée         }
191d96bf49bSAlex Bennée     }
192d96bf49bSAlex Bennée     sig = gdbserver_state.signal;
193d96bf49bSAlex Bennée     gdbserver_state.signal = 0;
194d96bf49bSAlex Bennée     return sig;
195d96bf49bSAlex Bennée }
196d96bf49bSAlex Bennée 
197d96bf49bSAlex Bennée /* Tell the remote gdb that the process has exited due to SIG.  */
198d96bf49bSAlex Bennée void gdb_signalled(CPUArchState *env, int sig)
199d96bf49bSAlex Bennée {
200d96bf49bSAlex Bennée     char buf[4];
201d96bf49bSAlex Bennée 
20275837005SMatheus Tavares Bernardino     if (!gdbserver_state.init || gdbserver_user_state.fd < 0 ||
20375837005SMatheus Tavares Bernardino         !gdbserver_state.allow_stop_reply) {
204d96bf49bSAlex Bennée         return;
205d96bf49bSAlex Bennée     }
206d96bf49bSAlex Bennée 
207d96bf49bSAlex Bennée     snprintf(buf, sizeof(buf), "X%02x", gdb_target_signal_to_gdb(sig));
208d96bf49bSAlex Bennée     gdb_put_packet(buf);
20975837005SMatheus Tavares Bernardino     gdbserver_state.allow_stop_reply = false;
210d96bf49bSAlex Bennée }
211d96bf49bSAlex Bennée 
212d96bf49bSAlex Bennée static void gdb_accept_init(int fd)
213d96bf49bSAlex Bennée {
214d96bf49bSAlex Bennée     gdb_init_gdbserver_state();
215d96bf49bSAlex Bennée     gdb_create_default_process(&gdbserver_state);
216d96bf49bSAlex Bennée     gdbserver_state.processes[0].attached = true;
217d96bf49bSAlex Bennée     gdbserver_state.c_cpu = gdb_first_attached_cpu();
218d96bf49bSAlex Bennée     gdbserver_state.g_cpu = gdbserver_state.c_cpu;
219d96bf49bSAlex Bennée     gdbserver_user_state.fd = fd;
220d96bf49bSAlex Bennée }
221d96bf49bSAlex Bennée 
222d96bf49bSAlex Bennée static bool gdb_accept_socket(int gdb_fd)
223d96bf49bSAlex Bennée {
224d96bf49bSAlex Bennée     int fd;
225d96bf49bSAlex Bennée 
226d96bf49bSAlex Bennée     for (;;) {
227d96bf49bSAlex Bennée         fd = accept(gdb_fd, NULL, NULL);
228d96bf49bSAlex Bennée         if (fd < 0 && errno != EINTR) {
229d96bf49bSAlex Bennée             perror("accept socket");
230d96bf49bSAlex Bennée             return false;
231d96bf49bSAlex Bennée         } else if (fd >= 0) {
232d96bf49bSAlex Bennée             qemu_set_cloexec(fd);
233d96bf49bSAlex Bennée             break;
234d96bf49bSAlex Bennée         }
235d96bf49bSAlex Bennée     }
236d96bf49bSAlex Bennée 
237d96bf49bSAlex Bennée     gdb_accept_init(fd);
238d96bf49bSAlex Bennée     return true;
239d96bf49bSAlex Bennée }
240d96bf49bSAlex Bennée 
241d96bf49bSAlex Bennée static int gdbserver_open_socket(const char *path)
242d96bf49bSAlex Bennée {
243d96bf49bSAlex Bennée     struct sockaddr_un sockaddr = {};
244d96bf49bSAlex Bennée     int fd, ret;
245d96bf49bSAlex Bennée 
246d96bf49bSAlex Bennée     fd = socket(AF_UNIX, SOCK_STREAM, 0);
247d96bf49bSAlex Bennée     if (fd < 0) {
248d96bf49bSAlex Bennée         perror("create socket");
249d96bf49bSAlex Bennée         return -1;
250d96bf49bSAlex Bennée     }
251d96bf49bSAlex Bennée 
252d96bf49bSAlex Bennée     sockaddr.sun_family = AF_UNIX;
253d96bf49bSAlex Bennée     pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path);
254d96bf49bSAlex Bennée     ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
255d96bf49bSAlex Bennée     if (ret < 0) {
256d96bf49bSAlex Bennée         perror("bind socket");
257d96bf49bSAlex Bennée         close(fd);
258d96bf49bSAlex Bennée         return -1;
259d96bf49bSAlex Bennée     }
260d96bf49bSAlex Bennée     ret = listen(fd, 1);
261d96bf49bSAlex Bennée     if (ret < 0) {
262d96bf49bSAlex Bennée         perror("listen socket");
263d96bf49bSAlex Bennée         close(fd);
264d96bf49bSAlex Bennée         return -1;
265d96bf49bSAlex Bennée     }
266d96bf49bSAlex Bennée 
267d96bf49bSAlex Bennée     return fd;
268d96bf49bSAlex Bennée }
269d96bf49bSAlex Bennée 
270d96bf49bSAlex Bennée static bool gdb_accept_tcp(int gdb_fd)
271d96bf49bSAlex Bennée {
272d96bf49bSAlex Bennée     struct sockaddr_in sockaddr = {};
273d96bf49bSAlex Bennée     socklen_t len;
274d96bf49bSAlex Bennée     int fd;
275d96bf49bSAlex Bennée 
276d96bf49bSAlex Bennée     for (;;) {
277d96bf49bSAlex Bennée         len = sizeof(sockaddr);
278d96bf49bSAlex Bennée         fd = accept(gdb_fd, (struct sockaddr *)&sockaddr, &len);
279d96bf49bSAlex Bennée         if (fd < 0 && errno != EINTR) {
280d96bf49bSAlex Bennée             perror("accept");
281d96bf49bSAlex Bennée             return false;
282d96bf49bSAlex Bennée         } else if (fd >= 0) {
283d96bf49bSAlex Bennée             qemu_set_cloexec(fd);
284d96bf49bSAlex Bennée             break;
285d96bf49bSAlex Bennée         }
286d96bf49bSAlex Bennée     }
287d96bf49bSAlex Bennée 
288d96bf49bSAlex Bennée     /* set short latency */
289d96bf49bSAlex Bennée     if (socket_set_nodelay(fd)) {
290d96bf49bSAlex Bennée         perror("setsockopt");
291d96bf49bSAlex Bennée         close(fd);
292d96bf49bSAlex Bennée         return false;
293d96bf49bSAlex Bennée     }
294d96bf49bSAlex Bennée 
295d96bf49bSAlex Bennée     gdb_accept_init(fd);
296d96bf49bSAlex Bennée     return true;
297d96bf49bSAlex Bennée }
298d96bf49bSAlex Bennée 
299d96bf49bSAlex Bennée static int gdbserver_open_port(int port)
300d96bf49bSAlex Bennée {
301d96bf49bSAlex Bennée     struct sockaddr_in sockaddr;
302d96bf49bSAlex Bennée     int fd, ret;
303d96bf49bSAlex Bennée 
304d96bf49bSAlex Bennée     fd = socket(PF_INET, SOCK_STREAM, 0);
305d96bf49bSAlex Bennée     if (fd < 0) {
306d96bf49bSAlex Bennée         perror("socket");
307d96bf49bSAlex Bennée         return -1;
308d96bf49bSAlex Bennée     }
309d96bf49bSAlex Bennée     qemu_set_cloexec(fd);
310d96bf49bSAlex Bennée 
311d96bf49bSAlex Bennée     socket_set_fast_reuse(fd);
312d96bf49bSAlex Bennée 
313d96bf49bSAlex Bennée     sockaddr.sin_family = AF_INET;
314d96bf49bSAlex Bennée     sockaddr.sin_port = htons(port);
315d96bf49bSAlex Bennée     sockaddr.sin_addr.s_addr = 0;
316d96bf49bSAlex Bennée     ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
317d96bf49bSAlex Bennée     if (ret < 0) {
318d96bf49bSAlex Bennée         perror("bind");
319d96bf49bSAlex Bennée         close(fd);
320d96bf49bSAlex Bennée         return -1;
321d96bf49bSAlex Bennée     }
322d96bf49bSAlex Bennée     ret = listen(fd, 1);
323d96bf49bSAlex Bennée     if (ret < 0) {
324d96bf49bSAlex Bennée         perror("listen");
325d96bf49bSAlex Bennée         close(fd);
326d96bf49bSAlex Bennée         return -1;
327d96bf49bSAlex Bennée     }
328d96bf49bSAlex Bennée 
329d96bf49bSAlex Bennée     return fd;
330d96bf49bSAlex Bennée }
331d96bf49bSAlex Bennée 
332d96bf49bSAlex Bennée int gdbserver_start(const char *port_or_path)
333d96bf49bSAlex Bennée {
334d96bf49bSAlex Bennée     int port = g_ascii_strtoull(port_or_path, NULL, 10);
335d96bf49bSAlex Bennée     int gdb_fd;
336d96bf49bSAlex Bennée 
337d96bf49bSAlex Bennée     if (port > 0) {
338d96bf49bSAlex Bennée         gdb_fd = gdbserver_open_port(port);
339d96bf49bSAlex Bennée     } else {
340d96bf49bSAlex Bennée         gdb_fd = gdbserver_open_socket(port_or_path);
341d96bf49bSAlex Bennée     }
342d96bf49bSAlex Bennée 
343d96bf49bSAlex Bennée     if (gdb_fd < 0) {
344d96bf49bSAlex Bennée         return -1;
345d96bf49bSAlex Bennée     }
346d96bf49bSAlex Bennée 
347d96bf49bSAlex Bennée     if (port > 0 && gdb_accept_tcp(gdb_fd)) {
348d96bf49bSAlex Bennée         return 0;
349d96bf49bSAlex Bennée     } else if (gdb_accept_socket(gdb_fd)) {
350d96bf49bSAlex Bennée         gdbserver_user_state.socket_path = g_strdup(port_or_path);
351d96bf49bSAlex Bennée         return 0;
352d96bf49bSAlex Bennée     }
353d96bf49bSAlex Bennée 
354d96bf49bSAlex Bennée     /* gone wrong */
355d96bf49bSAlex Bennée     close(gdb_fd);
356d96bf49bSAlex Bennée     return -1;
357d96bf49bSAlex Bennée }
358d96bf49bSAlex Bennée 
3593d6ed98dSIlya Leoshkevich void gdbserver_fork_start(void)
3603d6ed98dSIlya Leoshkevich {
3613d6ed98dSIlya Leoshkevich }
3623d6ed98dSIlya Leoshkevich 
3631ea96f1dSIlya Leoshkevich static void disable_gdbstub(CPUState *thread_cpu)
3641ea96f1dSIlya Leoshkevich {
3651ea96f1dSIlya Leoshkevich     CPUState *cpu;
3661ea96f1dSIlya Leoshkevich 
3671ea96f1dSIlya Leoshkevich     close(gdbserver_user_state.fd);
3681ea96f1dSIlya Leoshkevich     gdbserver_user_state.fd = -1;
3691ea96f1dSIlya Leoshkevich     CPU_FOREACH(cpu) {
3701ea96f1dSIlya Leoshkevich         cpu_breakpoint_remove_all(cpu, BP_GDB);
3711ea96f1dSIlya Leoshkevich         /* no cpu_watchpoint_remove_all for user-mode */
3721ea96f1dSIlya Leoshkevich         cpu_single_step(cpu, 0);
3731ea96f1dSIlya Leoshkevich     }
3741ea96f1dSIlya Leoshkevich     tb_flush(thread_cpu);
3751ea96f1dSIlya Leoshkevich }
3761ea96f1dSIlya Leoshkevich 
3776604b057SIlya Leoshkevich void gdbserver_fork_end(CPUState *cpu, pid_t pid)
378d96bf49bSAlex Bennée {
3796604b057SIlya Leoshkevich     if (pid != 0 || !gdbserver_state.init || gdbserver_user_state.fd < 0) {
380d96bf49bSAlex Bennée         return;
381d96bf49bSAlex Bennée     }
3821ea96f1dSIlya Leoshkevich     disable_gdbstub(cpu);
383d96bf49bSAlex Bennée }
384d96bf49bSAlex Bennée 
385*6d923112SIlya Leoshkevich void gdb_handle_query_supported_user(const char *gdb_supported)
386*6d923112SIlya Leoshkevich {
387*6d923112SIlya Leoshkevich }
388*6d923112SIlya Leoshkevich 
389d96bf49bSAlex Bennée /*
390d96bf49bSAlex Bennée  * Execution state helpers
391d96bf49bSAlex Bennée  */
392d96bf49bSAlex Bennée 
3938a2025b3SAlex Bennée void gdb_handle_query_attached(GArray *params, void *user_ctx)
3948a2025b3SAlex Bennée {
3958a2025b3SAlex Bennée     gdb_put_packet("0");
3968a2025b3SAlex Bennée }
3978a2025b3SAlex Bennée 
398d96bf49bSAlex Bennée void gdb_continue(void)
399d96bf49bSAlex Bennée {
400d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 1;
401d96bf49bSAlex Bennée     trace_gdbstub_op_continue();
402d96bf49bSAlex Bennée }
403d96bf49bSAlex Bennée 
404d96bf49bSAlex Bennée /*
405d96bf49bSAlex Bennée  * Resume execution, for user-mode emulation it's equivalent to
406d96bf49bSAlex Bennée  * gdb_continue.
407d96bf49bSAlex Bennée  */
408d96bf49bSAlex Bennée int gdb_continue_partial(char *newstates)
409d96bf49bSAlex Bennée {
410d96bf49bSAlex Bennée     CPUState *cpu;
411d96bf49bSAlex Bennée     int res = 0;
412d96bf49bSAlex Bennée     /*
413d96bf49bSAlex Bennée      * This is not exactly accurate, but it's an improvement compared to the
414d96bf49bSAlex Bennée      * previous situation, where only one CPU would be single-stepped.
415d96bf49bSAlex Bennée      */
416d96bf49bSAlex Bennée     CPU_FOREACH(cpu) {
417d96bf49bSAlex Bennée         if (newstates[cpu->cpu_index] == 's') {
418d96bf49bSAlex Bennée             trace_gdbstub_op_stepping(cpu->cpu_index);
419d96bf49bSAlex Bennée             cpu_single_step(cpu, gdbserver_state.sstep_flags);
420d96bf49bSAlex Bennée         }
421d96bf49bSAlex Bennée     }
422d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 1;
423d96bf49bSAlex Bennée     return res;
424d96bf49bSAlex Bennée }
425d96bf49bSAlex Bennée 
426d96bf49bSAlex Bennée /*
427589a5867SAlex Bennée  * Memory access helpers
428589a5867SAlex Bennée  */
429589a5867SAlex Bennée int gdb_target_memory_rw_debug(CPUState *cpu, hwaddr addr,
430589a5867SAlex Bennée                                uint8_t *buf, int len, bool is_write)
431589a5867SAlex Bennée {
432589a5867SAlex Bennée     CPUClass *cc;
433589a5867SAlex Bennée 
434589a5867SAlex Bennée     cc = CPU_GET_CLASS(cpu);
435589a5867SAlex Bennée     if (cc->memory_rw_debug) {
436589a5867SAlex Bennée         return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
437589a5867SAlex Bennée     }
438589a5867SAlex Bennée     return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
439589a5867SAlex Bennée }
440589a5867SAlex Bennée 
441589a5867SAlex Bennée /*
4427ea0c33dSAlex Bennée  * cpu helpers
4437ea0c33dSAlex Bennée  */
4447ea0c33dSAlex Bennée 
4457ea0c33dSAlex Bennée unsigned int gdb_get_max_cpus(void)
4467ea0c33dSAlex Bennée {
4477ea0c33dSAlex Bennée     CPUState *cpu;
4487ea0c33dSAlex Bennée     unsigned int max_cpus = 1;
4497ea0c33dSAlex Bennée 
4507ea0c33dSAlex Bennée     CPU_FOREACH(cpu) {
4517ea0c33dSAlex Bennée         max_cpus = max_cpus <= cpu->cpu_index ? cpu->cpu_index + 1 : max_cpus;
4527ea0c33dSAlex Bennée     }
4537ea0c33dSAlex Bennée 
4547ea0c33dSAlex Bennée     return max_cpus;
4557ea0c33dSAlex Bennée }
4567ea0c33dSAlex Bennée 
457505601d5SAlex Bennée /* replay not supported for user-mode */
458505601d5SAlex Bennée bool gdb_can_reverse(void)
459505601d5SAlex Bennée {
460505601d5SAlex Bennée     return false;
461505601d5SAlex Bennée }
4627ea0c33dSAlex Bennée 
4637ea0c33dSAlex Bennée /*
464d96bf49bSAlex Bennée  * Break/Watch point helpers
465d96bf49bSAlex Bennée  */
466d96bf49bSAlex Bennée 
467a48e7d9eSAlex Bennée bool gdb_supports_guest_debug(void)
468a48e7d9eSAlex Bennée {
469a48e7d9eSAlex Bennée     /* user-mode == TCG == supported */
470a48e7d9eSAlex Bennée     return true;
471a48e7d9eSAlex Bennée }
472a48e7d9eSAlex Bennée 
47355b5b8e9SPhilippe Mathieu-Daudé int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len)
474ae7467b1SAlex Bennée {
475ae7467b1SAlex Bennée     CPUState *cpu;
476ae7467b1SAlex Bennée     int err = 0;
477ae7467b1SAlex Bennée 
478ae7467b1SAlex Bennée     switch (type) {
479ae7467b1SAlex Bennée     case GDB_BREAKPOINT_SW:
480ae7467b1SAlex Bennée     case GDB_BREAKPOINT_HW:
481ae7467b1SAlex Bennée         CPU_FOREACH(cpu) {
482ae7467b1SAlex Bennée             err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL);
483ae7467b1SAlex Bennée             if (err) {
484ae7467b1SAlex Bennée                 break;
485ae7467b1SAlex Bennée             }
486ae7467b1SAlex Bennée         }
487ae7467b1SAlex Bennée         return err;
488ae7467b1SAlex Bennée     default:
489ae7467b1SAlex Bennée         /* user-mode doesn't support watchpoints */
490ae7467b1SAlex Bennée         return -ENOSYS;
491ae7467b1SAlex Bennée     }
492ae7467b1SAlex Bennée }
493ae7467b1SAlex Bennée 
49455b5b8e9SPhilippe Mathieu-Daudé int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len)
495ae7467b1SAlex Bennée {
496ae7467b1SAlex Bennée     CPUState *cpu;
497ae7467b1SAlex Bennée     int err = 0;
498ae7467b1SAlex Bennée 
499ae7467b1SAlex Bennée     switch (type) {
500ae7467b1SAlex Bennée     case GDB_BREAKPOINT_SW:
501ae7467b1SAlex Bennée     case GDB_BREAKPOINT_HW:
502ae7467b1SAlex Bennée         CPU_FOREACH(cpu) {
503ae7467b1SAlex Bennée             err = cpu_breakpoint_remove(cpu, addr, BP_GDB);
504ae7467b1SAlex Bennée             if (err) {
505ae7467b1SAlex Bennée                 break;
506ae7467b1SAlex Bennée             }
507ae7467b1SAlex Bennée         }
508ae7467b1SAlex Bennée         return err;
509ae7467b1SAlex Bennée     default:
510ae7467b1SAlex Bennée         /* user-mode doesn't support watchpoints */
511ae7467b1SAlex Bennée         return -ENOSYS;
512ae7467b1SAlex Bennée     }
513ae7467b1SAlex Bennée }
514ae7467b1SAlex Bennée 
515ae7467b1SAlex Bennée void gdb_breakpoint_remove_all(CPUState *cs)
516ae7467b1SAlex Bennée {
517ae7467b1SAlex Bennée     cpu_breakpoint_remove_all(cs, BP_GDB);
518ae7467b1SAlex Bennée }
519131f387dSAlex Bennée 
520131f387dSAlex Bennée /*
521131f387dSAlex Bennée  * For user-mode syscall support we send the system call immediately
522131f387dSAlex Bennée  * and then return control to gdb for it to process the syscall request.
523131f387dSAlex Bennée  * Since the protocol requires that gdb hands control back to us
524131f387dSAlex Bennée  * using a "here are the results" F packet, we don't need to check
525131f387dSAlex Bennée  * gdb_handlesig's return value (which is the signal to deliver if
526131f387dSAlex Bennée  * execution was resumed via a continue packet).
527131f387dSAlex Bennée  */
528131f387dSAlex Bennée void gdb_syscall_handling(const char *syscall_packet)
529131f387dSAlex Bennée {
530131f387dSAlex Bennée     gdb_put_packet(syscall_packet);
531131f387dSAlex Bennée     gdb_handlesig(gdbserver_state.c_cpu, 0);
532131f387dSAlex Bennée }
5330a0d87c9SIlya Leoshkevich 
534046f143cSIlya Leoshkevich static bool should_catch_syscall(int num)
535046f143cSIlya Leoshkevich {
536046f143cSIlya Leoshkevich     if (gdbserver_user_state.catch_all_syscalls) {
537046f143cSIlya Leoshkevich         return true;
538046f143cSIlya Leoshkevich     }
539046f143cSIlya Leoshkevich     if (num < 0 || num >= GDB_NR_SYSCALLS) {
540046f143cSIlya Leoshkevich         return false;
541046f143cSIlya Leoshkevich     }
542046f143cSIlya Leoshkevich     return test_bit(num, gdbserver_user_state.catch_syscalls_mask);
543046f143cSIlya Leoshkevich }
544046f143cSIlya Leoshkevich 
5450a0d87c9SIlya Leoshkevich void gdb_syscall_entry(CPUState *cs, int num)
5460a0d87c9SIlya Leoshkevich {
547046f143cSIlya Leoshkevich     if (should_catch_syscall(num)) {
548046f143cSIlya Leoshkevich         g_autofree char *reason = g_strdup_printf("syscall_entry:%x;", num);
549046f143cSIlya Leoshkevich         gdb_handlesig_reason(cs, gdb_target_sigtrap(), reason);
550046f143cSIlya Leoshkevich     }
5510a0d87c9SIlya Leoshkevich }
5520a0d87c9SIlya Leoshkevich 
5530a0d87c9SIlya Leoshkevich void gdb_syscall_return(CPUState *cs, int num)
5540a0d87c9SIlya Leoshkevich {
555046f143cSIlya Leoshkevich     if (should_catch_syscall(num)) {
556046f143cSIlya Leoshkevich         g_autofree char *reason = g_strdup_printf("syscall_return:%x;", num);
557046f143cSIlya Leoshkevich         gdb_handlesig_reason(cs, gdb_target_sigtrap(), reason);
558046f143cSIlya Leoshkevich     }
559046f143cSIlya Leoshkevich }
560046f143cSIlya Leoshkevich 
561046f143cSIlya Leoshkevich void gdb_handle_set_catch_syscalls(GArray *params, void *user_ctx)
562046f143cSIlya Leoshkevich {
563046f143cSIlya Leoshkevich     const char *param = get_param(params, 0)->data;
564046f143cSIlya Leoshkevich     GDBSyscallsMask catch_syscalls_mask;
565046f143cSIlya Leoshkevich     bool catch_all_syscalls;
566046f143cSIlya Leoshkevich     unsigned int num;
567046f143cSIlya Leoshkevich     const char *p;
568046f143cSIlya Leoshkevich 
569046f143cSIlya Leoshkevich     /* "0" means not catching any syscalls. */
570046f143cSIlya Leoshkevich     if (strcmp(param, "0") == 0) {
571046f143cSIlya Leoshkevich         gdbserver_user_state.catch_all_syscalls = false;
572046f143cSIlya Leoshkevich         memset(gdbserver_user_state.catch_syscalls_mask, 0,
573046f143cSIlya Leoshkevich                sizeof(gdbserver_user_state.catch_syscalls_mask));
574046f143cSIlya Leoshkevich         gdb_put_packet("OK");
575046f143cSIlya Leoshkevich         return;
576046f143cSIlya Leoshkevich     }
577046f143cSIlya Leoshkevich 
578046f143cSIlya Leoshkevich     /* "1" means catching all syscalls. */
579046f143cSIlya Leoshkevich     if (strcmp(param, "1") == 0) {
580046f143cSIlya Leoshkevich         gdbserver_user_state.catch_all_syscalls = true;
581046f143cSIlya Leoshkevich         gdb_put_packet("OK");
582046f143cSIlya Leoshkevich         return;
583046f143cSIlya Leoshkevich     }
584046f143cSIlya Leoshkevich 
585046f143cSIlya Leoshkevich     /*
586046f143cSIlya Leoshkevich      * "1;..." means catching only the specified syscalls.
587046f143cSIlya Leoshkevich      * The syscall list must not be empty.
588046f143cSIlya Leoshkevich      */
589046f143cSIlya Leoshkevich     if (param[0] == '1' && param[1] == ';') {
590046f143cSIlya Leoshkevich         catch_all_syscalls = false;
591046f143cSIlya Leoshkevich         memset(catch_syscalls_mask, 0, sizeof(catch_syscalls_mask));
592046f143cSIlya Leoshkevich         for (p = &param[2];; p++) {
593046f143cSIlya Leoshkevich             if (qemu_strtoui(p, &p, 16, &num) || (*p && *p != ';')) {
594046f143cSIlya Leoshkevich                 goto err;
595046f143cSIlya Leoshkevich             }
596046f143cSIlya Leoshkevich             if (num >= GDB_NR_SYSCALLS) {
597046f143cSIlya Leoshkevich                 /*
598046f143cSIlya Leoshkevich                  * Fall back to reporting all syscalls. Reporting extra
599046f143cSIlya Leoshkevich                  * syscalls is inefficient, but the spec explicitly allows it.
600046f143cSIlya Leoshkevich                  * Keep parsing in case there is a syntax error ahead.
601046f143cSIlya Leoshkevich                  */
602046f143cSIlya Leoshkevich                 catch_all_syscalls = true;
603046f143cSIlya Leoshkevich             } else {
604046f143cSIlya Leoshkevich                 set_bit(num, catch_syscalls_mask);
605046f143cSIlya Leoshkevich             }
606046f143cSIlya Leoshkevich             if (!*p) {
607046f143cSIlya Leoshkevich                 break;
608046f143cSIlya Leoshkevich             }
609046f143cSIlya Leoshkevich         }
610046f143cSIlya Leoshkevich         gdbserver_user_state.catch_all_syscalls = catch_all_syscalls;
611046f143cSIlya Leoshkevich         if (!catch_all_syscalls) {
612046f143cSIlya Leoshkevich             memcpy(gdbserver_user_state.catch_syscalls_mask,
613046f143cSIlya Leoshkevich                    catch_syscalls_mask, sizeof(catch_syscalls_mask));
614046f143cSIlya Leoshkevich         }
615046f143cSIlya Leoshkevich         gdb_put_packet("OK");
616046f143cSIlya Leoshkevich         return;
617046f143cSIlya Leoshkevich     }
618046f143cSIlya Leoshkevich 
619046f143cSIlya Leoshkevich err:
620046f143cSIlya Leoshkevich     gdb_put_packet("E00");
6210a0d87c9SIlya Leoshkevich }
622