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