xref: /qemu/gdbstub/gdbstub.c (revision 59272469)
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
35*59272469SPhilippe Mathieu-Daudé #include "accel/tcg/vcpu-state.h"
36d96bf49bSAlex Bennée #include "gdbstub/user.h"
37842b42dfSAlex Bennée #else
38842b42dfSAlex Bennée #include "hw/cpu/cluster.h"
39842b42dfSAlex Bennée #include "hw/boards.h"
40842b42dfSAlex Bennée #endif
41fe766734SPhilippe Mathieu-Daudé #include "hw/core/cpu.h"
42842b42dfSAlex Bennée 
43842b42dfSAlex Bennée #include "sysemu/hw_accel.h"
44842b42dfSAlex Bennée #include "sysemu/runstate.h"
455b5968c4SPhilippe Mathieu-Daudé #include "exec/replay-core.h"
46548c9609SAlex Bennée #include "exec/hwaddr.h"
47842b42dfSAlex Bennée 
48ae7467b1SAlex Bennée #include "internals.h"
49ae7467b1SAlex Bennée 
50842b42dfSAlex Bennée typedef struct GDBRegisterState {
51842b42dfSAlex Bennée     int base_reg;
52842b42dfSAlex Bennée     gdb_get_reg_cb get_reg;
53842b42dfSAlex Bennée     gdb_set_reg_cb set_reg;
54c494f8f5SAkihiko Odaki     const GDBFeature *feature;
55842b42dfSAlex Bennée } GDBRegisterState;
56842b42dfSAlex Bennée 
57b6fa2ec2SAlex Bennée GDBState gdbserver_state;
58842b42dfSAlex Bennée 
gdb_init_gdbserver_state(void)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 /* writes 2*len+1 bytes in buf */
gdb_memtohex(GString * buf,const uint8_t * mem,int len)7936e067b2SAlex Bennée void gdb_memtohex(GString *buf, const uint8_t *mem, int len)
80842b42dfSAlex Bennée {
81842b42dfSAlex Bennée     int i, c;
82842b42dfSAlex Bennée     for(i = 0; i < len; i++) {
83842b42dfSAlex Bennée         c = mem[i];
84842b42dfSAlex Bennée         g_string_append_c(buf, tohex(c >> 4));
85842b42dfSAlex Bennée         g_string_append_c(buf, tohex(c & 0xf));
86842b42dfSAlex Bennée     }
87842b42dfSAlex Bennée     g_string_append_c(buf, '\0');
88842b42dfSAlex Bennée }
89842b42dfSAlex Bennée 
gdb_hextomem(GByteArray * mem,const char * buf,int len)9036e067b2SAlex Bennée void gdb_hextomem(GByteArray *mem, const char *buf, int len)
91842b42dfSAlex Bennée {
92842b42dfSAlex Bennée     int i;
93842b42dfSAlex Bennée 
94842b42dfSAlex Bennée     for(i = 0; i < len; i++) {
95842b42dfSAlex Bennée         guint8 byte = fromhex(buf[0]) << 4 | fromhex(buf[1]);
96842b42dfSAlex Bennée         g_byte_array_append(mem, &byte, 1);
97842b42dfSAlex Bennée         buf += 2;
98842b42dfSAlex Bennée     }
99842b42dfSAlex Bennée }
100842b42dfSAlex Bennée 
hexdump(const char * buf,int len,void (* trace_fn)(size_t ofs,char const * text))101842b42dfSAlex Bennée static void hexdump(const char *buf, int len,
102842b42dfSAlex Bennée                     void (*trace_fn)(size_t ofs, char const *text))
103842b42dfSAlex Bennée {
104842b42dfSAlex Bennée     char line_buffer[3 * 16 + 4 + 16 + 1];
105842b42dfSAlex Bennée 
106842b42dfSAlex Bennée     size_t i;
107842b42dfSAlex Bennée     for (i = 0; i < len || (i & 0xF); ++i) {
108842b42dfSAlex Bennée         size_t byte_ofs = i & 15;
109842b42dfSAlex Bennée 
110842b42dfSAlex Bennée         if (byte_ofs == 0) {
111842b42dfSAlex Bennée             memset(line_buffer, ' ', 3 * 16 + 4 + 16);
112842b42dfSAlex Bennée             line_buffer[3 * 16 + 4 + 16] = 0;
113842b42dfSAlex Bennée         }
114842b42dfSAlex Bennée 
115842b42dfSAlex Bennée         size_t col_group = (i >> 2) & 3;
116842b42dfSAlex Bennée         size_t hex_col = byte_ofs * 3 + col_group;
117842b42dfSAlex Bennée         size_t txt_col = 3 * 16 + 4 + byte_ofs;
118842b42dfSAlex Bennée 
119842b42dfSAlex Bennée         if (i < len) {
120842b42dfSAlex Bennée             char value = buf[i];
121842b42dfSAlex Bennée 
122842b42dfSAlex Bennée             line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF);
123842b42dfSAlex Bennée             line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF);
124842b42dfSAlex Bennée             line_buffer[txt_col + 0] = (value >= ' ' && value < 127)
125842b42dfSAlex Bennée                     ? value
126842b42dfSAlex Bennée                     : '.';
127842b42dfSAlex Bennée         }
128842b42dfSAlex Bennée 
129842b42dfSAlex Bennée         if (byte_ofs == 0xF)
130842b42dfSAlex Bennée             trace_fn(i & -16, line_buffer);
131842b42dfSAlex Bennée     }
132842b42dfSAlex Bennée }
133842b42dfSAlex Bennée 
134842b42dfSAlex Bennée /* return -1 if error, 0 if OK */
gdb_put_packet_binary(const char * buf,int len,bool dump)13536e067b2SAlex Bennée int gdb_put_packet_binary(const char *buf, int len, bool dump)
136842b42dfSAlex Bennée {
137842b42dfSAlex Bennée     int csum, i;
138842b42dfSAlex Bennée     uint8_t footer[3];
139842b42dfSAlex Bennée 
140842b42dfSAlex Bennée     if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) {
141842b42dfSAlex Bennée         hexdump(buf, len, trace_gdbstub_io_binaryreply);
142842b42dfSAlex Bennée     }
143842b42dfSAlex Bennée 
144842b42dfSAlex Bennée     for(;;) {
145842b42dfSAlex Bennée         g_byte_array_set_size(gdbserver_state.last_packet, 0);
146842b42dfSAlex Bennée         g_byte_array_append(gdbserver_state.last_packet,
147842b42dfSAlex Bennée                             (const uint8_t *) "$", 1);
148842b42dfSAlex Bennée         g_byte_array_append(gdbserver_state.last_packet,
149842b42dfSAlex Bennée                             (const uint8_t *) buf, len);
150842b42dfSAlex Bennée         csum = 0;
151842b42dfSAlex Bennée         for(i = 0; i < len; i++) {
152842b42dfSAlex Bennée             csum += buf[i];
153842b42dfSAlex Bennée         }
154842b42dfSAlex Bennée         footer[0] = '#';
155842b42dfSAlex Bennée         footer[1] = tohex((csum >> 4) & 0xf);
156842b42dfSAlex Bennée         footer[2] = tohex((csum) & 0xf);
157842b42dfSAlex Bennée         g_byte_array_append(gdbserver_state.last_packet, footer, 3);
158842b42dfSAlex Bennée 
15936e067b2SAlex Bennée         gdb_put_buffer(gdbserver_state.last_packet->data,
160842b42dfSAlex Bennée                    gdbserver_state.last_packet->len);
161842b42dfSAlex Bennée 
162a7e0f9bdSAlex Bennée         if (gdb_got_immediate_ack()) {
163842b42dfSAlex Bennée             break;
164a7e0f9bdSAlex Bennée         }
165842b42dfSAlex Bennée     }
166842b42dfSAlex Bennée     return 0;
167842b42dfSAlex Bennée }
168842b42dfSAlex Bennée 
169842b42dfSAlex Bennée /* return -1 if error, 0 if OK */
gdb_put_packet(const char * buf)17036e067b2SAlex Bennée int gdb_put_packet(const char *buf)
171842b42dfSAlex Bennée {
172842b42dfSAlex Bennée     trace_gdbstub_io_reply(buf);
173842b42dfSAlex Bennée 
17436e067b2SAlex Bennée     return gdb_put_packet_binary(buf, strlen(buf), false);
175842b42dfSAlex Bennée }
176842b42dfSAlex Bennée 
gdb_put_strbuf(void)17736e067b2SAlex Bennée void gdb_put_strbuf(void)
178842b42dfSAlex Bennée {
17936e067b2SAlex Bennée     gdb_put_packet(gdbserver_state.str_buf->str);
180842b42dfSAlex Bennée }
181842b42dfSAlex Bennée 
182842b42dfSAlex Bennée /* Encode data using the encoding for 'x' packets.  */
gdb_memtox(GString * buf,const char * mem,int len)18336e067b2SAlex Bennée void gdb_memtox(GString *buf, const char *mem, int len)
184842b42dfSAlex Bennée {
185842b42dfSAlex Bennée     char c;
186842b42dfSAlex Bennée 
187842b42dfSAlex Bennée     while (len--) {
188842b42dfSAlex Bennée         c = *(mem++);
189842b42dfSAlex Bennée         switch (c) {
190842b42dfSAlex Bennée         case '#': case '$': case '*': case '}':
191842b42dfSAlex Bennée             g_string_append_c(buf, '}');
192842b42dfSAlex Bennée             g_string_append_c(buf, c ^ 0x20);
193842b42dfSAlex Bennée             break;
194842b42dfSAlex Bennée         default:
195842b42dfSAlex Bennée             g_string_append_c(buf, c);
196842b42dfSAlex Bennée             break;
197842b42dfSAlex Bennée         }
198842b42dfSAlex Bennée     }
199842b42dfSAlex Bennée }
200842b42dfSAlex Bennée 
gdb_get_cpu_pid(CPUState * cpu)201842b42dfSAlex Bennée static uint32_t gdb_get_cpu_pid(CPUState *cpu)
202842b42dfSAlex Bennée {
203dc14a7a6SIlya Leoshkevich #ifdef CONFIG_USER_ONLY
204dc14a7a6SIlya Leoshkevich     return getpid();
205dc14a7a6SIlya Leoshkevich #else
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;
212dc14a7a6SIlya Leoshkevich #endif
213842b42dfSAlex Bennée }
214842b42dfSAlex Bennée 
gdb_get_process(uint32_t pid)215a3fcc111SIlya Leoshkevich GDBProcess *gdb_get_process(uint32_t pid)
216842b42dfSAlex Bennée {
217842b42dfSAlex Bennée     int i;
218842b42dfSAlex Bennée 
219842b42dfSAlex Bennée     if (!pid) {
220842b42dfSAlex Bennée         /* 0 means any process, we take the first one */
221842b42dfSAlex Bennée         return &gdbserver_state.processes[0];
222842b42dfSAlex Bennée     }
223842b42dfSAlex Bennée 
224842b42dfSAlex Bennée     for (i = 0; i < gdbserver_state.process_num; i++) {
225842b42dfSAlex Bennée         if (gdbserver_state.processes[i].pid == pid) {
226842b42dfSAlex Bennée             return &gdbserver_state.processes[i];
227842b42dfSAlex Bennée         }
228842b42dfSAlex Bennée     }
229842b42dfSAlex Bennée 
230842b42dfSAlex Bennée     return NULL;
231842b42dfSAlex Bennée }
232842b42dfSAlex Bennée 
gdb_get_cpu_process(CPUState * cpu)233842b42dfSAlex Bennée static GDBProcess *gdb_get_cpu_process(CPUState *cpu)
234842b42dfSAlex Bennée {
235842b42dfSAlex Bennée     return gdb_get_process(gdb_get_cpu_pid(cpu));
236842b42dfSAlex Bennée }
237842b42dfSAlex Bennée 
find_cpu(uint32_t thread_id)238842b42dfSAlex Bennée static CPUState *find_cpu(uint32_t thread_id)
239842b42dfSAlex Bennée {
240842b42dfSAlex Bennée     CPUState *cpu;
241842b42dfSAlex Bennée 
242842b42dfSAlex Bennée     CPU_FOREACH(cpu) {
24336e067b2SAlex Bennée         if (gdb_get_cpu_index(cpu) == thread_id) {
244842b42dfSAlex Bennée             return cpu;
245842b42dfSAlex Bennée         }
246842b42dfSAlex Bennée     }
247842b42dfSAlex Bennée 
248842b42dfSAlex Bennée     return NULL;
249842b42dfSAlex Bennée }
250842b42dfSAlex Bennée 
gdb_get_first_cpu_in_process(GDBProcess * process)251a3fcc111SIlya Leoshkevich CPUState *gdb_get_first_cpu_in_process(GDBProcess *process)
252842b42dfSAlex Bennée {
253842b42dfSAlex Bennée     CPUState *cpu;
254842b42dfSAlex Bennée 
255842b42dfSAlex Bennée     CPU_FOREACH(cpu) {
256842b42dfSAlex Bennée         if (gdb_get_cpu_pid(cpu) == process->pid) {
257842b42dfSAlex Bennée             return cpu;
258842b42dfSAlex Bennée         }
259842b42dfSAlex Bennée     }
260842b42dfSAlex Bennée 
261842b42dfSAlex Bennée     return NULL;
262842b42dfSAlex Bennée }
263842b42dfSAlex Bennée 
gdb_next_cpu_in_process(CPUState * cpu)264842b42dfSAlex Bennée static CPUState *gdb_next_cpu_in_process(CPUState *cpu)
265842b42dfSAlex Bennée {
266842b42dfSAlex Bennée     uint32_t pid = gdb_get_cpu_pid(cpu);
267842b42dfSAlex Bennée     cpu = CPU_NEXT(cpu);
268842b42dfSAlex Bennée 
269842b42dfSAlex Bennée     while (cpu) {
270842b42dfSAlex Bennée         if (gdb_get_cpu_pid(cpu) == pid) {
271842b42dfSAlex Bennée             break;
272842b42dfSAlex Bennée         }
273842b42dfSAlex Bennée 
274842b42dfSAlex Bennée         cpu = CPU_NEXT(cpu);
275842b42dfSAlex Bennée     }
276842b42dfSAlex Bennée 
277842b42dfSAlex Bennée     return cpu;
278842b42dfSAlex Bennée }
279842b42dfSAlex Bennée 
280842b42dfSAlex Bennée /* Return the cpu following @cpu, while ignoring unattached processes. */
gdb_next_attached_cpu(CPUState * cpu)281842b42dfSAlex Bennée static CPUState *gdb_next_attached_cpu(CPUState *cpu)
282842b42dfSAlex Bennée {
283842b42dfSAlex Bennée     cpu = CPU_NEXT(cpu);
284842b42dfSAlex Bennée 
285842b42dfSAlex Bennée     while (cpu) {
286842b42dfSAlex Bennée         if (gdb_get_cpu_process(cpu)->attached) {
287842b42dfSAlex Bennée             break;
288842b42dfSAlex Bennée         }
289842b42dfSAlex Bennée 
290842b42dfSAlex Bennée         cpu = CPU_NEXT(cpu);
291842b42dfSAlex Bennée     }
292842b42dfSAlex Bennée 
293842b42dfSAlex Bennée     return cpu;
294842b42dfSAlex Bennée }
295842b42dfSAlex Bennée 
296842b42dfSAlex Bennée /* Return the first attached cpu */
gdb_first_attached_cpu(void)29736e067b2SAlex Bennée CPUState *gdb_first_attached_cpu(void)
298842b42dfSAlex Bennée {
299842b42dfSAlex Bennée     CPUState *cpu = first_cpu;
300842b42dfSAlex Bennée     GDBProcess *process = gdb_get_cpu_process(cpu);
301842b42dfSAlex Bennée 
302842b42dfSAlex Bennée     if (!process->attached) {
303842b42dfSAlex Bennée         return gdb_next_attached_cpu(cpu);
304842b42dfSAlex Bennée     }
305842b42dfSAlex Bennée 
306842b42dfSAlex Bennée     return cpu;
307842b42dfSAlex Bennée }
308842b42dfSAlex Bennée 
gdb_get_cpu(uint32_t pid,uint32_t tid)309842b42dfSAlex Bennée static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid)
310842b42dfSAlex Bennée {
311842b42dfSAlex Bennée     GDBProcess *process;
312842b42dfSAlex Bennée     CPUState *cpu;
313842b42dfSAlex Bennée 
314842b42dfSAlex Bennée     if (!pid && !tid) {
315842b42dfSAlex Bennée         /* 0 means any process/thread, we take the first attached one */
316842b42dfSAlex Bennée         return gdb_first_attached_cpu();
317842b42dfSAlex Bennée     } else if (pid && !tid) {
318842b42dfSAlex Bennée         /* any thread in a specific process */
319842b42dfSAlex Bennée         process = gdb_get_process(pid);
320842b42dfSAlex Bennée 
321842b42dfSAlex Bennée         if (process == NULL) {
322842b42dfSAlex Bennée             return NULL;
323842b42dfSAlex Bennée         }
324842b42dfSAlex Bennée 
325842b42dfSAlex Bennée         if (!process->attached) {
326842b42dfSAlex Bennée             return NULL;
327842b42dfSAlex Bennée         }
328842b42dfSAlex Bennée 
329a3fcc111SIlya Leoshkevich         return gdb_get_first_cpu_in_process(process);
330842b42dfSAlex Bennée     } else {
331842b42dfSAlex Bennée         /* a specific thread */
332842b42dfSAlex Bennée         cpu = find_cpu(tid);
333842b42dfSAlex Bennée 
334842b42dfSAlex Bennée         if (cpu == NULL) {
335842b42dfSAlex Bennée             return NULL;
336842b42dfSAlex Bennée         }
337842b42dfSAlex Bennée 
338842b42dfSAlex Bennée         process = gdb_get_cpu_process(cpu);
339842b42dfSAlex Bennée 
340842b42dfSAlex Bennée         if (pid && process->pid != pid) {
341842b42dfSAlex Bennée             return NULL;
342842b42dfSAlex Bennée         }
343842b42dfSAlex Bennée 
344842b42dfSAlex Bennée         if (!process->attached) {
345842b42dfSAlex Bennée             return NULL;
346842b42dfSAlex Bennée         }
347842b42dfSAlex Bennée 
348842b42dfSAlex Bennée         return cpu;
349842b42dfSAlex Bennée     }
350842b42dfSAlex Bennée }
351842b42dfSAlex Bennée 
get_feature_xml(const char * p,const char ** newp,GDBProcess * process)352842b42dfSAlex Bennée static const char *get_feature_xml(const char *p, const char **newp,
353842b42dfSAlex Bennée                                    GDBProcess *process)
354842b42dfSAlex Bennée {
355a3fcc111SIlya Leoshkevich     CPUState *cpu = gdb_get_first_cpu_in_process(process);
356842b42dfSAlex Bennée     CPUClass *cc = CPU_GET_CLASS(cpu);
357ee59fa1dSAkihiko Odaki     GDBRegisterState *r;
35856e534bdSAlex Bennée     size_t len;
359842b42dfSAlex Bennée 
36056e534bdSAlex Bennée     /*
36156e534bdSAlex Bennée      * qXfer:features:read:ANNEX:OFFSET,LENGTH'
36256e534bdSAlex Bennée      *                     ^p    ^newp
36356e534bdSAlex Bennée      */
36456e534bdSAlex Bennée     char *term = strchr(p, ':');
36556e534bdSAlex Bennée     *newp = term + 1;
36656e534bdSAlex Bennée     len = term - p;
367842b42dfSAlex Bennée 
36856e534bdSAlex Bennée     /* Is it the main target xml? */
369842b42dfSAlex Bennée     if (strncmp(p, "target.xml", len) == 0) {
37056e534bdSAlex Bennée         if (!process->target_xml) {
3716d8f77a6SAkihiko Odaki             g_autoptr(GPtrArray) xml = g_ptr_array_new_with_free_func(g_free);
372842b42dfSAlex Bennée 
3736d8f77a6SAkihiko Odaki             g_ptr_array_add(
3746d8f77a6SAkihiko Odaki                 xml,
3756d8f77a6SAkihiko Odaki                 g_strdup("<?xml version=\"1.0\"?>"
376842b42dfSAlex Bennée                          "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
3776d8f77a6SAkihiko Odaki                          "<target>"));
378842b42dfSAlex Bennée 
37956e534bdSAlex Bennée             if (cc->gdb_arch_name) {
3806d8f77a6SAkihiko Odaki                 g_ptr_array_add(
3816d8f77a6SAkihiko Odaki                     xml,
3826d8f77a6SAkihiko Odaki                     g_markup_printf_escaped("<architecture>%s</architecture>",
3836d8f77a6SAkihiko Odaki                                             cc->gdb_arch_name(cpu)));
38456e534bdSAlex Bennée             }
38573c392c2SAkihiko Odaki             for (guint i = 0; i < cpu->gdb_regs->len; i++) {
38673c392c2SAkihiko Odaki                 r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
3876d8f77a6SAkihiko Odaki                 g_ptr_array_add(
3886d8f77a6SAkihiko Odaki                     xml,
3896d8f77a6SAkihiko Odaki                     g_markup_printf_escaped("<xi:include href=\"%s\"/>",
390c494f8f5SAkihiko Odaki                                             r->feature->xmlname));
39156e534bdSAlex Bennée             }
3926d8f77a6SAkihiko Odaki             g_ptr_array_add(xml, g_strdup("</target>"));
3936d8f77a6SAkihiko Odaki             g_ptr_array_add(xml, NULL);
39456e534bdSAlex Bennée 
3956d8f77a6SAkihiko Odaki             process->target_xml = g_strjoinv(NULL, (void *)xml->pdata);
39656e534bdSAlex Bennée         }
3975d1ab242SAkihiko Odaki         return process->target_xml;
39856e534bdSAlex Bennée     }
399ee59fa1dSAkihiko Odaki     /* Is it one of the features? */
400ee59fa1dSAkihiko Odaki     for (guint i = 0; i < cpu->gdb_regs->len; i++) {
401ee59fa1dSAkihiko Odaki         r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
402ee59fa1dSAkihiko Odaki         if (strncmp(p, r->feature->xmlname, len) == 0) {
403ee59fa1dSAkihiko Odaki             return r->feature->xml;
404842b42dfSAlex Bennée         }
40556e534bdSAlex Bennée     }
40656e534bdSAlex Bennée 
40756e534bdSAlex Bennée     /* failed */
40856e534bdSAlex Bennée     return NULL;
409842b42dfSAlex Bennée }
410842b42dfSAlex Bennée 
gdb_feature_builder_init(GDBFeatureBuilder * builder,GDBFeature * feature,const char * name,const char * xmlname,int base_reg)411e84f4524SAkihiko Odaki void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
412e84f4524SAkihiko Odaki                               const char *name, const char *xmlname,
413e84f4524SAkihiko Odaki                               int base_reg)
414e84f4524SAkihiko Odaki {
415e84f4524SAkihiko Odaki     char *header = g_markup_printf_escaped(
416e84f4524SAkihiko Odaki         "<?xml version=\"1.0\"?>"
417e84f4524SAkihiko Odaki         "<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">"
418e84f4524SAkihiko Odaki         "<feature name=\"%s\">",
419e84f4524SAkihiko Odaki         name);
420e84f4524SAkihiko Odaki 
421e84f4524SAkihiko Odaki     builder->feature = feature;
422e84f4524SAkihiko Odaki     builder->xml = g_ptr_array_new();
423e84f4524SAkihiko Odaki     g_ptr_array_add(builder->xml, header);
424eb37086fSAkihiko Odaki     builder->regs = g_ptr_array_new();
425e84f4524SAkihiko Odaki     builder->base_reg = base_reg;
426e84f4524SAkihiko Odaki     feature->xmlname = xmlname;
427eb37086fSAkihiko Odaki     feature->name = name;
428e84f4524SAkihiko Odaki }
429e84f4524SAkihiko Odaki 
gdb_feature_builder_append_tag(const GDBFeatureBuilder * builder,const char * format,...)430e84f4524SAkihiko Odaki void gdb_feature_builder_append_tag(const GDBFeatureBuilder *builder,
431e84f4524SAkihiko Odaki                                     const char *format, ...)
432e84f4524SAkihiko Odaki {
433e84f4524SAkihiko Odaki     va_list ap;
434e84f4524SAkihiko Odaki     va_start(ap, format);
435e84f4524SAkihiko Odaki     g_ptr_array_add(builder->xml, g_markup_vprintf_escaped(format, ap));
436e84f4524SAkihiko Odaki     va_end(ap);
437e84f4524SAkihiko Odaki }
438e84f4524SAkihiko Odaki 
gdb_feature_builder_append_reg(const GDBFeatureBuilder * builder,const char * name,int bitsize,int regnum,const char * type,const char * group)439e84f4524SAkihiko Odaki void gdb_feature_builder_append_reg(const GDBFeatureBuilder *builder,
440e84f4524SAkihiko Odaki                                     const char *name,
441e84f4524SAkihiko Odaki                                     int bitsize,
442e84f4524SAkihiko Odaki                                     int regnum,
443e84f4524SAkihiko Odaki                                     const char *type,
444e84f4524SAkihiko Odaki                                     const char *group)
445e84f4524SAkihiko Odaki {
446eb37086fSAkihiko Odaki     if (builder->regs->len <= regnum) {
447eb37086fSAkihiko Odaki         g_ptr_array_set_size(builder->regs, regnum + 1);
448e84f4524SAkihiko Odaki     }
449e84f4524SAkihiko Odaki 
450eb37086fSAkihiko Odaki     builder->regs->pdata[regnum] = (gpointer *)name;
451eb37086fSAkihiko Odaki 
452e84f4524SAkihiko Odaki     if (group) {
453e84f4524SAkihiko Odaki         gdb_feature_builder_append_tag(
454e84f4524SAkihiko Odaki             builder,
455e84f4524SAkihiko Odaki             "<reg name=\"%s\" bitsize=\"%d\" regnum=\"%d\" type=\"%s\" group=\"%s\"/>",
456e84f4524SAkihiko Odaki             name, bitsize, builder->base_reg + regnum, type, group);
457e84f4524SAkihiko Odaki     } else {
458e84f4524SAkihiko Odaki         gdb_feature_builder_append_tag(
459e84f4524SAkihiko Odaki             builder,
460e84f4524SAkihiko Odaki             "<reg name=\"%s\" bitsize=\"%d\" regnum=\"%d\" type=\"%s\"/>",
461e84f4524SAkihiko Odaki             name, bitsize, builder->base_reg + regnum, type);
462e84f4524SAkihiko Odaki     }
463e84f4524SAkihiko Odaki }
464e84f4524SAkihiko Odaki 
gdb_feature_builder_end(const GDBFeatureBuilder * builder)465e84f4524SAkihiko Odaki void gdb_feature_builder_end(const GDBFeatureBuilder *builder)
466e84f4524SAkihiko Odaki {
467e84f4524SAkihiko Odaki     g_ptr_array_add(builder->xml, (void *)"</feature>");
468e84f4524SAkihiko Odaki     g_ptr_array_add(builder->xml, NULL);
469e84f4524SAkihiko Odaki 
470e84f4524SAkihiko Odaki     builder->feature->xml = g_strjoinv(NULL, (void *)builder->xml->pdata);
471e84f4524SAkihiko Odaki 
472e84f4524SAkihiko Odaki     for (guint i = 0; i < builder->xml->len - 2; i++) {
473e84f4524SAkihiko Odaki         g_free(g_ptr_array_index(builder->xml, i));
474e84f4524SAkihiko Odaki     }
475e84f4524SAkihiko Odaki 
476e84f4524SAkihiko Odaki     g_ptr_array_free(builder->xml, TRUE);
477eb37086fSAkihiko Odaki 
478eb37086fSAkihiko Odaki     builder->feature->num_regs = builder->regs->len;
479eb37086fSAkihiko Odaki     builder->feature->regs = (void *)g_ptr_array_free(builder->regs, FALSE);
480e84f4524SAkihiko Odaki }
481e84f4524SAkihiko Odaki 
gdb_find_static_feature(const char * xmlname)4821218b68eSAkihiko Odaki const GDBFeature *gdb_find_static_feature(const char *xmlname)
4831218b68eSAkihiko Odaki {
4841218b68eSAkihiko Odaki     const GDBFeature *feature;
4851218b68eSAkihiko Odaki 
4861218b68eSAkihiko Odaki     for (feature = gdb_static_features; feature->xmlname; feature++) {
4871218b68eSAkihiko Odaki         if (!strcmp(feature->xmlname, xmlname)) {
4881218b68eSAkihiko Odaki             return feature;
4891218b68eSAkihiko Odaki         }
4901218b68eSAkihiko Odaki     }
4911218b68eSAkihiko Odaki 
4921218b68eSAkihiko Odaki     g_assert_not_reached();
4931218b68eSAkihiko Odaki }
4941218b68eSAkihiko Odaki 
gdb_get_register_list(CPUState * cpu)495c3d0b466SAlex Bennée GArray *gdb_get_register_list(CPUState *cpu)
496c3d0b466SAlex Bennée {
497c3d0b466SAlex Bennée     GArray *results = g_array_new(true, true, sizeof(GDBRegDesc));
498c3d0b466SAlex Bennée 
499c3d0b466SAlex Bennée     /* registers are only available once the CPU is initialised */
500c3d0b466SAlex Bennée     if (!cpu->gdb_regs) {
501c3d0b466SAlex Bennée         return results;
502c3d0b466SAlex Bennée     }
503c3d0b466SAlex Bennée 
504c3d0b466SAlex Bennée     for (int f = 0; f < cpu->gdb_regs->len; f++) {
505c3d0b466SAlex Bennée         GDBRegisterState *r = &g_array_index(cpu->gdb_regs, GDBRegisterState, f);
506c3d0b466SAlex Bennée         for (int i = 0; i < r->feature->num_regs; i++) {
507c3d0b466SAlex Bennée             const char *name = r->feature->regs[i];
508c3d0b466SAlex Bennée             GDBRegDesc desc = {
509c3d0b466SAlex Bennée                 r->base_reg + i,
510c3d0b466SAlex Bennée                 name,
511c3d0b466SAlex Bennée                 r->feature->name
512c3d0b466SAlex Bennée             };
513c3d0b466SAlex Bennée             g_array_append_val(results, desc);
514c3d0b466SAlex Bennée         }
515c3d0b466SAlex Bennée     }
516c3d0b466SAlex Bennée 
517c3d0b466SAlex Bennée     return results;
518c3d0b466SAlex Bennée }
519c3d0b466SAlex Bennée 
gdb_read_register(CPUState * cpu,GByteArray * buf,int reg)520c3d0b466SAlex Bennée int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
521842b42dfSAlex Bennée {
522842b42dfSAlex Bennée     CPUClass *cc = CPU_GET_CLASS(cpu);
523842b42dfSAlex Bennée     GDBRegisterState *r;
524842b42dfSAlex Bennée 
525842b42dfSAlex Bennée     if (reg < cc->gdb_num_core_regs) {
526842b42dfSAlex Bennée         return cc->gdb_read_register(cpu, buf, reg);
527842b42dfSAlex Bennée     }
528842b42dfSAlex Bennée 
52973c392c2SAkihiko Odaki     for (guint i = 0; i < cpu->gdb_regs->len; i++) {
53073c392c2SAkihiko Odaki         r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
531c494f8f5SAkihiko Odaki         if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
53266260159SAkihiko Odaki             return r->get_reg(cpu, buf, reg - r->base_reg);
533842b42dfSAlex Bennée         }
534842b42dfSAlex Bennée     }
535842b42dfSAlex Bennée     return 0;
536842b42dfSAlex Bennée }
537842b42dfSAlex Bennée 
gdb_write_register(CPUState * cpu,uint8_t * mem_buf,int reg)538842b42dfSAlex Bennée static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
539842b42dfSAlex Bennée {
540842b42dfSAlex Bennée     CPUClass *cc = CPU_GET_CLASS(cpu);
541842b42dfSAlex Bennée     GDBRegisterState *r;
542842b42dfSAlex Bennée 
543842b42dfSAlex Bennée     if (reg < cc->gdb_num_core_regs) {
544842b42dfSAlex Bennée         return cc->gdb_write_register(cpu, mem_buf, reg);
545842b42dfSAlex Bennée     }
546842b42dfSAlex Bennée 
54773c392c2SAkihiko Odaki     for (guint i = 0; i < cpu->gdb_regs->len; i++) {
54873c392c2SAkihiko Odaki         r =  &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
549c494f8f5SAkihiko Odaki         if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
55066260159SAkihiko Odaki             return r->set_reg(cpu, mem_buf, reg - r->base_reg);
551842b42dfSAlex Bennée         }
552842b42dfSAlex Bennée     }
553842b42dfSAlex Bennée     return 0;
554842b42dfSAlex Bennée }
555842b42dfSAlex Bennée 
gdb_register_feature(CPUState * cpu,int base_reg,gdb_get_reg_cb get_reg,gdb_set_reg_cb set_reg,const GDBFeature * feature)556ee59fa1dSAkihiko Odaki static void gdb_register_feature(CPUState *cpu, int base_reg,
557ee59fa1dSAkihiko Odaki                                  gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
558ee59fa1dSAkihiko Odaki                                  const GDBFeature *feature)
559ee59fa1dSAkihiko Odaki {
560ee59fa1dSAkihiko Odaki     GDBRegisterState s = {
561ee59fa1dSAkihiko Odaki         .base_reg = base_reg,
562ee59fa1dSAkihiko Odaki         .get_reg = get_reg,
563ee59fa1dSAkihiko Odaki         .set_reg = set_reg,
564ee59fa1dSAkihiko Odaki         .feature = feature
565ee59fa1dSAkihiko Odaki     };
566ee59fa1dSAkihiko Odaki 
567ee59fa1dSAkihiko Odaki     g_array_append_val(cpu->gdb_regs, s);
568ee59fa1dSAkihiko Odaki }
569ee59fa1dSAkihiko Odaki 
gdb_init_cpu(CPUState * cpu)570ee59fa1dSAkihiko Odaki void gdb_init_cpu(CPUState *cpu)
571ee59fa1dSAkihiko Odaki {
572ee59fa1dSAkihiko Odaki     CPUClass *cc = CPU_GET_CLASS(cpu);
573ee59fa1dSAkihiko Odaki     const GDBFeature *feature;
574ee59fa1dSAkihiko Odaki 
575ee59fa1dSAkihiko Odaki     cpu->gdb_regs = g_array_new(false, false, sizeof(GDBRegisterState));
576ee59fa1dSAkihiko Odaki 
577ee59fa1dSAkihiko Odaki     if (cc->gdb_core_xml_file) {
578ee59fa1dSAkihiko Odaki         feature = gdb_find_static_feature(cc->gdb_core_xml_file);
579ee59fa1dSAkihiko Odaki         gdb_register_feature(cpu, 0,
580ee59fa1dSAkihiko Odaki                              cc->gdb_read_register, cc->gdb_write_register,
581ee59fa1dSAkihiko Odaki                              feature);
582ecd6f6a8SAkihiko Odaki         cpu->gdb_num_regs = cpu->gdb_num_g_regs = feature->num_regs;
583ee59fa1dSAkihiko Odaki     }
584ee59fa1dSAkihiko Odaki 
585ecd6f6a8SAkihiko Odaki     if (cc->gdb_num_core_regs) {
586ee59fa1dSAkihiko Odaki         cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs;
587ee59fa1dSAkihiko Odaki     }
588ecd6f6a8SAkihiko Odaki }
589ee59fa1dSAkihiko Odaki 
gdb_register_coprocessor(CPUState * cpu,gdb_get_reg_cb get_reg,gdb_set_reg_cb set_reg,const GDBFeature * feature,int g_pos)590842b42dfSAlex Bennée void gdb_register_coprocessor(CPUState *cpu,
591842b42dfSAlex Bennée                               gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
592ac1e8671SAkihiko Odaki                               const GDBFeature *feature, int g_pos)
593842b42dfSAlex Bennée {
594842b42dfSAlex Bennée     GDBRegisterState *s;
59573c392c2SAkihiko Odaki     guint i;
596ee59fa1dSAkihiko Odaki     int base_reg = cpu->gdb_num_regs;
597842b42dfSAlex Bennée 
59873c392c2SAkihiko Odaki     for (i = 0; i < cpu->gdb_regs->len; i++) {
599842b42dfSAlex Bennée         /* Check for duplicates.  */
60073c392c2SAkihiko Odaki         s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
601c494f8f5SAkihiko Odaki         if (s->feature == feature) {
602842b42dfSAlex Bennée             return;
60373c392c2SAkihiko Odaki         }
60473c392c2SAkihiko Odaki     }
605842b42dfSAlex Bennée 
606ee59fa1dSAkihiko Odaki     gdb_register_feature(cpu, base_reg, get_reg, set_reg, feature);
607842b42dfSAlex Bennée 
608842b42dfSAlex Bennée     /* Add to end of list.  */
609ac1e8671SAkihiko Odaki     cpu->gdb_num_regs += feature->num_regs;
610842b42dfSAlex Bennée     if (g_pos) {
611ee59fa1dSAkihiko Odaki         if (g_pos != base_reg) {
612842b42dfSAlex Bennée             error_report("Error: Bad gdb register numbering for '%s', "
613ee59fa1dSAkihiko Odaki                          "expected %d got %d", feature->xml, g_pos, base_reg);
614842b42dfSAlex Bennée         } else {
615842b42dfSAlex Bennée             cpu->gdb_num_g_regs = cpu->gdb_num_regs;
616842b42dfSAlex Bennée         }
617842b42dfSAlex Bennée     }
618842b42dfSAlex Bennée }
619842b42dfSAlex Bennée 
gdb_process_breakpoint_remove_all(GDBProcess * p)620842b42dfSAlex Bennée static void gdb_process_breakpoint_remove_all(GDBProcess *p)
621842b42dfSAlex Bennée {
622a3fcc111SIlya Leoshkevich     CPUState *cpu = gdb_get_first_cpu_in_process(p);
623842b42dfSAlex Bennée 
624842b42dfSAlex Bennée     while (cpu) {
625ae7467b1SAlex Bennée         gdb_breakpoint_remove_all(cpu);
626842b42dfSAlex Bennée         cpu = gdb_next_cpu_in_process(cpu);
627842b42dfSAlex Bennée     }
628842b42dfSAlex Bennée }
629842b42dfSAlex Bennée 
630842b42dfSAlex Bennée 
gdb_set_cpu_pc(vaddr pc)631b428ad12SAlex Bennée static void gdb_set_cpu_pc(vaddr pc)
632842b42dfSAlex Bennée {
633842b42dfSAlex Bennée     CPUState *cpu = gdbserver_state.c_cpu;
634842b42dfSAlex Bennée 
635842b42dfSAlex Bennée     cpu_synchronize_state(cpu);
636842b42dfSAlex Bennée     cpu_set_pc(cpu, pc);
637842b42dfSAlex Bennée }
638842b42dfSAlex Bennée 
gdb_append_thread_id(CPUState * cpu,GString * buf)63936e067b2SAlex Bennée void gdb_append_thread_id(CPUState *cpu, GString *buf)
640842b42dfSAlex Bennée {
641842b42dfSAlex Bennée     if (gdbserver_state.multiprocess) {
642842b42dfSAlex Bennée         g_string_append_printf(buf, "p%02x.%02x",
64336e067b2SAlex Bennée                                gdb_get_cpu_pid(cpu), gdb_get_cpu_index(cpu));
644842b42dfSAlex Bennée     } else {
64536e067b2SAlex Bennée         g_string_append_printf(buf, "%02x", gdb_get_cpu_index(cpu));
646842b42dfSAlex Bennée     }
647842b42dfSAlex Bennée }
648842b42dfSAlex Bennée 
read_thread_id(const char * buf,const char ** end_buf,uint32_t * pid,uint32_t * tid)649842b42dfSAlex Bennée static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf,
650842b42dfSAlex Bennée                                       uint32_t *pid, uint32_t *tid)
651842b42dfSAlex Bennée {
652842b42dfSAlex Bennée     unsigned long p, t;
653842b42dfSAlex Bennée     int ret;
654842b42dfSAlex Bennée 
655842b42dfSAlex Bennée     if (*buf == 'p') {
656842b42dfSAlex Bennée         buf++;
657842b42dfSAlex Bennée         ret = qemu_strtoul(buf, &buf, 16, &p);
658842b42dfSAlex Bennée 
659842b42dfSAlex Bennée         if (ret) {
660842b42dfSAlex Bennée             return GDB_READ_THREAD_ERR;
661842b42dfSAlex Bennée         }
662842b42dfSAlex Bennée 
663842b42dfSAlex Bennée         /* Skip '.' */
664842b42dfSAlex Bennée         buf++;
665842b42dfSAlex Bennée     } else {
6666c78de6eSMatheus Tavares Bernardino         p = 0;
667842b42dfSAlex Bennée     }
668842b42dfSAlex Bennée 
669842b42dfSAlex Bennée     ret = qemu_strtoul(buf, &buf, 16, &t);
670842b42dfSAlex Bennée 
671842b42dfSAlex Bennée     if (ret) {
672842b42dfSAlex Bennée         return GDB_READ_THREAD_ERR;
673842b42dfSAlex Bennée     }
674842b42dfSAlex Bennée 
675842b42dfSAlex Bennée     *end_buf = buf;
676842b42dfSAlex Bennée 
677842b42dfSAlex Bennée     if (p == -1) {
678842b42dfSAlex Bennée         return GDB_ALL_PROCESSES;
679842b42dfSAlex Bennée     }
680842b42dfSAlex Bennée 
681842b42dfSAlex Bennée     if (pid) {
682842b42dfSAlex Bennée         *pid = p;
683842b42dfSAlex Bennée     }
684842b42dfSAlex Bennée 
685842b42dfSAlex Bennée     if (t == -1) {
686842b42dfSAlex Bennée         return GDB_ALL_THREADS;
687842b42dfSAlex Bennée     }
688842b42dfSAlex Bennée 
689842b42dfSAlex Bennée     if (tid) {
690842b42dfSAlex Bennée         *tid = t;
691842b42dfSAlex Bennée     }
692842b42dfSAlex Bennée 
693842b42dfSAlex Bennée     return GDB_ONE_THREAD;
694842b42dfSAlex Bennée }
695842b42dfSAlex Bennée 
696842b42dfSAlex Bennée /**
697842b42dfSAlex Bennée  * gdb_handle_vcont - Parses and handles a vCont packet.
698842b42dfSAlex Bennée  * returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is
699842b42dfSAlex Bennée  *         a format error, 0 on success.
700842b42dfSAlex Bennée  */
gdb_handle_vcont(const char * p)701842b42dfSAlex Bennée static int gdb_handle_vcont(const char *p)
702842b42dfSAlex Bennée {
703842b42dfSAlex Bennée     int res, signal = 0;
704842b42dfSAlex Bennée     char cur_action;
705842b42dfSAlex Bennée     unsigned long tmp;
706842b42dfSAlex Bennée     uint32_t pid, tid;
707842b42dfSAlex Bennée     GDBProcess *process;
708842b42dfSAlex Bennée     CPUState *cpu;
709842b42dfSAlex Bennée     GDBThreadIdKind kind;
7107ea0c33dSAlex Bennée     unsigned int max_cpus = gdb_get_max_cpus();
711842b42dfSAlex Bennée     /* uninitialised CPUs stay 0 */
7122261b73cSAlex Bennée     g_autofree char *newstates = g_new0(char, max_cpus);
713842b42dfSAlex Bennée 
714842b42dfSAlex Bennée     /* mark valid CPUs with 1 */
715842b42dfSAlex Bennée     CPU_FOREACH(cpu) {
716842b42dfSAlex Bennée         newstates[cpu->cpu_index] = 1;
717842b42dfSAlex Bennée     }
718842b42dfSAlex Bennée 
719842b42dfSAlex Bennée     /*
720842b42dfSAlex Bennée      * res keeps track of what error we are returning, with -ENOTSUP meaning
721842b42dfSAlex Bennée      * that the command is unknown or unsupported, thus returning an empty
722842b42dfSAlex Bennée      * packet, while -EINVAL and -ERANGE cause an E22 packet, due to invalid,
723842b42dfSAlex Bennée      *  or incorrect parameters passed.
724842b42dfSAlex Bennée      */
725842b42dfSAlex Bennée     res = 0;
726761e3c10SMatheus Branco Borella 
727761e3c10SMatheus Branco Borella     /*
728761e3c10SMatheus Branco Borella      * target_count and last_target keep track of how many CPUs we are going to
729761e3c10SMatheus Branco Borella      * step or resume, and a pointer to the state structure of one of them,
730ac2786f0SMichael Tokarev      * respectively
731761e3c10SMatheus Branco Borella      */
732761e3c10SMatheus Branco Borella     int target_count = 0;
733761e3c10SMatheus Branco Borella     CPUState *last_target = NULL;
734761e3c10SMatheus Branco Borella 
735842b42dfSAlex Bennée     while (*p) {
736842b42dfSAlex Bennée         if (*p++ != ';') {
7372261b73cSAlex Bennée             return -ENOTSUP;
738842b42dfSAlex Bennée         }
739842b42dfSAlex Bennée 
740842b42dfSAlex Bennée         cur_action = *p++;
741842b42dfSAlex Bennée         if (cur_action == 'C' || cur_action == 'S') {
742842b42dfSAlex Bennée             cur_action = qemu_tolower(cur_action);
743842b42dfSAlex Bennée             res = qemu_strtoul(p, &p, 16, &tmp);
744842b42dfSAlex Bennée             if (res) {
7452261b73cSAlex Bennée                 return res;
746842b42dfSAlex Bennée             }
747842b42dfSAlex Bennée             signal = gdb_signal_to_target(tmp);
748842b42dfSAlex Bennée         } else if (cur_action != 'c' && cur_action != 's') {
749842b42dfSAlex Bennée             /* unknown/invalid/unsupported command */
7502261b73cSAlex Bennée             return -ENOTSUP;
751842b42dfSAlex Bennée         }
752842b42dfSAlex Bennée 
753842b42dfSAlex Bennée         if (*p == '\0' || *p == ';') {
754842b42dfSAlex Bennée             /*
755842b42dfSAlex Bennée              * No thread specifier, action is on "all threads". The
756842b42dfSAlex Bennée              * specification is unclear regarding the process to act on. We
757842b42dfSAlex Bennée              * choose all processes.
758842b42dfSAlex Bennée              */
759842b42dfSAlex Bennée             kind = GDB_ALL_PROCESSES;
760842b42dfSAlex Bennée         } else if (*p++ == ':') {
761842b42dfSAlex Bennée             kind = read_thread_id(p, &p, &pid, &tid);
762842b42dfSAlex Bennée         } else {
7632261b73cSAlex Bennée             return -ENOTSUP;
764842b42dfSAlex Bennée         }
765842b42dfSAlex Bennée 
766842b42dfSAlex Bennée         switch (kind) {
767842b42dfSAlex Bennée         case GDB_READ_THREAD_ERR:
7682261b73cSAlex Bennée             return -EINVAL;
769842b42dfSAlex Bennée 
770842b42dfSAlex Bennée         case GDB_ALL_PROCESSES:
771842b42dfSAlex Bennée             cpu = gdb_first_attached_cpu();
772842b42dfSAlex Bennée             while (cpu) {
773842b42dfSAlex Bennée                 if (newstates[cpu->cpu_index] == 1) {
774842b42dfSAlex Bennée                     newstates[cpu->cpu_index] = cur_action;
775761e3c10SMatheus Branco Borella 
776761e3c10SMatheus Branco Borella                     target_count++;
777761e3c10SMatheus Branco Borella                     last_target = cpu;
778842b42dfSAlex Bennée                 }
779842b42dfSAlex Bennée 
780842b42dfSAlex Bennée                 cpu = gdb_next_attached_cpu(cpu);
781842b42dfSAlex Bennée             }
782842b42dfSAlex Bennée             break;
783842b42dfSAlex Bennée 
784842b42dfSAlex Bennée         case GDB_ALL_THREADS:
785842b42dfSAlex Bennée             process = gdb_get_process(pid);
786842b42dfSAlex Bennée 
787842b42dfSAlex Bennée             if (!process->attached) {
7882261b73cSAlex Bennée                 return -EINVAL;
789842b42dfSAlex Bennée             }
790842b42dfSAlex Bennée 
791a3fcc111SIlya Leoshkevich             cpu = gdb_get_first_cpu_in_process(process);
792842b42dfSAlex Bennée             while (cpu) {
793842b42dfSAlex Bennée                 if (newstates[cpu->cpu_index] == 1) {
794842b42dfSAlex Bennée                     newstates[cpu->cpu_index] = cur_action;
795761e3c10SMatheus Branco Borella 
796761e3c10SMatheus Branco Borella                     target_count++;
797761e3c10SMatheus Branco Borella                     last_target = cpu;
798842b42dfSAlex Bennée                 }
799842b42dfSAlex Bennée 
800842b42dfSAlex Bennée                 cpu = gdb_next_cpu_in_process(cpu);
801842b42dfSAlex Bennée             }
802842b42dfSAlex Bennée             break;
803842b42dfSAlex Bennée 
804842b42dfSAlex Bennée         case GDB_ONE_THREAD:
805842b42dfSAlex Bennée             cpu = gdb_get_cpu(pid, tid);
806842b42dfSAlex Bennée 
807842b42dfSAlex Bennée             /* invalid CPU/thread specified */
808842b42dfSAlex Bennée             if (!cpu) {
8092261b73cSAlex Bennée                 return -EINVAL;
810842b42dfSAlex Bennée             }
811842b42dfSAlex Bennée 
812842b42dfSAlex Bennée             /* only use if no previous match occourred */
813842b42dfSAlex Bennée             if (newstates[cpu->cpu_index] == 1) {
814842b42dfSAlex Bennée                 newstates[cpu->cpu_index] = cur_action;
815761e3c10SMatheus Branco Borella 
816761e3c10SMatheus Branco Borella                 target_count++;
817761e3c10SMatheus Branco Borella                 last_target = cpu;
818842b42dfSAlex Bennée             }
819842b42dfSAlex Bennée             break;
820842b42dfSAlex Bennée         }
821842b42dfSAlex Bennée     }
8222261b73cSAlex Bennée 
823761e3c10SMatheus Branco Borella     /*
824761e3c10SMatheus Branco Borella      * if we're about to resume a specific set of CPUs/threads, make it so that
825761e3c10SMatheus Branco Borella      * in case execution gets interrupted, we can send GDB a stop reply with a
826761e3c10SMatheus Branco Borella      * correct value. it doesn't really matter which CPU we tell GDB the signal
827761e3c10SMatheus Branco Borella      * happened in (VM pauses stop all of them anyway), so long as it is one of
828761e3c10SMatheus Branco Borella      * the ones we resumed/single stepped here.
829761e3c10SMatheus Branco Borella      */
830761e3c10SMatheus Branco Borella     if (target_count > 0) {
831761e3c10SMatheus Branco Borella         gdbserver_state.c_cpu = last_target;
832761e3c10SMatheus Branco Borella     }
833761e3c10SMatheus Branco Borella 
834842b42dfSAlex Bennée     gdbserver_state.signal = signal;
835842b42dfSAlex Bennée     gdb_continue_partial(newstates);
836842b42dfSAlex Bennée     return res;
837842b42dfSAlex Bennée }
838842b42dfSAlex Bennée 
cmd_next_param(const char * param,const char delimiter)839842b42dfSAlex Bennée static const char *cmd_next_param(const char *param, const char delimiter)
840842b42dfSAlex Bennée {
841842b42dfSAlex Bennée     static const char all_delimiters[] = ",;:=";
842842b42dfSAlex Bennée     char curr_delimiters[2] = {0};
843842b42dfSAlex Bennée     const char *delimiters;
844842b42dfSAlex Bennée 
845842b42dfSAlex Bennée     if (delimiter == '?') {
846842b42dfSAlex Bennée         delimiters = all_delimiters;
847842b42dfSAlex Bennée     } else if (delimiter == '0') {
848842b42dfSAlex Bennée         return strchr(param, '\0');
849842b42dfSAlex Bennée     } else if (delimiter == '.' && *param) {
850842b42dfSAlex Bennée         return param + 1;
851842b42dfSAlex Bennée     } else {
852842b42dfSAlex Bennée         curr_delimiters[0] = delimiter;
853842b42dfSAlex Bennée         delimiters = curr_delimiters;
854842b42dfSAlex Bennée     }
855842b42dfSAlex Bennée 
856842b42dfSAlex Bennée     param += strcspn(param, delimiters);
857842b42dfSAlex Bennée     if (*param) {
858842b42dfSAlex Bennée         param++;
859842b42dfSAlex Bennée     }
860842b42dfSAlex Bennée     return param;
861842b42dfSAlex Bennée }
862842b42dfSAlex Bennée 
cmd_parse_params(const char * data,const char * schema,GArray * params)863842b42dfSAlex Bennée static int cmd_parse_params(const char *data, const char *schema,
864842b42dfSAlex Bennée                             GArray *params)
865842b42dfSAlex Bennée {
866842b42dfSAlex Bennée     const char *curr_schema, *curr_data;
867842b42dfSAlex Bennée 
868842b42dfSAlex Bennée     g_assert(schema);
869842b42dfSAlex Bennée     g_assert(params->len == 0);
870842b42dfSAlex Bennée 
871842b42dfSAlex Bennée     curr_schema = schema;
872842b42dfSAlex Bennée     curr_data = data;
873842b42dfSAlex Bennée     while (curr_schema[0] && curr_schema[1] && *curr_data) {
874842b42dfSAlex Bennée         GdbCmdVariant this_param;
875842b42dfSAlex Bennée 
876842b42dfSAlex Bennée         switch (curr_schema[0]) {
877842b42dfSAlex Bennée         case 'l':
878842b42dfSAlex Bennée             if (qemu_strtoul(curr_data, &curr_data, 16,
879842b42dfSAlex Bennée                              &this_param.val_ul)) {
880842b42dfSAlex Bennée                 return -EINVAL;
881842b42dfSAlex Bennée             }
882842b42dfSAlex Bennée             curr_data = cmd_next_param(curr_data, curr_schema[1]);
883842b42dfSAlex Bennée             g_array_append_val(params, this_param);
884842b42dfSAlex Bennée             break;
885842b42dfSAlex Bennée         case 'L':
886842b42dfSAlex Bennée             if (qemu_strtou64(curr_data, &curr_data, 16,
887842b42dfSAlex Bennée                               (uint64_t *)&this_param.val_ull)) {
888842b42dfSAlex Bennée                 return -EINVAL;
889842b42dfSAlex Bennée             }
890842b42dfSAlex Bennée             curr_data = cmd_next_param(curr_data, curr_schema[1]);
891842b42dfSAlex Bennée             g_array_append_val(params, this_param);
892842b42dfSAlex Bennée             break;
893842b42dfSAlex Bennée         case 's':
894842b42dfSAlex Bennée             this_param.data = curr_data;
895842b42dfSAlex Bennée             curr_data = cmd_next_param(curr_data, curr_schema[1]);
896842b42dfSAlex Bennée             g_array_append_val(params, this_param);
897842b42dfSAlex Bennée             break;
898842b42dfSAlex Bennée         case 'o':
899842b42dfSAlex Bennée             this_param.opcode = *(uint8_t *)curr_data;
900842b42dfSAlex Bennée             curr_data = cmd_next_param(curr_data, curr_schema[1]);
901842b42dfSAlex Bennée             g_array_append_val(params, this_param);
902842b42dfSAlex Bennée             break;
903842b42dfSAlex Bennée         case 't':
904842b42dfSAlex Bennée             this_param.thread_id.kind =
905842b42dfSAlex Bennée                 read_thread_id(curr_data, &curr_data,
906842b42dfSAlex Bennée                                &this_param.thread_id.pid,
907842b42dfSAlex Bennée                                &this_param.thread_id.tid);
908842b42dfSAlex Bennée             curr_data = cmd_next_param(curr_data, curr_schema[1]);
909842b42dfSAlex Bennée             g_array_append_val(params, this_param);
910842b42dfSAlex Bennée             break;
911842b42dfSAlex Bennée         case '?':
912842b42dfSAlex Bennée             curr_data = cmd_next_param(curr_data, curr_schema[1]);
913842b42dfSAlex Bennée             break;
914842b42dfSAlex Bennée         default:
915842b42dfSAlex Bennée             return -EINVAL;
916842b42dfSAlex Bennée         }
917842b42dfSAlex Bennée         curr_schema += 2;
918842b42dfSAlex Bennée     }
919842b42dfSAlex Bennée 
920842b42dfSAlex Bennée     return 0;
921842b42dfSAlex Bennée }
922842b42dfSAlex Bennée 
923842b42dfSAlex Bennée typedef void (*GdbCmdHandler)(GArray *params, void *user_ctx);
924842b42dfSAlex Bennée 
925842b42dfSAlex Bennée /*
926842b42dfSAlex Bennée  * cmd_startswith -> cmd is compared using startswith
927842b42dfSAlex Bennée  *
92875837005SMatheus Tavares Bernardino  * allow_stop_reply -> true iff the gdbstub can respond to this command with a
92975837005SMatheus Tavares Bernardino  *   "stop reply" packet. The list of commands that accept such response is
93075837005SMatheus Tavares Bernardino  *   defined at the GDB Remote Serial Protocol documentation. see:
93175837005SMatheus Tavares Bernardino  *   https://sourceware.org/gdb/onlinedocs/gdb/Stop-Reply-Packets.html#Stop-Reply-Packets.
932842b42dfSAlex Bennée  *
933842b42dfSAlex Bennée  * schema definitions:
934842b42dfSAlex Bennée  * Each schema parameter entry consists of 2 chars,
935842b42dfSAlex Bennée  * the first char represents the parameter type handling
936842b42dfSAlex Bennée  * the second char represents the delimiter for the next parameter
937842b42dfSAlex Bennée  *
938842b42dfSAlex Bennée  * Currently supported schema types:
939842b42dfSAlex Bennée  * 'l' -> unsigned long (stored in .val_ul)
940842b42dfSAlex Bennée  * 'L' -> unsigned long long (stored in .val_ull)
941842b42dfSAlex Bennée  * 's' -> string (stored in .data)
942842b42dfSAlex Bennée  * 'o' -> single char (stored in .opcode)
943842b42dfSAlex Bennée  * 't' -> thread id (stored in .thread_id)
944842b42dfSAlex Bennée  * '?' -> skip according to delimiter
945842b42dfSAlex Bennée  *
946842b42dfSAlex Bennée  * Currently supported delimiters:
947842b42dfSAlex Bennée  * '?' -> Stop at any delimiter (",;:=\0")
948842b42dfSAlex Bennée  * '0' -> Stop at "\0"
949842b42dfSAlex Bennée  * '.' -> Skip 1 char unless reached "\0"
950842b42dfSAlex Bennée  * Any other value is treated as the delimiter value itself
951842b42dfSAlex Bennée  */
952842b42dfSAlex Bennée typedef struct GdbCmdParseEntry {
953842b42dfSAlex Bennée     GdbCmdHandler handler;
954842b42dfSAlex Bennée     const char *cmd;
955842b42dfSAlex Bennée     bool cmd_startswith;
956842b42dfSAlex Bennée     const char *schema;
95775837005SMatheus Tavares Bernardino     bool allow_stop_reply;
958842b42dfSAlex Bennée } GdbCmdParseEntry;
959842b42dfSAlex Bennée 
startswith(const char * string,const char * pattern)960842b42dfSAlex Bennée static inline int startswith(const char *string, const char *pattern)
961842b42dfSAlex Bennée {
962842b42dfSAlex Bennée   return !strncmp(string, pattern, strlen(pattern));
963842b42dfSAlex Bennée }
964842b42dfSAlex Bennée 
process_string_cmd(const char * data,const GdbCmdParseEntry * cmds,int num_cmds)9655b030993SAlex Bennée static int process_string_cmd(const char *data,
966842b42dfSAlex Bennée                               const GdbCmdParseEntry *cmds, int num_cmds)
967842b42dfSAlex Bennée {
968842b42dfSAlex Bennée     int i;
969842b42dfSAlex Bennée     g_autoptr(GArray) params = g_array_new(false, true, sizeof(GdbCmdVariant));
970842b42dfSAlex Bennée 
971842b42dfSAlex Bennée     if (!cmds) {
972842b42dfSAlex Bennée         return -1;
973842b42dfSAlex Bennée     }
974842b42dfSAlex Bennée 
975842b42dfSAlex Bennée     for (i = 0; i < num_cmds; i++) {
976842b42dfSAlex Bennée         const GdbCmdParseEntry *cmd = &cmds[i];
977842b42dfSAlex Bennée         g_assert(cmd->handler && cmd->cmd);
978842b42dfSAlex Bennée 
979842b42dfSAlex Bennée         if ((cmd->cmd_startswith && !startswith(data, cmd->cmd)) ||
980842b42dfSAlex Bennée             (!cmd->cmd_startswith && strcmp(cmd->cmd, data))) {
981842b42dfSAlex Bennée             continue;
982842b42dfSAlex Bennée         }
983842b42dfSAlex Bennée 
984842b42dfSAlex Bennée         if (cmd->schema) {
985842b42dfSAlex Bennée             if (cmd_parse_params(&data[strlen(cmd->cmd)],
986842b42dfSAlex Bennée                                  cmd->schema, params)) {
987842b42dfSAlex Bennée                 return -1;
988842b42dfSAlex Bennée             }
989842b42dfSAlex Bennée         }
990842b42dfSAlex Bennée 
99175837005SMatheus Tavares Bernardino         gdbserver_state.allow_stop_reply = cmd->allow_stop_reply;
9925b030993SAlex Bennée         cmd->handler(params, NULL);
993842b42dfSAlex Bennée         return 0;
994842b42dfSAlex Bennée     }
995842b42dfSAlex Bennée 
996842b42dfSAlex Bennée     return -1;
997842b42dfSAlex Bennée }
998842b42dfSAlex Bennée 
run_cmd_parser(const char * data,const GdbCmdParseEntry * cmd)999842b42dfSAlex Bennée static void run_cmd_parser(const char *data, const GdbCmdParseEntry *cmd)
1000842b42dfSAlex Bennée {
1001842b42dfSAlex Bennée     if (!data) {
1002842b42dfSAlex Bennée         return;
1003842b42dfSAlex Bennée     }
1004842b42dfSAlex Bennée 
1005842b42dfSAlex Bennée     g_string_set_size(gdbserver_state.str_buf, 0);
1006842b42dfSAlex Bennée     g_byte_array_set_size(gdbserver_state.mem_buf, 0);
1007842b42dfSAlex Bennée 
1008842b42dfSAlex Bennée     /* In case there was an error during the command parsing we must
1009842b42dfSAlex Bennée     * send a NULL packet to indicate the command is not supported */
10105b030993SAlex Bennée     if (process_string_cmd(data, cmd, 1)) {
101136e067b2SAlex Bennée         gdb_put_packet("");
1012842b42dfSAlex Bennée     }
1013842b42dfSAlex Bennée }
1014842b42dfSAlex Bennée 
handle_detach(GArray * params,void * user_ctx)1015842b42dfSAlex Bennée static void handle_detach(GArray *params, void *user_ctx)
1016842b42dfSAlex Bennée {
1017842b42dfSAlex Bennée     GDBProcess *process;
1018842b42dfSAlex Bennée     uint32_t pid = 1;
1019842b42dfSAlex Bennée 
1020842b42dfSAlex Bennée     if (gdbserver_state.multiprocess) {
1021842b42dfSAlex Bennée         if (!params->len) {
102236e067b2SAlex Bennée             gdb_put_packet("E22");
1023842b42dfSAlex Bennée             return;
1024842b42dfSAlex Bennée         }
1025842b42dfSAlex Bennée 
1026842b42dfSAlex Bennée         pid = get_param(params, 0)->val_ul;
1027842b42dfSAlex Bennée     }
1028842b42dfSAlex Bennée 
1029539cb4ecSIlya Leoshkevich #ifdef CONFIG_USER_ONLY
1030539cb4ecSIlya Leoshkevich     if (gdb_handle_detach_user(pid)) {
1031539cb4ecSIlya Leoshkevich         return;
1032539cb4ecSIlya Leoshkevich     }
1033539cb4ecSIlya Leoshkevich #endif
1034539cb4ecSIlya Leoshkevich 
1035842b42dfSAlex Bennée     process = gdb_get_process(pid);
1036842b42dfSAlex Bennée     gdb_process_breakpoint_remove_all(process);
1037842b42dfSAlex Bennée     process->attached = false;
1038842b42dfSAlex Bennée 
1039842b42dfSAlex Bennée     if (pid == gdb_get_cpu_pid(gdbserver_state.c_cpu)) {
1040842b42dfSAlex Bennée         gdbserver_state.c_cpu = gdb_first_attached_cpu();
1041842b42dfSAlex Bennée     }
1042842b42dfSAlex Bennée 
1043842b42dfSAlex Bennée     if (pid == gdb_get_cpu_pid(gdbserver_state.g_cpu)) {
1044842b42dfSAlex Bennée         gdbserver_state.g_cpu = gdb_first_attached_cpu();
1045842b42dfSAlex Bennée     }
1046842b42dfSAlex Bennée 
1047842b42dfSAlex Bennée     if (!gdbserver_state.c_cpu) {
1048842b42dfSAlex Bennée         /* No more process attached */
1049c566080cSAlex Bennée         gdb_disable_syscalls();
1050842b42dfSAlex Bennée         gdb_continue();
1051842b42dfSAlex Bennée     }
105236e067b2SAlex Bennée     gdb_put_packet("OK");
1053842b42dfSAlex Bennée }
1054842b42dfSAlex Bennée 
handle_thread_alive(GArray * params,void * user_ctx)1055842b42dfSAlex Bennée static void handle_thread_alive(GArray *params, void *user_ctx)
1056842b42dfSAlex Bennée {
1057842b42dfSAlex Bennée     CPUState *cpu;
1058842b42dfSAlex Bennée 
1059842b42dfSAlex Bennée     if (!params->len) {
106036e067b2SAlex Bennée         gdb_put_packet("E22");
1061842b42dfSAlex Bennée         return;
1062842b42dfSAlex Bennée     }
1063842b42dfSAlex Bennée 
1064842b42dfSAlex Bennée     if (get_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) {
106536e067b2SAlex Bennée         gdb_put_packet("E22");
1066842b42dfSAlex Bennée         return;
1067842b42dfSAlex Bennée     }
1068842b42dfSAlex Bennée 
1069842b42dfSAlex Bennée     cpu = gdb_get_cpu(get_param(params, 0)->thread_id.pid,
1070842b42dfSAlex Bennée                       get_param(params, 0)->thread_id.tid);
1071842b42dfSAlex Bennée     if (!cpu) {
107236e067b2SAlex Bennée         gdb_put_packet("E22");
1073842b42dfSAlex Bennée         return;
1074842b42dfSAlex Bennée     }
1075842b42dfSAlex Bennée 
107636e067b2SAlex Bennée     gdb_put_packet("OK");
1077842b42dfSAlex Bennée }
1078842b42dfSAlex Bennée 
handle_continue(GArray * params,void * user_ctx)1079842b42dfSAlex Bennée static void handle_continue(GArray *params, void *user_ctx)
1080842b42dfSAlex Bennée {
1081842b42dfSAlex Bennée     if (params->len) {
1082842b42dfSAlex Bennée         gdb_set_cpu_pc(get_param(params, 0)->val_ull);
1083842b42dfSAlex Bennée     }
1084842b42dfSAlex Bennée 
1085842b42dfSAlex Bennée     gdbserver_state.signal = 0;
1086842b42dfSAlex Bennée     gdb_continue();
1087842b42dfSAlex Bennée }
1088842b42dfSAlex Bennée 
handle_cont_with_sig(GArray * params,void * user_ctx)1089842b42dfSAlex Bennée static void handle_cont_with_sig(GArray *params, void *user_ctx)
1090842b42dfSAlex Bennée {
1091842b42dfSAlex Bennée     unsigned long signal = 0;
1092842b42dfSAlex Bennée 
1093842b42dfSAlex Bennée     /*
1094842b42dfSAlex Bennée      * Note: C sig;[addr] is currently unsupported and we simply
1095842b42dfSAlex Bennée      *       omit the addr parameter
1096842b42dfSAlex Bennée      */
1097842b42dfSAlex Bennée     if (params->len) {
1098842b42dfSAlex Bennée         signal = get_param(params, 0)->val_ul;
1099842b42dfSAlex Bennée     }
1100842b42dfSAlex Bennée 
1101842b42dfSAlex Bennée     gdbserver_state.signal = gdb_signal_to_target(signal);
1102842b42dfSAlex Bennée     if (gdbserver_state.signal == -1) {
1103842b42dfSAlex Bennée         gdbserver_state.signal = 0;
1104842b42dfSAlex Bennée     }
1105842b42dfSAlex Bennée     gdb_continue();
1106842b42dfSAlex Bennée }
1107842b42dfSAlex Bennée 
handle_set_thread(GArray * params,void * user_ctx)1108842b42dfSAlex Bennée static void handle_set_thread(GArray *params, void *user_ctx)
1109842b42dfSAlex Bennée {
1110e454f2feSIlya Leoshkevich     uint32_t pid, tid;
1111842b42dfSAlex Bennée     CPUState *cpu;
1112842b42dfSAlex Bennée 
1113842b42dfSAlex Bennée     if (params->len != 2) {
111436e067b2SAlex Bennée         gdb_put_packet("E22");
1115842b42dfSAlex Bennée         return;
1116842b42dfSAlex Bennée     }
1117842b42dfSAlex Bennée 
1118842b42dfSAlex Bennée     if (get_param(params, 1)->thread_id.kind == GDB_READ_THREAD_ERR) {
111936e067b2SAlex Bennée         gdb_put_packet("E22");
1120842b42dfSAlex Bennée         return;
1121842b42dfSAlex Bennée     }
1122842b42dfSAlex Bennée 
1123842b42dfSAlex Bennée     if (get_param(params, 1)->thread_id.kind != GDB_ONE_THREAD) {
112436e067b2SAlex Bennée         gdb_put_packet("OK");
1125842b42dfSAlex Bennée         return;
1126842b42dfSAlex Bennée     }
1127842b42dfSAlex Bennée 
1128e454f2feSIlya Leoshkevich     pid = get_param(params, 1)->thread_id.pid;
1129e454f2feSIlya Leoshkevich     tid = get_param(params, 1)->thread_id.tid;
1130e454f2feSIlya Leoshkevich #ifdef CONFIG_USER_ONLY
1131e454f2feSIlya Leoshkevich     if (gdb_handle_set_thread_user(pid, tid)) {
1132e454f2feSIlya Leoshkevich         return;
1133e454f2feSIlya Leoshkevich     }
1134e454f2feSIlya Leoshkevich #endif
1135e454f2feSIlya Leoshkevich     cpu = gdb_get_cpu(pid, tid);
1136842b42dfSAlex Bennée     if (!cpu) {
113736e067b2SAlex Bennée         gdb_put_packet("E22");
1138842b42dfSAlex Bennée         return;
1139842b42dfSAlex Bennée     }
1140842b42dfSAlex Bennée 
1141842b42dfSAlex Bennée     /*
1142842b42dfSAlex Bennée      * Note: This command is deprecated and modern gdb's will be using the
1143842b42dfSAlex Bennée      *       vCont command instead.
1144842b42dfSAlex Bennée      */
1145842b42dfSAlex Bennée     switch (get_param(params, 0)->opcode) {
1146842b42dfSAlex Bennée     case 'c':
1147842b42dfSAlex Bennée         gdbserver_state.c_cpu = cpu;
114836e067b2SAlex Bennée         gdb_put_packet("OK");
1149842b42dfSAlex Bennée         break;
1150842b42dfSAlex Bennée     case 'g':
1151842b42dfSAlex Bennée         gdbserver_state.g_cpu = cpu;
115236e067b2SAlex Bennée         gdb_put_packet("OK");
1153842b42dfSAlex Bennée         break;
1154842b42dfSAlex Bennée     default:
115536e067b2SAlex Bennée         gdb_put_packet("E22");
1156842b42dfSAlex Bennée         break;
1157842b42dfSAlex Bennée     }
1158842b42dfSAlex Bennée }
1159842b42dfSAlex Bennée 
handle_insert_bp(GArray * params,void * user_ctx)1160842b42dfSAlex Bennée static void handle_insert_bp(GArray *params, void *user_ctx)
1161842b42dfSAlex Bennée {
1162842b42dfSAlex Bennée     int res;
1163842b42dfSAlex Bennée 
1164842b42dfSAlex Bennée     if (params->len != 3) {
116536e067b2SAlex Bennée         gdb_put_packet("E22");
1166842b42dfSAlex Bennée         return;
1167842b42dfSAlex Bennée     }
1168842b42dfSAlex Bennée 
1169ae7467b1SAlex Bennée     res = gdb_breakpoint_insert(gdbserver_state.c_cpu,
1170ae7467b1SAlex Bennée                                 get_param(params, 0)->val_ul,
1171842b42dfSAlex Bennée                                 get_param(params, 1)->val_ull,
1172842b42dfSAlex Bennée                                 get_param(params, 2)->val_ull);
1173842b42dfSAlex Bennée     if (res >= 0) {
117436e067b2SAlex Bennée         gdb_put_packet("OK");
1175842b42dfSAlex Bennée         return;
1176842b42dfSAlex Bennée     } else if (res == -ENOSYS) {
117736e067b2SAlex Bennée         gdb_put_packet("");
1178842b42dfSAlex Bennée         return;
1179842b42dfSAlex Bennée     }
1180842b42dfSAlex Bennée 
118136e067b2SAlex Bennée     gdb_put_packet("E22");
1182842b42dfSAlex Bennée }
1183842b42dfSAlex Bennée 
handle_remove_bp(GArray * params,void * user_ctx)1184842b42dfSAlex Bennée static void handle_remove_bp(GArray *params, void *user_ctx)
1185842b42dfSAlex Bennée {
1186842b42dfSAlex Bennée     int res;
1187842b42dfSAlex Bennée 
1188842b42dfSAlex Bennée     if (params->len != 3) {
118936e067b2SAlex Bennée         gdb_put_packet("E22");
1190842b42dfSAlex Bennée         return;
1191842b42dfSAlex Bennée     }
1192842b42dfSAlex Bennée 
1193ae7467b1SAlex Bennée     res = gdb_breakpoint_remove(gdbserver_state.c_cpu,
1194ae7467b1SAlex Bennée                                 get_param(params, 0)->val_ul,
1195842b42dfSAlex Bennée                                 get_param(params, 1)->val_ull,
1196842b42dfSAlex Bennée                                 get_param(params, 2)->val_ull);
1197842b42dfSAlex Bennée     if (res >= 0) {
119836e067b2SAlex Bennée         gdb_put_packet("OK");
1199842b42dfSAlex Bennée         return;
1200842b42dfSAlex Bennée     } else if (res == -ENOSYS) {
120136e067b2SAlex Bennée         gdb_put_packet("");
1202842b42dfSAlex Bennée         return;
1203842b42dfSAlex Bennée     }
1204842b42dfSAlex Bennée 
120536e067b2SAlex Bennée     gdb_put_packet("E22");
1206842b42dfSAlex Bennée }
1207842b42dfSAlex Bennée 
1208842b42dfSAlex Bennée /*
1209842b42dfSAlex Bennée  * handle_set/get_reg
1210842b42dfSAlex Bennée  *
1211842b42dfSAlex Bennée  * Older gdb are really dumb, and don't use 'G/g' if 'P/p' is available.
1212842b42dfSAlex Bennée  * This works, but can be very slow. Anything new enough to understand
1213842b42dfSAlex Bennée  * XML also knows how to use this properly. However to use this we
1214842b42dfSAlex Bennée  * need to define a local XML file as well as be talking to a
1215842b42dfSAlex Bennée  * reasonably modern gdb. Responding with an empty packet will cause
1216842b42dfSAlex Bennée  * the remote gdb to fallback to older methods.
1217842b42dfSAlex Bennée  */
1218842b42dfSAlex Bennée 
handle_set_reg(GArray * params,void * user_ctx)1219842b42dfSAlex Bennée static void handle_set_reg(GArray *params, void *user_ctx)
1220842b42dfSAlex Bennée {
1221842b42dfSAlex Bennée     int reg_size;
1222842b42dfSAlex Bennée 
1223842b42dfSAlex Bennée     if (params->len != 2) {
122436e067b2SAlex Bennée         gdb_put_packet("E22");
1225842b42dfSAlex Bennée         return;
1226842b42dfSAlex Bennée     }
1227842b42dfSAlex Bennée 
1228842b42dfSAlex Bennée     reg_size = strlen(get_param(params, 1)->data) / 2;
122936e067b2SAlex Bennée     gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 1)->data, reg_size);
1230842b42dfSAlex Bennée     gdb_write_register(gdbserver_state.g_cpu, gdbserver_state.mem_buf->data,
1231842b42dfSAlex Bennée                        get_param(params, 0)->val_ull);
123236e067b2SAlex Bennée     gdb_put_packet("OK");
1233842b42dfSAlex Bennée }
1234842b42dfSAlex Bennée 
handle_get_reg(GArray * params,void * user_ctx)1235842b42dfSAlex Bennée static void handle_get_reg(GArray *params, void *user_ctx)
1236842b42dfSAlex Bennée {
1237842b42dfSAlex Bennée     int reg_size;
1238842b42dfSAlex Bennée 
1239842b42dfSAlex Bennée     if (!params->len) {
124036e067b2SAlex Bennée         gdb_put_packet("E14");
1241842b42dfSAlex Bennée         return;
1242842b42dfSAlex Bennée     }
1243842b42dfSAlex Bennée 
1244842b42dfSAlex Bennée     reg_size = gdb_read_register(gdbserver_state.g_cpu,
1245842b42dfSAlex Bennée                                  gdbserver_state.mem_buf,
1246842b42dfSAlex Bennée                                  get_param(params, 0)->val_ull);
1247842b42dfSAlex Bennée     if (!reg_size) {
124836e067b2SAlex Bennée         gdb_put_packet("E14");
1249842b42dfSAlex Bennée         return;
1250842b42dfSAlex Bennée     } else {
1251842b42dfSAlex Bennée         g_byte_array_set_size(gdbserver_state.mem_buf, reg_size);
1252842b42dfSAlex Bennée     }
1253842b42dfSAlex Bennée 
125436e067b2SAlex Bennée     gdb_memtohex(gdbserver_state.str_buf,
125536e067b2SAlex Bennée                  gdbserver_state.mem_buf->data, reg_size);
125636e067b2SAlex Bennée     gdb_put_strbuf();
1257842b42dfSAlex Bennée }
1258842b42dfSAlex Bennée 
handle_write_mem(GArray * params,void * user_ctx)1259842b42dfSAlex Bennée static void handle_write_mem(GArray *params, void *user_ctx)
1260842b42dfSAlex Bennée {
1261842b42dfSAlex Bennée     if (params->len != 3) {
126236e067b2SAlex Bennée         gdb_put_packet("E22");
1263842b42dfSAlex Bennée         return;
1264842b42dfSAlex Bennée     }
1265842b42dfSAlex Bennée 
126636e067b2SAlex Bennée     /* gdb_hextomem() reads 2*len bytes */
1267842b42dfSAlex Bennée     if (get_param(params, 1)->val_ull >
1268842b42dfSAlex Bennée         strlen(get_param(params, 2)->data) / 2) {
126936e067b2SAlex Bennée         gdb_put_packet("E22");
1270842b42dfSAlex Bennée         return;
1271842b42dfSAlex Bennée     }
1272842b42dfSAlex Bennée 
127336e067b2SAlex Bennée     gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 2)->data,
1274842b42dfSAlex Bennée                  get_param(params, 1)->val_ull);
1275589a5867SAlex Bennée     if (gdb_target_memory_rw_debug(gdbserver_state.g_cpu,
1276842b42dfSAlex Bennée                                    get_param(params, 0)->val_ull,
1277842b42dfSAlex Bennée                                    gdbserver_state.mem_buf->data,
1278842b42dfSAlex Bennée                                    gdbserver_state.mem_buf->len, true)) {
127936e067b2SAlex Bennée         gdb_put_packet("E14");
1280842b42dfSAlex Bennée         return;
1281842b42dfSAlex Bennée     }
1282842b42dfSAlex Bennée 
128336e067b2SAlex Bennée     gdb_put_packet("OK");
1284842b42dfSAlex Bennée }
1285842b42dfSAlex Bennée 
handle_read_mem(GArray * params,void * user_ctx)1286842b42dfSAlex Bennée static void handle_read_mem(GArray *params, void *user_ctx)
1287842b42dfSAlex Bennée {
1288842b42dfSAlex Bennée     if (params->len != 2) {
128936e067b2SAlex Bennée         gdb_put_packet("E22");
1290842b42dfSAlex Bennée         return;
1291842b42dfSAlex Bennée     }
1292842b42dfSAlex Bennée 
129336e067b2SAlex Bennée     /* gdb_memtohex() doubles the required space */
1294842b42dfSAlex Bennée     if (get_param(params, 1)->val_ull > MAX_PACKET_LENGTH / 2) {
129536e067b2SAlex Bennée         gdb_put_packet("E22");
1296842b42dfSAlex Bennée         return;
1297842b42dfSAlex Bennée     }
1298842b42dfSAlex Bennée 
1299842b42dfSAlex Bennée     g_byte_array_set_size(gdbserver_state.mem_buf,
1300842b42dfSAlex Bennée                           get_param(params, 1)->val_ull);
1301842b42dfSAlex Bennée 
1302589a5867SAlex Bennée     if (gdb_target_memory_rw_debug(gdbserver_state.g_cpu,
1303842b42dfSAlex Bennée                                    get_param(params, 0)->val_ull,
1304842b42dfSAlex Bennée                                    gdbserver_state.mem_buf->data,
1305842b42dfSAlex Bennée                                    gdbserver_state.mem_buf->len, false)) {
130636e067b2SAlex Bennée         gdb_put_packet("E14");
1307842b42dfSAlex Bennée         return;
1308842b42dfSAlex Bennée     }
1309842b42dfSAlex Bennée 
131036e067b2SAlex Bennée     gdb_memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data,
1311842b42dfSAlex Bennée              gdbserver_state.mem_buf->len);
131236e067b2SAlex Bennée     gdb_put_strbuf();
1313842b42dfSAlex Bennée }
1314842b42dfSAlex Bennée 
handle_write_all_regs(GArray * params,void * user_ctx)1315842b42dfSAlex Bennée static void handle_write_all_regs(GArray *params, void *user_ctx)
1316842b42dfSAlex Bennée {
1317379b42e8SAlex Bennée     int reg_id;
1318379b42e8SAlex Bennée     size_t len;
1319842b42dfSAlex Bennée     uint8_t *registers;
1320842b42dfSAlex Bennée     int reg_size;
1321842b42dfSAlex Bennée 
1322842b42dfSAlex Bennée     if (!params->len) {
1323842b42dfSAlex Bennée         return;
1324842b42dfSAlex Bennée     }
1325842b42dfSAlex Bennée 
1326842b42dfSAlex Bennée     cpu_synchronize_state(gdbserver_state.g_cpu);
1327842b42dfSAlex Bennée     len = strlen(get_param(params, 0)->data) / 2;
132836e067b2SAlex Bennée     gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 0)->data, len);
1329842b42dfSAlex Bennée     registers = gdbserver_state.mem_buf->data;
1330379b42e8SAlex Bennée     for (reg_id = 0;
1331379b42e8SAlex Bennée          reg_id < gdbserver_state.g_cpu->gdb_num_g_regs && len > 0;
1332379b42e8SAlex Bennée          reg_id++) {
1333379b42e8SAlex Bennée         reg_size = gdb_write_register(gdbserver_state.g_cpu, registers, reg_id);
1334842b42dfSAlex Bennée         len -= reg_size;
1335842b42dfSAlex Bennée         registers += reg_size;
1336842b42dfSAlex Bennée     }
133736e067b2SAlex Bennée     gdb_put_packet("OK");
1338842b42dfSAlex Bennée }
1339842b42dfSAlex Bennée 
handle_read_all_regs(GArray * params,void * user_ctx)1340842b42dfSAlex Bennée static void handle_read_all_regs(GArray *params, void *user_ctx)
1341842b42dfSAlex Bennée {
1342379b42e8SAlex Bennée     int reg_id;
1343379b42e8SAlex Bennée     size_t len;
1344842b42dfSAlex Bennée 
1345842b42dfSAlex Bennée     cpu_synchronize_state(gdbserver_state.g_cpu);
1346842b42dfSAlex Bennée     g_byte_array_set_size(gdbserver_state.mem_buf, 0);
1347842b42dfSAlex Bennée     len = 0;
1348379b42e8SAlex Bennée     for (reg_id = 0; reg_id < gdbserver_state.g_cpu->gdb_num_g_regs; reg_id++) {
1349842b42dfSAlex Bennée         len += gdb_read_register(gdbserver_state.g_cpu,
1350842b42dfSAlex Bennée                                  gdbserver_state.mem_buf,
1351379b42e8SAlex Bennée                                  reg_id);
1352842b42dfSAlex Bennée     }
1353842b42dfSAlex Bennée     g_assert(len == gdbserver_state.mem_buf->len);
1354842b42dfSAlex Bennée 
135536e067b2SAlex Bennée     gdb_memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, len);
135636e067b2SAlex Bennée     gdb_put_strbuf();
1357842b42dfSAlex Bennée }
1358842b42dfSAlex Bennée 
1359842b42dfSAlex Bennée 
handle_step(GArray * params,void * user_ctx)1360842b42dfSAlex Bennée static void handle_step(GArray *params, void *user_ctx)
1361842b42dfSAlex Bennée {
1362842b42dfSAlex Bennée     if (params->len) {
1363b428ad12SAlex Bennée         gdb_set_cpu_pc(get_param(params, 0)->val_ull);
1364842b42dfSAlex Bennée     }
1365842b42dfSAlex Bennée 
1366842b42dfSAlex Bennée     cpu_single_step(gdbserver_state.c_cpu, gdbserver_state.sstep_flags);
1367842b42dfSAlex Bennée     gdb_continue();
1368842b42dfSAlex Bennée }
1369842b42dfSAlex Bennée 
handle_backward(GArray * params,void * user_ctx)1370842b42dfSAlex Bennée static void handle_backward(GArray *params, void *user_ctx)
1371842b42dfSAlex Bennée {
1372505601d5SAlex Bennée     if (!gdb_can_reverse()) {
137336e067b2SAlex Bennée         gdb_put_packet("E22");
1374842b42dfSAlex Bennée     }
1375842b42dfSAlex Bennée     if (params->len == 1) {
1376842b42dfSAlex Bennée         switch (get_param(params, 0)->opcode) {
1377842b42dfSAlex Bennée         case 's':
1378842b42dfSAlex Bennée             if (replay_reverse_step()) {
1379842b42dfSAlex Bennée                 gdb_continue();
1380842b42dfSAlex Bennée             } else {
138136e067b2SAlex Bennée                 gdb_put_packet("E14");
1382842b42dfSAlex Bennée             }
1383842b42dfSAlex Bennée             return;
1384842b42dfSAlex Bennée         case 'c':
1385842b42dfSAlex Bennée             if (replay_reverse_continue()) {
1386842b42dfSAlex Bennée                 gdb_continue();
1387842b42dfSAlex Bennée             } else {
138836e067b2SAlex Bennée                 gdb_put_packet("E14");
1389842b42dfSAlex Bennée             }
1390842b42dfSAlex Bennée             return;
1391842b42dfSAlex Bennée         }
1392842b42dfSAlex Bennée     }
1393842b42dfSAlex Bennée 
1394842b42dfSAlex Bennée     /* Default invalid command */
139536e067b2SAlex Bennée     gdb_put_packet("");
1396842b42dfSAlex Bennée }
1397842b42dfSAlex Bennée 
handle_v_cont_query(GArray * params,void * user_ctx)1398842b42dfSAlex Bennée static void handle_v_cont_query(GArray *params, void *user_ctx)
1399842b42dfSAlex Bennée {
140036e067b2SAlex Bennée     gdb_put_packet("vCont;c;C;s;S");
1401842b42dfSAlex Bennée }
1402842b42dfSAlex Bennée 
handle_v_cont(GArray * params,void * user_ctx)1403842b42dfSAlex Bennée static void handle_v_cont(GArray *params, void *user_ctx)
1404842b42dfSAlex Bennée {
1405842b42dfSAlex Bennée     int res;
1406842b42dfSAlex Bennée 
1407842b42dfSAlex Bennée     if (!params->len) {
1408842b42dfSAlex Bennée         return;
1409842b42dfSAlex Bennée     }
1410842b42dfSAlex Bennée 
1411842b42dfSAlex Bennée     res = gdb_handle_vcont(get_param(params, 0)->data);
1412842b42dfSAlex Bennée     if ((res == -EINVAL) || (res == -ERANGE)) {
141336e067b2SAlex Bennée         gdb_put_packet("E22");
1414842b42dfSAlex Bennée     } else if (res) {
141536e067b2SAlex Bennée         gdb_put_packet("");
1416842b42dfSAlex Bennée     }
1417842b42dfSAlex Bennée }
1418842b42dfSAlex Bennée 
handle_v_attach(GArray * params,void * user_ctx)1419842b42dfSAlex Bennée static void handle_v_attach(GArray *params, void *user_ctx)
1420842b42dfSAlex Bennée {
1421842b42dfSAlex Bennée     GDBProcess *process;
1422842b42dfSAlex Bennée     CPUState *cpu;
1423842b42dfSAlex Bennée 
1424842b42dfSAlex Bennée     g_string_assign(gdbserver_state.str_buf, "E22");
1425842b42dfSAlex Bennée     if (!params->len) {
1426842b42dfSAlex Bennée         goto cleanup;
1427842b42dfSAlex Bennée     }
1428842b42dfSAlex Bennée 
1429842b42dfSAlex Bennée     process = gdb_get_process(get_param(params, 0)->val_ul);
1430842b42dfSAlex Bennée     if (!process) {
1431842b42dfSAlex Bennée         goto cleanup;
1432842b42dfSAlex Bennée     }
1433842b42dfSAlex Bennée 
1434a3fcc111SIlya Leoshkevich     cpu = gdb_get_first_cpu_in_process(process);
1435842b42dfSAlex Bennée     if (!cpu) {
1436842b42dfSAlex Bennée         goto cleanup;
1437842b42dfSAlex Bennée     }
1438842b42dfSAlex Bennée 
1439842b42dfSAlex Bennée     process->attached = true;
1440842b42dfSAlex Bennée     gdbserver_state.g_cpu = cpu;
1441842b42dfSAlex Bennée     gdbserver_state.c_cpu = cpu;
1442842b42dfSAlex Bennée 
144375837005SMatheus Tavares Bernardino     if (gdbserver_state.allow_stop_reply) {
1444842b42dfSAlex Bennée         g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
1445842b42dfSAlex Bennée         gdb_append_thread_id(cpu, gdbserver_state.str_buf);
1446842b42dfSAlex Bennée         g_string_append_c(gdbserver_state.str_buf, ';');
144775837005SMatheus Tavares Bernardino         gdbserver_state.allow_stop_reply = false;
1448842b42dfSAlex Bennée cleanup:
144936e067b2SAlex Bennée         gdb_put_strbuf();
1450842b42dfSAlex Bennée     }
145175837005SMatheus Tavares Bernardino }
1452842b42dfSAlex Bennée 
handle_v_kill(GArray * params,void * user_ctx)1453842b42dfSAlex Bennée static void handle_v_kill(GArray *params, void *user_ctx)
1454842b42dfSAlex Bennée {
1455842b42dfSAlex Bennée     /* Kill the target */
145636e067b2SAlex Bennée     gdb_put_packet("OK");
1457842b42dfSAlex Bennée     error_report("QEMU: Terminated via GDBstub");
1458842b42dfSAlex Bennée     gdb_exit(0);
1459e216256aSClément Chigot     gdb_qemu_exit(0);
1460842b42dfSAlex Bennée }
1461842b42dfSAlex Bennée 
1462842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_v_commands_table[] = {
1463842b42dfSAlex Bennée     /* Order is important if has same prefix */
1464842b42dfSAlex Bennée     {
1465842b42dfSAlex Bennée         .handler = handle_v_cont_query,
1466842b42dfSAlex Bennée         .cmd = "Cont?",
1467842b42dfSAlex Bennée         .cmd_startswith = 1
1468842b42dfSAlex Bennée     },
1469842b42dfSAlex Bennée     {
1470842b42dfSAlex Bennée         .handler = handle_v_cont,
1471842b42dfSAlex Bennée         .cmd = "Cont",
1472842b42dfSAlex Bennée         .cmd_startswith = 1,
147375837005SMatheus Tavares Bernardino         .allow_stop_reply = true,
1474842b42dfSAlex Bennée         .schema = "s0"
1475842b42dfSAlex Bennée     },
1476842b42dfSAlex Bennée     {
1477842b42dfSAlex Bennée         .handler = handle_v_attach,
1478842b42dfSAlex Bennée         .cmd = "Attach;",
1479842b42dfSAlex Bennée         .cmd_startswith = 1,
148075837005SMatheus Tavares Bernardino         .allow_stop_reply = true,
1481842b42dfSAlex Bennée         .schema = "l0"
1482842b42dfSAlex Bennée     },
1483842b42dfSAlex Bennée     {
1484842b42dfSAlex Bennée         .handler = handle_v_kill,
1485842b42dfSAlex Bennée         .cmd = "Kill;",
1486842b42dfSAlex Bennée         .cmd_startswith = 1
1487842b42dfSAlex Bennée     },
1488e282010bSIlya Leoshkevich #ifdef CONFIG_USER_ONLY
1489e282010bSIlya Leoshkevich     /*
1490e282010bSIlya Leoshkevich      * Host I/O Packets. See [1] for details.
1491e282010bSIlya Leoshkevich      * [1] https://sourceware.org/gdb/onlinedocs/gdb/Host-I_002fO-Packets.html
1492e282010bSIlya Leoshkevich      */
1493e282010bSIlya Leoshkevich     {
1494e282010bSIlya Leoshkevich         .handler = gdb_handle_v_file_open,
1495e282010bSIlya Leoshkevich         .cmd = "File:open:",
1496e282010bSIlya Leoshkevich         .cmd_startswith = 1,
1497e282010bSIlya Leoshkevich         .schema = "s,L,L0"
1498e282010bSIlya Leoshkevich     },
1499e282010bSIlya Leoshkevich     {
1500e282010bSIlya Leoshkevich         .handler = gdb_handle_v_file_close,
1501e282010bSIlya Leoshkevich         .cmd = "File:close:",
1502e282010bSIlya Leoshkevich         .cmd_startswith = 1,
1503e282010bSIlya Leoshkevich         .schema = "l0"
1504e282010bSIlya Leoshkevich     },
1505e282010bSIlya Leoshkevich     {
1506e282010bSIlya Leoshkevich         .handler = gdb_handle_v_file_pread,
1507e282010bSIlya Leoshkevich         .cmd = "File:pread:",
1508e282010bSIlya Leoshkevich         .cmd_startswith = 1,
1509e282010bSIlya Leoshkevich         .schema = "l,L,L0"
1510e282010bSIlya Leoshkevich     },
1511e282010bSIlya Leoshkevich     {
1512e282010bSIlya Leoshkevich         .handler = gdb_handle_v_file_readlink,
1513e282010bSIlya Leoshkevich         .cmd = "File:readlink:",
1514e282010bSIlya Leoshkevich         .cmd_startswith = 1,
1515e282010bSIlya Leoshkevich         .schema = "s0"
1516e282010bSIlya Leoshkevich     },
1517e282010bSIlya Leoshkevich #endif
1518842b42dfSAlex Bennée };
1519842b42dfSAlex Bennée 
handle_v_commands(GArray * params,void * user_ctx)1520842b42dfSAlex Bennée static void handle_v_commands(GArray *params, void *user_ctx)
1521842b42dfSAlex Bennée {
1522842b42dfSAlex Bennée     if (!params->len) {
1523842b42dfSAlex Bennée         return;
1524842b42dfSAlex Bennée     }
1525842b42dfSAlex Bennée 
15265b030993SAlex Bennée     if (process_string_cmd(get_param(params, 0)->data,
1527842b42dfSAlex Bennée                            gdb_v_commands_table,
1528842b42dfSAlex Bennée                            ARRAY_SIZE(gdb_v_commands_table))) {
152936e067b2SAlex Bennée         gdb_put_packet("");
1530842b42dfSAlex Bennée     }
1531842b42dfSAlex Bennée }
1532842b42dfSAlex Bennée 
handle_query_qemu_sstepbits(GArray * params,void * user_ctx)1533842b42dfSAlex Bennée static void handle_query_qemu_sstepbits(GArray *params, void *user_ctx)
1534842b42dfSAlex Bennée {
1535842b42dfSAlex Bennée     g_string_printf(gdbserver_state.str_buf, "ENABLE=%x", SSTEP_ENABLE);
1536842b42dfSAlex Bennée 
1537842b42dfSAlex Bennée     if (gdbserver_state.supported_sstep_flags & SSTEP_NOIRQ) {
1538842b42dfSAlex Bennée         g_string_append_printf(gdbserver_state.str_buf, ",NOIRQ=%x",
1539842b42dfSAlex Bennée                                SSTEP_NOIRQ);
1540842b42dfSAlex Bennée     }
1541842b42dfSAlex Bennée 
1542842b42dfSAlex Bennée     if (gdbserver_state.supported_sstep_flags & SSTEP_NOTIMER) {
1543842b42dfSAlex Bennée         g_string_append_printf(gdbserver_state.str_buf, ",NOTIMER=%x",
1544842b42dfSAlex Bennée                                SSTEP_NOTIMER);
1545842b42dfSAlex Bennée     }
1546842b42dfSAlex Bennée 
154736e067b2SAlex Bennée     gdb_put_strbuf();
1548842b42dfSAlex Bennée }
1549842b42dfSAlex Bennée 
handle_set_qemu_sstep(GArray * params,void * user_ctx)1550842b42dfSAlex Bennée static void handle_set_qemu_sstep(GArray *params, void *user_ctx)
1551842b42dfSAlex Bennée {
1552842b42dfSAlex Bennée     int new_sstep_flags;
1553842b42dfSAlex Bennée 
1554842b42dfSAlex Bennée     if (!params->len) {
1555842b42dfSAlex Bennée         return;
1556842b42dfSAlex Bennée     }
1557842b42dfSAlex Bennée 
1558842b42dfSAlex Bennée     new_sstep_flags = get_param(params, 0)->val_ul;
1559842b42dfSAlex Bennée 
1560842b42dfSAlex Bennée     if (new_sstep_flags  & ~gdbserver_state.supported_sstep_flags) {
156136e067b2SAlex Bennée         gdb_put_packet("E22");
1562842b42dfSAlex Bennée         return;
1563842b42dfSAlex Bennée     }
1564842b42dfSAlex Bennée 
1565842b42dfSAlex Bennée     gdbserver_state.sstep_flags = new_sstep_flags;
156636e067b2SAlex Bennée     gdb_put_packet("OK");
1567842b42dfSAlex Bennée }
1568842b42dfSAlex Bennée 
handle_query_qemu_sstep(GArray * params,void * user_ctx)1569842b42dfSAlex Bennée static void handle_query_qemu_sstep(GArray *params, void *user_ctx)
1570842b42dfSAlex Bennée {
1571842b42dfSAlex Bennée     g_string_printf(gdbserver_state.str_buf, "0x%x",
1572842b42dfSAlex Bennée                     gdbserver_state.sstep_flags);
157336e067b2SAlex Bennée     gdb_put_strbuf();
1574842b42dfSAlex Bennée }
1575842b42dfSAlex Bennée 
handle_query_curr_tid(GArray * params,void * user_ctx)1576842b42dfSAlex Bennée static void handle_query_curr_tid(GArray *params, void *user_ctx)
1577842b42dfSAlex Bennée {
1578842b42dfSAlex Bennée     CPUState *cpu;
1579842b42dfSAlex Bennée     GDBProcess *process;
1580842b42dfSAlex Bennée 
1581842b42dfSAlex Bennée     /*
1582842b42dfSAlex Bennée      * "Current thread" remains vague in the spec, so always return
1583842b42dfSAlex Bennée      * the first thread of the current process (gdb returns the
1584842b42dfSAlex Bennée      * first thread).
1585842b42dfSAlex Bennée      */
1586842b42dfSAlex Bennée     process = gdb_get_cpu_process(gdbserver_state.g_cpu);
1587a3fcc111SIlya Leoshkevich     cpu = gdb_get_first_cpu_in_process(process);
1588842b42dfSAlex Bennée     g_string_assign(gdbserver_state.str_buf, "QC");
1589842b42dfSAlex Bennée     gdb_append_thread_id(cpu, gdbserver_state.str_buf);
159036e067b2SAlex Bennée     gdb_put_strbuf();
1591842b42dfSAlex Bennée }
1592842b42dfSAlex Bennée 
handle_query_threads(GArray * params,void * user_ctx)1593842b42dfSAlex Bennée static void handle_query_threads(GArray *params, void *user_ctx)
1594842b42dfSAlex Bennée {
1595842b42dfSAlex Bennée     if (!gdbserver_state.query_cpu) {
159636e067b2SAlex Bennée         gdb_put_packet("l");
1597842b42dfSAlex Bennée         return;
1598842b42dfSAlex Bennée     }
1599842b42dfSAlex Bennée 
1600842b42dfSAlex Bennée     g_string_assign(gdbserver_state.str_buf, "m");
1601842b42dfSAlex Bennée     gdb_append_thread_id(gdbserver_state.query_cpu, gdbserver_state.str_buf);
160236e067b2SAlex Bennée     gdb_put_strbuf();
1603842b42dfSAlex Bennée     gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu);
1604842b42dfSAlex Bennée }
1605842b42dfSAlex Bennée 
handle_query_first_threads(GArray * params,void * user_ctx)1606842b42dfSAlex Bennée static void handle_query_first_threads(GArray *params, void *user_ctx)
1607842b42dfSAlex Bennée {
1608842b42dfSAlex Bennée     gdbserver_state.query_cpu = gdb_first_attached_cpu();
1609842b42dfSAlex Bennée     handle_query_threads(params, user_ctx);
1610842b42dfSAlex Bennée }
1611842b42dfSAlex Bennée 
handle_query_thread_extra(GArray * params,void * user_ctx)1612842b42dfSAlex Bennée static void handle_query_thread_extra(GArray *params, void *user_ctx)
1613842b42dfSAlex Bennée {
1614842b42dfSAlex Bennée     g_autoptr(GString) rs = g_string_new(NULL);
1615842b42dfSAlex Bennée     CPUState *cpu;
1616842b42dfSAlex Bennée 
1617842b42dfSAlex Bennée     if (!params->len ||
1618842b42dfSAlex Bennée         get_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) {
161936e067b2SAlex Bennée         gdb_put_packet("E22");
1620842b42dfSAlex Bennée         return;
1621842b42dfSAlex Bennée     }
1622842b42dfSAlex Bennée 
1623842b42dfSAlex Bennée     cpu = gdb_get_cpu(get_param(params, 0)->thread_id.pid,
1624842b42dfSAlex Bennée                       get_param(params, 0)->thread_id.tid);
1625842b42dfSAlex Bennée     if (!cpu) {
1626842b42dfSAlex Bennée         return;
1627842b42dfSAlex Bennée     }
1628842b42dfSAlex Bennée 
1629842b42dfSAlex Bennée     cpu_synchronize_state(cpu);
1630842b42dfSAlex Bennée 
1631842b42dfSAlex Bennée     if (gdbserver_state.multiprocess && (gdbserver_state.process_num > 1)) {
1632842b42dfSAlex Bennée         /* Print the CPU model and name in multiprocess mode */
1633842b42dfSAlex Bennée         ObjectClass *oc = object_get_class(OBJECT(cpu));
1634842b42dfSAlex Bennée         const char *cpu_model = object_class_get_name(oc);
1635842b42dfSAlex Bennée         const char *cpu_name =
1636842b42dfSAlex Bennée             object_get_canonical_path_component(OBJECT(cpu));
1637842b42dfSAlex Bennée         g_string_printf(rs, "%s %s [%s]", cpu_model, cpu_name,
1638842b42dfSAlex Bennée                         cpu->halted ? "halted " : "running");
1639842b42dfSAlex Bennée     } else {
1640842b42dfSAlex Bennée         g_string_printf(rs, "CPU#%d [%s]", cpu->cpu_index,
1641842b42dfSAlex Bennée                         cpu->halted ? "halted " : "running");
1642842b42dfSAlex Bennée     }
1643842b42dfSAlex Bennée     trace_gdbstub_op_extra_info(rs->str);
164436e067b2SAlex Bennée     gdb_memtohex(gdbserver_state.str_buf, (uint8_t *)rs->str, rs->len);
164536e067b2SAlex Bennée     gdb_put_strbuf();
1646842b42dfSAlex Bennée }
1647842b42dfSAlex Bennée 
handle_query_supported(GArray * params,void * user_ctx)1648842b42dfSAlex Bennée static void handle_query_supported(GArray *params, void *user_ctx)
1649842b42dfSAlex Bennée {
1650842b42dfSAlex Bennée     CPUClass *cc;
1651842b42dfSAlex Bennée 
1652842b42dfSAlex Bennée     g_string_printf(gdbserver_state.str_buf, "PacketSize=%x", MAX_PACKET_LENGTH);
1653842b42dfSAlex Bennée     cc = CPU_GET_CLASS(first_cpu);
1654842b42dfSAlex Bennée     if (cc->gdb_core_xml_file) {
1655842b42dfSAlex Bennée         g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+");
1656842b42dfSAlex Bennée     }
1657842b42dfSAlex Bennée 
1658505601d5SAlex Bennée     if (gdb_can_reverse()) {
1659842b42dfSAlex Bennée         g_string_append(gdbserver_state.str_buf,
1660842b42dfSAlex Bennée             ";ReverseStep+;ReverseContinue+");
1661842b42dfSAlex Bennée     }
1662842b42dfSAlex Bennée 
1663e282010bSIlya Leoshkevich #if defined(CONFIG_USER_ONLY)
1664e282010bSIlya Leoshkevich #if defined(CONFIG_LINUX)
1665*59272469SPhilippe Mathieu-Daudé     if (get_task_state(gdbserver_state.c_cpu)) {
1666842b42dfSAlex Bennée         g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
1667842b42dfSAlex Bennée     }
1668046f143cSIlya Leoshkevich     g_string_append(gdbserver_state.str_buf, ";QCatchSyscalls+");
16699ae5801dSGustavo Romero 
16709ae5801dSGustavo Romero     g_string_append(gdbserver_state.str_buf, ";qXfer:siginfo:read+");
1671842b42dfSAlex Bennée #endif
1672e282010bSIlya Leoshkevich     g_string_append(gdbserver_state.str_buf, ";qXfer:exec-file:read+");
1673e282010bSIlya Leoshkevich #endif
1674842b42dfSAlex Bennée 
16756d923112SIlya Leoshkevich     if (params->len) {
16766d923112SIlya Leoshkevich         const char *gdb_supported = get_param(params, 0)->data;
16776d923112SIlya Leoshkevich 
16786d923112SIlya Leoshkevich         if (strstr(gdb_supported, "multiprocess+")) {
1679842b42dfSAlex Bennée             gdbserver_state.multiprocess = true;
1680842b42dfSAlex Bennée         }
16816d923112SIlya Leoshkevich #if defined(CONFIG_USER_ONLY)
16826d923112SIlya Leoshkevich         gdb_handle_query_supported_user(gdb_supported);
16836d923112SIlya Leoshkevich #endif
16846d923112SIlya Leoshkevich     }
1685842b42dfSAlex Bennée 
1686842b42dfSAlex Bennée     g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
168736e067b2SAlex Bennée     gdb_put_strbuf();
1688842b42dfSAlex Bennée }
1689842b42dfSAlex Bennée 
handle_query_xfer_features(GArray * params,void * user_ctx)1690842b42dfSAlex Bennée static void handle_query_xfer_features(GArray *params, void *user_ctx)
1691842b42dfSAlex Bennée {
1692842b42dfSAlex Bennée     GDBProcess *process;
1693842b42dfSAlex Bennée     CPUClass *cc;
1694842b42dfSAlex Bennée     unsigned long len, total_len, addr;
1695842b42dfSAlex Bennée     const char *xml;
1696842b42dfSAlex Bennée     const char *p;
1697842b42dfSAlex Bennée 
1698842b42dfSAlex Bennée     if (params->len < 3) {
169936e067b2SAlex Bennée         gdb_put_packet("E22");
1700842b42dfSAlex Bennée         return;
1701842b42dfSAlex Bennée     }
1702842b42dfSAlex Bennée 
1703842b42dfSAlex Bennée     process = gdb_get_cpu_process(gdbserver_state.g_cpu);
1704842b42dfSAlex Bennée     cc = CPU_GET_CLASS(gdbserver_state.g_cpu);
1705842b42dfSAlex Bennée     if (!cc->gdb_core_xml_file) {
170636e067b2SAlex Bennée         gdb_put_packet("");
1707842b42dfSAlex Bennée         return;
1708842b42dfSAlex Bennée     }
1709842b42dfSAlex Bennée 
1710842b42dfSAlex Bennée     p = get_param(params, 0)->data;
1711842b42dfSAlex Bennée     xml = get_feature_xml(p, &p, process);
1712842b42dfSAlex Bennée     if (!xml) {
171336e067b2SAlex Bennée         gdb_put_packet("E00");
1714842b42dfSAlex Bennée         return;
1715842b42dfSAlex Bennée     }
1716842b42dfSAlex Bennée 
1717842b42dfSAlex Bennée     addr = get_param(params, 1)->val_ul;
1718842b42dfSAlex Bennée     len = get_param(params, 2)->val_ul;
1719842b42dfSAlex Bennée     total_len = strlen(xml);
1720842b42dfSAlex Bennée     if (addr > total_len) {
172136e067b2SAlex Bennée         gdb_put_packet("E00");
1722842b42dfSAlex Bennée         return;
1723842b42dfSAlex Bennée     }
1724842b42dfSAlex Bennée 
1725842b42dfSAlex Bennée     if (len > (MAX_PACKET_LENGTH - 5) / 2) {
1726842b42dfSAlex Bennée         len = (MAX_PACKET_LENGTH - 5) / 2;
1727842b42dfSAlex Bennée     }
1728842b42dfSAlex Bennée 
1729842b42dfSAlex Bennée     if (len < total_len - addr) {
1730842b42dfSAlex Bennée         g_string_assign(gdbserver_state.str_buf, "m");
173136e067b2SAlex Bennée         gdb_memtox(gdbserver_state.str_buf, xml + addr, len);
1732842b42dfSAlex Bennée     } else {
1733842b42dfSAlex Bennée         g_string_assign(gdbserver_state.str_buf, "l");
173436e067b2SAlex Bennée         gdb_memtox(gdbserver_state.str_buf, xml + addr, total_len - addr);
1735842b42dfSAlex Bennée     }
1736842b42dfSAlex Bennée 
173736e067b2SAlex Bennée     gdb_put_packet_binary(gdbserver_state.str_buf->str,
1738842b42dfSAlex Bennée                       gdbserver_state.str_buf->len, true);
1739842b42dfSAlex Bennée }
1740842b42dfSAlex Bennée 
handle_query_qemu_supported(GArray * params,void * user_ctx)1741842b42dfSAlex Bennée static void handle_query_qemu_supported(GArray *params, void *user_ctx)
1742842b42dfSAlex Bennée {
1743842b42dfSAlex Bennée     g_string_printf(gdbserver_state.str_buf, "sstepbits;sstep");
1744842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY
1745842b42dfSAlex Bennée     g_string_append(gdbserver_state.str_buf, ";PhyMemMode");
1746842b42dfSAlex Bennée #endif
174736e067b2SAlex Bennée     gdb_put_strbuf();
1748842b42dfSAlex Bennée }
1749842b42dfSAlex Bennée 
1750842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
1751842b42dfSAlex Bennée     /* Order is important if has same prefix */
1752842b42dfSAlex Bennée     {
1753842b42dfSAlex Bennée         .handler = handle_query_qemu_sstepbits,
1754842b42dfSAlex Bennée         .cmd = "qemu.sstepbits",
1755842b42dfSAlex Bennée     },
1756842b42dfSAlex Bennée     {
1757842b42dfSAlex Bennée         .handler = handle_query_qemu_sstep,
1758842b42dfSAlex Bennée         .cmd = "qemu.sstep",
1759842b42dfSAlex Bennée     },
1760842b42dfSAlex Bennée     {
1761842b42dfSAlex Bennée         .handler = handle_set_qemu_sstep,
1762842b42dfSAlex Bennée         .cmd = "qemu.sstep=",
1763842b42dfSAlex Bennée         .cmd_startswith = 1,
1764842b42dfSAlex Bennée         .schema = "l0"
1765842b42dfSAlex Bennée     },
1766842b42dfSAlex Bennée };
1767842b42dfSAlex Bennée 
1768842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_gen_query_table[] = {
1769842b42dfSAlex Bennée     {
1770842b42dfSAlex Bennée         .handler = handle_query_curr_tid,
1771842b42dfSAlex Bennée         .cmd = "C",
1772842b42dfSAlex Bennée     },
1773842b42dfSAlex Bennée     {
1774842b42dfSAlex Bennée         .handler = handle_query_threads,
1775842b42dfSAlex Bennée         .cmd = "sThreadInfo",
1776842b42dfSAlex Bennée     },
1777842b42dfSAlex Bennée     {
1778842b42dfSAlex Bennée         .handler = handle_query_first_threads,
1779842b42dfSAlex Bennée         .cmd = "fThreadInfo",
1780842b42dfSAlex Bennée     },
1781842b42dfSAlex Bennée     {
1782842b42dfSAlex Bennée         .handler = handle_query_thread_extra,
1783842b42dfSAlex Bennée         .cmd = "ThreadExtraInfo,",
1784842b42dfSAlex Bennée         .cmd_startswith = 1,
1785842b42dfSAlex Bennée         .schema = "t0"
1786842b42dfSAlex Bennée     },
1787842b42dfSAlex Bennée #ifdef CONFIG_USER_ONLY
1788842b42dfSAlex Bennée     {
1789d96bf49bSAlex Bennée         .handler = gdb_handle_query_offsets,
1790842b42dfSAlex Bennée         .cmd = "Offsets",
1791842b42dfSAlex Bennée     },
1792842b42dfSAlex Bennée #else
1793842b42dfSAlex Bennée     {
1794b6fa2ec2SAlex Bennée         .handler = gdb_handle_query_rcmd,
1795842b42dfSAlex Bennée         .cmd = "Rcmd,",
1796842b42dfSAlex Bennée         .cmd_startswith = 1,
1797842b42dfSAlex Bennée         .schema = "s0"
1798842b42dfSAlex Bennée     },
1799842b42dfSAlex Bennée #endif
1800842b42dfSAlex Bennée     {
1801842b42dfSAlex Bennée         .handler = handle_query_supported,
1802842b42dfSAlex Bennée         .cmd = "Supported:",
1803842b42dfSAlex Bennée         .cmd_startswith = 1,
1804842b42dfSAlex Bennée         .schema = "s0"
1805842b42dfSAlex Bennée     },
1806842b42dfSAlex Bennée     {
1807842b42dfSAlex Bennée         .handler = handle_query_supported,
1808842b42dfSAlex Bennée         .cmd = "Supported",
1809842b42dfSAlex Bennée         .schema = "s0"
1810842b42dfSAlex Bennée     },
1811842b42dfSAlex Bennée     {
1812842b42dfSAlex Bennée         .handler = handle_query_xfer_features,
1813842b42dfSAlex Bennée         .cmd = "Xfer:features:read:",
1814842b42dfSAlex Bennée         .cmd_startswith = 1,
1815842b42dfSAlex Bennée         .schema = "s:l,l0"
1816842b42dfSAlex Bennée     },
1817e282010bSIlya Leoshkevich #if defined(CONFIG_USER_ONLY)
1818e282010bSIlya Leoshkevich #if defined(CONFIG_LINUX)
1819842b42dfSAlex Bennée     {
1820d96bf49bSAlex Bennée         .handler = gdb_handle_query_xfer_auxv,
1821842b42dfSAlex Bennée         .cmd = "Xfer:auxv:read::",
1822842b42dfSAlex Bennée         .cmd_startswith = 1,
1823842b42dfSAlex Bennée         .schema = "l,l0"
1824842b42dfSAlex Bennée     },
18259ae5801dSGustavo Romero     {
18269ae5801dSGustavo Romero         .handler = gdb_handle_query_xfer_siginfo,
18279ae5801dSGustavo Romero         .cmd = "Xfer:siginfo:read::",
18289ae5801dSGustavo Romero         .cmd_startswith = 1,
18299ae5801dSGustavo Romero         .schema = "l,l0"
18309ae5801dSGustavo Romero      },
1831842b42dfSAlex Bennée #endif
1832842b42dfSAlex Bennée     {
1833e282010bSIlya Leoshkevich         .handler = gdb_handle_query_xfer_exec_file,
1834e282010bSIlya Leoshkevich         .cmd = "Xfer:exec-file:read:",
1835e282010bSIlya Leoshkevich         .cmd_startswith = 1,
1836e282010bSIlya Leoshkevich         .schema = "l:l,l0"
1837e282010bSIlya Leoshkevich     },
1838e282010bSIlya Leoshkevich #endif
1839e282010bSIlya Leoshkevich     {
18408a2025b3SAlex Bennée         .handler = gdb_handle_query_attached,
1841842b42dfSAlex Bennée         .cmd = "Attached:",
1842842b42dfSAlex Bennée         .cmd_startswith = 1
1843842b42dfSAlex Bennée     },
1844842b42dfSAlex Bennée     {
18458a2025b3SAlex Bennée         .handler = gdb_handle_query_attached,
1846842b42dfSAlex Bennée         .cmd = "Attached",
1847842b42dfSAlex Bennée     },
1848842b42dfSAlex Bennée     {
1849842b42dfSAlex Bennée         .handler = handle_query_qemu_supported,
1850842b42dfSAlex Bennée         .cmd = "qemu.Supported",
1851842b42dfSAlex Bennée     },
1852842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY
1853842b42dfSAlex Bennée     {
1854589a5867SAlex Bennée         .handler = gdb_handle_query_qemu_phy_mem_mode,
1855842b42dfSAlex Bennée         .cmd = "qemu.PhyMemMode",
1856842b42dfSAlex Bennée     },
1857842b42dfSAlex Bennée #endif
1858842b42dfSAlex Bennée };
1859842b42dfSAlex Bennée 
1860842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_gen_set_table[] = {
1861842b42dfSAlex Bennée     /* Order is important if has same prefix */
1862842b42dfSAlex Bennée     {
1863842b42dfSAlex Bennée         .handler = handle_set_qemu_sstep,
1864842b42dfSAlex Bennée         .cmd = "qemu.sstep:",
1865842b42dfSAlex Bennée         .cmd_startswith = 1,
1866842b42dfSAlex Bennée         .schema = "l0"
1867842b42dfSAlex Bennée     },
1868842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY
1869842b42dfSAlex Bennée     {
1870589a5867SAlex Bennée         .handler = gdb_handle_set_qemu_phy_mem_mode,
1871842b42dfSAlex Bennée         .cmd = "qemu.PhyMemMode:",
1872842b42dfSAlex Bennée         .cmd_startswith = 1,
1873842b42dfSAlex Bennée         .schema = "l0"
1874842b42dfSAlex Bennée     },
1875842b42dfSAlex Bennée #endif
1876046f143cSIlya Leoshkevich #if defined(CONFIG_USER_ONLY)
1877046f143cSIlya Leoshkevich     {
1878046f143cSIlya Leoshkevich         .handler = gdb_handle_set_catch_syscalls,
1879046f143cSIlya Leoshkevich         .cmd = "CatchSyscalls:",
1880046f143cSIlya Leoshkevich         .cmd_startswith = 1,
1881046f143cSIlya Leoshkevich         .schema = "s0",
1882046f143cSIlya Leoshkevich     },
1883046f143cSIlya Leoshkevich #endif
1884842b42dfSAlex Bennée };
1885842b42dfSAlex Bennée 
handle_gen_query(GArray * params,void * user_ctx)1886842b42dfSAlex Bennée static void handle_gen_query(GArray *params, void *user_ctx)
1887842b42dfSAlex Bennée {
1888842b42dfSAlex Bennée     if (!params->len) {
1889842b42dfSAlex Bennée         return;
1890842b42dfSAlex Bennée     }
1891842b42dfSAlex Bennée 
18925b030993SAlex Bennée     if (!process_string_cmd(get_param(params, 0)->data,
1893842b42dfSAlex Bennée                             gdb_gen_query_set_common_table,
1894842b42dfSAlex Bennée                             ARRAY_SIZE(gdb_gen_query_set_common_table))) {
1895842b42dfSAlex Bennée         return;
1896842b42dfSAlex Bennée     }
1897842b42dfSAlex Bennée 
18985b030993SAlex Bennée     if (process_string_cmd(get_param(params, 0)->data,
1899842b42dfSAlex Bennée                            gdb_gen_query_table,
1900842b42dfSAlex Bennée                            ARRAY_SIZE(gdb_gen_query_table))) {
190136e067b2SAlex Bennée         gdb_put_packet("");
1902842b42dfSAlex Bennée     }
1903842b42dfSAlex Bennée }
1904842b42dfSAlex Bennée 
handle_gen_set(GArray * params,void * user_ctx)1905842b42dfSAlex Bennée static void handle_gen_set(GArray *params, void *user_ctx)
1906842b42dfSAlex Bennée {
1907842b42dfSAlex Bennée     if (!params->len) {
1908842b42dfSAlex Bennée         return;
1909842b42dfSAlex Bennée     }
1910842b42dfSAlex Bennée 
19115b030993SAlex Bennée     if (!process_string_cmd(get_param(params, 0)->data,
1912842b42dfSAlex Bennée                             gdb_gen_query_set_common_table,
1913842b42dfSAlex Bennée                             ARRAY_SIZE(gdb_gen_query_set_common_table))) {
1914842b42dfSAlex Bennée         return;
1915842b42dfSAlex Bennée     }
1916842b42dfSAlex Bennée 
19175b030993SAlex Bennée     if (process_string_cmd(get_param(params, 0)->data,
1918842b42dfSAlex Bennée                            gdb_gen_set_table,
1919842b42dfSAlex Bennée                            ARRAY_SIZE(gdb_gen_set_table))) {
192036e067b2SAlex Bennée         gdb_put_packet("");
1921842b42dfSAlex Bennée     }
1922842b42dfSAlex Bennée }
1923842b42dfSAlex Bennée 
handle_target_halt(GArray * params,void * user_ctx)1924842b42dfSAlex Bennée static void handle_target_halt(GArray *params, void *user_ctx)
1925842b42dfSAlex Bennée {
192675837005SMatheus Tavares Bernardino     if (gdbserver_state.allow_stop_reply) {
1927842b42dfSAlex Bennée         g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
1928842b42dfSAlex Bennée         gdb_append_thread_id(gdbserver_state.c_cpu, gdbserver_state.str_buf);
1929842b42dfSAlex Bennée         g_string_append_c(gdbserver_state.str_buf, ';');
193036e067b2SAlex Bennée         gdb_put_strbuf();
193175837005SMatheus Tavares Bernardino         gdbserver_state.allow_stop_reply = false;
193275837005SMatheus Tavares Bernardino     }
1933842b42dfSAlex Bennée     /*
1934842b42dfSAlex Bennée      * Remove all the breakpoints when this query is issued,
1935842b42dfSAlex Bennée      * because gdb is doing an initial connect and the state
1936842b42dfSAlex Bennée      * should be cleaned up.
1937842b42dfSAlex Bennée      */
1938ae7467b1SAlex Bennée     gdb_breakpoint_remove_all(gdbserver_state.c_cpu);
1939842b42dfSAlex Bennée }
1940842b42dfSAlex Bennée 
gdb_handle_packet(const char * line_buf)1941842b42dfSAlex Bennée static int gdb_handle_packet(const char *line_buf)
1942842b42dfSAlex Bennée {
1943842b42dfSAlex Bennée     const GdbCmdParseEntry *cmd_parser = NULL;
1944842b42dfSAlex Bennée 
1945842b42dfSAlex Bennée     trace_gdbstub_io_command(line_buf);
1946842b42dfSAlex Bennée 
1947842b42dfSAlex Bennée     switch (line_buf[0]) {
1948842b42dfSAlex Bennée     case '!':
194936e067b2SAlex Bennée         gdb_put_packet("OK");
1950842b42dfSAlex Bennée         break;
1951842b42dfSAlex Bennée     case '?':
1952842b42dfSAlex Bennée         {
1953842b42dfSAlex Bennée             static const GdbCmdParseEntry target_halted_cmd_desc = {
1954842b42dfSAlex Bennée                 .handler = handle_target_halt,
1955842b42dfSAlex Bennée                 .cmd = "?",
195675837005SMatheus Tavares Bernardino                 .cmd_startswith = 1,
195775837005SMatheus Tavares Bernardino                 .allow_stop_reply = true,
1958842b42dfSAlex Bennée             };
1959842b42dfSAlex Bennée             cmd_parser = &target_halted_cmd_desc;
1960842b42dfSAlex Bennée         }
1961842b42dfSAlex Bennée         break;
1962842b42dfSAlex Bennée     case 'c':
1963842b42dfSAlex Bennée         {
1964842b42dfSAlex Bennée             static const GdbCmdParseEntry continue_cmd_desc = {
1965842b42dfSAlex Bennée                 .handler = handle_continue,
1966842b42dfSAlex Bennée                 .cmd = "c",
1967842b42dfSAlex Bennée                 .cmd_startswith = 1,
196875837005SMatheus Tavares Bernardino                 .allow_stop_reply = true,
1969842b42dfSAlex Bennée                 .schema = "L0"
1970842b42dfSAlex Bennée             };
1971842b42dfSAlex Bennée             cmd_parser = &continue_cmd_desc;
1972842b42dfSAlex Bennée         }
1973842b42dfSAlex Bennée         break;
1974842b42dfSAlex Bennée     case 'C':
1975842b42dfSAlex Bennée         {
1976842b42dfSAlex Bennée             static const GdbCmdParseEntry cont_with_sig_cmd_desc = {
1977842b42dfSAlex Bennée                 .handler = handle_cont_with_sig,
1978842b42dfSAlex Bennée                 .cmd = "C",
1979842b42dfSAlex Bennée                 .cmd_startswith = 1,
198075837005SMatheus Tavares Bernardino                 .allow_stop_reply = true,
1981842b42dfSAlex Bennée                 .schema = "l0"
1982842b42dfSAlex Bennée             };
1983842b42dfSAlex Bennée             cmd_parser = &cont_with_sig_cmd_desc;
1984842b42dfSAlex Bennée         }
1985842b42dfSAlex Bennée         break;
1986842b42dfSAlex Bennée     case 'v':
1987842b42dfSAlex Bennée         {
1988842b42dfSAlex Bennée             static const GdbCmdParseEntry v_cmd_desc = {
1989842b42dfSAlex Bennée                 .handler = handle_v_commands,
1990842b42dfSAlex Bennée                 .cmd = "v",
1991842b42dfSAlex Bennée                 .cmd_startswith = 1,
1992842b42dfSAlex Bennée                 .schema = "s0"
1993842b42dfSAlex Bennée             };
1994842b42dfSAlex Bennée             cmd_parser = &v_cmd_desc;
1995842b42dfSAlex Bennée         }
1996842b42dfSAlex Bennée         break;
1997842b42dfSAlex Bennée     case 'k':
1998842b42dfSAlex Bennée         /* Kill the target */
1999842b42dfSAlex Bennée         error_report("QEMU: Terminated via GDBstub");
2000842b42dfSAlex Bennée         gdb_exit(0);
2001e216256aSClément Chigot         gdb_qemu_exit(0);
2002e216256aSClément Chigot         break;
2003842b42dfSAlex Bennée     case 'D':
2004842b42dfSAlex Bennée         {
2005842b42dfSAlex Bennée             static const GdbCmdParseEntry detach_cmd_desc = {
2006842b42dfSAlex Bennée                 .handler = handle_detach,
2007842b42dfSAlex Bennée                 .cmd = "D",
2008842b42dfSAlex Bennée                 .cmd_startswith = 1,
2009842b42dfSAlex Bennée                 .schema = "?.l0"
2010842b42dfSAlex Bennée             };
2011842b42dfSAlex Bennée             cmd_parser = &detach_cmd_desc;
2012842b42dfSAlex Bennée         }
2013842b42dfSAlex Bennée         break;
2014842b42dfSAlex Bennée     case 's':
2015842b42dfSAlex Bennée         {
2016842b42dfSAlex Bennée             static const GdbCmdParseEntry step_cmd_desc = {
2017842b42dfSAlex Bennée                 .handler = handle_step,
2018842b42dfSAlex Bennée                 .cmd = "s",
2019842b42dfSAlex Bennée                 .cmd_startswith = 1,
202075837005SMatheus Tavares Bernardino                 .allow_stop_reply = true,
2021842b42dfSAlex Bennée                 .schema = "L0"
2022842b42dfSAlex Bennée             };
2023842b42dfSAlex Bennée             cmd_parser = &step_cmd_desc;
2024842b42dfSAlex Bennée         }
2025842b42dfSAlex Bennée         break;
2026842b42dfSAlex Bennée     case 'b':
2027842b42dfSAlex Bennée         {
2028842b42dfSAlex Bennée             static const GdbCmdParseEntry backward_cmd_desc = {
2029842b42dfSAlex Bennée                 .handler = handle_backward,
2030842b42dfSAlex Bennée                 .cmd = "b",
2031842b42dfSAlex Bennée                 .cmd_startswith = 1,
20323b72d681SNicholas Piggin                 .allow_stop_reply = true,
2033842b42dfSAlex Bennée                 .schema = "o0"
2034842b42dfSAlex Bennée             };
2035842b42dfSAlex Bennée             cmd_parser = &backward_cmd_desc;
2036842b42dfSAlex Bennée         }
2037842b42dfSAlex Bennée         break;
2038842b42dfSAlex Bennée     case 'F':
2039842b42dfSAlex Bennée         {
2040842b42dfSAlex Bennée             static const GdbCmdParseEntry file_io_cmd_desc = {
2041c566080cSAlex Bennée                 .handler = gdb_handle_file_io,
2042842b42dfSAlex Bennée                 .cmd = "F",
2043842b42dfSAlex Bennée                 .cmd_startswith = 1,
2044842b42dfSAlex Bennée                 .schema = "L,L,o0"
2045842b42dfSAlex Bennée             };
2046842b42dfSAlex Bennée             cmd_parser = &file_io_cmd_desc;
2047842b42dfSAlex Bennée         }
2048842b42dfSAlex Bennée         break;
2049842b42dfSAlex Bennée     case 'g':
2050842b42dfSAlex Bennée         {
2051842b42dfSAlex Bennée             static const GdbCmdParseEntry read_all_regs_cmd_desc = {
2052842b42dfSAlex Bennée                 .handler = handle_read_all_regs,
2053842b42dfSAlex Bennée                 .cmd = "g",
2054842b42dfSAlex Bennée                 .cmd_startswith = 1
2055842b42dfSAlex Bennée             };
2056842b42dfSAlex Bennée             cmd_parser = &read_all_regs_cmd_desc;
2057842b42dfSAlex Bennée         }
2058842b42dfSAlex Bennée         break;
2059842b42dfSAlex Bennée     case 'G':
2060842b42dfSAlex Bennée         {
2061842b42dfSAlex Bennée             static const GdbCmdParseEntry write_all_regs_cmd_desc = {
2062842b42dfSAlex Bennée                 .handler = handle_write_all_regs,
2063842b42dfSAlex Bennée                 .cmd = "G",
2064842b42dfSAlex Bennée                 .cmd_startswith = 1,
2065842b42dfSAlex Bennée                 .schema = "s0"
2066842b42dfSAlex Bennée             };
2067842b42dfSAlex Bennée             cmd_parser = &write_all_regs_cmd_desc;
2068842b42dfSAlex Bennée         }
2069842b42dfSAlex Bennée         break;
2070842b42dfSAlex Bennée     case 'm':
2071842b42dfSAlex Bennée         {
2072842b42dfSAlex Bennée             static const GdbCmdParseEntry read_mem_cmd_desc = {
2073842b42dfSAlex Bennée                 .handler = handle_read_mem,
2074842b42dfSAlex Bennée                 .cmd = "m",
2075842b42dfSAlex Bennée                 .cmd_startswith = 1,
2076842b42dfSAlex Bennée                 .schema = "L,L0"
2077842b42dfSAlex Bennée             };
2078842b42dfSAlex Bennée             cmd_parser = &read_mem_cmd_desc;
2079842b42dfSAlex Bennée         }
2080842b42dfSAlex Bennée         break;
2081842b42dfSAlex Bennée     case 'M':
2082842b42dfSAlex Bennée         {
2083842b42dfSAlex Bennée             static const GdbCmdParseEntry write_mem_cmd_desc = {
2084842b42dfSAlex Bennée                 .handler = handle_write_mem,
2085842b42dfSAlex Bennée                 .cmd = "M",
2086842b42dfSAlex Bennée                 .cmd_startswith = 1,
2087842b42dfSAlex Bennée                 .schema = "L,L:s0"
2088842b42dfSAlex Bennée             };
2089842b42dfSAlex Bennée             cmd_parser = &write_mem_cmd_desc;
2090842b42dfSAlex Bennée         }
2091842b42dfSAlex Bennée         break;
2092842b42dfSAlex Bennée     case 'p':
2093842b42dfSAlex Bennée         {
2094842b42dfSAlex Bennée             static const GdbCmdParseEntry get_reg_cmd_desc = {
2095842b42dfSAlex Bennée                 .handler = handle_get_reg,
2096842b42dfSAlex Bennée                 .cmd = "p",
2097842b42dfSAlex Bennée                 .cmd_startswith = 1,
2098842b42dfSAlex Bennée                 .schema = "L0"
2099842b42dfSAlex Bennée             };
2100842b42dfSAlex Bennée             cmd_parser = &get_reg_cmd_desc;
2101842b42dfSAlex Bennée         }
2102842b42dfSAlex Bennée         break;
2103842b42dfSAlex Bennée     case 'P':
2104842b42dfSAlex Bennée         {
2105842b42dfSAlex Bennée             static const GdbCmdParseEntry set_reg_cmd_desc = {
2106842b42dfSAlex Bennée                 .handler = handle_set_reg,
2107842b42dfSAlex Bennée                 .cmd = "P",
2108842b42dfSAlex Bennée                 .cmd_startswith = 1,
2109842b42dfSAlex Bennée                 .schema = "L?s0"
2110842b42dfSAlex Bennée             };
2111842b42dfSAlex Bennée             cmd_parser = &set_reg_cmd_desc;
2112842b42dfSAlex Bennée         }
2113842b42dfSAlex Bennée         break;
2114842b42dfSAlex Bennée     case 'Z':
2115842b42dfSAlex Bennée         {
2116842b42dfSAlex Bennée             static const GdbCmdParseEntry insert_bp_cmd_desc = {
2117842b42dfSAlex Bennée                 .handler = handle_insert_bp,
2118842b42dfSAlex Bennée                 .cmd = "Z",
2119842b42dfSAlex Bennée                 .cmd_startswith = 1,
2120842b42dfSAlex Bennée                 .schema = "l?L?L0"
2121842b42dfSAlex Bennée             };
2122842b42dfSAlex Bennée             cmd_parser = &insert_bp_cmd_desc;
2123842b42dfSAlex Bennée         }
2124842b42dfSAlex Bennée         break;
2125842b42dfSAlex Bennée     case 'z':
2126842b42dfSAlex Bennée         {
2127842b42dfSAlex Bennée             static const GdbCmdParseEntry remove_bp_cmd_desc = {
2128842b42dfSAlex Bennée                 .handler = handle_remove_bp,
2129842b42dfSAlex Bennée                 .cmd = "z",
2130842b42dfSAlex Bennée                 .cmd_startswith = 1,
2131842b42dfSAlex Bennée                 .schema = "l?L?L0"
2132842b42dfSAlex Bennée             };
2133842b42dfSAlex Bennée             cmd_parser = &remove_bp_cmd_desc;
2134842b42dfSAlex Bennée         }
2135842b42dfSAlex Bennée         break;
2136842b42dfSAlex Bennée     case 'H':
2137842b42dfSAlex Bennée         {
2138842b42dfSAlex Bennée             static const GdbCmdParseEntry set_thread_cmd_desc = {
2139842b42dfSAlex Bennée                 .handler = handle_set_thread,
2140842b42dfSAlex Bennée                 .cmd = "H",
2141842b42dfSAlex Bennée                 .cmd_startswith = 1,
2142842b42dfSAlex Bennée                 .schema = "o.t0"
2143842b42dfSAlex Bennée             };
2144842b42dfSAlex Bennée             cmd_parser = &set_thread_cmd_desc;
2145842b42dfSAlex Bennée         }
2146842b42dfSAlex Bennée         break;
2147842b42dfSAlex Bennée     case 'T':
2148842b42dfSAlex Bennée         {
2149842b42dfSAlex Bennée             static const GdbCmdParseEntry thread_alive_cmd_desc = {
2150842b42dfSAlex Bennée                 .handler = handle_thread_alive,
2151842b42dfSAlex Bennée                 .cmd = "T",
2152842b42dfSAlex Bennée                 .cmd_startswith = 1,
2153842b42dfSAlex Bennée                 .schema = "t0"
2154842b42dfSAlex Bennée             };
2155842b42dfSAlex Bennée             cmd_parser = &thread_alive_cmd_desc;
2156842b42dfSAlex Bennée         }
2157842b42dfSAlex Bennée         break;
2158842b42dfSAlex Bennée     case 'q':
2159842b42dfSAlex Bennée         {
2160842b42dfSAlex Bennée             static const GdbCmdParseEntry gen_query_cmd_desc = {
2161842b42dfSAlex Bennée                 .handler = handle_gen_query,
2162842b42dfSAlex Bennée                 .cmd = "q",
2163842b42dfSAlex Bennée                 .cmd_startswith = 1,
2164842b42dfSAlex Bennée                 .schema = "s0"
2165842b42dfSAlex Bennée             };
2166842b42dfSAlex Bennée             cmd_parser = &gen_query_cmd_desc;
2167842b42dfSAlex Bennée         }
2168842b42dfSAlex Bennée         break;
2169842b42dfSAlex Bennée     case 'Q':
2170842b42dfSAlex Bennée         {
2171842b42dfSAlex Bennée             static const GdbCmdParseEntry gen_set_cmd_desc = {
2172842b42dfSAlex Bennée                 .handler = handle_gen_set,
2173842b42dfSAlex Bennée                 .cmd = "Q",
2174842b42dfSAlex Bennée                 .cmd_startswith = 1,
2175842b42dfSAlex Bennée                 .schema = "s0"
2176842b42dfSAlex Bennée             };
2177842b42dfSAlex Bennée             cmd_parser = &gen_set_cmd_desc;
2178842b42dfSAlex Bennée         }
2179842b42dfSAlex Bennée         break;
2180842b42dfSAlex Bennée     default:
2181842b42dfSAlex Bennée         /* put empty packet */
218236e067b2SAlex Bennée         gdb_put_packet("");
2183842b42dfSAlex Bennée         break;
2184842b42dfSAlex Bennée     }
2185842b42dfSAlex Bennée 
2186842b42dfSAlex Bennée     if (cmd_parser) {
2187842b42dfSAlex Bennée         run_cmd_parser(line_buf, cmd_parser);
2188842b42dfSAlex Bennée     }
2189842b42dfSAlex Bennée 
2190842b42dfSAlex Bennée     return RS_IDLE;
2191842b42dfSAlex Bennée }
2192842b42dfSAlex Bennée 
gdb_set_stop_cpu(CPUState * cpu)2193842b42dfSAlex Bennée void gdb_set_stop_cpu(CPUState *cpu)
2194842b42dfSAlex Bennée {
2195842b42dfSAlex Bennée     GDBProcess *p = gdb_get_cpu_process(cpu);
2196842b42dfSAlex Bennée 
2197842b42dfSAlex Bennée     if (!p->attached) {
2198842b42dfSAlex Bennée         /*
2199842b42dfSAlex Bennée          * Having a stop CPU corresponding to a process that is not attached
2200842b42dfSAlex Bennée          * confuses GDB. So we ignore the request.
2201842b42dfSAlex Bennée          */
2202842b42dfSAlex Bennée         return;
2203842b42dfSAlex Bennée     }
2204842b42dfSAlex Bennée 
2205842b42dfSAlex Bennée     gdbserver_state.c_cpu = cpu;
2206842b42dfSAlex Bennée     gdbserver_state.g_cpu = cpu;
2207842b42dfSAlex Bennée }
2208842b42dfSAlex Bennée 
gdb_read_byte(uint8_t ch)220936e067b2SAlex Bennée void gdb_read_byte(uint8_t ch)
2210842b42dfSAlex Bennée {
2211842b42dfSAlex Bennée     uint8_t reply;
2212842b42dfSAlex Bennée 
221375837005SMatheus Tavares Bernardino     gdbserver_state.allow_stop_reply = false;
2214842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY
2215842b42dfSAlex Bennée     if (gdbserver_state.last_packet->len) {
2216842b42dfSAlex Bennée         /* Waiting for a response to the last packet.  If we see the start
2217842b42dfSAlex Bennée            of a new command then abandon the previous response.  */
2218842b42dfSAlex Bennée         if (ch == '-') {
2219842b42dfSAlex Bennée             trace_gdbstub_err_got_nack();
222036e067b2SAlex Bennée             gdb_put_buffer(gdbserver_state.last_packet->data,
2221842b42dfSAlex Bennée                        gdbserver_state.last_packet->len);
2222842b42dfSAlex Bennée         } else if (ch == '+') {
2223842b42dfSAlex Bennée             trace_gdbstub_io_got_ack();
2224842b42dfSAlex Bennée         } else {
2225842b42dfSAlex Bennée             trace_gdbstub_io_got_unexpected(ch);
2226842b42dfSAlex Bennée         }
2227842b42dfSAlex Bennée 
2228842b42dfSAlex Bennée         if (ch == '+' || ch == '$') {
2229842b42dfSAlex Bennée             g_byte_array_set_size(gdbserver_state.last_packet, 0);
2230842b42dfSAlex Bennée         }
2231842b42dfSAlex Bennée         if (ch != '$')
2232842b42dfSAlex Bennée             return;
2233842b42dfSAlex Bennée     }
2234842b42dfSAlex Bennée     if (runstate_is_running()) {
2235108e8180SNicholas Piggin         /*
2236108e8180SNicholas Piggin          * When the CPU is running, we cannot do anything except stop
2237108e8180SNicholas Piggin          * it when receiving a char. This is expected on a Ctrl-C in the
2238108e8180SNicholas Piggin          * gdb client. Because we are in all-stop mode, gdb sends a
2239108e8180SNicholas Piggin          * 0x03 byte which is not a usual packet, so we handle it specially
2240108e8180SNicholas Piggin          * here, but it does expect a stop reply.
2241108e8180SNicholas Piggin          */
2242108e8180SNicholas Piggin         if (ch != 0x03) {
22433869eb7eSAlex Bennée             trace_gdbstub_err_unexpected_runpkt(ch);
22443869eb7eSAlex Bennée         } else {
2245108e8180SNicholas Piggin             gdbserver_state.allow_stop_reply = true;
22463869eb7eSAlex Bennée         }
2247842b42dfSAlex Bennée         vm_stop(RUN_STATE_PAUSED);
2248842b42dfSAlex Bennée     } else
2249842b42dfSAlex Bennée #endif
2250842b42dfSAlex Bennée     {
2251842b42dfSAlex Bennée         switch(gdbserver_state.state) {
2252842b42dfSAlex Bennée         case RS_IDLE:
2253842b42dfSAlex Bennée             if (ch == '$') {
2254842b42dfSAlex Bennée                 /* start of command packet */
2255842b42dfSAlex Bennée                 gdbserver_state.line_buf_index = 0;
2256842b42dfSAlex Bennée                 gdbserver_state.line_sum = 0;
2257842b42dfSAlex Bennée                 gdbserver_state.state = RS_GETLINE;
2258f1b0f894SAlex Bennée             } else if (ch == '+') {
2259f1b0f894SAlex Bennée                 /*
2260f1b0f894SAlex Bennée                  * do nothing, gdb may preemptively send out ACKs on
2261f1b0f894SAlex Bennée                  * initial connection
2262f1b0f894SAlex Bennée                  */
2263842b42dfSAlex Bennée             } else {
2264842b42dfSAlex Bennée                 trace_gdbstub_err_garbage(ch);
2265842b42dfSAlex Bennée             }
2266842b42dfSAlex Bennée             break;
2267842b42dfSAlex Bennée         case RS_GETLINE:
2268842b42dfSAlex Bennée             if (ch == '}') {
2269842b42dfSAlex Bennée                 /* start escape sequence */
2270842b42dfSAlex Bennée                 gdbserver_state.state = RS_GETLINE_ESC;
2271842b42dfSAlex Bennée                 gdbserver_state.line_sum += ch;
2272842b42dfSAlex Bennée             } else if (ch == '*') {
2273842b42dfSAlex Bennée                 /* start run length encoding sequence */
2274842b42dfSAlex Bennée                 gdbserver_state.state = RS_GETLINE_RLE;
2275842b42dfSAlex Bennée                 gdbserver_state.line_sum += ch;
2276842b42dfSAlex Bennée             } else if (ch == '#') {
2277842b42dfSAlex Bennée                 /* end of command, start of checksum*/
2278842b42dfSAlex Bennée                 gdbserver_state.state = RS_CHKSUM1;
2279842b42dfSAlex Bennée             } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {
2280842b42dfSAlex Bennée                 trace_gdbstub_err_overrun();
2281842b42dfSAlex Bennée                 gdbserver_state.state = RS_IDLE;
2282842b42dfSAlex Bennée             } else {
2283842b42dfSAlex Bennée                 /* unescaped command character */
2284842b42dfSAlex Bennée                 gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch;
2285842b42dfSAlex Bennée                 gdbserver_state.line_sum += ch;
2286842b42dfSAlex Bennée             }
2287842b42dfSAlex Bennée             break;
2288842b42dfSAlex Bennée         case RS_GETLINE_ESC:
2289842b42dfSAlex Bennée             if (ch == '#') {
2290842b42dfSAlex Bennée                 /* unexpected end of command in escape sequence */
2291842b42dfSAlex Bennée                 gdbserver_state.state = RS_CHKSUM1;
2292842b42dfSAlex Bennée             } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {
2293842b42dfSAlex Bennée                 /* command buffer overrun */
2294842b42dfSAlex Bennée                 trace_gdbstub_err_overrun();
2295842b42dfSAlex Bennée                 gdbserver_state.state = RS_IDLE;
2296842b42dfSAlex Bennée             } else {
2297842b42dfSAlex Bennée                 /* parse escaped character and leave escape state */
2298842b42dfSAlex Bennée                 gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch ^ 0x20;
2299842b42dfSAlex Bennée                 gdbserver_state.line_sum += ch;
2300842b42dfSAlex Bennée                 gdbserver_state.state = RS_GETLINE;
2301842b42dfSAlex Bennée             }
2302842b42dfSAlex Bennée             break;
2303842b42dfSAlex Bennée         case RS_GETLINE_RLE:
2304842b42dfSAlex Bennée             /*
2305842b42dfSAlex Bennée              * Run-length encoding is explained in "Debugging with GDB /
2306842b42dfSAlex Bennée              * Appendix E GDB Remote Serial Protocol / Overview".
2307842b42dfSAlex Bennée              */
2308842b42dfSAlex Bennée             if (ch < ' ' || ch == '#' || ch == '$' || ch > 126) {
2309842b42dfSAlex Bennée                 /* invalid RLE count encoding */
2310842b42dfSAlex Bennée                 trace_gdbstub_err_invalid_repeat(ch);
2311842b42dfSAlex Bennée                 gdbserver_state.state = RS_GETLINE;
2312842b42dfSAlex Bennée             } else {
2313842b42dfSAlex Bennée                 /* decode repeat length */
2314842b42dfSAlex Bennée                 int repeat = ch - ' ' + 3;
2315842b42dfSAlex Bennée                 if (gdbserver_state.line_buf_index + repeat >= sizeof(gdbserver_state.line_buf) - 1) {
2316842b42dfSAlex Bennée                     /* that many repeats would overrun the command buffer */
2317842b42dfSAlex Bennée                     trace_gdbstub_err_overrun();
2318842b42dfSAlex Bennée                     gdbserver_state.state = RS_IDLE;
2319842b42dfSAlex Bennée                 } else if (gdbserver_state.line_buf_index < 1) {
2320842b42dfSAlex Bennée                     /* got a repeat but we have nothing to repeat */
2321842b42dfSAlex Bennée                     trace_gdbstub_err_invalid_rle();
2322842b42dfSAlex Bennée                     gdbserver_state.state = RS_GETLINE;
2323842b42dfSAlex Bennée                 } else {
2324842b42dfSAlex Bennée                     /* repeat the last character */
2325842b42dfSAlex Bennée                     memset(gdbserver_state.line_buf + gdbserver_state.line_buf_index,
2326842b42dfSAlex Bennée                            gdbserver_state.line_buf[gdbserver_state.line_buf_index - 1], repeat);
2327842b42dfSAlex Bennée                     gdbserver_state.line_buf_index += repeat;
2328842b42dfSAlex Bennée                     gdbserver_state.line_sum += ch;
2329842b42dfSAlex Bennée                     gdbserver_state.state = RS_GETLINE;
2330842b42dfSAlex Bennée                 }
2331842b42dfSAlex Bennée             }
2332842b42dfSAlex Bennée             break;
2333842b42dfSAlex Bennée         case RS_CHKSUM1:
2334842b42dfSAlex Bennée             /* get high hex digit of checksum */
2335842b42dfSAlex Bennée             if (!isxdigit(ch)) {
2336842b42dfSAlex Bennée                 trace_gdbstub_err_checksum_invalid(ch);
2337842b42dfSAlex Bennée                 gdbserver_state.state = RS_GETLINE;
2338842b42dfSAlex Bennée                 break;
2339842b42dfSAlex Bennée             }
2340842b42dfSAlex Bennée             gdbserver_state.line_buf[gdbserver_state.line_buf_index] = '\0';
2341842b42dfSAlex Bennée             gdbserver_state.line_csum = fromhex(ch) << 4;
2342842b42dfSAlex Bennée             gdbserver_state.state = RS_CHKSUM2;
2343842b42dfSAlex Bennée             break;
2344842b42dfSAlex Bennée         case RS_CHKSUM2:
2345842b42dfSAlex Bennée             /* get low hex digit of checksum */
2346842b42dfSAlex Bennée             if (!isxdigit(ch)) {
2347842b42dfSAlex Bennée                 trace_gdbstub_err_checksum_invalid(ch);
2348842b42dfSAlex Bennée                 gdbserver_state.state = RS_GETLINE;
2349842b42dfSAlex Bennée                 break;
2350842b42dfSAlex Bennée             }
2351842b42dfSAlex Bennée             gdbserver_state.line_csum |= fromhex(ch);
2352842b42dfSAlex Bennée 
2353842b42dfSAlex Bennée             if (gdbserver_state.line_csum != (gdbserver_state.line_sum & 0xff)) {
2354842b42dfSAlex Bennée                 trace_gdbstub_err_checksum_incorrect(gdbserver_state.line_sum, gdbserver_state.line_csum);
2355842b42dfSAlex Bennée                 /* send NAK reply */
2356842b42dfSAlex Bennée                 reply = '-';
235736e067b2SAlex Bennée                 gdb_put_buffer(&reply, 1);
2358842b42dfSAlex Bennée                 gdbserver_state.state = RS_IDLE;
2359842b42dfSAlex Bennée             } else {
2360842b42dfSAlex Bennée                 /* send ACK reply */
2361842b42dfSAlex Bennée                 reply = '+';
236236e067b2SAlex Bennée                 gdb_put_buffer(&reply, 1);
2363842b42dfSAlex Bennée                 gdbserver_state.state = gdb_handle_packet(gdbserver_state.line_buf);
2364842b42dfSAlex Bennée             }
2365842b42dfSAlex Bennée             break;
2366842b42dfSAlex Bennée         default:
2367842b42dfSAlex Bennée             abort();
2368842b42dfSAlex Bennée         }
2369842b42dfSAlex Bennée     }
2370842b42dfSAlex Bennée }
2371842b42dfSAlex Bennée 
2372842b42dfSAlex Bennée /*
2373842b42dfSAlex Bennée  * Create the process that will contain all the "orphan" CPUs (that are not
2374842b42dfSAlex Bennée  * part of a CPU cluster). Note that if this process contains no CPUs, it won't
2375842b42dfSAlex Bennée  * be attachable and thus will be invisible to the user.
2376842b42dfSAlex Bennée  */
gdb_create_default_process(GDBState * s)237736e067b2SAlex Bennée void gdb_create_default_process(GDBState *s)
2378842b42dfSAlex Bennée {
2379842b42dfSAlex Bennée     GDBProcess *process;
2380dc14a7a6SIlya Leoshkevich     int pid;
2381842b42dfSAlex Bennée 
2382dc14a7a6SIlya Leoshkevich #ifdef CONFIG_USER_ONLY
2383dc14a7a6SIlya Leoshkevich     assert(gdbserver_state.process_num == 0);
2384dc14a7a6SIlya Leoshkevich     pid = getpid();
2385dc14a7a6SIlya Leoshkevich #else
2386842b42dfSAlex Bennée     if (gdbserver_state.process_num) {
2387dc14a7a6SIlya Leoshkevich         pid = s->processes[s->process_num - 1].pid;
2388dc14a7a6SIlya Leoshkevich     } else {
2389dc14a7a6SIlya Leoshkevich         pid = 0;
2390842b42dfSAlex Bennée     }
2391dc14a7a6SIlya Leoshkevich     /* We need an available PID slot for this process */
2392dc14a7a6SIlya Leoshkevich     assert(pid < UINT32_MAX);
2393dc14a7a6SIlya Leoshkevich     pid++;
2394dc14a7a6SIlya Leoshkevich #endif
2395842b42dfSAlex Bennée 
2396842b42dfSAlex Bennée     s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
2397842b42dfSAlex Bennée     process = &s->processes[s->process_num - 1];
2398dc14a7a6SIlya Leoshkevich     process->pid = pid;
2399842b42dfSAlex Bennée     process->attached = false;
240056e534bdSAlex Bennée     process->target_xml = NULL;
2401842b42dfSAlex Bennée }
2402842b42dfSAlex Bennée 
2403