xref: /qemu/gdbstub/gdbstub.c (revision a3fcc111)
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