1842b42dfSAlex Bennée /* 2842b42dfSAlex Bennée * gdb server stub 3842b42dfSAlex Bennée * 4842b42dfSAlex Bennée * This implements a subset of the remote protocol as described in: 5842b42dfSAlex Bennée * 6842b42dfSAlex Bennée * https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html 7842b42dfSAlex Bennée * 8842b42dfSAlex Bennée * Copyright (c) 2003-2005 Fabrice Bellard 9842b42dfSAlex Bennée * 10842b42dfSAlex Bennée * This library is free software; you can redistribute it and/or 11842b42dfSAlex Bennée * modify it under the terms of the GNU Lesser General Public 12842b42dfSAlex Bennée * License as published by the Free Software Foundation; either 13842b42dfSAlex Bennée * version 2 of the License, or (at your option) any later version. 14842b42dfSAlex Bennée * 15842b42dfSAlex Bennée * This library is distributed in the hope that it will be useful, 16842b42dfSAlex Bennée * but WITHOUT ANY WARRANTY; without even the implied warranty of 17842b42dfSAlex Bennée * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18842b42dfSAlex Bennée * Lesser General Public License for more details. 19842b42dfSAlex Bennée * 20842b42dfSAlex Bennée * You should have received a copy of the GNU Lesser General Public 21842b42dfSAlex Bennée * License along with this library; if not, see <http://www.gnu.org/licenses/>. 22842b42dfSAlex Bennée * 23842b42dfSAlex Bennée * SPDX-License-Identifier: LGPL-2.0+ 24842b42dfSAlex Bennée */ 25842b42dfSAlex Bennée 26842b42dfSAlex Bennée #include "qemu/osdep.h" 27842b42dfSAlex Bennée #include "qemu/ctype.h" 28842b42dfSAlex Bennée #include "qemu/cutils.h" 29842b42dfSAlex Bennée #include "qemu/module.h" 30cc37d98bSRichard Henderson #include "qemu/error-report.h" 31842b42dfSAlex Bennée #include "trace.h" 32842b42dfSAlex Bennée #include "exec/gdbstub.h" 33c566080cSAlex Bennée #include "gdbstub/syscalls.h" 34842b42dfSAlex Bennée #ifdef CONFIG_USER_ONLY 35d96bf49bSAlex Bennée #include "gdbstub/user.h" 36842b42dfSAlex Bennée #else 37842b42dfSAlex Bennée #include "hw/cpu/cluster.h" 38842b42dfSAlex Bennée #include "hw/boards.h" 39842b42dfSAlex Bennée #endif 40842b42dfSAlex Bennée 41842b42dfSAlex Bennée #include "sysemu/hw_accel.h" 42842b42dfSAlex Bennée #include "sysemu/runstate.h" 435b5968c4SPhilippe Mathieu-Daudé #include "exec/replay-core.h" 44548c9609SAlex Bennée #include "exec/hwaddr.h" 45842b42dfSAlex Bennée 46ae7467b1SAlex Bennée #include "internals.h" 47ae7467b1SAlex Bennée 48842b42dfSAlex Bennée typedef struct GDBRegisterState { 49842b42dfSAlex Bennée int base_reg; 50842b42dfSAlex Bennée int num_regs; 51842b42dfSAlex Bennée gdb_get_reg_cb get_reg; 52842b42dfSAlex Bennée gdb_set_reg_cb set_reg; 53842b42dfSAlex Bennée const char *xml; 54842b42dfSAlex Bennée struct GDBRegisterState *next; 55842b42dfSAlex Bennée } GDBRegisterState; 56842b42dfSAlex Bennée 57b6fa2ec2SAlex Bennée GDBState gdbserver_state; 58842b42dfSAlex Bennée 5936e067b2SAlex Bennée void gdb_init_gdbserver_state(void) 60842b42dfSAlex Bennée { 61842b42dfSAlex Bennée g_assert(!gdbserver_state.init); 62842b42dfSAlex Bennée memset(&gdbserver_state, 0, sizeof(GDBState)); 63842b42dfSAlex Bennée gdbserver_state.init = true; 64842b42dfSAlex Bennée gdbserver_state.str_buf = g_string_new(NULL); 65842b42dfSAlex Bennée gdbserver_state.mem_buf = g_byte_array_sized_new(MAX_PACKET_LENGTH); 66842b42dfSAlex Bennée gdbserver_state.last_packet = g_byte_array_sized_new(MAX_PACKET_LENGTH + 4); 67842b42dfSAlex Bennée 68842b42dfSAlex Bennée /* 693b7a9388SAlex Bennée * What single-step modes are supported is accelerator dependent. 703b7a9388SAlex Bennée * By default try to use no IRQs and no timers while single 713b7a9388SAlex Bennée * stepping so as to make single stepping like a typical ICE HW step. 72842b42dfSAlex Bennée */ 733b7a9388SAlex Bennée gdbserver_state.supported_sstep_flags = accel_supported_gdbstub_sstep_flags(); 74842b42dfSAlex Bennée gdbserver_state.sstep_flags = SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER; 75842b42dfSAlex Bennée gdbserver_state.sstep_flags &= gdbserver_state.supported_sstep_flags; 76842b42dfSAlex Bennée } 77842b42dfSAlex Bennée 78842b42dfSAlex Bennée bool gdb_has_xml; 79842b42dfSAlex Bennée 80842b42dfSAlex Bennée /* writes 2*len+1 bytes in buf */ 8136e067b2SAlex Bennée void gdb_memtohex(GString *buf, const uint8_t *mem, int len) 82842b42dfSAlex Bennée { 83842b42dfSAlex Bennée int i, c; 84842b42dfSAlex Bennée for(i = 0; i < len; i++) { 85842b42dfSAlex Bennée c = mem[i]; 86842b42dfSAlex Bennée g_string_append_c(buf, tohex(c >> 4)); 87842b42dfSAlex Bennée g_string_append_c(buf, tohex(c & 0xf)); 88842b42dfSAlex Bennée } 89842b42dfSAlex Bennée g_string_append_c(buf, '\0'); 90842b42dfSAlex Bennée } 91842b42dfSAlex Bennée 9236e067b2SAlex Bennée void gdb_hextomem(GByteArray *mem, const char *buf, int len) 93842b42dfSAlex Bennée { 94842b42dfSAlex Bennée int i; 95842b42dfSAlex Bennée 96842b42dfSAlex Bennée for(i = 0; i < len; i++) { 97842b42dfSAlex Bennée guint8 byte = fromhex(buf[0]) << 4 | fromhex(buf[1]); 98842b42dfSAlex Bennée g_byte_array_append(mem, &byte, 1); 99842b42dfSAlex Bennée buf += 2; 100842b42dfSAlex Bennée } 101842b42dfSAlex Bennée } 102842b42dfSAlex Bennée 103842b42dfSAlex Bennée static void hexdump(const char *buf, int len, 104842b42dfSAlex Bennée void (*trace_fn)(size_t ofs, char const *text)) 105842b42dfSAlex Bennée { 106842b42dfSAlex Bennée char line_buffer[3 * 16 + 4 + 16 + 1]; 107842b42dfSAlex Bennée 108842b42dfSAlex Bennée size_t i; 109842b42dfSAlex Bennée for (i = 0; i < len || (i & 0xF); ++i) { 110842b42dfSAlex Bennée size_t byte_ofs = i & 15; 111842b42dfSAlex Bennée 112842b42dfSAlex Bennée if (byte_ofs == 0) { 113842b42dfSAlex Bennée memset(line_buffer, ' ', 3 * 16 + 4 + 16); 114842b42dfSAlex Bennée line_buffer[3 * 16 + 4 + 16] = 0; 115842b42dfSAlex Bennée } 116842b42dfSAlex Bennée 117842b42dfSAlex Bennée size_t col_group = (i >> 2) & 3; 118842b42dfSAlex Bennée size_t hex_col = byte_ofs * 3 + col_group; 119842b42dfSAlex Bennée size_t txt_col = 3 * 16 + 4 + byte_ofs; 120842b42dfSAlex Bennée 121842b42dfSAlex Bennée if (i < len) { 122842b42dfSAlex Bennée char value = buf[i]; 123842b42dfSAlex Bennée 124842b42dfSAlex Bennée line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF); 125842b42dfSAlex Bennée line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF); 126842b42dfSAlex Bennée line_buffer[txt_col + 0] = (value >= ' ' && value < 127) 127842b42dfSAlex Bennée ? value 128842b42dfSAlex Bennée : '.'; 129842b42dfSAlex Bennée } 130842b42dfSAlex Bennée 131842b42dfSAlex Bennée if (byte_ofs == 0xF) 132842b42dfSAlex Bennée trace_fn(i & -16, line_buffer); 133842b42dfSAlex Bennée } 134842b42dfSAlex Bennée } 135842b42dfSAlex Bennée 136842b42dfSAlex Bennée /* return -1 if error, 0 if OK */ 13736e067b2SAlex Bennée int gdb_put_packet_binary(const char *buf, int len, bool dump) 138842b42dfSAlex Bennée { 139842b42dfSAlex Bennée int csum, i; 140842b42dfSAlex Bennée uint8_t footer[3]; 141842b42dfSAlex Bennée 142842b42dfSAlex Bennée if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) { 143842b42dfSAlex Bennée hexdump(buf, len, trace_gdbstub_io_binaryreply); 144842b42dfSAlex Bennée } 145842b42dfSAlex Bennée 146842b42dfSAlex Bennée for(;;) { 147842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.last_packet, 0); 148842b42dfSAlex Bennée g_byte_array_append(gdbserver_state.last_packet, 149842b42dfSAlex Bennée (const uint8_t *) "$", 1); 150842b42dfSAlex Bennée g_byte_array_append(gdbserver_state.last_packet, 151842b42dfSAlex Bennée (const uint8_t *) buf, len); 152842b42dfSAlex Bennée csum = 0; 153842b42dfSAlex Bennée for(i = 0; i < len; i++) { 154842b42dfSAlex Bennée csum += buf[i]; 155842b42dfSAlex Bennée } 156842b42dfSAlex Bennée footer[0] = '#'; 157842b42dfSAlex Bennée footer[1] = tohex((csum >> 4) & 0xf); 158842b42dfSAlex Bennée footer[2] = tohex((csum) & 0xf); 159842b42dfSAlex Bennée g_byte_array_append(gdbserver_state.last_packet, footer, 3); 160842b42dfSAlex Bennée 16136e067b2SAlex Bennée gdb_put_buffer(gdbserver_state.last_packet->data, 162842b42dfSAlex Bennée gdbserver_state.last_packet->len); 163842b42dfSAlex Bennée 164a7e0f9bdSAlex Bennée if (gdb_got_immediate_ack()) { 165842b42dfSAlex Bennée break; 166a7e0f9bdSAlex Bennée } 167842b42dfSAlex Bennée } 168842b42dfSAlex Bennée return 0; 169842b42dfSAlex Bennée } 170842b42dfSAlex Bennée 171842b42dfSAlex Bennée /* return -1 if error, 0 if OK */ 17236e067b2SAlex Bennée int gdb_put_packet(const char *buf) 173842b42dfSAlex Bennée { 174842b42dfSAlex Bennée trace_gdbstub_io_reply(buf); 175842b42dfSAlex Bennée 17636e067b2SAlex Bennée return gdb_put_packet_binary(buf, strlen(buf), false); 177842b42dfSAlex Bennée } 178842b42dfSAlex Bennée 17936e067b2SAlex Bennée void gdb_put_strbuf(void) 180842b42dfSAlex Bennée { 18136e067b2SAlex Bennée gdb_put_packet(gdbserver_state.str_buf->str); 182842b42dfSAlex Bennée } 183842b42dfSAlex Bennée 184842b42dfSAlex Bennée /* Encode data using the encoding for 'x' packets. */ 18536e067b2SAlex Bennée void gdb_memtox(GString *buf, const char *mem, int len) 186842b42dfSAlex Bennée { 187842b42dfSAlex Bennée char c; 188842b42dfSAlex Bennée 189842b42dfSAlex Bennée while (len--) { 190842b42dfSAlex Bennée c = *(mem++); 191842b42dfSAlex Bennée switch (c) { 192842b42dfSAlex Bennée case '#': case '$': case '*': case '}': 193842b42dfSAlex Bennée g_string_append_c(buf, '}'); 194842b42dfSAlex Bennée g_string_append_c(buf, c ^ 0x20); 195842b42dfSAlex Bennée break; 196842b42dfSAlex Bennée default: 197842b42dfSAlex Bennée g_string_append_c(buf, c); 198842b42dfSAlex Bennée break; 199842b42dfSAlex Bennée } 200842b42dfSAlex Bennée } 201842b42dfSAlex Bennée } 202842b42dfSAlex Bennée 203842b42dfSAlex Bennée static uint32_t gdb_get_cpu_pid(CPUState *cpu) 204842b42dfSAlex Bennée { 205842b42dfSAlex Bennée /* TODO: In user mode, we should use the task state PID */ 206842b42dfSAlex Bennée if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) { 207842b42dfSAlex Bennée /* Return the default process' PID */ 208842b42dfSAlex Bennée int index = gdbserver_state.process_num - 1; 209842b42dfSAlex Bennée return gdbserver_state.processes[index].pid; 210842b42dfSAlex Bennée } 211842b42dfSAlex Bennée return cpu->cluster_index + 1; 212842b42dfSAlex Bennée } 213842b42dfSAlex Bennée 214a3fcc111SIlya Leoshkevich GDBProcess *gdb_get_process(uint32_t pid) 215842b42dfSAlex Bennée { 216842b42dfSAlex Bennée int i; 217842b42dfSAlex Bennée 218842b42dfSAlex Bennée if (!pid) { 219842b42dfSAlex Bennée /* 0 means any process, we take the first one */ 220842b42dfSAlex Bennée return &gdbserver_state.processes[0]; 221842b42dfSAlex Bennée } 222842b42dfSAlex Bennée 223842b42dfSAlex Bennée for (i = 0; i < gdbserver_state.process_num; i++) { 224842b42dfSAlex Bennée if (gdbserver_state.processes[i].pid == pid) { 225842b42dfSAlex Bennée return &gdbserver_state.processes[i]; 226842b42dfSAlex Bennée } 227842b42dfSAlex Bennée } 228842b42dfSAlex Bennée 229842b42dfSAlex Bennée return NULL; 230842b42dfSAlex Bennée } 231842b42dfSAlex Bennée 232842b42dfSAlex Bennée static GDBProcess *gdb_get_cpu_process(CPUState *cpu) 233842b42dfSAlex Bennée { 234842b42dfSAlex Bennée return gdb_get_process(gdb_get_cpu_pid(cpu)); 235842b42dfSAlex Bennée } 236842b42dfSAlex Bennée 237842b42dfSAlex Bennée static CPUState *find_cpu(uint32_t thread_id) 238842b42dfSAlex Bennée { 239842b42dfSAlex Bennée CPUState *cpu; 240842b42dfSAlex Bennée 241842b42dfSAlex Bennée CPU_FOREACH(cpu) { 24236e067b2SAlex Bennée if (gdb_get_cpu_index(cpu) == thread_id) { 243842b42dfSAlex Bennée return cpu; 244842b42dfSAlex Bennée } 245842b42dfSAlex Bennée } 246842b42dfSAlex Bennée 247842b42dfSAlex Bennée return NULL; 248842b42dfSAlex Bennée } 249842b42dfSAlex Bennée 250a3fcc111SIlya Leoshkevich CPUState *gdb_get_first_cpu_in_process(GDBProcess *process) 251842b42dfSAlex Bennée { 252842b42dfSAlex Bennée CPUState *cpu; 253842b42dfSAlex Bennée 254842b42dfSAlex Bennée CPU_FOREACH(cpu) { 255842b42dfSAlex Bennée if (gdb_get_cpu_pid(cpu) == process->pid) { 256842b42dfSAlex Bennée return cpu; 257842b42dfSAlex Bennée } 258842b42dfSAlex Bennée } 259842b42dfSAlex Bennée 260842b42dfSAlex Bennée return NULL; 261842b42dfSAlex Bennée } 262842b42dfSAlex Bennée 263842b42dfSAlex Bennée static CPUState *gdb_next_cpu_in_process(CPUState *cpu) 264842b42dfSAlex Bennée { 265842b42dfSAlex Bennée uint32_t pid = gdb_get_cpu_pid(cpu); 266842b42dfSAlex Bennée cpu = CPU_NEXT(cpu); 267842b42dfSAlex Bennée 268842b42dfSAlex Bennée while (cpu) { 269842b42dfSAlex Bennée if (gdb_get_cpu_pid(cpu) == pid) { 270842b42dfSAlex Bennée break; 271842b42dfSAlex Bennée } 272842b42dfSAlex Bennée 273842b42dfSAlex Bennée cpu = CPU_NEXT(cpu); 274842b42dfSAlex Bennée } 275842b42dfSAlex Bennée 276842b42dfSAlex Bennée return cpu; 277842b42dfSAlex Bennée } 278842b42dfSAlex Bennée 279842b42dfSAlex Bennée /* Return the cpu following @cpu, while ignoring unattached processes. */ 280842b42dfSAlex Bennée static CPUState *gdb_next_attached_cpu(CPUState *cpu) 281842b42dfSAlex Bennée { 282842b42dfSAlex Bennée cpu = CPU_NEXT(cpu); 283842b42dfSAlex Bennée 284842b42dfSAlex Bennée while (cpu) { 285842b42dfSAlex Bennée if (gdb_get_cpu_process(cpu)->attached) { 286842b42dfSAlex Bennée break; 287842b42dfSAlex Bennée } 288842b42dfSAlex Bennée 289842b42dfSAlex Bennée cpu = CPU_NEXT(cpu); 290842b42dfSAlex Bennée } 291842b42dfSAlex Bennée 292842b42dfSAlex Bennée return cpu; 293842b42dfSAlex Bennée } 294842b42dfSAlex Bennée 295842b42dfSAlex Bennée /* Return the first attached cpu */ 29636e067b2SAlex Bennée CPUState *gdb_first_attached_cpu(void) 297842b42dfSAlex Bennée { 298842b42dfSAlex Bennée CPUState *cpu = first_cpu; 299842b42dfSAlex Bennée GDBProcess *process = gdb_get_cpu_process(cpu); 300842b42dfSAlex Bennée 301842b42dfSAlex Bennée if (!process->attached) { 302842b42dfSAlex Bennée return gdb_next_attached_cpu(cpu); 303842b42dfSAlex Bennée } 304842b42dfSAlex Bennée 305842b42dfSAlex Bennée return cpu; 306842b42dfSAlex Bennée } 307842b42dfSAlex Bennée 308842b42dfSAlex Bennée static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid) 309842b42dfSAlex Bennée { 310842b42dfSAlex Bennée GDBProcess *process; 311842b42dfSAlex Bennée CPUState *cpu; 312842b42dfSAlex Bennée 313842b42dfSAlex Bennée if (!pid && !tid) { 314842b42dfSAlex Bennée /* 0 means any process/thread, we take the first attached one */ 315842b42dfSAlex Bennée return gdb_first_attached_cpu(); 316842b42dfSAlex Bennée } else if (pid && !tid) { 317842b42dfSAlex Bennée /* any thread in a specific process */ 318842b42dfSAlex Bennée process = gdb_get_process(pid); 319842b42dfSAlex Bennée 320842b42dfSAlex Bennée if (process == NULL) { 321842b42dfSAlex Bennée return NULL; 322842b42dfSAlex Bennée } 323842b42dfSAlex Bennée 324842b42dfSAlex Bennée if (!process->attached) { 325842b42dfSAlex Bennée return NULL; 326842b42dfSAlex Bennée } 327842b42dfSAlex Bennée 328a3fcc111SIlya Leoshkevich return gdb_get_first_cpu_in_process(process); 329842b42dfSAlex Bennée } else { 330842b42dfSAlex Bennée /* a specific thread */ 331842b42dfSAlex Bennée cpu = find_cpu(tid); 332842b42dfSAlex Bennée 333842b42dfSAlex Bennée if (cpu == NULL) { 334842b42dfSAlex Bennée return NULL; 335842b42dfSAlex Bennée } 336842b42dfSAlex Bennée 337842b42dfSAlex Bennée process = gdb_get_cpu_process(cpu); 338842b42dfSAlex Bennée 339842b42dfSAlex Bennée if (pid && process->pid != pid) { 340842b42dfSAlex Bennée return NULL; 341842b42dfSAlex Bennée } 342842b42dfSAlex Bennée 343842b42dfSAlex Bennée if (!process->attached) { 344842b42dfSAlex Bennée return NULL; 345842b42dfSAlex Bennée } 346842b42dfSAlex Bennée 347842b42dfSAlex Bennée return cpu; 348842b42dfSAlex Bennée } 349842b42dfSAlex Bennée } 350842b42dfSAlex Bennée 351842b42dfSAlex Bennée static const char *get_feature_xml(const char *p, const char **newp, 352842b42dfSAlex Bennée GDBProcess *process) 353842b42dfSAlex Bennée { 354842b42dfSAlex Bennée size_t len; 355842b42dfSAlex Bennée int i; 356842b42dfSAlex Bennée const char *name; 357a3fcc111SIlya Leoshkevich CPUState *cpu = gdb_get_first_cpu_in_process(process); 358842b42dfSAlex Bennée CPUClass *cc = CPU_GET_CLASS(cpu); 359842b42dfSAlex Bennée 360842b42dfSAlex Bennée len = 0; 361842b42dfSAlex Bennée while (p[len] && p[len] != ':') 362842b42dfSAlex Bennée len++; 363842b42dfSAlex Bennée *newp = p + len; 364842b42dfSAlex Bennée 365842b42dfSAlex Bennée name = NULL; 366842b42dfSAlex Bennée if (strncmp(p, "target.xml", len) == 0) { 367842b42dfSAlex Bennée char *buf = process->target_xml; 368842b42dfSAlex Bennée const size_t buf_sz = sizeof(process->target_xml); 369842b42dfSAlex Bennée 370842b42dfSAlex Bennée /* Generate the XML description for this CPU. */ 371842b42dfSAlex Bennée if (!buf[0]) { 372842b42dfSAlex Bennée GDBRegisterState *r; 373842b42dfSAlex Bennée 374842b42dfSAlex Bennée pstrcat(buf, buf_sz, 375842b42dfSAlex Bennée "<?xml version=\"1.0\"?>" 376842b42dfSAlex Bennée "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">" 377842b42dfSAlex Bennée "<target>"); 378842b42dfSAlex Bennée if (cc->gdb_arch_name) { 379842b42dfSAlex Bennée gchar *arch = cc->gdb_arch_name(cpu); 380842b42dfSAlex Bennée pstrcat(buf, buf_sz, "<architecture>"); 381842b42dfSAlex Bennée pstrcat(buf, buf_sz, arch); 382842b42dfSAlex Bennée pstrcat(buf, buf_sz, "</architecture>"); 383842b42dfSAlex Bennée g_free(arch); 384842b42dfSAlex Bennée } 385842b42dfSAlex Bennée pstrcat(buf, buf_sz, "<xi:include href=\""); 386842b42dfSAlex Bennée pstrcat(buf, buf_sz, cc->gdb_core_xml_file); 387842b42dfSAlex Bennée pstrcat(buf, buf_sz, "\"/>"); 388842b42dfSAlex Bennée for (r = cpu->gdb_regs; r; r = r->next) { 389842b42dfSAlex Bennée pstrcat(buf, buf_sz, "<xi:include href=\""); 390842b42dfSAlex Bennée pstrcat(buf, buf_sz, r->xml); 391842b42dfSAlex Bennée pstrcat(buf, buf_sz, "\"/>"); 392842b42dfSAlex Bennée } 393842b42dfSAlex Bennée pstrcat(buf, buf_sz, "</target>"); 394842b42dfSAlex Bennée } 395842b42dfSAlex Bennée return buf; 396842b42dfSAlex Bennée } 397842b42dfSAlex Bennée if (cc->gdb_get_dynamic_xml) { 398842b42dfSAlex Bennée char *xmlname = g_strndup(p, len); 399842b42dfSAlex Bennée const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname); 400842b42dfSAlex Bennée 401842b42dfSAlex Bennée g_free(xmlname); 402842b42dfSAlex Bennée if (xml) { 403842b42dfSAlex Bennée return xml; 404842b42dfSAlex Bennée } 405842b42dfSAlex Bennée } 406842b42dfSAlex Bennée for (i = 0; ; i++) { 407842b42dfSAlex Bennée name = xml_builtin[i][0]; 408842b42dfSAlex Bennée if (!name || (strncmp(name, p, len) == 0 && strlen(name) == len)) 409842b42dfSAlex Bennée break; 410842b42dfSAlex Bennée } 411842b42dfSAlex Bennée return name ? xml_builtin[i][1] : NULL; 412842b42dfSAlex Bennée } 413842b42dfSAlex Bennée 414842b42dfSAlex Bennée static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) 415842b42dfSAlex Bennée { 416842b42dfSAlex Bennée CPUClass *cc = CPU_GET_CLASS(cpu); 417842b42dfSAlex Bennée CPUArchState *env = cpu->env_ptr; 418842b42dfSAlex Bennée GDBRegisterState *r; 419842b42dfSAlex Bennée 420842b42dfSAlex Bennée if (reg < cc->gdb_num_core_regs) { 421842b42dfSAlex Bennée return cc->gdb_read_register(cpu, buf, reg); 422842b42dfSAlex Bennée } 423842b42dfSAlex Bennée 424842b42dfSAlex Bennée for (r = cpu->gdb_regs; r; r = r->next) { 425842b42dfSAlex Bennée if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { 426842b42dfSAlex Bennée return r->get_reg(env, buf, reg - r->base_reg); 427842b42dfSAlex Bennée } 428842b42dfSAlex Bennée } 429842b42dfSAlex Bennée return 0; 430842b42dfSAlex Bennée } 431842b42dfSAlex Bennée 432842b42dfSAlex Bennée static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) 433842b42dfSAlex Bennée { 434842b42dfSAlex Bennée CPUClass *cc = CPU_GET_CLASS(cpu); 435842b42dfSAlex Bennée CPUArchState *env = cpu->env_ptr; 436842b42dfSAlex Bennée GDBRegisterState *r; 437842b42dfSAlex Bennée 438842b42dfSAlex Bennée if (reg < cc->gdb_num_core_regs) { 439842b42dfSAlex Bennée return cc->gdb_write_register(cpu, mem_buf, reg); 440842b42dfSAlex Bennée } 441842b42dfSAlex Bennée 442842b42dfSAlex Bennée for (r = cpu->gdb_regs; r; r = r->next) { 443842b42dfSAlex Bennée if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { 444842b42dfSAlex Bennée return r->set_reg(env, mem_buf, reg - r->base_reg); 445842b42dfSAlex Bennée } 446842b42dfSAlex Bennée } 447842b42dfSAlex Bennée return 0; 448842b42dfSAlex Bennée } 449842b42dfSAlex Bennée 450842b42dfSAlex Bennée /* Register a supplemental set of CPU registers. If g_pos is nonzero it 451842b42dfSAlex Bennée specifies the first register number and these registers are included in 452842b42dfSAlex Bennée a standard "g" packet. Direction is relative to gdb, i.e. get_reg is 453842b42dfSAlex Bennée gdb reading a CPU register, and set_reg is gdb modifying a CPU register. 454842b42dfSAlex Bennée */ 455842b42dfSAlex Bennée 456842b42dfSAlex Bennée void gdb_register_coprocessor(CPUState *cpu, 457842b42dfSAlex Bennée gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg, 458842b42dfSAlex Bennée int num_regs, const char *xml, int g_pos) 459842b42dfSAlex Bennée { 460842b42dfSAlex Bennée GDBRegisterState *s; 461842b42dfSAlex Bennée GDBRegisterState **p; 462842b42dfSAlex Bennée 463842b42dfSAlex Bennée p = &cpu->gdb_regs; 464842b42dfSAlex Bennée while (*p) { 465842b42dfSAlex Bennée /* Check for duplicates. */ 466842b42dfSAlex Bennée if (strcmp((*p)->xml, xml) == 0) 467842b42dfSAlex Bennée return; 468842b42dfSAlex Bennée p = &(*p)->next; 469842b42dfSAlex Bennée } 470842b42dfSAlex Bennée 471842b42dfSAlex Bennée s = g_new0(GDBRegisterState, 1); 472842b42dfSAlex Bennée s->base_reg = cpu->gdb_num_regs; 473842b42dfSAlex Bennée s->num_regs = num_regs; 474842b42dfSAlex Bennée s->get_reg = get_reg; 475842b42dfSAlex Bennée s->set_reg = set_reg; 476842b42dfSAlex Bennée s->xml = xml; 477842b42dfSAlex Bennée 478842b42dfSAlex Bennée /* Add to end of list. */ 479842b42dfSAlex Bennée cpu->gdb_num_regs += num_regs; 480842b42dfSAlex Bennée *p = s; 481842b42dfSAlex Bennée if (g_pos) { 482842b42dfSAlex Bennée if (g_pos != s->base_reg) { 483842b42dfSAlex Bennée error_report("Error: Bad gdb register numbering for '%s', " 484842b42dfSAlex Bennée "expected %d got %d", xml, g_pos, s->base_reg); 485842b42dfSAlex Bennée } else { 486842b42dfSAlex Bennée cpu->gdb_num_g_regs = cpu->gdb_num_regs; 487842b42dfSAlex Bennée } 488842b42dfSAlex Bennée } 489842b42dfSAlex Bennée } 490842b42dfSAlex Bennée 491842b42dfSAlex Bennée static void gdb_process_breakpoint_remove_all(GDBProcess *p) 492842b42dfSAlex Bennée { 493a3fcc111SIlya Leoshkevich CPUState *cpu = gdb_get_first_cpu_in_process(p); 494842b42dfSAlex Bennée 495842b42dfSAlex Bennée while (cpu) { 496ae7467b1SAlex Bennée gdb_breakpoint_remove_all(cpu); 497842b42dfSAlex Bennée cpu = gdb_next_cpu_in_process(cpu); 498842b42dfSAlex Bennée } 499842b42dfSAlex Bennée } 500842b42dfSAlex Bennée 501842b42dfSAlex Bennée 502b428ad12SAlex Bennée static void gdb_set_cpu_pc(vaddr pc) 503842b42dfSAlex Bennée { 504842b42dfSAlex Bennée CPUState *cpu = gdbserver_state.c_cpu; 505842b42dfSAlex Bennée 506842b42dfSAlex Bennée cpu_synchronize_state(cpu); 507842b42dfSAlex Bennée cpu_set_pc(cpu, pc); 508842b42dfSAlex Bennée } 509842b42dfSAlex Bennée 51036e067b2SAlex Bennée void gdb_append_thread_id(CPUState *cpu, GString *buf) 511842b42dfSAlex Bennée { 512842b42dfSAlex Bennée if (gdbserver_state.multiprocess) { 513842b42dfSAlex Bennée g_string_append_printf(buf, "p%02x.%02x", 51436e067b2SAlex Bennée gdb_get_cpu_pid(cpu), gdb_get_cpu_index(cpu)); 515842b42dfSAlex Bennée } else { 51636e067b2SAlex Bennée g_string_append_printf(buf, "%02x", gdb_get_cpu_index(cpu)); 517842b42dfSAlex Bennée } 518842b42dfSAlex Bennée } 519842b42dfSAlex Bennée 520842b42dfSAlex Bennée static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf, 521842b42dfSAlex Bennée uint32_t *pid, uint32_t *tid) 522842b42dfSAlex Bennée { 523842b42dfSAlex Bennée unsigned long p, t; 524842b42dfSAlex Bennée int ret; 525842b42dfSAlex Bennée 526842b42dfSAlex Bennée if (*buf == 'p') { 527842b42dfSAlex Bennée buf++; 528842b42dfSAlex Bennée ret = qemu_strtoul(buf, &buf, 16, &p); 529842b42dfSAlex Bennée 530842b42dfSAlex Bennée if (ret) { 531842b42dfSAlex Bennée return GDB_READ_THREAD_ERR; 532842b42dfSAlex Bennée } 533842b42dfSAlex Bennée 534842b42dfSAlex Bennée /* Skip '.' */ 535842b42dfSAlex Bennée buf++; 536842b42dfSAlex Bennée } else { 537842b42dfSAlex Bennée p = 1; 538842b42dfSAlex Bennée } 539842b42dfSAlex Bennée 540842b42dfSAlex Bennée ret = qemu_strtoul(buf, &buf, 16, &t); 541842b42dfSAlex Bennée 542842b42dfSAlex Bennée if (ret) { 543842b42dfSAlex Bennée return GDB_READ_THREAD_ERR; 544842b42dfSAlex Bennée } 545842b42dfSAlex Bennée 546842b42dfSAlex Bennée *end_buf = buf; 547842b42dfSAlex Bennée 548842b42dfSAlex Bennée if (p == -1) { 549842b42dfSAlex Bennée return GDB_ALL_PROCESSES; 550842b42dfSAlex Bennée } 551842b42dfSAlex Bennée 552842b42dfSAlex Bennée if (pid) { 553842b42dfSAlex Bennée *pid = p; 554842b42dfSAlex Bennée } 555842b42dfSAlex Bennée 556842b42dfSAlex Bennée if (t == -1) { 557842b42dfSAlex Bennée return GDB_ALL_THREADS; 558842b42dfSAlex Bennée } 559842b42dfSAlex Bennée 560842b42dfSAlex Bennée if (tid) { 561842b42dfSAlex Bennée *tid = t; 562842b42dfSAlex Bennée } 563842b42dfSAlex Bennée 564842b42dfSAlex Bennée return GDB_ONE_THREAD; 565842b42dfSAlex Bennée } 566842b42dfSAlex Bennée 567842b42dfSAlex Bennée /** 568842b42dfSAlex Bennée * gdb_handle_vcont - Parses and handles a vCont packet. 569842b42dfSAlex Bennée * returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is 570842b42dfSAlex Bennée * a format error, 0 on success. 571842b42dfSAlex Bennée */ 572842b42dfSAlex Bennée static int gdb_handle_vcont(const char *p) 573842b42dfSAlex Bennée { 574842b42dfSAlex Bennée int res, signal = 0; 575842b42dfSAlex Bennée char cur_action; 576842b42dfSAlex Bennée unsigned long tmp; 577842b42dfSAlex Bennée uint32_t pid, tid; 578842b42dfSAlex Bennée GDBProcess *process; 579842b42dfSAlex Bennée CPUState *cpu; 580842b42dfSAlex Bennée GDBThreadIdKind kind; 5817ea0c33dSAlex Bennée unsigned int max_cpus = gdb_get_max_cpus(); 582842b42dfSAlex Bennée /* uninitialised CPUs stay 0 */ 5832261b73cSAlex Bennée g_autofree char *newstates = g_new0(char, max_cpus); 584842b42dfSAlex Bennée 585842b42dfSAlex Bennée /* mark valid CPUs with 1 */ 586842b42dfSAlex Bennée CPU_FOREACH(cpu) { 587842b42dfSAlex Bennée newstates[cpu->cpu_index] = 1; 588842b42dfSAlex Bennée } 589842b42dfSAlex Bennée 590842b42dfSAlex Bennée /* 591842b42dfSAlex Bennée * res keeps track of what error we are returning, with -ENOTSUP meaning 592842b42dfSAlex Bennée * that the command is unknown or unsupported, thus returning an empty 593842b42dfSAlex Bennée * packet, while -EINVAL and -ERANGE cause an E22 packet, due to invalid, 594842b42dfSAlex Bennée * or incorrect parameters passed. 595842b42dfSAlex Bennée */ 596842b42dfSAlex Bennée res = 0; 597842b42dfSAlex Bennée while (*p) { 598842b42dfSAlex Bennée if (*p++ != ';') { 5992261b73cSAlex Bennée return -ENOTSUP; 600842b42dfSAlex Bennée } 601842b42dfSAlex Bennée 602842b42dfSAlex Bennée cur_action = *p++; 603842b42dfSAlex Bennée if (cur_action == 'C' || cur_action == 'S') { 604842b42dfSAlex Bennée cur_action = qemu_tolower(cur_action); 605842b42dfSAlex Bennée res = qemu_strtoul(p, &p, 16, &tmp); 606842b42dfSAlex Bennée if (res) { 6072261b73cSAlex Bennée return res; 608842b42dfSAlex Bennée } 609842b42dfSAlex Bennée signal = gdb_signal_to_target(tmp); 610842b42dfSAlex Bennée } else if (cur_action != 'c' && cur_action != 's') { 611842b42dfSAlex Bennée /* unknown/invalid/unsupported command */ 6122261b73cSAlex Bennée return -ENOTSUP; 613842b42dfSAlex Bennée } 614842b42dfSAlex Bennée 615842b42dfSAlex Bennée if (*p == '\0' || *p == ';') { 616842b42dfSAlex Bennée /* 617842b42dfSAlex Bennée * No thread specifier, action is on "all threads". The 618842b42dfSAlex Bennée * specification is unclear regarding the process to act on. We 619842b42dfSAlex Bennée * choose all processes. 620842b42dfSAlex Bennée */ 621842b42dfSAlex Bennée kind = GDB_ALL_PROCESSES; 622842b42dfSAlex Bennée } else if (*p++ == ':') { 623842b42dfSAlex Bennée kind = read_thread_id(p, &p, &pid, &tid); 624842b42dfSAlex Bennée } else { 6252261b73cSAlex Bennée return -ENOTSUP; 626842b42dfSAlex Bennée } 627842b42dfSAlex Bennée 628842b42dfSAlex Bennée switch (kind) { 629842b42dfSAlex Bennée case GDB_READ_THREAD_ERR: 6302261b73cSAlex Bennée return -EINVAL; 631842b42dfSAlex Bennée 632842b42dfSAlex Bennée case GDB_ALL_PROCESSES: 633842b42dfSAlex Bennée cpu = gdb_first_attached_cpu(); 634842b42dfSAlex Bennée while (cpu) { 635842b42dfSAlex Bennée if (newstates[cpu->cpu_index] == 1) { 636842b42dfSAlex Bennée newstates[cpu->cpu_index] = cur_action; 637842b42dfSAlex Bennée } 638842b42dfSAlex Bennée 639842b42dfSAlex Bennée cpu = gdb_next_attached_cpu(cpu); 640842b42dfSAlex Bennée } 641842b42dfSAlex Bennée break; 642842b42dfSAlex Bennée 643842b42dfSAlex Bennée case GDB_ALL_THREADS: 644842b42dfSAlex Bennée process = gdb_get_process(pid); 645842b42dfSAlex Bennée 646842b42dfSAlex Bennée if (!process->attached) { 6472261b73cSAlex Bennée return -EINVAL; 648842b42dfSAlex Bennée } 649842b42dfSAlex Bennée 650a3fcc111SIlya Leoshkevich cpu = gdb_get_first_cpu_in_process(process); 651842b42dfSAlex Bennée while (cpu) { 652842b42dfSAlex Bennée if (newstates[cpu->cpu_index] == 1) { 653842b42dfSAlex Bennée newstates[cpu->cpu_index] = cur_action; 654842b42dfSAlex Bennée } 655842b42dfSAlex Bennée 656842b42dfSAlex Bennée cpu = gdb_next_cpu_in_process(cpu); 657842b42dfSAlex Bennée } 658842b42dfSAlex Bennée break; 659842b42dfSAlex Bennée 660842b42dfSAlex Bennée case GDB_ONE_THREAD: 661842b42dfSAlex Bennée cpu = gdb_get_cpu(pid, tid); 662842b42dfSAlex Bennée 663842b42dfSAlex Bennée /* invalid CPU/thread specified */ 664842b42dfSAlex Bennée if (!cpu) { 6652261b73cSAlex Bennée return -EINVAL; 666842b42dfSAlex Bennée } 667842b42dfSAlex Bennée 668842b42dfSAlex Bennée /* only use if no previous match occourred */ 669842b42dfSAlex Bennée if (newstates[cpu->cpu_index] == 1) { 670842b42dfSAlex Bennée newstates[cpu->cpu_index] = cur_action; 671842b42dfSAlex Bennée } 672842b42dfSAlex Bennée break; 673842b42dfSAlex Bennée } 674842b42dfSAlex Bennée } 6752261b73cSAlex Bennée 676842b42dfSAlex Bennée gdbserver_state.signal = signal; 677842b42dfSAlex Bennée gdb_continue_partial(newstates); 678842b42dfSAlex Bennée return res; 679842b42dfSAlex Bennée } 680842b42dfSAlex Bennée 681842b42dfSAlex Bennée static const char *cmd_next_param(const char *param, const char delimiter) 682842b42dfSAlex Bennée { 683842b42dfSAlex Bennée static const char all_delimiters[] = ",;:="; 684842b42dfSAlex Bennée char curr_delimiters[2] = {0}; 685842b42dfSAlex Bennée const char *delimiters; 686842b42dfSAlex Bennée 687842b42dfSAlex Bennée if (delimiter == '?') { 688842b42dfSAlex Bennée delimiters = all_delimiters; 689842b42dfSAlex Bennée } else if (delimiter == '0') { 690842b42dfSAlex Bennée return strchr(param, '\0'); 691842b42dfSAlex Bennée } else if (delimiter == '.' && *param) { 692842b42dfSAlex Bennée return param + 1; 693842b42dfSAlex Bennée } else { 694842b42dfSAlex Bennée curr_delimiters[0] = delimiter; 695842b42dfSAlex Bennée delimiters = curr_delimiters; 696842b42dfSAlex Bennée } 697842b42dfSAlex Bennée 698842b42dfSAlex Bennée param += strcspn(param, delimiters); 699842b42dfSAlex Bennée if (*param) { 700842b42dfSAlex Bennée param++; 701842b42dfSAlex Bennée } 702842b42dfSAlex Bennée return param; 703842b42dfSAlex Bennée } 704842b42dfSAlex Bennée 705842b42dfSAlex Bennée static int cmd_parse_params(const char *data, const char *schema, 706842b42dfSAlex Bennée GArray *params) 707842b42dfSAlex Bennée { 708842b42dfSAlex Bennée const char *curr_schema, *curr_data; 709842b42dfSAlex Bennée 710842b42dfSAlex Bennée g_assert(schema); 711842b42dfSAlex Bennée g_assert(params->len == 0); 712842b42dfSAlex Bennée 713842b42dfSAlex Bennée curr_schema = schema; 714842b42dfSAlex Bennée curr_data = data; 715842b42dfSAlex Bennée while (curr_schema[0] && curr_schema[1] && *curr_data) { 716842b42dfSAlex Bennée GdbCmdVariant this_param; 717842b42dfSAlex Bennée 718842b42dfSAlex Bennée switch (curr_schema[0]) { 719842b42dfSAlex Bennée case 'l': 720842b42dfSAlex Bennée if (qemu_strtoul(curr_data, &curr_data, 16, 721842b42dfSAlex Bennée &this_param.val_ul)) { 722842b42dfSAlex Bennée return -EINVAL; 723842b42dfSAlex Bennée } 724842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]); 725842b42dfSAlex Bennée g_array_append_val(params, this_param); 726842b42dfSAlex Bennée break; 727842b42dfSAlex Bennée case 'L': 728842b42dfSAlex Bennée if (qemu_strtou64(curr_data, &curr_data, 16, 729842b42dfSAlex Bennée (uint64_t *)&this_param.val_ull)) { 730842b42dfSAlex Bennée return -EINVAL; 731842b42dfSAlex Bennée } 732842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]); 733842b42dfSAlex Bennée g_array_append_val(params, this_param); 734842b42dfSAlex Bennée break; 735842b42dfSAlex Bennée case 's': 736842b42dfSAlex Bennée this_param.data = curr_data; 737842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]); 738842b42dfSAlex Bennée g_array_append_val(params, this_param); 739842b42dfSAlex Bennée break; 740842b42dfSAlex Bennée case 'o': 741842b42dfSAlex Bennée this_param.opcode = *(uint8_t *)curr_data; 742842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]); 743842b42dfSAlex Bennée g_array_append_val(params, this_param); 744842b42dfSAlex Bennée break; 745842b42dfSAlex Bennée case 't': 746842b42dfSAlex Bennée this_param.thread_id.kind = 747842b42dfSAlex Bennée read_thread_id(curr_data, &curr_data, 748842b42dfSAlex Bennée &this_param.thread_id.pid, 749842b42dfSAlex Bennée &this_param.thread_id.tid); 750842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]); 751842b42dfSAlex Bennée g_array_append_val(params, this_param); 752842b42dfSAlex Bennée break; 753842b42dfSAlex Bennée case '?': 754842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]); 755842b42dfSAlex Bennée break; 756842b42dfSAlex Bennée default: 757842b42dfSAlex Bennée return -EINVAL; 758842b42dfSAlex Bennée } 759842b42dfSAlex Bennée curr_schema += 2; 760842b42dfSAlex Bennée } 761842b42dfSAlex Bennée 762842b42dfSAlex Bennée return 0; 763842b42dfSAlex Bennée } 764842b42dfSAlex Bennée 765842b42dfSAlex Bennée typedef void (*GdbCmdHandler)(GArray *params, void *user_ctx); 766842b42dfSAlex Bennée 767842b42dfSAlex Bennée /* 768842b42dfSAlex Bennée * cmd_startswith -> cmd is compared using startswith 769842b42dfSAlex Bennée * 77075837005SMatheus Tavares Bernardino * allow_stop_reply -> true iff the gdbstub can respond to this command with a 77175837005SMatheus Tavares Bernardino * "stop reply" packet. The list of commands that accept such response is 77275837005SMatheus Tavares Bernardino * defined at the GDB Remote Serial Protocol documentation. see: 77375837005SMatheus Tavares Bernardino * https://sourceware.org/gdb/onlinedocs/gdb/Stop-Reply-Packets.html#Stop-Reply-Packets. 774842b42dfSAlex Bennée * 775842b42dfSAlex Bennée * schema definitions: 776842b42dfSAlex Bennée * Each schema parameter entry consists of 2 chars, 777842b42dfSAlex Bennée * the first char represents the parameter type handling 778842b42dfSAlex Bennée * the second char represents the delimiter for the next parameter 779842b42dfSAlex Bennée * 780842b42dfSAlex Bennée * Currently supported schema types: 781842b42dfSAlex Bennée * 'l' -> unsigned long (stored in .val_ul) 782842b42dfSAlex Bennée * 'L' -> unsigned long long (stored in .val_ull) 783842b42dfSAlex Bennée * 's' -> string (stored in .data) 784842b42dfSAlex Bennée * 'o' -> single char (stored in .opcode) 785842b42dfSAlex Bennée * 't' -> thread id (stored in .thread_id) 786842b42dfSAlex Bennée * '?' -> skip according to delimiter 787842b42dfSAlex Bennée * 788842b42dfSAlex Bennée * Currently supported delimiters: 789842b42dfSAlex Bennée * '?' -> Stop at any delimiter (",;:=\0") 790842b42dfSAlex Bennée * '0' -> Stop at "\0" 791842b42dfSAlex Bennée * '.' -> Skip 1 char unless reached "\0" 792842b42dfSAlex Bennée * Any other value is treated as the delimiter value itself 793842b42dfSAlex Bennée */ 794842b42dfSAlex Bennée typedef struct GdbCmdParseEntry { 795842b42dfSAlex Bennée GdbCmdHandler handler; 796842b42dfSAlex Bennée const char *cmd; 797842b42dfSAlex Bennée bool cmd_startswith; 798842b42dfSAlex Bennée const char *schema; 79975837005SMatheus Tavares Bernardino bool allow_stop_reply; 800842b42dfSAlex Bennée } GdbCmdParseEntry; 801842b42dfSAlex Bennée 802842b42dfSAlex Bennée static inline int startswith(const char *string, const char *pattern) 803842b42dfSAlex Bennée { 804842b42dfSAlex Bennée return !strncmp(string, pattern, strlen(pattern)); 805842b42dfSAlex Bennée } 806842b42dfSAlex Bennée 807842b42dfSAlex Bennée static int process_string_cmd(void *user_ctx, const char *data, 808842b42dfSAlex Bennée const GdbCmdParseEntry *cmds, int num_cmds) 809842b42dfSAlex Bennée { 810842b42dfSAlex Bennée int i; 811842b42dfSAlex Bennée g_autoptr(GArray) params = g_array_new(false, true, sizeof(GdbCmdVariant)); 812842b42dfSAlex Bennée 813842b42dfSAlex Bennée if (!cmds) { 814842b42dfSAlex Bennée return -1; 815842b42dfSAlex Bennée } 816842b42dfSAlex Bennée 817842b42dfSAlex Bennée for (i = 0; i < num_cmds; i++) { 818842b42dfSAlex Bennée const GdbCmdParseEntry *cmd = &cmds[i]; 819842b42dfSAlex Bennée g_assert(cmd->handler && cmd->cmd); 820842b42dfSAlex Bennée 821842b42dfSAlex Bennée if ((cmd->cmd_startswith && !startswith(data, cmd->cmd)) || 822842b42dfSAlex Bennée (!cmd->cmd_startswith && strcmp(cmd->cmd, data))) { 823842b42dfSAlex Bennée continue; 824842b42dfSAlex Bennée } 825842b42dfSAlex Bennée 826842b42dfSAlex Bennée if (cmd->schema) { 827842b42dfSAlex Bennée if (cmd_parse_params(&data[strlen(cmd->cmd)], 828842b42dfSAlex Bennée cmd->schema, params)) { 829842b42dfSAlex Bennée return -1; 830842b42dfSAlex Bennée } 831842b42dfSAlex Bennée } 832842b42dfSAlex Bennée 83375837005SMatheus Tavares Bernardino gdbserver_state.allow_stop_reply = cmd->allow_stop_reply; 834842b42dfSAlex Bennée cmd->handler(params, user_ctx); 835842b42dfSAlex Bennée return 0; 836842b42dfSAlex Bennée } 837842b42dfSAlex Bennée 838842b42dfSAlex Bennée return -1; 839842b42dfSAlex Bennée } 840842b42dfSAlex Bennée 841842b42dfSAlex Bennée static void run_cmd_parser(const char *data, const GdbCmdParseEntry *cmd) 842842b42dfSAlex Bennée { 843842b42dfSAlex Bennée if (!data) { 844842b42dfSAlex Bennée return; 845842b42dfSAlex Bennée } 846842b42dfSAlex Bennée 847842b42dfSAlex Bennée g_string_set_size(gdbserver_state.str_buf, 0); 848842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.mem_buf, 0); 849842b42dfSAlex Bennée 850842b42dfSAlex Bennée /* In case there was an error during the command parsing we must 851842b42dfSAlex Bennée * send a NULL packet to indicate the command is not supported */ 852842b42dfSAlex Bennée if (process_string_cmd(NULL, data, cmd, 1)) { 85336e067b2SAlex Bennée gdb_put_packet(""); 854842b42dfSAlex Bennée } 855842b42dfSAlex Bennée } 856842b42dfSAlex Bennée 857842b42dfSAlex Bennée static void handle_detach(GArray *params, void *user_ctx) 858842b42dfSAlex Bennée { 859842b42dfSAlex Bennée GDBProcess *process; 860842b42dfSAlex Bennée uint32_t pid = 1; 861842b42dfSAlex Bennée 862842b42dfSAlex Bennée if (gdbserver_state.multiprocess) { 863842b42dfSAlex Bennée if (!params->len) { 86436e067b2SAlex Bennée gdb_put_packet("E22"); 865842b42dfSAlex Bennée return; 866842b42dfSAlex Bennée } 867842b42dfSAlex Bennée 868842b42dfSAlex Bennée pid = get_param(params, 0)->val_ul; 869842b42dfSAlex Bennée } 870842b42dfSAlex Bennée 871842b42dfSAlex Bennée process = gdb_get_process(pid); 872842b42dfSAlex Bennée gdb_process_breakpoint_remove_all(process); 873842b42dfSAlex Bennée process->attached = false; 874842b42dfSAlex Bennée 875842b42dfSAlex Bennée if (pid == gdb_get_cpu_pid(gdbserver_state.c_cpu)) { 876842b42dfSAlex Bennée gdbserver_state.c_cpu = gdb_first_attached_cpu(); 877842b42dfSAlex Bennée } 878842b42dfSAlex Bennée 879842b42dfSAlex Bennée if (pid == gdb_get_cpu_pid(gdbserver_state.g_cpu)) { 880842b42dfSAlex Bennée gdbserver_state.g_cpu = gdb_first_attached_cpu(); 881842b42dfSAlex Bennée } 882842b42dfSAlex Bennée 883842b42dfSAlex Bennée if (!gdbserver_state.c_cpu) { 884842b42dfSAlex Bennée /* No more process attached */ 885c566080cSAlex Bennée gdb_disable_syscalls(); 886842b42dfSAlex Bennée gdb_continue(); 887842b42dfSAlex Bennée } 88836e067b2SAlex Bennée gdb_put_packet("OK"); 889842b42dfSAlex Bennée } 890842b42dfSAlex Bennée 891842b42dfSAlex Bennée static void handle_thread_alive(GArray *params, void *user_ctx) 892842b42dfSAlex Bennée { 893842b42dfSAlex Bennée CPUState *cpu; 894842b42dfSAlex Bennée 895842b42dfSAlex Bennée if (!params->len) { 89636e067b2SAlex Bennée gdb_put_packet("E22"); 897842b42dfSAlex Bennée return; 898842b42dfSAlex Bennée } 899842b42dfSAlex Bennée 900842b42dfSAlex Bennée if (get_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) { 90136e067b2SAlex Bennée gdb_put_packet("E22"); 902842b42dfSAlex Bennée return; 903842b42dfSAlex Bennée } 904842b42dfSAlex Bennée 905842b42dfSAlex Bennée cpu = gdb_get_cpu(get_param(params, 0)->thread_id.pid, 906842b42dfSAlex Bennée get_param(params, 0)->thread_id.tid); 907842b42dfSAlex Bennée if (!cpu) { 90836e067b2SAlex Bennée gdb_put_packet("E22"); 909842b42dfSAlex Bennée return; 910842b42dfSAlex Bennée } 911842b42dfSAlex Bennée 91236e067b2SAlex Bennée gdb_put_packet("OK"); 913842b42dfSAlex Bennée } 914842b42dfSAlex Bennée 915842b42dfSAlex Bennée static void handle_continue(GArray *params, void *user_ctx) 916842b42dfSAlex Bennée { 917842b42dfSAlex Bennée if (params->len) { 918842b42dfSAlex Bennée gdb_set_cpu_pc(get_param(params, 0)->val_ull); 919842b42dfSAlex Bennée } 920842b42dfSAlex Bennée 921842b42dfSAlex Bennée gdbserver_state.signal = 0; 922842b42dfSAlex Bennée gdb_continue(); 923842b42dfSAlex Bennée } 924842b42dfSAlex Bennée 925842b42dfSAlex Bennée static void handle_cont_with_sig(GArray *params, void *user_ctx) 926842b42dfSAlex Bennée { 927842b42dfSAlex Bennée unsigned long signal = 0; 928842b42dfSAlex Bennée 929842b42dfSAlex Bennée /* 930842b42dfSAlex Bennée * Note: C sig;[addr] is currently unsupported and we simply 931842b42dfSAlex Bennée * omit the addr parameter 932842b42dfSAlex Bennée */ 933842b42dfSAlex Bennée if (params->len) { 934842b42dfSAlex Bennée signal = get_param(params, 0)->val_ul; 935842b42dfSAlex Bennée } 936842b42dfSAlex Bennée 937842b42dfSAlex Bennée gdbserver_state.signal = gdb_signal_to_target(signal); 938842b42dfSAlex Bennée if (gdbserver_state.signal == -1) { 939842b42dfSAlex Bennée gdbserver_state.signal = 0; 940842b42dfSAlex Bennée } 941842b42dfSAlex Bennée gdb_continue(); 942842b42dfSAlex Bennée } 943842b42dfSAlex Bennée 944842b42dfSAlex Bennée static void handle_set_thread(GArray *params, void *user_ctx) 945842b42dfSAlex Bennée { 946842b42dfSAlex Bennée CPUState *cpu; 947842b42dfSAlex Bennée 948842b42dfSAlex Bennée if (params->len != 2) { 94936e067b2SAlex Bennée gdb_put_packet("E22"); 950842b42dfSAlex Bennée return; 951842b42dfSAlex Bennée } 952842b42dfSAlex Bennée 953842b42dfSAlex Bennée if (get_param(params, 1)->thread_id.kind == GDB_READ_THREAD_ERR) { 95436e067b2SAlex Bennée gdb_put_packet("E22"); 955842b42dfSAlex Bennée return; 956842b42dfSAlex Bennée } 957842b42dfSAlex Bennée 958842b42dfSAlex Bennée if (get_param(params, 1)->thread_id.kind != GDB_ONE_THREAD) { 95936e067b2SAlex Bennée gdb_put_packet("OK"); 960842b42dfSAlex Bennée return; 961842b42dfSAlex Bennée } 962842b42dfSAlex Bennée 963842b42dfSAlex Bennée cpu = gdb_get_cpu(get_param(params, 1)->thread_id.pid, 964842b42dfSAlex Bennée get_param(params, 1)->thread_id.tid); 965842b42dfSAlex Bennée if (!cpu) { 96636e067b2SAlex Bennée gdb_put_packet("E22"); 967842b42dfSAlex Bennée return; 968842b42dfSAlex Bennée } 969842b42dfSAlex Bennée 970842b42dfSAlex Bennée /* 971842b42dfSAlex Bennée * Note: This command is deprecated and modern gdb's will be using the 972842b42dfSAlex Bennée * vCont command instead. 973842b42dfSAlex Bennée */ 974842b42dfSAlex Bennée switch (get_param(params, 0)->opcode) { 975842b42dfSAlex Bennée case 'c': 976842b42dfSAlex Bennée gdbserver_state.c_cpu = cpu; 97736e067b2SAlex Bennée gdb_put_packet("OK"); 978842b42dfSAlex Bennée break; 979842b42dfSAlex Bennée case 'g': 980842b42dfSAlex Bennée gdbserver_state.g_cpu = cpu; 98136e067b2SAlex Bennée gdb_put_packet("OK"); 982842b42dfSAlex Bennée break; 983842b42dfSAlex Bennée default: 98436e067b2SAlex Bennée gdb_put_packet("E22"); 985842b42dfSAlex Bennée break; 986842b42dfSAlex Bennée } 987842b42dfSAlex Bennée } 988842b42dfSAlex Bennée 989842b42dfSAlex Bennée static void handle_insert_bp(GArray *params, void *user_ctx) 990842b42dfSAlex Bennée { 991842b42dfSAlex Bennée int res; 992842b42dfSAlex Bennée 993842b42dfSAlex Bennée if (params->len != 3) { 99436e067b2SAlex Bennée gdb_put_packet("E22"); 995842b42dfSAlex Bennée return; 996842b42dfSAlex Bennée } 997842b42dfSAlex Bennée 998ae7467b1SAlex Bennée res = gdb_breakpoint_insert(gdbserver_state.c_cpu, 999ae7467b1SAlex Bennée get_param(params, 0)->val_ul, 1000842b42dfSAlex Bennée get_param(params, 1)->val_ull, 1001842b42dfSAlex Bennée get_param(params, 2)->val_ull); 1002842b42dfSAlex Bennée if (res >= 0) { 100336e067b2SAlex Bennée gdb_put_packet("OK"); 1004842b42dfSAlex Bennée return; 1005842b42dfSAlex Bennée } else if (res == -ENOSYS) { 100636e067b2SAlex Bennée gdb_put_packet(""); 1007842b42dfSAlex Bennée return; 1008842b42dfSAlex Bennée } 1009842b42dfSAlex Bennée 101036e067b2SAlex Bennée gdb_put_packet("E22"); 1011842b42dfSAlex Bennée } 1012842b42dfSAlex Bennée 1013842b42dfSAlex Bennée static void handle_remove_bp(GArray *params, void *user_ctx) 1014842b42dfSAlex Bennée { 1015842b42dfSAlex Bennée int res; 1016842b42dfSAlex Bennée 1017842b42dfSAlex Bennée if (params->len != 3) { 101836e067b2SAlex Bennée gdb_put_packet("E22"); 1019842b42dfSAlex Bennée return; 1020842b42dfSAlex Bennée } 1021842b42dfSAlex Bennée 1022ae7467b1SAlex Bennée res = gdb_breakpoint_remove(gdbserver_state.c_cpu, 1023ae7467b1SAlex Bennée get_param(params, 0)->val_ul, 1024842b42dfSAlex Bennée get_param(params, 1)->val_ull, 1025842b42dfSAlex Bennée get_param(params, 2)->val_ull); 1026842b42dfSAlex Bennée if (res >= 0) { 102736e067b2SAlex Bennée gdb_put_packet("OK"); 1028842b42dfSAlex Bennée return; 1029842b42dfSAlex Bennée } else if (res == -ENOSYS) { 103036e067b2SAlex Bennée gdb_put_packet(""); 1031842b42dfSAlex Bennée return; 1032842b42dfSAlex Bennée } 1033842b42dfSAlex Bennée 103436e067b2SAlex Bennée gdb_put_packet("E22"); 1035842b42dfSAlex Bennée } 1036842b42dfSAlex Bennée 1037842b42dfSAlex Bennée /* 1038842b42dfSAlex Bennée * handle_set/get_reg 1039842b42dfSAlex Bennée * 1040842b42dfSAlex Bennée * Older gdb are really dumb, and don't use 'G/g' if 'P/p' is available. 1041842b42dfSAlex Bennée * This works, but can be very slow. Anything new enough to understand 1042842b42dfSAlex Bennée * XML also knows how to use this properly. However to use this we 1043842b42dfSAlex Bennée * need to define a local XML file as well as be talking to a 1044842b42dfSAlex Bennée * reasonably modern gdb. Responding with an empty packet will cause 1045842b42dfSAlex Bennée * the remote gdb to fallback to older methods. 1046842b42dfSAlex Bennée */ 1047842b42dfSAlex Bennée 1048842b42dfSAlex Bennée static void handle_set_reg(GArray *params, void *user_ctx) 1049842b42dfSAlex Bennée { 1050842b42dfSAlex Bennée int reg_size; 1051842b42dfSAlex Bennée 1052842b42dfSAlex Bennée if (!gdb_has_xml) { 105336e067b2SAlex Bennée gdb_put_packet(""); 1054842b42dfSAlex Bennée return; 1055842b42dfSAlex Bennée } 1056842b42dfSAlex Bennée 1057842b42dfSAlex Bennée if (params->len != 2) { 105836e067b2SAlex Bennée gdb_put_packet("E22"); 1059842b42dfSAlex Bennée return; 1060842b42dfSAlex Bennée } 1061842b42dfSAlex Bennée 1062842b42dfSAlex Bennée reg_size = strlen(get_param(params, 1)->data) / 2; 106336e067b2SAlex Bennée gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 1)->data, reg_size); 1064842b42dfSAlex Bennée gdb_write_register(gdbserver_state.g_cpu, gdbserver_state.mem_buf->data, 1065842b42dfSAlex Bennée get_param(params, 0)->val_ull); 106636e067b2SAlex Bennée gdb_put_packet("OK"); 1067842b42dfSAlex Bennée } 1068842b42dfSAlex Bennée 1069842b42dfSAlex Bennée static void handle_get_reg(GArray *params, void *user_ctx) 1070842b42dfSAlex Bennée { 1071842b42dfSAlex Bennée int reg_size; 1072842b42dfSAlex Bennée 1073842b42dfSAlex Bennée if (!gdb_has_xml) { 107436e067b2SAlex Bennée gdb_put_packet(""); 1075842b42dfSAlex Bennée return; 1076842b42dfSAlex Bennée } 1077842b42dfSAlex Bennée 1078842b42dfSAlex Bennée if (!params->len) { 107936e067b2SAlex Bennée gdb_put_packet("E14"); 1080842b42dfSAlex Bennée return; 1081842b42dfSAlex Bennée } 1082842b42dfSAlex Bennée 1083842b42dfSAlex Bennée reg_size = gdb_read_register(gdbserver_state.g_cpu, 1084842b42dfSAlex Bennée gdbserver_state.mem_buf, 1085842b42dfSAlex Bennée get_param(params, 0)->val_ull); 1086842b42dfSAlex Bennée if (!reg_size) { 108736e067b2SAlex Bennée gdb_put_packet("E14"); 1088842b42dfSAlex Bennée return; 1089842b42dfSAlex Bennée } else { 1090842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.mem_buf, reg_size); 1091842b42dfSAlex Bennée } 1092842b42dfSAlex Bennée 109336e067b2SAlex Bennée gdb_memtohex(gdbserver_state.str_buf, 109436e067b2SAlex Bennée gdbserver_state.mem_buf->data, reg_size); 109536e067b2SAlex Bennée gdb_put_strbuf(); 1096842b42dfSAlex Bennée } 1097842b42dfSAlex Bennée 1098842b42dfSAlex Bennée static void handle_write_mem(GArray *params, void *user_ctx) 1099842b42dfSAlex Bennée { 1100842b42dfSAlex Bennée if (params->len != 3) { 110136e067b2SAlex Bennée gdb_put_packet("E22"); 1102842b42dfSAlex Bennée return; 1103842b42dfSAlex Bennée } 1104842b42dfSAlex Bennée 110536e067b2SAlex Bennée /* gdb_hextomem() reads 2*len bytes */ 1106842b42dfSAlex Bennée if (get_param(params, 1)->val_ull > 1107842b42dfSAlex Bennée strlen(get_param(params, 2)->data) / 2) { 110836e067b2SAlex Bennée gdb_put_packet("E22"); 1109842b42dfSAlex Bennée return; 1110842b42dfSAlex Bennée } 1111842b42dfSAlex Bennée 111236e067b2SAlex Bennée gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 2)->data, 1113842b42dfSAlex Bennée get_param(params, 1)->val_ull); 1114589a5867SAlex Bennée if (gdb_target_memory_rw_debug(gdbserver_state.g_cpu, 1115842b42dfSAlex Bennée get_param(params, 0)->val_ull, 1116842b42dfSAlex Bennée gdbserver_state.mem_buf->data, 1117842b42dfSAlex Bennée gdbserver_state.mem_buf->len, true)) { 111836e067b2SAlex Bennée gdb_put_packet("E14"); 1119842b42dfSAlex Bennée return; 1120842b42dfSAlex Bennée } 1121842b42dfSAlex Bennée 112236e067b2SAlex Bennée gdb_put_packet("OK"); 1123842b42dfSAlex Bennée } 1124842b42dfSAlex Bennée 1125842b42dfSAlex Bennée static void handle_read_mem(GArray *params, void *user_ctx) 1126842b42dfSAlex Bennée { 1127842b42dfSAlex Bennée if (params->len != 2) { 112836e067b2SAlex Bennée gdb_put_packet("E22"); 1129842b42dfSAlex Bennée return; 1130842b42dfSAlex Bennée } 1131842b42dfSAlex Bennée 113236e067b2SAlex Bennée /* gdb_memtohex() doubles the required space */ 1133842b42dfSAlex Bennée if (get_param(params, 1)->val_ull > MAX_PACKET_LENGTH / 2) { 113436e067b2SAlex Bennée gdb_put_packet("E22"); 1135842b42dfSAlex Bennée return; 1136842b42dfSAlex Bennée } 1137842b42dfSAlex Bennée 1138842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.mem_buf, 1139842b42dfSAlex Bennée get_param(params, 1)->val_ull); 1140842b42dfSAlex Bennée 1141589a5867SAlex Bennée if (gdb_target_memory_rw_debug(gdbserver_state.g_cpu, 1142842b42dfSAlex Bennée get_param(params, 0)->val_ull, 1143842b42dfSAlex Bennée gdbserver_state.mem_buf->data, 1144842b42dfSAlex Bennée gdbserver_state.mem_buf->len, false)) { 114536e067b2SAlex Bennée gdb_put_packet("E14"); 1146842b42dfSAlex Bennée return; 1147842b42dfSAlex Bennée } 1148842b42dfSAlex Bennée 114936e067b2SAlex Bennée gdb_memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, 1150842b42dfSAlex Bennée gdbserver_state.mem_buf->len); 115136e067b2SAlex Bennée gdb_put_strbuf(); 1152842b42dfSAlex Bennée } 1153842b42dfSAlex Bennée 1154842b42dfSAlex Bennée static void handle_write_all_regs(GArray *params, void *user_ctx) 1155842b42dfSAlex Bennée { 1156379b42e8SAlex Bennée int reg_id; 1157379b42e8SAlex Bennée size_t len; 1158842b42dfSAlex Bennée uint8_t *registers; 1159842b42dfSAlex Bennée int reg_size; 1160842b42dfSAlex Bennée 1161842b42dfSAlex Bennée if (!params->len) { 1162842b42dfSAlex Bennée return; 1163842b42dfSAlex Bennée } 1164842b42dfSAlex Bennée 1165842b42dfSAlex Bennée cpu_synchronize_state(gdbserver_state.g_cpu); 1166842b42dfSAlex Bennée len = strlen(get_param(params, 0)->data) / 2; 116736e067b2SAlex Bennée gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 0)->data, len); 1168842b42dfSAlex Bennée registers = gdbserver_state.mem_buf->data; 1169379b42e8SAlex Bennée for (reg_id = 0; 1170379b42e8SAlex Bennée reg_id < gdbserver_state.g_cpu->gdb_num_g_regs && len > 0; 1171379b42e8SAlex Bennée reg_id++) { 1172379b42e8SAlex Bennée reg_size = gdb_write_register(gdbserver_state.g_cpu, registers, reg_id); 1173842b42dfSAlex Bennée len -= reg_size; 1174842b42dfSAlex Bennée registers += reg_size; 1175842b42dfSAlex Bennée } 117636e067b2SAlex Bennée gdb_put_packet("OK"); 1177842b42dfSAlex Bennée } 1178842b42dfSAlex Bennée 1179842b42dfSAlex Bennée static void handle_read_all_regs(GArray *params, void *user_ctx) 1180842b42dfSAlex Bennée { 1181379b42e8SAlex Bennée int reg_id; 1182379b42e8SAlex Bennée size_t len; 1183842b42dfSAlex Bennée 1184842b42dfSAlex Bennée cpu_synchronize_state(gdbserver_state.g_cpu); 1185842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.mem_buf, 0); 1186842b42dfSAlex Bennée len = 0; 1187379b42e8SAlex Bennée for (reg_id = 0; reg_id < gdbserver_state.g_cpu->gdb_num_g_regs; reg_id++) { 1188842b42dfSAlex Bennée len += gdb_read_register(gdbserver_state.g_cpu, 1189842b42dfSAlex Bennée gdbserver_state.mem_buf, 1190379b42e8SAlex Bennée reg_id); 1191842b42dfSAlex Bennée } 1192842b42dfSAlex Bennée g_assert(len == gdbserver_state.mem_buf->len); 1193842b42dfSAlex Bennée 119436e067b2SAlex Bennée gdb_memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, len); 119536e067b2SAlex Bennée gdb_put_strbuf(); 1196842b42dfSAlex Bennée } 1197842b42dfSAlex Bennée 1198842b42dfSAlex Bennée 1199842b42dfSAlex Bennée static void handle_step(GArray *params, void *user_ctx) 1200842b42dfSAlex Bennée { 1201842b42dfSAlex Bennée if (params->len) { 1202b428ad12SAlex Bennée gdb_set_cpu_pc(get_param(params, 0)->val_ull); 1203842b42dfSAlex Bennée } 1204842b42dfSAlex Bennée 1205842b42dfSAlex Bennée cpu_single_step(gdbserver_state.c_cpu, gdbserver_state.sstep_flags); 1206842b42dfSAlex Bennée gdb_continue(); 1207842b42dfSAlex Bennée } 1208842b42dfSAlex Bennée 1209842b42dfSAlex Bennée static void handle_backward(GArray *params, void *user_ctx) 1210842b42dfSAlex Bennée { 1211505601d5SAlex Bennée if (!gdb_can_reverse()) { 121236e067b2SAlex Bennée gdb_put_packet("E22"); 1213842b42dfSAlex Bennée } 1214842b42dfSAlex Bennée if (params->len == 1) { 1215842b42dfSAlex Bennée switch (get_param(params, 0)->opcode) { 1216842b42dfSAlex Bennée case 's': 1217842b42dfSAlex Bennée if (replay_reverse_step()) { 1218842b42dfSAlex Bennée gdb_continue(); 1219842b42dfSAlex Bennée } else { 122036e067b2SAlex Bennée gdb_put_packet("E14"); 1221842b42dfSAlex Bennée } 1222842b42dfSAlex Bennée return; 1223842b42dfSAlex Bennée case 'c': 1224842b42dfSAlex Bennée if (replay_reverse_continue()) { 1225842b42dfSAlex Bennée gdb_continue(); 1226842b42dfSAlex Bennée } else { 122736e067b2SAlex Bennée gdb_put_packet("E14"); 1228842b42dfSAlex Bennée } 1229842b42dfSAlex Bennée return; 1230842b42dfSAlex Bennée } 1231842b42dfSAlex Bennée } 1232842b42dfSAlex Bennée 1233842b42dfSAlex Bennée /* Default invalid command */ 123436e067b2SAlex Bennée gdb_put_packet(""); 1235842b42dfSAlex Bennée } 1236842b42dfSAlex Bennée 1237842b42dfSAlex Bennée static void handle_v_cont_query(GArray *params, void *user_ctx) 1238842b42dfSAlex Bennée { 123936e067b2SAlex Bennée gdb_put_packet("vCont;c;C;s;S"); 1240842b42dfSAlex Bennée } 1241842b42dfSAlex Bennée 1242842b42dfSAlex Bennée static void handle_v_cont(GArray *params, void *user_ctx) 1243842b42dfSAlex Bennée { 1244842b42dfSAlex Bennée int res; 1245842b42dfSAlex Bennée 1246842b42dfSAlex Bennée if (!params->len) { 1247842b42dfSAlex Bennée return; 1248842b42dfSAlex Bennée } 1249842b42dfSAlex Bennée 1250842b42dfSAlex Bennée res = gdb_handle_vcont(get_param(params, 0)->data); 1251842b42dfSAlex Bennée if ((res == -EINVAL) || (res == -ERANGE)) { 125236e067b2SAlex Bennée gdb_put_packet("E22"); 1253842b42dfSAlex Bennée } else if (res) { 125436e067b2SAlex Bennée gdb_put_packet(""); 1255842b42dfSAlex Bennée } 1256842b42dfSAlex Bennée } 1257842b42dfSAlex Bennée 1258842b42dfSAlex Bennée static void handle_v_attach(GArray *params, void *user_ctx) 1259842b42dfSAlex Bennée { 1260842b42dfSAlex Bennée GDBProcess *process; 1261842b42dfSAlex Bennée CPUState *cpu; 1262842b42dfSAlex Bennée 1263842b42dfSAlex Bennée g_string_assign(gdbserver_state.str_buf, "E22"); 1264842b42dfSAlex Bennée if (!params->len) { 1265842b42dfSAlex Bennée goto cleanup; 1266842b42dfSAlex Bennée } 1267842b42dfSAlex Bennée 1268842b42dfSAlex Bennée process = gdb_get_process(get_param(params, 0)->val_ul); 1269842b42dfSAlex Bennée if (!process) { 1270842b42dfSAlex Bennée goto cleanup; 1271842b42dfSAlex Bennée } 1272842b42dfSAlex Bennée 1273a3fcc111SIlya Leoshkevich cpu = gdb_get_first_cpu_in_process(process); 1274842b42dfSAlex Bennée if (!cpu) { 1275842b42dfSAlex Bennée goto cleanup; 1276842b42dfSAlex Bennée } 1277842b42dfSAlex Bennée 1278842b42dfSAlex Bennée process->attached = true; 1279842b42dfSAlex Bennée gdbserver_state.g_cpu = cpu; 1280842b42dfSAlex Bennée gdbserver_state.c_cpu = cpu; 1281842b42dfSAlex Bennée 128275837005SMatheus Tavares Bernardino if (gdbserver_state.allow_stop_reply) { 1283842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP); 1284842b42dfSAlex Bennée gdb_append_thread_id(cpu, gdbserver_state.str_buf); 1285842b42dfSAlex Bennée g_string_append_c(gdbserver_state.str_buf, ';'); 128675837005SMatheus Tavares Bernardino gdbserver_state.allow_stop_reply = false; 1287842b42dfSAlex Bennée cleanup: 128836e067b2SAlex Bennée gdb_put_strbuf(); 1289842b42dfSAlex Bennée } 129075837005SMatheus Tavares Bernardino } 1291842b42dfSAlex Bennée 1292842b42dfSAlex Bennée static void handle_v_kill(GArray *params, void *user_ctx) 1293842b42dfSAlex Bennée { 1294842b42dfSAlex Bennée /* Kill the target */ 129536e067b2SAlex Bennée gdb_put_packet("OK"); 1296842b42dfSAlex Bennée error_report("QEMU: Terminated via GDBstub"); 1297842b42dfSAlex Bennée gdb_exit(0); 1298842b42dfSAlex Bennée exit(0); 1299842b42dfSAlex Bennée } 1300842b42dfSAlex Bennée 1301842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_v_commands_table[] = { 1302842b42dfSAlex Bennée /* Order is important if has same prefix */ 1303842b42dfSAlex Bennée { 1304842b42dfSAlex Bennée .handler = handle_v_cont_query, 1305842b42dfSAlex Bennée .cmd = "Cont?", 1306842b42dfSAlex Bennée .cmd_startswith = 1 1307842b42dfSAlex Bennée }, 1308842b42dfSAlex Bennée { 1309842b42dfSAlex Bennée .handler = handle_v_cont, 1310842b42dfSAlex Bennée .cmd = "Cont", 1311842b42dfSAlex Bennée .cmd_startswith = 1, 131275837005SMatheus Tavares Bernardino .allow_stop_reply = true, 1313842b42dfSAlex Bennée .schema = "s0" 1314842b42dfSAlex Bennée }, 1315842b42dfSAlex Bennée { 1316842b42dfSAlex Bennée .handler = handle_v_attach, 1317842b42dfSAlex Bennée .cmd = "Attach;", 1318842b42dfSAlex Bennée .cmd_startswith = 1, 131975837005SMatheus Tavares Bernardino .allow_stop_reply = true, 1320842b42dfSAlex Bennée .schema = "l0" 1321842b42dfSAlex Bennée }, 1322842b42dfSAlex Bennée { 1323842b42dfSAlex Bennée .handler = handle_v_kill, 1324842b42dfSAlex Bennée .cmd = "Kill;", 1325842b42dfSAlex Bennée .cmd_startswith = 1 1326842b42dfSAlex Bennée }, 1327842b42dfSAlex Bennée }; 1328842b42dfSAlex Bennée 1329842b42dfSAlex Bennée static void handle_v_commands(GArray *params, void *user_ctx) 1330842b42dfSAlex Bennée { 1331842b42dfSAlex Bennée if (!params->len) { 1332842b42dfSAlex Bennée return; 1333842b42dfSAlex Bennée } 1334842b42dfSAlex Bennée 1335842b42dfSAlex Bennée if (process_string_cmd(NULL, get_param(params, 0)->data, 1336842b42dfSAlex Bennée gdb_v_commands_table, 1337842b42dfSAlex Bennée ARRAY_SIZE(gdb_v_commands_table))) { 133836e067b2SAlex Bennée gdb_put_packet(""); 1339842b42dfSAlex Bennée } 1340842b42dfSAlex Bennée } 1341842b42dfSAlex Bennée 1342842b42dfSAlex Bennée static void handle_query_qemu_sstepbits(GArray *params, void *user_ctx) 1343842b42dfSAlex Bennée { 1344842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "ENABLE=%x", SSTEP_ENABLE); 1345842b42dfSAlex Bennée 1346842b42dfSAlex Bennée if (gdbserver_state.supported_sstep_flags & SSTEP_NOIRQ) { 1347842b42dfSAlex Bennée g_string_append_printf(gdbserver_state.str_buf, ",NOIRQ=%x", 1348842b42dfSAlex Bennée SSTEP_NOIRQ); 1349842b42dfSAlex Bennée } 1350842b42dfSAlex Bennée 1351842b42dfSAlex Bennée if (gdbserver_state.supported_sstep_flags & SSTEP_NOTIMER) { 1352842b42dfSAlex Bennée g_string_append_printf(gdbserver_state.str_buf, ",NOTIMER=%x", 1353842b42dfSAlex Bennée SSTEP_NOTIMER); 1354842b42dfSAlex Bennée } 1355842b42dfSAlex Bennée 135636e067b2SAlex Bennée gdb_put_strbuf(); 1357842b42dfSAlex Bennée } 1358842b42dfSAlex Bennée 1359842b42dfSAlex Bennée static void handle_set_qemu_sstep(GArray *params, void *user_ctx) 1360842b42dfSAlex Bennée { 1361842b42dfSAlex Bennée int new_sstep_flags; 1362842b42dfSAlex Bennée 1363842b42dfSAlex Bennée if (!params->len) { 1364842b42dfSAlex Bennée return; 1365842b42dfSAlex Bennée } 1366842b42dfSAlex Bennée 1367842b42dfSAlex Bennée new_sstep_flags = get_param(params, 0)->val_ul; 1368842b42dfSAlex Bennée 1369842b42dfSAlex Bennée if (new_sstep_flags & ~gdbserver_state.supported_sstep_flags) { 137036e067b2SAlex Bennée gdb_put_packet("E22"); 1371842b42dfSAlex Bennée return; 1372842b42dfSAlex Bennée } 1373842b42dfSAlex Bennée 1374842b42dfSAlex Bennée gdbserver_state.sstep_flags = new_sstep_flags; 137536e067b2SAlex Bennée gdb_put_packet("OK"); 1376842b42dfSAlex Bennée } 1377842b42dfSAlex Bennée 1378842b42dfSAlex Bennée static void handle_query_qemu_sstep(GArray *params, void *user_ctx) 1379842b42dfSAlex Bennée { 1380842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "0x%x", 1381842b42dfSAlex Bennée gdbserver_state.sstep_flags); 138236e067b2SAlex Bennée gdb_put_strbuf(); 1383842b42dfSAlex Bennée } 1384842b42dfSAlex Bennée 1385842b42dfSAlex Bennée static void handle_query_curr_tid(GArray *params, void *user_ctx) 1386842b42dfSAlex Bennée { 1387842b42dfSAlex Bennée CPUState *cpu; 1388842b42dfSAlex Bennée GDBProcess *process; 1389842b42dfSAlex Bennée 1390842b42dfSAlex Bennée /* 1391842b42dfSAlex Bennée * "Current thread" remains vague in the spec, so always return 1392842b42dfSAlex Bennée * the first thread of the current process (gdb returns the 1393842b42dfSAlex Bennée * first thread). 1394842b42dfSAlex Bennée */ 1395842b42dfSAlex Bennée process = gdb_get_cpu_process(gdbserver_state.g_cpu); 1396a3fcc111SIlya Leoshkevich cpu = gdb_get_first_cpu_in_process(process); 1397842b42dfSAlex Bennée g_string_assign(gdbserver_state.str_buf, "QC"); 1398842b42dfSAlex Bennée gdb_append_thread_id(cpu, gdbserver_state.str_buf); 139936e067b2SAlex Bennée gdb_put_strbuf(); 1400842b42dfSAlex Bennée } 1401842b42dfSAlex Bennée 1402842b42dfSAlex Bennée static void handle_query_threads(GArray *params, void *user_ctx) 1403842b42dfSAlex Bennée { 1404842b42dfSAlex Bennée if (!gdbserver_state.query_cpu) { 140536e067b2SAlex Bennée gdb_put_packet("l"); 1406842b42dfSAlex Bennée return; 1407842b42dfSAlex Bennée } 1408842b42dfSAlex Bennée 1409842b42dfSAlex Bennée g_string_assign(gdbserver_state.str_buf, "m"); 1410842b42dfSAlex Bennée gdb_append_thread_id(gdbserver_state.query_cpu, gdbserver_state.str_buf); 141136e067b2SAlex Bennée gdb_put_strbuf(); 1412842b42dfSAlex Bennée gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu); 1413842b42dfSAlex Bennée } 1414842b42dfSAlex Bennée 1415842b42dfSAlex Bennée static void handle_query_first_threads(GArray *params, void *user_ctx) 1416842b42dfSAlex Bennée { 1417842b42dfSAlex Bennée gdbserver_state.query_cpu = gdb_first_attached_cpu(); 1418842b42dfSAlex Bennée handle_query_threads(params, user_ctx); 1419842b42dfSAlex Bennée } 1420842b42dfSAlex Bennée 1421842b42dfSAlex Bennée static void handle_query_thread_extra(GArray *params, void *user_ctx) 1422842b42dfSAlex Bennée { 1423842b42dfSAlex Bennée g_autoptr(GString) rs = g_string_new(NULL); 1424842b42dfSAlex Bennée CPUState *cpu; 1425842b42dfSAlex Bennée 1426842b42dfSAlex Bennée if (!params->len || 1427842b42dfSAlex Bennée get_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) { 142836e067b2SAlex Bennée gdb_put_packet("E22"); 1429842b42dfSAlex Bennée return; 1430842b42dfSAlex Bennée } 1431842b42dfSAlex Bennée 1432842b42dfSAlex Bennée cpu = gdb_get_cpu(get_param(params, 0)->thread_id.pid, 1433842b42dfSAlex Bennée get_param(params, 0)->thread_id.tid); 1434842b42dfSAlex Bennée if (!cpu) { 1435842b42dfSAlex Bennée return; 1436842b42dfSAlex Bennée } 1437842b42dfSAlex Bennée 1438842b42dfSAlex Bennée cpu_synchronize_state(cpu); 1439842b42dfSAlex Bennée 1440842b42dfSAlex Bennée if (gdbserver_state.multiprocess && (gdbserver_state.process_num > 1)) { 1441842b42dfSAlex Bennée /* Print the CPU model and name in multiprocess mode */ 1442842b42dfSAlex Bennée ObjectClass *oc = object_get_class(OBJECT(cpu)); 1443842b42dfSAlex Bennée const char *cpu_model = object_class_get_name(oc); 1444842b42dfSAlex Bennée const char *cpu_name = 1445842b42dfSAlex Bennée object_get_canonical_path_component(OBJECT(cpu)); 1446842b42dfSAlex Bennée g_string_printf(rs, "%s %s [%s]", cpu_model, cpu_name, 1447842b42dfSAlex Bennée cpu->halted ? "halted " : "running"); 1448842b42dfSAlex Bennée } else { 1449842b42dfSAlex Bennée g_string_printf(rs, "CPU#%d [%s]", cpu->cpu_index, 1450842b42dfSAlex Bennée cpu->halted ? "halted " : "running"); 1451842b42dfSAlex Bennée } 1452842b42dfSAlex Bennée trace_gdbstub_op_extra_info(rs->str); 145336e067b2SAlex Bennée gdb_memtohex(gdbserver_state.str_buf, (uint8_t *)rs->str, rs->len); 145436e067b2SAlex Bennée gdb_put_strbuf(); 1455842b42dfSAlex Bennée } 1456842b42dfSAlex Bennée 1457842b42dfSAlex Bennée static void handle_query_supported(GArray *params, void *user_ctx) 1458842b42dfSAlex Bennée { 1459842b42dfSAlex Bennée CPUClass *cc; 1460842b42dfSAlex Bennée 1461842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "PacketSize=%x", MAX_PACKET_LENGTH); 1462842b42dfSAlex Bennée cc = CPU_GET_CLASS(first_cpu); 1463842b42dfSAlex Bennée if (cc->gdb_core_xml_file) { 1464842b42dfSAlex Bennée g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+"); 1465842b42dfSAlex Bennée } 1466842b42dfSAlex Bennée 1467505601d5SAlex Bennée if (gdb_can_reverse()) { 1468842b42dfSAlex Bennée g_string_append(gdbserver_state.str_buf, 1469842b42dfSAlex Bennée ";ReverseStep+;ReverseContinue+"); 1470842b42dfSAlex Bennée } 1471842b42dfSAlex Bennée 14720beaebc0SAlex Bennée #if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX) 1473842b42dfSAlex Bennée if (gdbserver_state.c_cpu->opaque) { 1474842b42dfSAlex Bennée g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+"); 1475842b42dfSAlex Bennée } 1476842b42dfSAlex Bennée #endif 1477842b42dfSAlex Bennée 1478842b42dfSAlex Bennée if (params->len && 1479842b42dfSAlex Bennée strstr(get_param(params, 0)->data, "multiprocess+")) { 1480842b42dfSAlex Bennée gdbserver_state.multiprocess = true; 1481842b42dfSAlex Bennée } 1482842b42dfSAlex Bennée 1483842b42dfSAlex Bennée g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+"); 148436e067b2SAlex Bennée gdb_put_strbuf(); 1485842b42dfSAlex Bennée } 1486842b42dfSAlex Bennée 1487842b42dfSAlex Bennée static void handle_query_xfer_features(GArray *params, void *user_ctx) 1488842b42dfSAlex Bennée { 1489842b42dfSAlex Bennée GDBProcess *process; 1490842b42dfSAlex Bennée CPUClass *cc; 1491842b42dfSAlex Bennée unsigned long len, total_len, addr; 1492842b42dfSAlex Bennée const char *xml; 1493842b42dfSAlex Bennée const char *p; 1494842b42dfSAlex Bennée 1495842b42dfSAlex Bennée if (params->len < 3) { 149636e067b2SAlex Bennée gdb_put_packet("E22"); 1497842b42dfSAlex Bennée return; 1498842b42dfSAlex Bennée } 1499842b42dfSAlex Bennée 1500842b42dfSAlex Bennée process = gdb_get_cpu_process(gdbserver_state.g_cpu); 1501842b42dfSAlex Bennée cc = CPU_GET_CLASS(gdbserver_state.g_cpu); 1502842b42dfSAlex Bennée if (!cc->gdb_core_xml_file) { 150336e067b2SAlex Bennée gdb_put_packet(""); 1504842b42dfSAlex Bennée return; 1505842b42dfSAlex Bennée } 1506842b42dfSAlex Bennée 1507842b42dfSAlex Bennée gdb_has_xml = true; 1508842b42dfSAlex Bennée p = get_param(params, 0)->data; 1509842b42dfSAlex Bennée xml = get_feature_xml(p, &p, process); 1510842b42dfSAlex Bennée if (!xml) { 151136e067b2SAlex Bennée gdb_put_packet("E00"); 1512842b42dfSAlex Bennée return; 1513842b42dfSAlex Bennée } 1514842b42dfSAlex Bennée 1515842b42dfSAlex Bennée addr = get_param(params, 1)->val_ul; 1516842b42dfSAlex Bennée len = get_param(params, 2)->val_ul; 1517842b42dfSAlex Bennée total_len = strlen(xml); 1518842b42dfSAlex Bennée if (addr > total_len) { 151936e067b2SAlex Bennée gdb_put_packet("E00"); 1520842b42dfSAlex Bennée return; 1521842b42dfSAlex Bennée } 1522842b42dfSAlex Bennée 1523842b42dfSAlex Bennée if (len > (MAX_PACKET_LENGTH - 5) / 2) { 1524842b42dfSAlex Bennée len = (MAX_PACKET_LENGTH - 5) / 2; 1525842b42dfSAlex Bennée } 1526842b42dfSAlex Bennée 1527842b42dfSAlex Bennée if (len < total_len - addr) { 1528842b42dfSAlex Bennée g_string_assign(gdbserver_state.str_buf, "m"); 152936e067b2SAlex Bennée gdb_memtox(gdbserver_state.str_buf, xml + addr, len); 1530842b42dfSAlex Bennée } else { 1531842b42dfSAlex Bennée g_string_assign(gdbserver_state.str_buf, "l"); 153236e067b2SAlex Bennée gdb_memtox(gdbserver_state.str_buf, xml + addr, total_len - addr); 1533842b42dfSAlex Bennée } 1534842b42dfSAlex Bennée 153536e067b2SAlex Bennée gdb_put_packet_binary(gdbserver_state.str_buf->str, 1536842b42dfSAlex Bennée gdbserver_state.str_buf->len, true); 1537842b42dfSAlex Bennée } 1538842b42dfSAlex Bennée 1539842b42dfSAlex Bennée static void handle_query_qemu_supported(GArray *params, void *user_ctx) 1540842b42dfSAlex Bennée { 1541842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "sstepbits;sstep"); 1542842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY 1543842b42dfSAlex Bennée g_string_append(gdbserver_state.str_buf, ";PhyMemMode"); 1544842b42dfSAlex Bennée #endif 154536e067b2SAlex Bennée gdb_put_strbuf(); 1546842b42dfSAlex Bennée } 1547842b42dfSAlex Bennée 1548842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_gen_query_set_common_table[] = { 1549842b42dfSAlex Bennée /* Order is important if has same prefix */ 1550842b42dfSAlex Bennée { 1551842b42dfSAlex Bennée .handler = handle_query_qemu_sstepbits, 1552842b42dfSAlex Bennée .cmd = "qemu.sstepbits", 1553842b42dfSAlex Bennée }, 1554842b42dfSAlex Bennée { 1555842b42dfSAlex Bennée .handler = handle_query_qemu_sstep, 1556842b42dfSAlex Bennée .cmd = "qemu.sstep", 1557842b42dfSAlex Bennée }, 1558842b42dfSAlex Bennée { 1559842b42dfSAlex Bennée .handler = handle_set_qemu_sstep, 1560842b42dfSAlex Bennée .cmd = "qemu.sstep=", 1561842b42dfSAlex Bennée .cmd_startswith = 1, 1562842b42dfSAlex Bennée .schema = "l0" 1563842b42dfSAlex Bennée }, 1564842b42dfSAlex Bennée }; 1565842b42dfSAlex Bennée 1566842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_gen_query_table[] = { 1567842b42dfSAlex Bennée { 1568842b42dfSAlex Bennée .handler = handle_query_curr_tid, 1569842b42dfSAlex Bennée .cmd = "C", 1570842b42dfSAlex Bennée }, 1571842b42dfSAlex Bennée { 1572842b42dfSAlex Bennée .handler = handle_query_threads, 1573842b42dfSAlex Bennée .cmd = "sThreadInfo", 1574842b42dfSAlex Bennée }, 1575842b42dfSAlex Bennée { 1576842b42dfSAlex Bennée .handler = handle_query_first_threads, 1577842b42dfSAlex Bennée .cmd = "fThreadInfo", 1578842b42dfSAlex Bennée }, 1579842b42dfSAlex Bennée { 1580842b42dfSAlex Bennée .handler = handle_query_thread_extra, 1581842b42dfSAlex Bennée .cmd = "ThreadExtraInfo,", 1582842b42dfSAlex Bennée .cmd_startswith = 1, 1583842b42dfSAlex Bennée .schema = "t0" 1584842b42dfSAlex Bennée }, 1585842b42dfSAlex Bennée #ifdef CONFIG_USER_ONLY 1586842b42dfSAlex Bennée { 1587d96bf49bSAlex Bennée .handler = gdb_handle_query_offsets, 1588842b42dfSAlex Bennée .cmd = "Offsets", 1589842b42dfSAlex Bennée }, 1590842b42dfSAlex Bennée #else 1591842b42dfSAlex Bennée { 1592b6fa2ec2SAlex Bennée .handler = gdb_handle_query_rcmd, 1593842b42dfSAlex Bennée .cmd = "Rcmd,", 1594842b42dfSAlex Bennée .cmd_startswith = 1, 1595842b42dfSAlex Bennée .schema = "s0" 1596842b42dfSAlex Bennée }, 1597842b42dfSAlex Bennée #endif 1598842b42dfSAlex Bennée { 1599842b42dfSAlex Bennée .handler = handle_query_supported, 1600842b42dfSAlex Bennée .cmd = "Supported:", 1601842b42dfSAlex Bennée .cmd_startswith = 1, 1602842b42dfSAlex Bennée .schema = "s0" 1603842b42dfSAlex Bennée }, 1604842b42dfSAlex Bennée { 1605842b42dfSAlex Bennée .handler = handle_query_supported, 1606842b42dfSAlex Bennée .cmd = "Supported", 1607842b42dfSAlex Bennée .schema = "s0" 1608842b42dfSAlex Bennée }, 1609842b42dfSAlex Bennée { 1610842b42dfSAlex Bennée .handler = handle_query_xfer_features, 1611842b42dfSAlex Bennée .cmd = "Xfer:features:read:", 1612842b42dfSAlex Bennée .cmd_startswith = 1, 1613842b42dfSAlex Bennée .schema = "s:l,l0" 1614842b42dfSAlex Bennée }, 161561b2e136SAlex Bennée #if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX) 1616842b42dfSAlex Bennée { 1617d96bf49bSAlex Bennée .handler = gdb_handle_query_xfer_auxv, 1618842b42dfSAlex Bennée .cmd = "Xfer:auxv:read::", 1619842b42dfSAlex Bennée .cmd_startswith = 1, 1620842b42dfSAlex Bennée .schema = "l,l0" 1621842b42dfSAlex Bennée }, 1622842b42dfSAlex Bennée #endif 1623842b42dfSAlex Bennée { 16248a2025b3SAlex Bennée .handler = gdb_handle_query_attached, 1625842b42dfSAlex Bennée .cmd = "Attached:", 1626842b42dfSAlex Bennée .cmd_startswith = 1 1627842b42dfSAlex Bennée }, 1628842b42dfSAlex Bennée { 16298a2025b3SAlex Bennée .handler = gdb_handle_query_attached, 1630842b42dfSAlex Bennée .cmd = "Attached", 1631842b42dfSAlex Bennée }, 1632842b42dfSAlex Bennée { 1633842b42dfSAlex Bennée .handler = handle_query_qemu_supported, 1634842b42dfSAlex Bennée .cmd = "qemu.Supported", 1635842b42dfSAlex Bennée }, 1636842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY 1637842b42dfSAlex Bennée { 1638589a5867SAlex Bennée .handler = gdb_handle_query_qemu_phy_mem_mode, 1639842b42dfSAlex Bennée .cmd = "qemu.PhyMemMode", 1640842b42dfSAlex Bennée }, 1641842b42dfSAlex Bennée #endif 1642842b42dfSAlex Bennée }; 1643842b42dfSAlex Bennée 1644842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_gen_set_table[] = { 1645842b42dfSAlex Bennée /* Order is important if has same prefix */ 1646842b42dfSAlex Bennée { 1647842b42dfSAlex Bennée .handler = handle_set_qemu_sstep, 1648842b42dfSAlex Bennée .cmd = "qemu.sstep:", 1649842b42dfSAlex Bennée .cmd_startswith = 1, 1650842b42dfSAlex Bennée .schema = "l0" 1651842b42dfSAlex Bennée }, 1652842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY 1653842b42dfSAlex Bennée { 1654589a5867SAlex Bennée .handler = gdb_handle_set_qemu_phy_mem_mode, 1655842b42dfSAlex Bennée .cmd = "qemu.PhyMemMode:", 1656842b42dfSAlex Bennée .cmd_startswith = 1, 1657842b42dfSAlex Bennée .schema = "l0" 1658842b42dfSAlex Bennée }, 1659842b42dfSAlex Bennée #endif 1660842b42dfSAlex Bennée }; 1661842b42dfSAlex Bennée 1662842b42dfSAlex Bennée static void handle_gen_query(GArray *params, void *user_ctx) 1663842b42dfSAlex Bennée { 1664842b42dfSAlex Bennée if (!params->len) { 1665842b42dfSAlex Bennée return; 1666842b42dfSAlex Bennée } 1667842b42dfSAlex Bennée 1668842b42dfSAlex Bennée if (!process_string_cmd(NULL, get_param(params, 0)->data, 1669842b42dfSAlex Bennée gdb_gen_query_set_common_table, 1670842b42dfSAlex Bennée ARRAY_SIZE(gdb_gen_query_set_common_table))) { 1671842b42dfSAlex Bennée return; 1672842b42dfSAlex Bennée } 1673842b42dfSAlex Bennée 1674842b42dfSAlex Bennée if (process_string_cmd(NULL, get_param(params, 0)->data, 1675842b42dfSAlex Bennée gdb_gen_query_table, 1676842b42dfSAlex Bennée ARRAY_SIZE(gdb_gen_query_table))) { 167736e067b2SAlex Bennée gdb_put_packet(""); 1678842b42dfSAlex Bennée } 1679842b42dfSAlex Bennée } 1680842b42dfSAlex Bennée 1681842b42dfSAlex Bennée static void handle_gen_set(GArray *params, void *user_ctx) 1682842b42dfSAlex Bennée { 1683842b42dfSAlex Bennée if (!params->len) { 1684842b42dfSAlex Bennée return; 1685842b42dfSAlex Bennée } 1686842b42dfSAlex Bennée 1687842b42dfSAlex Bennée if (!process_string_cmd(NULL, get_param(params, 0)->data, 1688842b42dfSAlex Bennée gdb_gen_query_set_common_table, 1689842b42dfSAlex Bennée ARRAY_SIZE(gdb_gen_query_set_common_table))) { 1690842b42dfSAlex Bennée return; 1691842b42dfSAlex Bennée } 1692842b42dfSAlex Bennée 1693842b42dfSAlex Bennée if (process_string_cmd(NULL, get_param(params, 0)->data, 1694842b42dfSAlex Bennée gdb_gen_set_table, 1695842b42dfSAlex Bennée ARRAY_SIZE(gdb_gen_set_table))) { 169636e067b2SAlex Bennée gdb_put_packet(""); 1697842b42dfSAlex Bennée } 1698842b42dfSAlex Bennée } 1699842b42dfSAlex Bennée 1700842b42dfSAlex Bennée static void handle_target_halt(GArray *params, void *user_ctx) 1701842b42dfSAlex Bennée { 170275837005SMatheus Tavares Bernardino if (gdbserver_state.allow_stop_reply) { 1703842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP); 1704842b42dfSAlex Bennée gdb_append_thread_id(gdbserver_state.c_cpu, gdbserver_state.str_buf); 1705842b42dfSAlex Bennée g_string_append_c(gdbserver_state.str_buf, ';'); 170636e067b2SAlex Bennée gdb_put_strbuf(); 170775837005SMatheus Tavares Bernardino gdbserver_state.allow_stop_reply = false; 170875837005SMatheus Tavares Bernardino } 1709842b42dfSAlex Bennée /* 1710842b42dfSAlex Bennée * Remove all the breakpoints when this query is issued, 1711842b42dfSAlex Bennée * because gdb is doing an initial connect and the state 1712842b42dfSAlex Bennée * should be cleaned up. 1713842b42dfSAlex Bennée */ 1714ae7467b1SAlex Bennée gdb_breakpoint_remove_all(gdbserver_state.c_cpu); 1715842b42dfSAlex Bennée } 1716842b42dfSAlex Bennée 1717842b42dfSAlex Bennée static int gdb_handle_packet(const char *line_buf) 1718842b42dfSAlex Bennée { 1719842b42dfSAlex Bennée const GdbCmdParseEntry *cmd_parser = NULL; 1720842b42dfSAlex Bennée 1721842b42dfSAlex Bennée trace_gdbstub_io_command(line_buf); 1722842b42dfSAlex Bennée 1723842b42dfSAlex Bennée switch (line_buf[0]) { 1724842b42dfSAlex Bennée case '!': 172536e067b2SAlex Bennée gdb_put_packet("OK"); 1726842b42dfSAlex Bennée break; 1727842b42dfSAlex Bennée case '?': 1728842b42dfSAlex Bennée { 1729842b42dfSAlex Bennée static const GdbCmdParseEntry target_halted_cmd_desc = { 1730842b42dfSAlex Bennée .handler = handle_target_halt, 1731842b42dfSAlex Bennée .cmd = "?", 173275837005SMatheus Tavares Bernardino .cmd_startswith = 1, 173375837005SMatheus Tavares Bernardino .allow_stop_reply = true, 1734842b42dfSAlex Bennée }; 1735842b42dfSAlex Bennée cmd_parser = &target_halted_cmd_desc; 1736842b42dfSAlex Bennée } 1737842b42dfSAlex Bennée break; 1738842b42dfSAlex Bennée case 'c': 1739842b42dfSAlex Bennée { 1740842b42dfSAlex Bennée static const GdbCmdParseEntry continue_cmd_desc = { 1741842b42dfSAlex Bennée .handler = handle_continue, 1742842b42dfSAlex Bennée .cmd = "c", 1743842b42dfSAlex Bennée .cmd_startswith = 1, 174475837005SMatheus Tavares Bernardino .allow_stop_reply = true, 1745842b42dfSAlex Bennée .schema = "L0" 1746842b42dfSAlex Bennée }; 1747842b42dfSAlex Bennée cmd_parser = &continue_cmd_desc; 1748842b42dfSAlex Bennée } 1749842b42dfSAlex Bennée break; 1750842b42dfSAlex Bennée case 'C': 1751842b42dfSAlex Bennée { 1752842b42dfSAlex Bennée static const GdbCmdParseEntry cont_with_sig_cmd_desc = { 1753842b42dfSAlex Bennée .handler = handle_cont_with_sig, 1754842b42dfSAlex Bennée .cmd = "C", 1755842b42dfSAlex Bennée .cmd_startswith = 1, 175675837005SMatheus Tavares Bernardino .allow_stop_reply = true, 1757842b42dfSAlex Bennée .schema = "l0" 1758842b42dfSAlex Bennée }; 1759842b42dfSAlex Bennée cmd_parser = &cont_with_sig_cmd_desc; 1760842b42dfSAlex Bennée } 1761842b42dfSAlex Bennée break; 1762842b42dfSAlex Bennée case 'v': 1763842b42dfSAlex Bennée { 1764842b42dfSAlex Bennée static const GdbCmdParseEntry v_cmd_desc = { 1765842b42dfSAlex Bennée .handler = handle_v_commands, 1766842b42dfSAlex Bennée .cmd = "v", 1767842b42dfSAlex Bennée .cmd_startswith = 1, 1768842b42dfSAlex Bennée .schema = "s0" 1769842b42dfSAlex Bennée }; 1770842b42dfSAlex Bennée cmd_parser = &v_cmd_desc; 1771842b42dfSAlex Bennée } 1772842b42dfSAlex Bennée break; 1773842b42dfSAlex Bennée case 'k': 1774842b42dfSAlex Bennée /* Kill the target */ 1775842b42dfSAlex Bennée error_report("QEMU: Terminated via GDBstub"); 1776842b42dfSAlex Bennée gdb_exit(0); 1777842b42dfSAlex Bennée exit(0); 1778842b42dfSAlex Bennée case 'D': 1779842b42dfSAlex Bennée { 1780842b42dfSAlex Bennée static const GdbCmdParseEntry detach_cmd_desc = { 1781842b42dfSAlex Bennée .handler = handle_detach, 1782842b42dfSAlex Bennée .cmd = "D", 1783842b42dfSAlex Bennée .cmd_startswith = 1, 1784842b42dfSAlex Bennée .schema = "?.l0" 1785842b42dfSAlex Bennée }; 1786842b42dfSAlex Bennée cmd_parser = &detach_cmd_desc; 1787842b42dfSAlex Bennée } 1788842b42dfSAlex Bennée break; 1789842b42dfSAlex Bennée case 's': 1790842b42dfSAlex Bennée { 1791842b42dfSAlex Bennée static const GdbCmdParseEntry step_cmd_desc = { 1792842b42dfSAlex Bennée .handler = handle_step, 1793842b42dfSAlex Bennée .cmd = "s", 1794842b42dfSAlex Bennée .cmd_startswith = 1, 179575837005SMatheus Tavares Bernardino .allow_stop_reply = true, 1796842b42dfSAlex Bennée .schema = "L0" 1797842b42dfSAlex Bennée }; 1798842b42dfSAlex Bennée cmd_parser = &step_cmd_desc; 1799842b42dfSAlex Bennée } 1800842b42dfSAlex Bennée break; 1801842b42dfSAlex Bennée case 'b': 1802842b42dfSAlex Bennée { 1803842b42dfSAlex Bennée static const GdbCmdParseEntry backward_cmd_desc = { 1804842b42dfSAlex Bennée .handler = handle_backward, 1805842b42dfSAlex Bennée .cmd = "b", 1806842b42dfSAlex Bennée .cmd_startswith = 1, 18073b72d681SNicholas Piggin .allow_stop_reply = true, 1808842b42dfSAlex Bennée .schema = "o0" 1809842b42dfSAlex Bennée }; 1810842b42dfSAlex Bennée cmd_parser = &backward_cmd_desc; 1811842b42dfSAlex Bennée } 1812842b42dfSAlex Bennée break; 1813842b42dfSAlex Bennée case 'F': 1814842b42dfSAlex Bennée { 1815842b42dfSAlex Bennée static const GdbCmdParseEntry file_io_cmd_desc = { 1816c566080cSAlex Bennée .handler = gdb_handle_file_io, 1817842b42dfSAlex Bennée .cmd = "F", 1818842b42dfSAlex Bennée .cmd_startswith = 1, 1819842b42dfSAlex Bennée .schema = "L,L,o0" 1820842b42dfSAlex Bennée }; 1821842b42dfSAlex Bennée cmd_parser = &file_io_cmd_desc; 1822842b42dfSAlex Bennée } 1823842b42dfSAlex Bennée break; 1824842b42dfSAlex Bennée case 'g': 1825842b42dfSAlex Bennée { 1826842b42dfSAlex Bennée static const GdbCmdParseEntry read_all_regs_cmd_desc = { 1827842b42dfSAlex Bennée .handler = handle_read_all_regs, 1828842b42dfSAlex Bennée .cmd = "g", 1829842b42dfSAlex Bennée .cmd_startswith = 1 1830842b42dfSAlex Bennée }; 1831842b42dfSAlex Bennée cmd_parser = &read_all_regs_cmd_desc; 1832842b42dfSAlex Bennée } 1833842b42dfSAlex Bennée break; 1834842b42dfSAlex Bennée case 'G': 1835842b42dfSAlex Bennée { 1836842b42dfSAlex Bennée static const GdbCmdParseEntry write_all_regs_cmd_desc = { 1837842b42dfSAlex Bennée .handler = handle_write_all_regs, 1838842b42dfSAlex Bennée .cmd = "G", 1839842b42dfSAlex Bennée .cmd_startswith = 1, 1840842b42dfSAlex Bennée .schema = "s0" 1841842b42dfSAlex Bennée }; 1842842b42dfSAlex Bennée cmd_parser = &write_all_regs_cmd_desc; 1843842b42dfSAlex Bennée } 1844842b42dfSAlex Bennée break; 1845842b42dfSAlex Bennée case 'm': 1846842b42dfSAlex Bennée { 1847842b42dfSAlex Bennée static const GdbCmdParseEntry read_mem_cmd_desc = { 1848842b42dfSAlex Bennée .handler = handle_read_mem, 1849842b42dfSAlex Bennée .cmd = "m", 1850842b42dfSAlex Bennée .cmd_startswith = 1, 1851842b42dfSAlex Bennée .schema = "L,L0" 1852842b42dfSAlex Bennée }; 1853842b42dfSAlex Bennée cmd_parser = &read_mem_cmd_desc; 1854842b42dfSAlex Bennée } 1855842b42dfSAlex Bennée break; 1856842b42dfSAlex Bennée case 'M': 1857842b42dfSAlex Bennée { 1858842b42dfSAlex Bennée static const GdbCmdParseEntry write_mem_cmd_desc = { 1859842b42dfSAlex Bennée .handler = handle_write_mem, 1860842b42dfSAlex Bennée .cmd = "M", 1861842b42dfSAlex Bennée .cmd_startswith = 1, 1862842b42dfSAlex Bennée .schema = "L,L:s0" 1863842b42dfSAlex Bennée }; 1864842b42dfSAlex Bennée cmd_parser = &write_mem_cmd_desc; 1865842b42dfSAlex Bennée } 1866842b42dfSAlex Bennée break; 1867842b42dfSAlex Bennée case 'p': 1868842b42dfSAlex Bennée { 1869842b42dfSAlex Bennée static const GdbCmdParseEntry get_reg_cmd_desc = { 1870842b42dfSAlex Bennée .handler = handle_get_reg, 1871842b42dfSAlex Bennée .cmd = "p", 1872842b42dfSAlex Bennée .cmd_startswith = 1, 1873842b42dfSAlex Bennée .schema = "L0" 1874842b42dfSAlex Bennée }; 1875842b42dfSAlex Bennée cmd_parser = &get_reg_cmd_desc; 1876842b42dfSAlex Bennée } 1877842b42dfSAlex Bennée break; 1878842b42dfSAlex Bennée case 'P': 1879842b42dfSAlex Bennée { 1880842b42dfSAlex Bennée static const GdbCmdParseEntry set_reg_cmd_desc = { 1881842b42dfSAlex Bennée .handler = handle_set_reg, 1882842b42dfSAlex Bennée .cmd = "P", 1883842b42dfSAlex Bennée .cmd_startswith = 1, 1884842b42dfSAlex Bennée .schema = "L?s0" 1885842b42dfSAlex Bennée }; 1886842b42dfSAlex Bennée cmd_parser = &set_reg_cmd_desc; 1887842b42dfSAlex Bennée } 1888842b42dfSAlex Bennée break; 1889842b42dfSAlex Bennée case 'Z': 1890842b42dfSAlex Bennée { 1891842b42dfSAlex Bennée static const GdbCmdParseEntry insert_bp_cmd_desc = { 1892842b42dfSAlex Bennée .handler = handle_insert_bp, 1893842b42dfSAlex Bennée .cmd = "Z", 1894842b42dfSAlex Bennée .cmd_startswith = 1, 1895842b42dfSAlex Bennée .schema = "l?L?L0" 1896842b42dfSAlex Bennée }; 1897842b42dfSAlex Bennée cmd_parser = &insert_bp_cmd_desc; 1898842b42dfSAlex Bennée } 1899842b42dfSAlex Bennée break; 1900842b42dfSAlex Bennée case 'z': 1901842b42dfSAlex Bennée { 1902842b42dfSAlex Bennée static const GdbCmdParseEntry remove_bp_cmd_desc = { 1903842b42dfSAlex Bennée .handler = handle_remove_bp, 1904842b42dfSAlex Bennée .cmd = "z", 1905842b42dfSAlex Bennée .cmd_startswith = 1, 1906842b42dfSAlex Bennée .schema = "l?L?L0" 1907842b42dfSAlex Bennée }; 1908842b42dfSAlex Bennée cmd_parser = &remove_bp_cmd_desc; 1909842b42dfSAlex Bennée } 1910842b42dfSAlex Bennée break; 1911842b42dfSAlex Bennée case 'H': 1912842b42dfSAlex Bennée { 1913842b42dfSAlex Bennée static const GdbCmdParseEntry set_thread_cmd_desc = { 1914842b42dfSAlex Bennée .handler = handle_set_thread, 1915842b42dfSAlex Bennée .cmd = "H", 1916842b42dfSAlex Bennée .cmd_startswith = 1, 1917842b42dfSAlex Bennée .schema = "o.t0" 1918842b42dfSAlex Bennée }; 1919842b42dfSAlex Bennée cmd_parser = &set_thread_cmd_desc; 1920842b42dfSAlex Bennée } 1921842b42dfSAlex Bennée break; 1922842b42dfSAlex Bennée case 'T': 1923842b42dfSAlex Bennée { 1924842b42dfSAlex Bennée static const GdbCmdParseEntry thread_alive_cmd_desc = { 1925842b42dfSAlex Bennée .handler = handle_thread_alive, 1926842b42dfSAlex Bennée .cmd = "T", 1927842b42dfSAlex Bennée .cmd_startswith = 1, 1928842b42dfSAlex Bennée .schema = "t0" 1929842b42dfSAlex Bennée }; 1930842b42dfSAlex Bennée cmd_parser = &thread_alive_cmd_desc; 1931842b42dfSAlex Bennée } 1932842b42dfSAlex Bennée break; 1933842b42dfSAlex Bennée case 'q': 1934842b42dfSAlex Bennée { 1935842b42dfSAlex Bennée static const GdbCmdParseEntry gen_query_cmd_desc = { 1936842b42dfSAlex Bennée .handler = handle_gen_query, 1937842b42dfSAlex Bennée .cmd = "q", 1938842b42dfSAlex Bennée .cmd_startswith = 1, 1939842b42dfSAlex Bennée .schema = "s0" 1940842b42dfSAlex Bennée }; 1941842b42dfSAlex Bennée cmd_parser = &gen_query_cmd_desc; 1942842b42dfSAlex Bennée } 1943842b42dfSAlex Bennée break; 1944842b42dfSAlex Bennée case 'Q': 1945842b42dfSAlex Bennée { 1946842b42dfSAlex Bennée static const GdbCmdParseEntry gen_set_cmd_desc = { 1947842b42dfSAlex Bennée .handler = handle_gen_set, 1948842b42dfSAlex Bennée .cmd = "Q", 1949842b42dfSAlex Bennée .cmd_startswith = 1, 1950842b42dfSAlex Bennée .schema = "s0" 1951842b42dfSAlex Bennée }; 1952842b42dfSAlex Bennée cmd_parser = &gen_set_cmd_desc; 1953842b42dfSAlex Bennée } 1954842b42dfSAlex Bennée break; 1955842b42dfSAlex Bennée default: 1956842b42dfSAlex Bennée /* put empty packet */ 195736e067b2SAlex Bennée gdb_put_packet(""); 1958842b42dfSAlex Bennée break; 1959842b42dfSAlex Bennée } 1960842b42dfSAlex Bennée 1961842b42dfSAlex Bennée if (cmd_parser) { 1962842b42dfSAlex Bennée run_cmd_parser(line_buf, cmd_parser); 1963842b42dfSAlex Bennée } 1964842b42dfSAlex Bennée 1965842b42dfSAlex Bennée return RS_IDLE; 1966842b42dfSAlex Bennée } 1967842b42dfSAlex Bennée 1968842b42dfSAlex Bennée void gdb_set_stop_cpu(CPUState *cpu) 1969842b42dfSAlex Bennée { 1970842b42dfSAlex Bennée GDBProcess *p = gdb_get_cpu_process(cpu); 1971842b42dfSAlex Bennée 1972842b42dfSAlex Bennée if (!p->attached) { 1973842b42dfSAlex Bennée /* 1974842b42dfSAlex Bennée * Having a stop CPU corresponding to a process that is not attached 1975842b42dfSAlex Bennée * confuses GDB. So we ignore the request. 1976842b42dfSAlex Bennée */ 1977842b42dfSAlex Bennée return; 1978842b42dfSAlex Bennée } 1979842b42dfSAlex Bennée 1980842b42dfSAlex Bennée gdbserver_state.c_cpu = cpu; 1981842b42dfSAlex Bennée gdbserver_state.g_cpu = cpu; 1982842b42dfSAlex Bennée } 1983842b42dfSAlex Bennée 198436e067b2SAlex Bennée void gdb_read_byte(uint8_t ch) 1985842b42dfSAlex Bennée { 1986842b42dfSAlex Bennée uint8_t reply; 1987842b42dfSAlex Bennée 198875837005SMatheus Tavares Bernardino gdbserver_state.allow_stop_reply = false; 1989842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY 1990842b42dfSAlex Bennée if (gdbserver_state.last_packet->len) { 1991842b42dfSAlex Bennée /* Waiting for a response to the last packet. If we see the start 1992842b42dfSAlex Bennée of a new command then abandon the previous response. */ 1993842b42dfSAlex Bennée if (ch == '-') { 1994842b42dfSAlex Bennée trace_gdbstub_err_got_nack(); 199536e067b2SAlex Bennée gdb_put_buffer(gdbserver_state.last_packet->data, 1996842b42dfSAlex Bennée gdbserver_state.last_packet->len); 1997842b42dfSAlex Bennée } else if (ch == '+') { 1998842b42dfSAlex Bennée trace_gdbstub_io_got_ack(); 1999842b42dfSAlex Bennée } else { 2000842b42dfSAlex Bennée trace_gdbstub_io_got_unexpected(ch); 2001842b42dfSAlex Bennée } 2002842b42dfSAlex Bennée 2003842b42dfSAlex Bennée if (ch == '+' || ch == '$') { 2004842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.last_packet, 0); 2005842b42dfSAlex Bennée } 2006842b42dfSAlex Bennée if (ch != '$') 2007842b42dfSAlex Bennée return; 2008842b42dfSAlex Bennée } 2009842b42dfSAlex Bennée if (runstate_is_running()) { 2010842b42dfSAlex Bennée /* when the CPU is running, we cannot do anything except stop 2011842b42dfSAlex Bennée it when receiving a char */ 2012842b42dfSAlex Bennée vm_stop(RUN_STATE_PAUSED); 2013842b42dfSAlex Bennée } else 2014842b42dfSAlex Bennée #endif 2015842b42dfSAlex Bennée { 2016842b42dfSAlex Bennée switch(gdbserver_state.state) { 2017842b42dfSAlex Bennée case RS_IDLE: 2018842b42dfSAlex Bennée if (ch == '$') { 2019842b42dfSAlex Bennée /* start of command packet */ 2020842b42dfSAlex Bennée gdbserver_state.line_buf_index = 0; 2021842b42dfSAlex Bennée gdbserver_state.line_sum = 0; 2022842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE; 2023842b42dfSAlex Bennée } else { 2024842b42dfSAlex Bennée trace_gdbstub_err_garbage(ch); 2025842b42dfSAlex Bennée } 2026842b42dfSAlex Bennée break; 2027842b42dfSAlex Bennée case RS_GETLINE: 2028842b42dfSAlex Bennée if (ch == '}') { 2029842b42dfSAlex Bennée /* start escape sequence */ 2030842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE_ESC; 2031842b42dfSAlex Bennée gdbserver_state.line_sum += ch; 2032842b42dfSAlex Bennée } else if (ch == '*') { 2033842b42dfSAlex Bennée /* start run length encoding sequence */ 2034842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE_RLE; 2035842b42dfSAlex Bennée gdbserver_state.line_sum += ch; 2036842b42dfSAlex Bennée } else if (ch == '#') { 2037842b42dfSAlex Bennée /* end of command, start of checksum*/ 2038842b42dfSAlex Bennée gdbserver_state.state = RS_CHKSUM1; 2039842b42dfSAlex Bennée } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) { 2040842b42dfSAlex Bennée trace_gdbstub_err_overrun(); 2041842b42dfSAlex Bennée gdbserver_state.state = RS_IDLE; 2042842b42dfSAlex Bennée } else { 2043842b42dfSAlex Bennée /* unescaped command character */ 2044842b42dfSAlex Bennée gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch; 2045842b42dfSAlex Bennée gdbserver_state.line_sum += ch; 2046842b42dfSAlex Bennée } 2047842b42dfSAlex Bennée break; 2048842b42dfSAlex Bennée case RS_GETLINE_ESC: 2049842b42dfSAlex Bennée if (ch == '#') { 2050842b42dfSAlex Bennée /* unexpected end of command in escape sequence */ 2051842b42dfSAlex Bennée gdbserver_state.state = RS_CHKSUM1; 2052842b42dfSAlex Bennée } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) { 2053842b42dfSAlex Bennée /* command buffer overrun */ 2054842b42dfSAlex Bennée trace_gdbstub_err_overrun(); 2055842b42dfSAlex Bennée gdbserver_state.state = RS_IDLE; 2056842b42dfSAlex Bennée } else { 2057842b42dfSAlex Bennée /* parse escaped character and leave escape state */ 2058842b42dfSAlex Bennée gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch ^ 0x20; 2059842b42dfSAlex Bennée gdbserver_state.line_sum += ch; 2060842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE; 2061842b42dfSAlex Bennée } 2062842b42dfSAlex Bennée break; 2063842b42dfSAlex Bennée case RS_GETLINE_RLE: 2064842b42dfSAlex Bennée /* 2065842b42dfSAlex Bennée * Run-length encoding is explained in "Debugging with GDB / 2066842b42dfSAlex Bennée * Appendix E GDB Remote Serial Protocol / Overview". 2067842b42dfSAlex Bennée */ 2068842b42dfSAlex Bennée if (ch < ' ' || ch == '#' || ch == '$' || ch > 126) { 2069842b42dfSAlex Bennée /* invalid RLE count encoding */ 2070842b42dfSAlex Bennée trace_gdbstub_err_invalid_repeat(ch); 2071842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE; 2072842b42dfSAlex Bennée } else { 2073842b42dfSAlex Bennée /* decode repeat length */ 2074842b42dfSAlex Bennée int repeat = ch - ' ' + 3; 2075842b42dfSAlex Bennée if (gdbserver_state.line_buf_index + repeat >= sizeof(gdbserver_state.line_buf) - 1) { 2076842b42dfSAlex Bennée /* that many repeats would overrun the command buffer */ 2077842b42dfSAlex Bennée trace_gdbstub_err_overrun(); 2078842b42dfSAlex Bennée gdbserver_state.state = RS_IDLE; 2079842b42dfSAlex Bennée } else if (gdbserver_state.line_buf_index < 1) { 2080842b42dfSAlex Bennée /* got a repeat but we have nothing to repeat */ 2081842b42dfSAlex Bennée trace_gdbstub_err_invalid_rle(); 2082842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE; 2083842b42dfSAlex Bennée } else { 2084842b42dfSAlex Bennée /* repeat the last character */ 2085842b42dfSAlex Bennée memset(gdbserver_state.line_buf + gdbserver_state.line_buf_index, 2086842b42dfSAlex Bennée gdbserver_state.line_buf[gdbserver_state.line_buf_index - 1], repeat); 2087842b42dfSAlex Bennée gdbserver_state.line_buf_index += repeat; 2088842b42dfSAlex Bennée gdbserver_state.line_sum += ch; 2089842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE; 2090842b42dfSAlex Bennée } 2091842b42dfSAlex Bennée } 2092842b42dfSAlex Bennée break; 2093842b42dfSAlex Bennée case RS_CHKSUM1: 2094842b42dfSAlex Bennée /* get high hex digit of checksum */ 2095842b42dfSAlex Bennée if (!isxdigit(ch)) { 2096842b42dfSAlex Bennée trace_gdbstub_err_checksum_invalid(ch); 2097842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE; 2098842b42dfSAlex Bennée break; 2099842b42dfSAlex Bennée } 2100842b42dfSAlex Bennée gdbserver_state.line_buf[gdbserver_state.line_buf_index] = '\0'; 2101842b42dfSAlex Bennée gdbserver_state.line_csum = fromhex(ch) << 4; 2102842b42dfSAlex Bennée gdbserver_state.state = RS_CHKSUM2; 2103842b42dfSAlex Bennée break; 2104842b42dfSAlex Bennée case RS_CHKSUM2: 2105842b42dfSAlex Bennée /* get low hex digit of checksum */ 2106842b42dfSAlex Bennée if (!isxdigit(ch)) { 2107842b42dfSAlex Bennée trace_gdbstub_err_checksum_invalid(ch); 2108842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE; 2109842b42dfSAlex Bennée break; 2110842b42dfSAlex Bennée } 2111842b42dfSAlex Bennée gdbserver_state.line_csum |= fromhex(ch); 2112842b42dfSAlex Bennée 2113842b42dfSAlex Bennée if (gdbserver_state.line_csum != (gdbserver_state.line_sum & 0xff)) { 2114842b42dfSAlex Bennée trace_gdbstub_err_checksum_incorrect(gdbserver_state.line_sum, gdbserver_state.line_csum); 2115842b42dfSAlex Bennée /* send NAK reply */ 2116842b42dfSAlex Bennée reply = '-'; 211736e067b2SAlex Bennée gdb_put_buffer(&reply, 1); 2118842b42dfSAlex Bennée gdbserver_state.state = RS_IDLE; 2119842b42dfSAlex Bennée } else { 2120842b42dfSAlex Bennée /* send ACK reply */ 2121842b42dfSAlex Bennée reply = '+'; 212236e067b2SAlex Bennée gdb_put_buffer(&reply, 1); 2123842b42dfSAlex Bennée gdbserver_state.state = gdb_handle_packet(gdbserver_state.line_buf); 2124842b42dfSAlex Bennée } 2125842b42dfSAlex Bennée break; 2126842b42dfSAlex Bennée default: 2127842b42dfSAlex Bennée abort(); 2128842b42dfSAlex Bennée } 2129842b42dfSAlex Bennée } 2130842b42dfSAlex Bennée } 2131842b42dfSAlex Bennée 2132842b42dfSAlex Bennée /* 2133842b42dfSAlex Bennée * Create the process that will contain all the "orphan" CPUs (that are not 2134842b42dfSAlex Bennée * part of a CPU cluster). Note that if this process contains no CPUs, it won't 2135842b42dfSAlex Bennée * be attachable and thus will be invisible to the user. 2136842b42dfSAlex Bennée */ 213736e067b2SAlex Bennée void gdb_create_default_process(GDBState *s) 2138842b42dfSAlex Bennée { 2139842b42dfSAlex Bennée GDBProcess *process; 2140842b42dfSAlex Bennée int max_pid = 0; 2141842b42dfSAlex Bennée 2142842b42dfSAlex Bennée if (gdbserver_state.process_num) { 2143842b42dfSAlex Bennée max_pid = s->processes[s->process_num - 1].pid; 2144842b42dfSAlex Bennée } 2145842b42dfSAlex Bennée 2146842b42dfSAlex Bennée s->processes = g_renew(GDBProcess, s->processes, ++s->process_num); 2147842b42dfSAlex Bennée process = &s->processes[s->process_num - 1]; 2148842b42dfSAlex Bennée 2149842b42dfSAlex Bennée /* We need an available PID slot for this process */ 2150842b42dfSAlex Bennée assert(max_pid < UINT32_MAX); 2151842b42dfSAlex Bennée 2152842b42dfSAlex Bennée process->pid = max_pid + 1; 2153842b42dfSAlex Bennée process->attached = false; 2154842b42dfSAlex Bennée process->target_xml[0] = '\0'; 2155842b42dfSAlex Bennée } 2156842b42dfSAlex Bennée 2157