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