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