xref: /qemu/gdbstub/user.c (revision 8b7fcb8e)
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"
13d96bf49bSAlex Bennée #include "qemu/cutils.h"
14d96bf49bSAlex Bennée #include "qemu/sockets.h"
15d96bf49bSAlex Bennée #include "exec/hwaddr.h"
16d96bf49bSAlex Bennée #include "exec/tb-flush.h"
17ae7467b1SAlex Bennée #include "exec/gdbstub.h"
18c566080cSAlex Bennée #include "gdbstub/syscalls.h"
19d96bf49bSAlex Bennée #include "gdbstub/user.h"
20ae7467b1SAlex Bennée #include "hw/core/cpu.h"
21d96bf49bSAlex Bennée #include "trace.h"
22ae7467b1SAlex Bennée #include "internals.h"
23ae7467b1SAlex Bennée 
24d96bf49bSAlex Bennée /* User-mode specific state */
25d96bf49bSAlex Bennée typedef struct {
26d96bf49bSAlex Bennée     int fd;
27d96bf49bSAlex Bennée     char *socket_path;
28d96bf49bSAlex Bennée     int running_state;
29d96bf49bSAlex Bennée } GDBUserState;
30d96bf49bSAlex Bennée 
31d96bf49bSAlex Bennée static GDBUserState gdbserver_user_state;
32d96bf49bSAlex Bennée 
33d96bf49bSAlex Bennée int gdb_get_char(void)
34d96bf49bSAlex Bennée {
35d96bf49bSAlex Bennée     uint8_t ch;
36d96bf49bSAlex Bennée     int ret;
37d96bf49bSAlex Bennée 
38d96bf49bSAlex Bennée     for (;;) {
39d96bf49bSAlex Bennée         ret = recv(gdbserver_user_state.fd, &ch, 1, 0);
40d96bf49bSAlex Bennée         if (ret < 0) {
41d96bf49bSAlex Bennée             if (errno == ECONNRESET) {
42d96bf49bSAlex Bennée                 gdbserver_user_state.fd = -1;
43d96bf49bSAlex Bennée             }
44d96bf49bSAlex Bennée             if (errno != EINTR) {
45d96bf49bSAlex Bennée                 return -1;
46d96bf49bSAlex Bennée             }
47d96bf49bSAlex Bennée         } else if (ret == 0) {
48d96bf49bSAlex Bennée             close(gdbserver_user_state.fd);
49d96bf49bSAlex Bennée             gdbserver_user_state.fd = -1;
50d96bf49bSAlex Bennée             return -1;
51d96bf49bSAlex Bennée         } else {
52d96bf49bSAlex Bennée             break;
53d96bf49bSAlex Bennée         }
54d96bf49bSAlex Bennée     }
55d96bf49bSAlex Bennée     return ch;
56d96bf49bSAlex Bennée }
57d96bf49bSAlex Bennée 
58a7e0f9bdSAlex Bennée bool gdb_got_immediate_ack(void)
59a7e0f9bdSAlex Bennée {
60a7e0f9bdSAlex Bennée     int i;
61a7e0f9bdSAlex Bennée 
62a7e0f9bdSAlex Bennée     i = gdb_get_char();
63a7e0f9bdSAlex Bennée     if (i < 0) {
64a7e0f9bdSAlex Bennée         /* no response, continue anyway */
65a7e0f9bdSAlex Bennée         return true;
66a7e0f9bdSAlex Bennée     }
67a7e0f9bdSAlex Bennée 
68a7e0f9bdSAlex Bennée     if (i == '+') {
69a7e0f9bdSAlex Bennée         /* received correctly, continue */
70a7e0f9bdSAlex Bennée         return true;
71a7e0f9bdSAlex Bennée     }
72a7e0f9bdSAlex Bennée 
73a7e0f9bdSAlex Bennée     /* anything else, including '-' then try again */
74a7e0f9bdSAlex Bennée     return false;
75a7e0f9bdSAlex Bennée }
76a7e0f9bdSAlex Bennée 
77d96bf49bSAlex Bennée void gdb_put_buffer(const uint8_t *buf, int len)
78d96bf49bSAlex Bennée {
79d96bf49bSAlex Bennée     int ret;
80d96bf49bSAlex Bennée 
81d96bf49bSAlex Bennée     while (len > 0) {
82d96bf49bSAlex Bennée         ret = send(gdbserver_user_state.fd, buf, len, 0);
83d96bf49bSAlex Bennée         if (ret < 0) {
84d96bf49bSAlex Bennée             if (errno != EINTR) {
85d96bf49bSAlex Bennée                 return;
86d96bf49bSAlex Bennée             }
87d96bf49bSAlex Bennée         } else {
88d96bf49bSAlex Bennée             buf += ret;
89d96bf49bSAlex Bennée             len -= ret;
90d96bf49bSAlex Bennée         }
91d96bf49bSAlex Bennée     }
92d96bf49bSAlex Bennée }
93d96bf49bSAlex Bennée 
94d96bf49bSAlex Bennée /* Tell the remote gdb that the process has exited.  */
95d96bf49bSAlex Bennée void gdb_exit(int code)
96d96bf49bSAlex Bennée {
97d96bf49bSAlex Bennée     char buf[4];
98d96bf49bSAlex Bennée 
99d96bf49bSAlex Bennée     if (!gdbserver_state.init) {
100d96bf49bSAlex Bennée         return;
101d96bf49bSAlex Bennée     }
102d96bf49bSAlex Bennée     if (gdbserver_user_state.socket_path) {
103d96bf49bSAlex Bennée         unlink(gdbserver_user_state.socket_path);
104d96bf49bSAlex Bennée     }
105d96bf49bSAlex Bennée     if (gdbserver_user_state.fd < 0) {
106d96bf49bSAlex Bennée         return;
107d96bf49bSAlex Bennée     }
108d96bf49bSAlex Bennée 
109d96bf49bSAlex Bennée     trace_gdbstub_op_exiting((uint8_t)code);
110d96bf49bSAlex Bennée 
11175837005SMatheus Tavares Bernardino     if (gdbserver_state.allow_stop_reply) {
112d96bf49bSAlex Bennée         snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
113d96bf49bSAlex Bennée         gdb_put_packet(buf);
11475837005SMatheus Tavares Bernardino         gdbserver_state.allow_stop_reply = false;
11575837005SMatheus Tavares Bernardino     }
116e216256aSClément Chigot 
117e216256aSClément Chigot }
118e216256aSClément Chigot 
119e216256aSClément Chigot void gdb_qemu_exit(int code)
120e216256aSClément Chigot {
121e216256aSClément Chigot     exit(code);
122d96bf49bSAlex Bennée }
123d96bf49bSAlex Bennée 
124*8b7fcb8eSIlya Leoshkevich int gdb_handlesig_reason(CPUState *cpu, int sig, const char *reason)
125d96bf49bSAlex Bennée {
126d96bf49bSAlex Bennée     char buf[256];
127d96bf49bSAlex Bennée     int n;
128d96bf49bSAlex Bennée 
129d96bf49bSAlex Bennée     if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
130d96bf49bSAlex Bennée         return sig;
131d96bf49bSAlex Bennée     }
132d96bf49bSAlex Bennée 
133d96bf49bSAlex Bennée     /* disable single step if it was enabled */
134d96bf49bSAlex Bennée     cpu_single_step(cpu, 0);
135d96bf49bSAlex Bennée     tb_flush(cpu);
136d96bf49bSAlex Bennée 
137d96bf49bSAlex Bennée     if (sig != 0) {
138d96bf49bSAlex Bennée         gdb_set_stop_cpu(cpu);
13975837005SMatheus Tavares Bernardino         if (gdbserver_state.allow_stop_reply) {
140d96bf49bSAlex Bennée             g_string_printf(gdbserver_state.str_buf,
141d96bf49bSAlex Bennée                             "T%02xthread:", gdb_target_signal_to_gdb(sig));
142d96bf49bSAlex Bennée             gdb_append_thread_id(cpu, gdbserver_state.str_buf);
143d96bf49bSAlex Bennée             g_string_append_c(gdbserver_state.str_buf, ';');
144*8b7fcb8eSIlya Leoshkevich             if (reason) {
145*8b7fcb8eSIlya Leoshkevich                 g_string_append(gdbserver_state.str_buf, reason);
146*8b7fcb8eSIlya Leoshkevich             }
147d96bf49bSAlex Bennée             gdb_put_strbuf();
14875837005SMatheus Tavares Bernardino             gdbserver_state.allow_stop_reply = false;
14975837005SMatheus Tavares Bernardino         }
150d96bf49bSAlex Bennée     }
151d96bf49bSAlex Bennée     /*
152d96bf49bSAlex Bennée      * gdb_put_packet() might have detected that the peer terminated the
153d96bf49bSAlex Bennée      * connection.
154d96bf49bSAlex Bennée      */
155d96bf49bSAlex Bennée     if (gdbserver_user_state.fd < 0) {
156d96bf49bSAlex Bennée         return sig;
157d96bf49bSAlex Bennée     }
158d96bf49bSAlex Bennée 
159d96bf49bSAlex Bennée     sig = 0;
160d96bf49bSAlex Bennée     gdbserver_state.state = RS_IDLE;
161d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 0;
162d96bf49bSAlex Bennée     while (gdbserver_user_state.running_state == 0) {
163d96bf49bSAlex Bennée         n = read(gdbserver_user_state.fd, buf, 256);
164d96bf49bSAlex Bennée         if (n > 0) {
165d96bf49bSAlex Bennée             int i;
166d96bf49bSAlex Bennée 
167d96bf49bSAlex Bennée             for (i = 0; i < n; i++) {
168d96bf49bSAlex Bennée                 gdb_read_byte(buf[i]);
169d96bf49bSAlex Bennée             }
170d96bf49bSAlex Bennée         } else {
171d96bf49bSAlex Bennée             /*
172d96bf49bSAlex Bennée              * XXX: Connection closed.  Should probably wait for another
173d96bf49bSAlex Bennée              * connection before continuing.
174d96bf49bSAlex Bennée              */
175d96bf49bSAlex Bennée             if (n == 0) {
176d96bf49bSAlex Bennée                 close(gdbserver_user_state.fd);
177d96bf49bSAlex Bennée             }
178d96bf49bSAlex Bennée             gdbserver_user_state.fd = -1;
179d96bf49bSAlex Bennée             return sig;
180d96bf49bSAlex Bennée         }
181d96bf49bSAlex Bennée     }
182d96bf49bSAlex Bennée     sig = gdbserver_state.signal;
183d96bf49bSAlex Bennée     gdbserver_state.signal = 0;
184d96bf49bSAlex Bennée     return sig;
185d96bf49bSAlex Bennée }
186d96bf49bSAlex Bennée 
187d96bf49bSAlex Bennée /* Tell the remote gdb that the process has exited due to SIG.  */
188d96bf49bSAlex Bennée void gdb_signalled(CPUArchState *env, int sig)
189d96bf49bSAlex Bennée {
190d96bf49bSAlex Bennée     char buf[4];
191d96bf49bSAlex Bennée 
19275837005SMatheus Tavares Bernardino     if (!gdbserver_state.init || gdbserver_user_state.fd < 0 ||
19375837005SMatheus Tavares Bernardino         !gdbserver_state.allow_stop_reply) {
194d96bf49bSAlex Bennée         return;
195d96bf49bSAlex Bennée     }
196d96bf49bSAlex Bennée 
197d96bf49bSAlex Bennée     snprintf(buf, sizeof(buf), "X%02x", gdb_target_signal_to_gdb(sig));
198d96bf49bSAlex Bennée     gdb_put_packet(buf);
19975837005SMatheus Tavares Bernardino     gdbserver_state.allow_stop_reply = false;
200d96bf49bSAlex Bennée }
201d96bf49bSAlex Bennée 
202d96bf49bSAlex Bennée static void gdb_accept_init(int fd)
203d96bf49bSAlex Bennée {
204d96bf49bSAlex Bennée     gdb_init_gdbserver_state();
205d96bf49bSAlex Bennée     gdb_create_default_process(&gdbserver_state);
206d96bf49bSAlex Bennée     gdbserver_state.processes[0].attached = true;
207d96bf49bSAlex Bennée     gdbserver_state.c_cpu = gdb_first_attached_cpu();
208d96bf49bSAlex Bennée     gdbserver_state.g_cpu = gdbserver_state.c_cpu;
209d96bf49bSAlex Bennée     gdbserver_user_state.fd = fd;
210d96bf49bSAlex Bennée }
211d96bf49bSAlex Bennée 
212d96bf49bSAlex Bennée static bool gdb_accept_socket(int gdb_fd)
213d96bf49bSAlex Bennée {
214d96bf49bSAlex Bennée     int fd;
215d96bf49bSAlex Bennée 
216d96bf49bSAlex Bennée     for (;;) {
217d96bf49bSAlex Bennée         fd = accept(gdb_fd, NULL, NULL);
218d96bf49bSAlex Bennée         if (fd < 0 && errno != EINTR) {
219d96bf49bSAlex Bennée             perror("accept socket");
220d96bf49bSAlex Bennée             return false;
221d96bf49bSAlex Bennée         } else if (fd >= 0) {
222d96bf49bSAlex Bennée             qemu_set_cloexec(fd);
223d96bf49bSAlex Bennée             break;
224d96bf49bSAlex Bennée         }
225d96bf49bSAlex Bennée     }
226d96bf49bSAlex Bennée 
227d96bf49bSAlex Bennée     gdb_accept_init(fd);
228d96bf49bSAlex Bennée     return true;
229d96bf49bSAlex Bennée }
230d96bf49bSAlex Bennée 
231d96bf49bSAlex Bennée static int gdbserver_open_socket(const char *path)
232d96bf49bSAlex Bennée {
233d96bf49bSAlex Bennée     struct sockaddr_un sockaddr = {};
234d96bf49bSAlex Bennée     int fd, ret;
235d96bf49bSAlex Bennée 
236d96bf49bSAlex Bennée     fd = socket(AF_UNIX, SOCK_STREAM, 0);
237d96bf49bSAlex Bennée     if (fd < 0) {
238d96bf49bSAlex Bennée         perror("create socket");
239d96bf49bSAlex Bennée         return -1;
240d96bf49bSAlex Bennée     }
241d96bf49bSAlex Bennée 
242d96bf49bSAlex Bennée     sockaddr.sun_family = AF_UNIX;
243d96bf49bSAlex Bennée     pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path);
244d96bf49bSAlex Bennée     ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
245d96bf49bSAlex Bennée     if (ret < 0) {
246d96bf49bSAlex Bennée         perror("bind socket");
247d96bf49bSAlex Bennée         close(fd);
248d96bf49bSAlex Bennée         return -1;
249d96bf49bSAlex Bennée     }
250d96bf49bSAlex Bennée     ret = listen(fd, 1);
251d96bf49bSAlex Bennée     if (ret < 0) {
252d96bf49bSAlex Bennée         perror("listen socket");
253d96bf49bSAlex Bennée         close(fd);
254d96bf49bSAlex Bennée         return -1;
255d96bf49bSAlex Bennée     }
256d96bf49bSAlex Bennée 
257d96bf49bSAlex Bennée     return fd;
258d96bf49bSAlex Bennée }
259d96bf49bSAlex Bennée 
260d96bf49bSAlex Bennée static bool gdb_accept_tcp(int gdb_fd)
261d96bf49bSAlex Bennée {
262d96bf49bSAlex Bennée     struct sockaddr_in sockaddr = {};
263d96bf49bSAlex Bennée     socklen_t len;
264d96bf49bSAlex Bennée     int fd;
265d96bf49bSAlex Bennée 
266d96bf49bSAlex Bennée     for (;;) {
267d96bf49bSAlex Bennée         len = sizeof(sockaddr);
268d96bf49bSAlex Bennée         fd = accept(gdb_fd, (struct sockaddr *)&sockaddr, &len);
269d96bf49bSAlex Bennée         if (fd < 0 && errno != EINTR) {
270d96bf49bSAlex Bennée             perror("accept");
271d96bf49bSAlex Bennée             return false;
272d96bf49bSAlex Bennée         } else if (fd >= 0) {
273d96bf49bSAlex Bennée             qemu_set_cloexec(fd);
274d96bf49bSAlex Bennée             break;
275d96bf49bSAlex Bennée         }
276d96bf49bSAlex Bennée     }
277d96bf49bSAlex Bennée 
278d96bf49bSAlex Bennée     /* set short latency */
279d96bf49bSAlex Bennée     if (socket_set_nodelay(fd)) {
280d96bf49bSAlex Bennée         perror("setsockopt");
281d96bf49bSAlex Bennée         close(fd);
282d96bf49bSAlex Bennée         return false;
283d96bf49bSAlex Bennée     }
284d96bf49bSAlex Bennée 
285d96bf49bSAlex Bennée     gdb_accept_init(fd);
286d96bf49bSAlex Bennée     return true;
287d96bf49bSAlex Bennée }
288d96bf49bSAlex Bennée 
289d96bf49bSAlex Bennée static int gdbserver_open_port(int port)
290d96bf49bSAlex Bennée {
291d96bf49bSAlex Bennée     struct sockaddr_in sockaddr;
292d96bf49bSAlex Bennée     int fd, ret;
293d96bf49bSAlex Bennée 
294d96bf49bSAlex Bennée     fd = socket(PF_INET, SOCK_STREAM, 0);
295d96bf49bSAlex Bennée     if (fd < 0) {
296d96bf49bSAlex Bennée         perror("socket");
297d96bf49bSAlex Bennée         return -1;
298d96bf49bSAlex Bennée     }
299d96bf49bSAlex Bennée     qemu_set_cloexec(fd);
300d96bf49bSAlex Bennée 
301d96bf49bSAlex Bennée     socket_set_fast_reuse(fd);
302d96bf49bSAlex Bennée 
303d96bf49bSAlex Bennée     sockaddr.sin_family = AF_INET;
304d96bf49bSAlex Bennée     sockaddr.sin_port = htons(port);
305d96bf49bSAlex Bennée     sockaddr.sin_addr.s_addr = 0;
306d96bf49bSAlex Bennée     ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
307d96bf49bSAlex Bennée     if (ret < 0) {
308d96bf49bSAlex Bennée         perror("bind");
309d96bf49bSAlex Bennée         close(fd);
310d96bf49bSAlex Bennée         return -1;
311d96bf49bSAlex Bennée     }
312d96bf49bSAlex Bennée     ret = listen(fd, 1);
313d96bf49bSAlex Bennée     if (ret < 0) {
314d96bf49bSAlex Bennée         perror("listen");
315d96bf49bSAlex Bennée         close(fd);
316d96bf49bSAlex Bennée         return -1;
317d96bf49bSAlex Bennée     }
318d96bf49bSAlex Bennée 
319d96bf49bSAlex Bennée     return fd;
320d96bf49bSAlex Bennée }
321d96bf49bSAlex Bennée 
322d96bf49bSAlex Bennée int gdbserver_start(const char *port_or_path)
323d96bf49bSAlex Bennée {
324d96bf49bSAlex Bennée     int port = g_ascii_strtoull(port_or_path, NULL, 10);
325d96bf49bSAlex Bennée     int gdb_fd;
326d96bf49bSAlex Bennée 
327d96bf49bSAlex Bennée     if (port > 0) {
328d96bf49bSAlex Bennée         gdb_fd = gdbserver_open_port(port);
329d96bf49bSAlex Bennée     } else {
330d96bf49bSAlex Bennée         gdb_fd = gdbserver_open_socket(port_or_path);
331d96bf49bSAlex Bennée     }
332d96bf49bSAlex Bennée 
333d96bf49bSAlex Bennée     if (gdb_fd < 0) {
334d96bf49bSAlex Bennée         return -1;
335d96bf49bSAlex Bennée     }
336d96bf49bSAlex Bennée 
337d96bf49bSAlex Bennée     if (port > 0 && gdb_accept_tcp(gdb_fd)) {
338d96bf49bSAlex Bennée         return 0;
339d96bf49bSAlex Bennée     } else if (gdb_accept_socket(gdb_fd)) {
340d96bf49bSAlex Bennée         gdbserver_user_state.socket_path = g_strdup(port_or_path);
341d96bf49bSAlex Bennée         return 0;
342d96bf49bSAlex Bennée     }
343d96bf49bSAlex Bennée 
344d96bf49bSAlex Bennée     /* gone wrong */
345d96bf49bSAlex Bennée     close(gdb_fd);
346d96bf49bSAlex Bennée     return -1;
347d96bf49bSAlex Bennée }
348d96bf49bSAlex Bennée 
349d96bf49bSAlex Bennée /* Disable gdb stub for child processes.  */
350d96bf49bSAlex Bennée void gdbserver_fork(CPUState *cpu)
351d96bf49bSAlex Bennée {
352d96bf49bSAlex Bennée     if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
353d96bf49bSAlex Bennée         return;
354d96bf49bSAlex Bennée     }
355d96bf49bSAlex Bennée     close(gdbserver_user_state.fd);
356d96bf49bSAlex Bennée     gdbserver_user_state.fd = -1;
357d96bf49bSAlex Bennée     cpu_breakpoint_remove_all(cpu, BP_GDB);
358d96bf49bSAlex Bennée     /* no cpu_watchpoint_remove_all for user-mode */
359d96bf49bSAlex Bennée }
360d96bf49bSAlex Bennée 
361d96bf49bSAlex Bennée /*
362d96bf49bSAlex Bennée  * Execution state helpers
363d96bf49bSAlex Bennée  */
364d96bf49bSAlex Bennée 
3658a2025b3SAlex Bennée void gdb_handle_query_attached(GArray *params, void *user_ctx)
3668a2025b3SAlex Bennée {
3678a2025b3SAlex Bennée     gdb_put_packet("0");
3688a2025b3SAlex Bennée }
3698a2025b3SAlex Bennée 
370d96bf49bSAlex Bennée void gdb_continue(void)
371d96bf49bSAlex Bennée {
372d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 1;
373d96bf49bSAlex Bennée     trace_gdbstub_op_continue();
374d96bf49bSAlex Bennée }
375d96bf49bSAlex Bennée 
376d96bf49bSAlex Bennée /*
377d96bf49bSAlex Bennée  * Resume execution, for user-mode emulation it's equivalent to
378d96bf49bSAlex Bennée  * gdb_continue.
379d96bf49bSAlex Bennée  */
380d96bf49bSAlex Bennée int gdb_continue_partial(char *newstates)
381d96bf49bSAlex Bennée {
382d96bf49bSAlex Bennée     CPUState *cpu;
383d96bf49bSAlex Bennée     int res = 0;
384d96bf49bSAlex Bennée     /*
385d96bf49bSAlex Bennée      * This is not exactly accurate, but it's an improvement compared to the
386d96bf49bSAlex Bennée      * previous situation, where only one CPU would be single-stepped.
387d96bf49bSAlex Bennée      */
388d96bf49bSAlex Bennée     CPU_FOREACH(cpu) {
389d96bf49bSAlex Bennée         if (newstates[cpu->cpu_index] == 's') {
390d96bf49bSAlex Bennée             trace_gdbstub_op_stepping(cpu->cpu_index);
391d96bf49bSAlex Bennée             cpu_single_step(cpu, gdbserver_state.sstep_flags);
392d96bf49bSAlex Bennée         }
393d96bf49bSAlex Bennée     }
394d96bf49bSAlex Bennée     gdbserver_user_state.running_state = 1;
395d96bf49bSAlex Bennée     return res;
396d96bf49bSAlex Bennée }
397d96bf49bSAlex Bennée 
398d96bf49bSAlex Bennée /*
399589a5867SAlex Bennée  * Memory access helpers
400589a5867SAlex Bennée  */
401589a5867SAlex Bennée int gdb_target_memory_rw_debug(CPUState *cpu, hwaddr addr,
402589a5867SAlex Bennée                                uint8_t *buf, int len, bool is_write)
403589a5867SAlex Bennée {
404589a5867SAlex Bennée     CPUClass *cc;
405589a5867SAlex Bennée 
406589a5867SAlex Bennée     cc = CPU_GET_CLASS(cpu);
407589a5867SAlex Bennée     if (cc->memory_rw_debug) {
408589a5867SAlex Bennée         return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
409589a5867SAlex Bennée     }
410589a5867SAlex Bennée     return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
411589a5867SAlex Bennée }
412589a5867SAlex Bennée 
413589a5867SAlex Bennée /*
4147ea0c33dSAlex Bennée  * cpu helpers
4157ea0c33dSAlex Bennée  */
4167ea0c33dSAlex Bennée 
4177ea0c33dSAlex Bennée unsigned int gdb_get_max_cpus(void)
4187ea0c33dSAlex Bennée {
4197ea0c33dSAlex Bennée     CPUState *cpu;
4207ea0c33dSAlex Bennée     unsigned int max_cpus = 1;
4217ea0c33dSAlex Bennée 
4227ea0c33dSAlex Bennée     CPU_FOREACH(cpu) {
4237ea0c33dSAlex Bennée         max_cpus = max_cpus <= cpu->cpu_index ? cpu->cpu_index + 1 : max_cpus;
4247ea0c33dSAlex Bennée     }
4257ea0c33dSAlex Bennée 
4267ea0c33dSAlex Bennée     return max_cpus;
4277ea0c33dSAlex Bennée }
4287ea0c33dSAlex Bennée 
429505601d5SAlex Bennée /* replay not supported for user-mode */
430505601d5SAlex Bennée bool gdb_can_reverse(void)
431505601d5SAlex Bennée {
432505601d5SAlex Bennée     return false;
433505601d5SAlex Bennée }
4347ea0c33dSAlex Bennée 
4357ea0c33dSAlex Bennée /*
436d96bf49bSAlex Bennée  * Break/Watch point helpers
437d96bf49bSAlex Bennée  */
438d96bf49bSAlex Bennée 
439a48e7d9eSAlex Bennée bool gdb_supports_guest_debug(void)
440a48e7d9eSAlex Bennée {
441a48e7d9eSAlex Bennée     /* user-mode == TCG == supported */
442a48e7d9eSAlex Bennée     return true;
443a48e7d9eSAlex Bennée }
444a48e7d9eSAlex Bennée 
44555b5b8e9SPhilippe Mathieu-Daudé int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len)
446ae7467b1SAlex Bennée {
447ae7467b1SAlex Bennée     CPUState *cpu;
448ae7467b1SAlex Bennée     int err = 0;
449ae7467b1SAlex Bennée 
450ae7467b1SAlex Bennée     switch (type) {
451ae7467b1SAlex Bennée     case GDB_BREAKPOINT_SW:
452ae7467b1SAlex Bennée     case GDB_BREAKPOINT_HW:
453ae7467b1SAlex Bennée         CPU_FOREACH(cpu) {
454ae7467b1SAlex Bennée             err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL);
455ae7467b1SAlex Bennée             if (err) {
456ae7467b1SAlex Bennée                 break;
457ae7467b1SAlex Bennée             }
458ae7467b1SAlex Bennée         }
459ae7467b1SAlex Bennée         return err;
460ae7467b1SAlex Bennée     default:
461ae7467b1SAlex Bennée         /* user-mode doesn't support watchpoints */
462ae7467b1SAlex Bennée         return -ENOSYS;
463ae7467b1SAlex Bennée     }
464ae7467b1SAlex Bennée }
465ae7467b1SAlex Bennée 
46655b5b8e9SPhilippe Mathieu-Daudé int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len)
467ae7467b1SAlex Bennée {
468ae7467b1SAlex Bennée     CPUState *cpu;
469ae7467b1SAlex Bennée     int err = 0;
470ae7467b1SAlex Bennée 
471ae7467b1SAlex Bennée     switch (type) {
472ae7467b1SAlex Bennée     case GDB_BREAKPOINT_SW:
473ae7467b1SAlex Bennée     case GDB_BREAKPOINT_HW:
474ae7467b1SAlex Bennée         CPU_FOREACH(cpu) {
475ae7467b1SAlex Bennée             err = cpu_breakpoint_remove(cpu, addr, BP_GDB);
476ae7467b1SAlex Bennée             if (err) {
477ae7467b1SAlex Bennée                 break;
478ae7467b1SAlex Bennée             }
479ae7467b1SAlex Bennée         }
480ae7467b1SAlex Bennée         return err;
481ae7467b1SAlex Bennée     default:
482ae7467b1SAlex Bennée         /* user-mode doesn't support watchpoints */
483ae7467b1SAlex Bennée         return -ENOSYS;
484ae7467b1SAlex Bennée     }
485ae7467b1SAlex Bennée }
486ae7467b1SAlex Bennée 
487ae7467b1SAlex Bennée void gdb_breakpoint_remove_all(CPUState *cs)
488ae7467b1SAlex Bennée {
489ae7467b1SAlex Bennée     cpu_breakpoint_remove_all(cs, BP_GDB);
490ae7467b1SAlex Bennée }
491131f387dSAlex Bennée 
492131f387dSAlex Bennée /*
493131f387dSAlex Bennée  * For user-mode syscall support we send the system call immediately
494131f387dSAlex Bennée  * and then return control to gdb for it to process the syscall request.
495131f387dSAlex Bennée  * Since the protocol requires that gdb hands control back to us
496131f387dSAlex Bennée  * using a "here are the results" F packet, we don't need to check
497131f387dSAlex Bennée  * gdb_handlesig's return value (which is the signal to deliver if
498131f387dSAlex Bennée  * execution was resumed via a continue packet).
499131f387dSAlex Bennée  */
500131f387dSAlex Bennée void gdb_syscall_handling(const char *syscall_packet)
501131f387dSAlex Bennée {
502131f387dSAlex Bennée     gdb_put_packet(syscall_packet);
503131f387dSAlex Bennée     gdb_handlesig(gdbserver_state.c_cpu, 0);
504131f387dSAlex Bennée }
505