]> git.proxmox.com Git - mirror_qemu.git/blame - gdbstub/user.c
gdbstub: move chunks of user code into own files
[mirror_qemu.git] / gdbstub / user.c
CommitLineData
ae7467b1
AB
1/*
2 * gdbstub user-mode helper routines.
3 *
4 * We know for user-mode we are using TCG so we can call stuff directly.
5 *
9455762f 6 * Copyright (c) 2003-2005 Fabrice Bellard
ae7467b1
AB
7 * Copyright (c) 2022 Linaro Ltd
8 *
9455762f 9 * SPDX-License-Identifier: LGPL-2.0+
ae7467b1
AB
10 */
11
12#include "qemu/osdep.h"
d96bf49b
AB
13#include "qemu/cutils.h"
14#include "qemu/sockets.h"
15#include "exec/hwaddr.h"
16#include "exec/tb-flush.h"
ae7467b1 17#include "exec/gdbstub.h"
d96bf49b 18#include "gdbstub/user.h"
ae7467b1 19#include "hw/core/cpu.h"
d96bf49b 20#include "trace.h"
ae7467b1
AB
21#include "internals.h"
22
d96bf49b
AB
23/* User-mode specific state */
24typedef struct {
25 int fd;
26 char *socket_path;
27 int running_state;
28} GDBUserState;
29
30static GDBUserState gdbserver_user_state;
31
32int gdb_get_char(void)
33{
34 uint8_t ch;
35 int ret;
36
37 for (;;) {
38 ret = recv(gdbserver_user_state.fd, &ch, 1, 0);
39 if (ret < 0) {
40 if (errno == ECONNRESET) {
41 gdbserver_user_state.fd = -1;
42 }
43 if (errno != EINTR) {
44 return -1;
45 }
46 } else if (ret == 0) {
47 close(gdbserver_user_state.fd);
48 gdbserver_user_state.fd = -1;
49 return -1;
50 } else {
51 break;
52 }
53 }
54 return ch;
55}
56
57void gdb_put_buffer(const uint8_t *buf, int len)
58{
59 int ret;
60
61 while (len > 0) {
62 ret = send(gdbserver_user_state.fd, buf, len, 0);
63 if (ret < 0) {
64 if (errno != EINTR) {
65 return;
66 }
67 } else {
68 buf += ret;
69 len -= ret;
70 }
71 }
72}
73
74/* Tell the remote gdb that the process has exited. */
75void gdb_exit(int code)
76{
77 char buf[4];
78
79 if (!gdbserver_state.init) {
80 return;
81 }
82 if (gdbserver_user_state.socket_path) {
83 unlink(gdbserver_user_state.socket_path);
84 }
85 if (gdbserver_user_state.fd < 0) {
86 return;
87 }
88
89 trace_gdbstub_op_exiting((uint8_t)code);
90
91 snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
92 gdb_put_packet(buf);
93}
94
95int gdb_handlesig(CPUState *cpu, int sig)
96{
97 char buf[256];
98 int n;
99
100 if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
101 return sig;
102 }
103
104 /* disable single step if it was enabled */
105 cpu_single_step(cpu, 0);
106 tb_flush(cpu);
107
108 if (sig != 0) {
109 gdb_set_stop_cpu(cpu);
110 g_string_printf(gdbserver_state.str_buf,
111 "T%02xthread:", gdb_target_signal_to_gdb(sig));
112 gdb_append_thread_id(cpu, gdbserver_state.str_buf);
113 g_string_append_c(gdbserver_state.str_buf, ';');
114 gdb_put_strbuf();
115 }
116 /*
117 * gdb_put_packet() might have detected that the peer terminated the
118 * connection.
119 */
120 if (gdbserver_user_state.fd < 0) {
121 return sig;
122 }
123
124 sig = 0;
125 gdbserver_state.state = RS_IDLE;
126 gdbserver_user_state.running_state = 0;
127 while (gdbserver_user_state.running_state == 0) {
128 n = read(gdbserver_user_state.fd, buf, 256);
129 if (n > 0) {
130 int i;
131
132 for (i = 0; i < n; i++) {
133 gdb_read_byte(buf[i]);
134 }
135 } else {
136 /*
137 * XXX: Connection closed. Should probably wait for another
138 * connection before continuing.
139 */
140 if (n == 0) {
141 close(gdbserver_user_state.fd);
142 }
143 gdbserver_user_state.fd = -1;
144 return sig;
145 }
146 }
147 sig = gdbserver_state.signal;
148 gdbserver_state.signal = 0;
149 return sig;
150}
151
152/* Tell the remote gdb that the process has exited due to SIG. */
153void gdb_signalled(CPUArchState *env, int sig)
154{
155 char buf[4];
156
157 if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
158 return;
159 }
160
161 snprintf(buf, sizeof(buf), "X%02x", gdb_target_signal_to_gdb(sig));
162 gdb_put_packet(buf);
163}
164
165static void gdb_accept_init(int fd)
166{
167 gdb_init_gdbserver_state();
168 gdb_create_default_process(&gdbserver_state);
169 gdbserver_state.processes[0].attached = true;
170 gdbserver_state.c_cpu = gdb_first_attached_cpu();
171 gdbserver_state.g_cpu = gdbserver_state.c_cpu;
172 gdbserver_user_state.fd = fd;
173 gdb_has_xml = false;
174}
175
176static bool gdb_accept_socket(int gdb_fd)
177{
178 int fd;
179
180 for (;;) {
181 fd = accept(gdb_fd, NULL, NULL);
182 if (fd < 0 && errno != EINTR) {
183 perror("accept socket");
184 return false;
185 } else if (fd >= 0) {
186 qemu_set_cloexec(fd);
187 break;
188 }
189 }
190
191 gdb_accept_init(fd);
192 return true;
193}
194
195static int gdbserver_open_socket(const char *path)
196{
197 struct sockaddr_un sockaddr = {};
198 int fd, ret;
199
200 fd = socket(AF_UNIX, SOCK_STREAM, 0);
201 if (fd < 0) {
202 perror("create socket");
203 return -1;
204 }
205
206 sockaddr.sun_family = AF_UNIX;
207 pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path);
208 ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
209 if (ret < 0) {
210 perror("bind socket");
211 close(fd);
212 return -1;
213 }
214 ret = listen(fd, 1);
215 if (ret < 0) {
216 perror("listen socket");
217 close(fd);
218 return -1;
219 }
220
221 return fd;
222}
223
224static bool gdb_accept_tcp(int gdb_fd)
225{
226 struct sockaddr_in sockaddr = {};
227 socklen_t len;
228 int fd;
229
230 for (;;) {
231 len = sizeof(sockaddr);
232 fd = accept(gdb_fd, (struct sockaddr *)&sockaddr, &len);
233 if (fd < 0 && errno != EINTR) {
234 perror("accept");
235 return false;
236 } else if (fd >= 0) {
237 qemu_set_cloexec(fd);
238 break;
239 }
240 }
241
242 /* set short latency */
243 if (socket_set_nodelay(fd)) {
244 perror("setsockopt");
245 close(fd);
246 return false;
247 }
248
249 gdb_accept_init(fd);
250 return true;
251}
252
253static int gdbserver_open_port(int port)
254{
255 struct sockaddr_in sockaddr;
256 int fd, ret;
257
258 fd = socket(PF_INET, SOCK_STREAM, 0);
259 if (fd < 0) {
260 perror("socket");
261 return -1;
262 }
263 qemu_set_cloexec(fd);
264
265 socket_set_fast_reuse(fd);
266
267 sockaddr.sin_family = AF_INET;
268 sockaddr.sin_port = htons(port);
269 sockaddr.sin_addr.s_addr = 0;
270 ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
271 if (ret < 0) {
272 perror("bind");
273 close(fd);
274 return -1;
275 }
276 ret = listen(fd, 1);
277 if (ret < 0) {
278 perror("listen");
279 close(fd);
280 return -1;
281 }
282
283 return fd;
284}
285
286int gdbserver_start(const char *port_or_path)
287{
288 int port = g_ascii_strtoull(port_or_path, NULL, 10);
289 int gdb_fd;
290
291 if (port > 0) {
292 gdb_fd = gdbserver_open_port(port);
293 } else {
294 gdb_fd = gdbserver_open_socket(port_or_path);
295 }
296
297 if (gdb_fd < 0) {
298 return -1;
299 }
300
301 if (port > 0 && gdb_accept_tcp(gdb_fd)) {
302 return 0;
303 } else if (gdb_accept_socket(gdb_fd)) {
304 gdbserver_user_state.socket_path = g_strdup(port_or_path);
305 return 0;
306 }
307
308 /* gone wrong */
309 close(gdb_fd);
310 return -1;
311}
312
313/* Disable gdb stub for child processes. */
314void gdbserver_fork(CPUState *cpu)
315{
316 if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
317 return;
318 }
319 close(gdbserver_user_state.fd);
320 gdbserver_user_state.fd = -1;
321 cpu_breakpoint_remove_all(cpu, BP_GDB);
322 /* no cpu_watchpoint_remove_all for user-mode */
323}
324
325/*
326 * Execution state helpers
327 */
328
329void gdb_continue(void)
330{
331 gdbserver_user_state.running_state = 1;
332 trace_gdbstub_op_continue();
333}
334
335/*
336 * Resume execution, for user-mode emulation it's equivalent to
337 * gdb_continue.
338 */
339int gdb_continue_partial(char *newstates)
340{
341 CPUState *cpu;
342 int res = 0;
343 /*
344 * This is not exactly accurate, but it's an improvement compared to the
345 * previous situation, where only one CPU would be single-stepped.
346 */
347 CPU_FOREACH(cpu) {
348 if (newstates[cpu->cpu_index] == 's') {
349 trace_gdbstub_op_stepping(cpu->cpu_index);
350 cpu_single_step(cpu, gdbserver_state.sstep_flags);
351 }
352 }
353 gdbserver_user_state.running_state = 1;
354 return res;
355}
356
357/*
358 * Break/Watch point helpers
359 */
360
a48e7d9e
AB
361bool gdb_supports_guest_debug(void)
362{
363 /* user-mode == TCG == supported */
364 return true;
365}
366
55b5b8e9 367int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len)
ae7467b1
AB
368{
369 CPUState *cpu;
370 int err = 0;
371
372 switch (type) {
373 case GDB_BREAKPOINT_SW:
374 case GDB_BREAKPOINT_HW:
375 CPU_FOREACH(cpu) {
376 err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL);
377 if (err) {
378 break;
379 }
380 }
381 return err;
382 default:
383 /* user-mode doesn't support watchpoints */
384 return -ENOSYS;
385 }
386}
387
55b5b8e9 388int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len)
ae7467b1
AB
389{
390 CPUState *cpu;
391 int err = 0;
392
393 switch (type) {
394 case GDB_BREAKPOINT_SW:
395 case GDB_BREAKPOINT_HW:
396 CPU_FOREACH(cpu) {
397 err = cpu_breakpoint_remove(cpu, addr, BP_GDB);
398 if (err) {
399 break;
400 }
401 }
402 return err;
403 default:
404 /* user-mode doesn't support watchpoints */
405 return -ENOSYS;
406 }
407}
408
409void gdb_breakpoint_remove_all(CPUState *cs)
410{
411 cpu_breakpoint_remove_all(cs, BP_GDB);
412}