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 *
23*b14d0649SPhilippe Mathieu-Daudé * SPDX-License-Identifier: LGPL-2.0-or-later
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"
33133f202bSGustavo Romero #include "gdbstub/commands.h"
34c566080cSAlex Bennée #include "gdbstub/syscalls.h"
35842b42dfSAlex Bennée #ifdef CONFIG_USER_ONLY
3659272469SPhilippe Mathieu-Daudé #include "accel/tcg/vcpu-state.h"
37d96bf49bSAlex Bennée #include "gdbstub/user.h"
38842b42dfSAlex Bennée #else
39842b42dfSAlex Bennée #include "hw/cpu/cluster.h"
40842b42dfSAlex Bennée #include "hw/boards.h"
41842b42dfSAlex Bennée #endif
42fe766734SPhilippe Mathieu-Daudé #include "hw/core/cpu.h"
43842b42dfSAlex Bennée
44842b42dfSAlex Bennée #include "sysemu/hw_accel.h"
45842b42dfSAlex Bennée #include "sysemu/runstate.h"
465b5968c4SPhilippe Mathieu-Daudé #include "exec/replay-core.h"
47548c9609SAlex Bennée #include "exec/hwaddr.h"
48842b42dfSAlex Bennée
49ae7467b1SAlex Bennée #include "internals.h"
50ae7467b1SAlex Bennée
51842b42dfSAlex Bennée typedef struct GDBRegisterState {
52842b42dfSAlex Bennée int base_reg;
53842b42dfSAlex Bennée gdb_get_reg_cb get_reg;
54842b42dfSAlex Bennée gdb_set_reg_cb set_reg;
55c494f8f5SAkihiko Odaki const GDBFeature *feature;
56842b42dfSAlex Bennée } GDBRegisterState;
57842b42dfSAlex Bennée
58b6fa2ec2SAlex Bennée GDBState gdbserver_state;
59842b42dfSAlex Bennée
gdb_init_gdbserver_state(void)6036e067b2SAlex Bennée void gdb_init_gdbserver_state(void)
61842b42dfSAlex Bennée {
62842b42dfSAlex Bennée g_assert(!gdbserver_state.init);
63842b42dfSAlex Bennée memset(&gdbserver_state, 0, sizeof(GDBState));
64842b42dfSAlex Bennée gdbserver_state.init = true;
65842b42dfSAlex Bennée gdbserver_state.str_buf = g_string_new(NULL);
66842b42dfSAlex Bennée gdbserver_state.mem_buf = g_byte_array_sized_new(MAX_PACKET_LENGTH);
67842b42dfSAlex Bennée gdbserver_state.last_packet = g_byte_array_sized_new(MAX_PACKET_LENGTH + 4);
68842b42dfSAlex Bennée
69842b42dfSAlex Bennée /*
703b7a9388SAlex Bennée * What single-step modes are supported is accelerator dependent.
713b7a9388SAlex Bennée * By default try to use no IRQs and no timers while single
723b7a9388SAlex Bennée * stepping so as to make single stepping like a typical ICE HW step.
73842b42dfSAlex Bennée */
743b7a9388SAlex Bennée gdbserver_state.supported_sstep_flags = accel_supported_gdbstub_sstep_flags();
75842b42dfSAlex Bennée gdbserver_state.sstep_flags = SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER;
76842b42dfSAlex Bennée gdbserver_state.sstep_flags &= gdbserver_state.supported_sstep_flags;
77842b42dfSAlex Bennée }
78842b42dfSAlex Bennée
79842b42dfSAlex Bennée /* writes 2*len+1 bytes in buf */
gdb_memtohex(GString * buf,const uint8_t * mem,int len)8036e067b2SAlex Bennée void gdb_memtohex(GString *buf, const uint8_t *mem, int len)
81842b42dfSAlex Bennée {
82842b42dfSAlex Bennée int i, c;
83842b42dfSAlex Bennée for(i = 0; i < len; i++) {
84842b42dfSAlex Bennée c = mem[i];
85842b42dfSAlex Bennée g_string_append_c(buf, tohex(c >> 4));
86842b42dfSAlex Bennée g_string_append_c(buf, tohex(c & 0xf));
87842b42dfSAlex Bennée }
88842b42dfSAlex Bennée g_string_append_c(buf, '\0');
89842b42dfSAlex Bennée }
90842b42dfSAlex Bennée
gdb_hextomem(GByteArray * mem,const char * buf,int len)9136e067b2SAlex Bennée void gdb_hextomem(GByteArray *mem, const char *buf, int len)
92842b42dfSAlex Bennée {
93842b42dfSAlex Bennée int i;
94842b42dfSAlex Bennée
95842b42dfSAlex Bennée for(i = 0; i < len; i++) {
96842b42dfSAlex Bennée guint8 byte = fromhex(buf[0]) << 4 | fromhex(buf[1]);
97842b42dfSAlex Bennée g_byte_array_append(mem, &byte, 1);
98842b42dfSAlex Bennée buf += 2;
99842b42dfSAlex Bennée }
100842b42dfSAlex Bennée }
101842b42dfSAlex Bennée
hexdump(const char * buf,int len,void (* trace_fn)(size_t ofs,char const * text))102842b42dfSAlex Bennée static void hexdump(const char *buf, int len,
103842b42dfSAlex Bennée void (*trace_fn)(size_t ofs, char const *text))
104842b42dfSAlex Bennée {
105842b42dfSAlex Bennée char line_buffer[3 * 16 + 4 + 16 + 1];
106842b42dfSAlex Bennée
107842b42dfSAlex Bennée size_t i;
108842b42dfSAlex Bennée for (i = 0; i < len || (i & 0xF); ++i) {
109842b42dfSAlex Bennée size_t byte_ofs = i & 15;
110842b42dfSAlex Bennée
111842b42dfSAlex Bennée if (byte_ofs == 0) {
112842b42dfSAlex Bennée memset(line_buffer, ' ', 3 * 16 + 4 + 16);
113842b42dfSAlex Bennée line_buffer[3 * 16 + 4 + 16] = 0;
114842b42dfSAlex Bennée }
115842b42dfSAlex Bennée
116842b42dfSAlex Bennée size_t col_group = (i >> 2) & 3;
117842b42dfSAlex Bennée size_t hex_col = byte_ofs * 3 + col_group;
118842b42dfSAlex Bennée size_t txt_col = 3 * 16 + 4 + byte_ofs;
119842b42dfSAlex Bennée
120842b42dfSAlex Bennée if (i < len) {
121842b42dfSAlex Bennée char value = buf[i];
122842b42dfSAlex Bennée
123842b42dfSAlex Bennée line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF);
124842b42dfSAlex Bennée line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF);
125842b42dfSAlex Bennée line_buffer[txt_col + 0] = (value >= ' ' && value < 127)
126842b42dfSAlex Bennée ? value
127842b42dfSAlex Bennée : '.';
128842b42dfSAlex Bennée }
129842b42dfSAlex Bennée
130842b42dfSAlex Bennée if (byte_ofs == 0xF)
131842b42dfSAlex Bennée trace_fn(i & -16, line_buffer);
132842b42dfSAlex Bennée }
133842b42dfSAlex Bennée }
134842b42dfSAlex Bennée
135842b42dfSAlex Bennée /* return -1 if error, 0 if OK */
gdb_put_packet_binary(const char * buf,int len,bool dump)13636e067b2SAlex Bennée int gdb_put_packet_binary(const char *buf, int len, bool dump)
137842b42dfSAlex Bennée {
138842b42dfSAlex Bennée int csum, i;
139842b42dfSAlex Bennée uint8_t footer[3];
140842b42dfSAlex Bennée
141842b42dfSAlex Bennée if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) {
142842b42dfSAlex Bennée hexdump(buf, len, trace_gdbstub_io_binaryreply);
143842b42dfSAlex Bennée }
144842b42dfSAlex Bennée
145842b42dfSAlex Bennée for(;;) {
146842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.last_packet, 0);
147842b42dfSAlex Bennée g_byte_array_append(gdbserver_state.last_packet,
148842b42dfSAlex Bennée (const uint8_t *) "$", 1);
149842b42dfSAlex Bennée g_byte_array_append(gdbserver_state.last_packet,
150842b42dfSAlex Bennée (const uint8_t *) buf, len);
151842b42dfSAlex Bennée csum = 0;
152842b42dfSAlex Bennée for(i = 0; i < len; i++) {
153842b42dfSAlex Bennée csum += buf[i];
154842b42dfSAlex Bennée }
155842b42dfSAlex Bennée footer[0] = '#';
156842b42dfSAlex Bennée footer[1] = tohex((csum >> 4) & 0xf);
157842b42dfSAlex Bennée footer[2] = tohex((csum) & 0xf);
158842b42dfSAlex Bennée g_byte_array_append(gdbserver_state.last_packet, footer, 3);
159842b42dfSAlex Bennée
16036e067b2SAlex Bennée gdb_put_buffer(gdbserver_state.last_packet->data,
161842b42dfSAlex Bennée gdbserver_state.last_packet->len);
162842b42dfSAlex Bennée
163a7e0f9bdSAlex Bennée if (gdb_got_immediate_ack()) {
164842b42dfSAlex Bennée break;
165a7e0f9bdSAlex Bennée }
166842b42dfSAlex Bennée }
167842b42dfSAlex Bennée return 0;
168842b42dfSAlex Bennée }
169842b42dfSAlex Bennée
170842b42dfSAlex Bennée /* return -1 if error, 0 if OK */
gdb_put_packet(const char * buf)17136e067b2SAlex Bennée int gdb_put_packet(const char *buf)
172842b42dfSAlex Bennée {
173842b42dfSAlex Bennée trace_gdbstub_io_reply(buf);
174842b42dfSAlex Bennée
17536e067b2SAlex Bennée return gdb_put_packet_binary(buf, strlen(buf), false);
176842b42dfSAlex Bennée }
177842b42dfSAlex Bennée
gdb_put_strbuf(void)17836e067b2SAlex Bennée void gdb_put_strbuf(void)
179842b42dfSAlex Bennée {
18036e067b2SAlex Bennée gdb_put_packet(gdbserver_state.str_buf->str);
181842b42dfSAlex Bennée }
182842b42dfSAlex Bennée
183842b42dfSAlex Bennée /* Encode data using the encoding for 'x' packets. */
gdb_memtox(GString * buf,const char * mem,int len)18436e067b2SAlex Bennée void gdb_memtox(GString *buf, const char *mem, int len)
185842b42dfSAlex Bennée {
186842b42dfSAlex Bennée char c;
187842b42dfSAlex Bennée
188842b42dfSAlex Bennée while (len--) {
189842b42dfSAlex Bennée c = *(mem++);
190842b42dfSAlex Bennée switch (c) {
191842b42dfSAlex Bennée case '#': case '$': case '*': case '}':
192842b42dfSAlex Bennée g_string_append_c(buf, '}');
193842b42dfSAlex Bennée g_string_append_c(buf, c ^ 0x20);
194842b42dfSAlex Bennée break;
195842b42dfSAlex Bennée default:
196842b42dfSAlex Bennée g_string_append_c(buf, c);
197842b42dfSAlex Bennée break;
198842b42dfSAlex Bennée }
199842b42dfSAlex Bennée }
200842b42dfSAlex Bennée }
201842b42dfSAlex Bennée
gdb_get_cpu_pid(CPUState * cpu)202842b42dfSAlex Bennée static uint32_t gdb_get_cpu_pid(CPUState *cpu)
203842b42dfSAlex Bennée {
204dc14a7a6SIlya Leoshkevich #ifdef CONFIG_USER_ONLY
205dc14a7a6SIlya Leoshkevich return getpid();
206dc14a7a6SIlya Leoshkevich #else
207842b42dfSAlex Bennée if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
208842b42dfSAlex Bennée /* Return the default process' PID */
209842b42dfSAlex Bennée int index = gdbserver_state.process_num - 1;
210842b42dfSAlex Bennée return gdbserver_state.processes[index].pid;
211842b42dfSAlex Bennée }
212842b42dfSAlex Bennée return cpu->cluster_index + 1;
213dc14a7a6SIlya Leoshkevich #endif
214842b42dfSAlex Bennée }
215842b42dfSAlex Bennée
gdb_get_process(uint32_t pid)216a3fcc111SIlya Leoshkevich GDBProcess *gdb_get_process(uint32_t pid)
217842b42dfSAlex Bennée {
218842b42dfSAlex Bennée int i;
219842b42dfSAlex Bennée
220842b42dfSAlex Bennée if (!pid) {
221842b42dfSAlex Bennée /* 0 means any process, we take the first one */
222842b42dfSAlex Bennée return &gdbserver_state.processes[0];
223842b42dfSAlex Bennée }
224842b42dfSAlex Bennée
225842b42dfSAlex Bennée for (i = 0; i < gdbserver_state.process_num; i++) {
226842b42dfSAlex Bennée if (gdbserver_state.processes[i].pid == pid) {
227842b42dfSAlex Bennée return &gdbserver_state.processes[i];
228842b42dfSAlex Bennée }
229842b42dfSAlex Bennée }
230842b42dfSAlex Bennée
231842b42dfSAlex Bennée return NULL;
232842b42dfSAlex Bennée }
233842b42dfSAlex Bennée
gdb_get_cpu_process(CPUState * cpu)234842b42dfSAlex Bennée static GDBProcess *gdb_get_cpu_process(CPUState *cpu)
235842b42dfSAlex Bennée {
236842b42dfSAlex Bennée return gdb_get_process(gdb_get_cpu_pid(cpu));
237842b42dfSAlex Bennée }
238842b42dfSAlex Bennée
find_cpu(uint32_t thread_id)239842b42dfSAlex Bennée static CPUState *find_cpu(uint32_t thread_id)
240842b42dfSAlex Bennée {
241842b42dfSAlex Bennée CPUState *cpu;
242842b42dfSAlex Bennée
243842b42dfSAlex Bennée CPU_FOREACH(cpu) {
24436e067b2SAlex Bennée if (gdb_get_cpu_index(cpu) == thread_id) {
245842b42dfSAlex Bennée return cpu;
246842b42dfSAlex Bennée }
247842b42dfSAlex Bennée }
248842b42dfSAlex Bennée
249842b42dfSAlex Bennée return NULL;
250842b42dfSAlex Bennée }
251842b42dfSAlex Bennée
gdb_get_first_cpu_in_process(GDBProcess * process)252a3fcc111SIlya Leoshkevich CPUState *gdb_get_first_cpu_in_process(GDBProcess *process)
253842b42dfSAlex Bennée {
254842b42dfSAlex Bennée CPUState *cpu;
255842b42dfSAlex Bennée
256842b42dfSAlex Bennée CPU_FOREACH(cpu) {
257842b42dfSAlex Bennée if (gdb_get_cpu_pid(cpu) == process->pid) {
258842b42dfSAlex Bennée return cpu;
259842b42dfSAlex Bennée }
260842b42dfSAlex Bennée }
261842b42dfSAlex Bennée
262842b42dfSAlex Bennée return NULL;
263842b42dfSAlex Bennée }
264842b42dfSAlex Bennée
gdb_next_cpu_in_process(CPUState * cpu)265842b42dfSAlex Bennée static CPUState *gdb_next_cpu_in_process(CPUState *cpu)
266842b42dfSAlex Bennée {
267842b42dfSAlex Bennée uint32_t pid = gdb_get_cpu_pid(cpu);
268842b42dfSAlex Bennée cpu = CPU_NEXT(cpu);
269842b42dfSAlex Bennée
270842b42dfSAlex Bennée while (cpu) {
271842b42dfSAlex Bennée if (gdb_get_cpu_pid(cpu) == pid) {
272842b42dfSAlex Bennée break;
273842b42dfSAlex Bennée }
274842b42dfSAlex Bennée
275842b42dfSAlex Bennée cpu = CPU_NEXT(cpu);
276842b42dfSAlex Bennée }
277842b42dfSAlex Bennée
278842b42dfSAlex Bennée return cpu;
279842b42dfSAlex Bennée }
280842b42dfSAlex Bennée
281842b42dfSAlex Bennée /* Return the cpu following @cpu, while ignoring unattached processes. */
gdb_next_attached_cpu(CPUState * cpu)282842b42dfSAlex Bennée static CPUState *gdb_next_attached_cpu(CPUState *cpu)
283842b42dfSAlex Bennée {
284842b42dfSAlex Bennée cpu = CPU_NEXT(cpu);
285842b42dfSAlex Bennée
286842b42dfSAlex Bennée while (cpu) {
287842b42dfSAlex Bennée if (gdb_get_cpu_process(cpu)->attached) {
288842b42dfSAlex Bennée break;
289842b42dfSAlex Bennée }
290842b42dfSAlex Bennée
291842b42dfSAlex Bennée cpu = CPU_NEXT(cpu);
292842b42dfSAlex Bennée }
293842b42dfSAlex Bennée
294842b42dfSAlex Bennée return cpu;
295842b42dfSAlex Bennée }
296842b42dfSAlex Bennée
297842b42dfSAlex Bennée /* Return the first attached cpu */
gdb_first_attached_cpu(void)29836e067b2SAlex Bennée CPUState *gdb_first_attached_cpu(void)
299842b42dfSAlex Bennée {
300842b42dfSAlex Bennée CPUState *cpu = first_cpu;
301842b42dfSAlex Bennée GDBProcess *process = gdb_get_cpu_process(cpu);
302842b42dfSAlex Bennée
303842b42dfSAlex Bennée if (!process->attached) {
304842b42dfSAlex Bennée return gdb_next_attached_cpu(cpu);
305842b42dfSAlex Bennée }
306842b42dfSAlex Bennée
307842b42dfSAlex Bennée return cpu;
308842b42dfSAlex Bennée }
309842b42dfSAlex Bennée
gdb_get_cpu(uint32_t pid,uint32_t tid)310842b42dfSAlex Bennée static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid)
311842b42dfSAlex Bennée {
312842b42dfSAlex Bennée GDBProcess *process;
313842b42dfSAlex Bennée CPUState *cpu;
314842b42dfSAlex Bennée
315842b42dfSAlex Bennée if (!pid && !tid) {
316842b42dfSAlex Bennée /* 0 means any process/thread, we take the first attached one */
317842b42dfSAlex Bennée return gdb_first_attached_cpu();
318842b42dfSAlex Bennée } else if (pid && !tid) {
319842b42dfSAlex Bennée /* any thread in a specific process */
320842b42dfSAlex Bennée process = gdb_get_process(pid);
321842b42dfSAlex Bennée
322842b42dfSAlex Bennée if (process == NULL) {
323842b42dfSAlex Bennée return NULL;
324842b42dfSAlex Bennée }
325842b42dfSAlex Bennée
326842b42dfSAlex Bennée if (!process->attached) {
327842b42dfSAlex Bennée return NULL;
328842b42dfSAlex Bennée }
329842b42dfSAlex Bennée
330a3fcc111SIlya Leoshkevich return gdb_get_first_cpu_in_process(process);
331842b42dfSAlex Bennée } else {
332842b42dfSAlex Bennée /* a specific thread */
333842b42dfSAlex Bennée cpu = find_cpu(tid);
334842b42dfSAlex Bennée
335842b42dfSAlex Bennée if (cpu == NULL) {
336842b42dfSAlex Bennée return NULL;
337842b42dfSAlex Bennée }
338842b42dfSAlex Bennée
339842b42dfSAlex Bennée process = gdb_get_cpu_process(cpu);
340842b42dfSAlex Bennée
341842b42dfSAlex Bennée if (pid && process->pid != pid) {
342842b42dfSAlex Bennée return NULL;
343842b42dfSAlex Bennée }
344842b42dfSAlex Bennée
345842b42dfSAlex Bennée if (!process->attached) {
346842b42dfSAlex Bennée return NULL;
347842b42dfSAlex Bennée }
348842b42dfSAlex Bennée
349842b42dfSAlex Bennée return cpu;
350842b42dfSAlex Bennée }
351842b42dfSAlex Bennée }
352842b42dfSAlex Bennée
get_feature_xml(const char * p,const char ** newp,GDBProcess * process)353842b42dfSAlex Bennée static const char *get_feature_xml(const char *p, const char **newp,
354842b42dfSAlex Bennée GDBProcess *process)
355842b42dfSAlex Bennée {
356a3fcc111SIlya Leoshkevich CPUState *cpu = gdb_get_first_cpu_in_process(process);
357842b42dfSAlex Bennée CPUClass *cc = CPU_GET_CLASS(cpu);
358ee59fa1dSAkihiko Odaki GDBRegisterState *r;
35956e534bdSAlex Bennée size_t len;
360842b42dfSAlex Bennée
36156e534bdSAlex Bennée /*
36256e534bdSAlex Bennée * qXfer:features:read:ANNEX:OFFSET,LENGTH'
36356e534bdSAlex Bennée * ^p ^newp
36456e534bdSAlex Bennée */
36556e534bdSAlex Bennée char *term = strchr(p, ':');
36656e534bdSAlex Bennée *newp = term + 1;
36756e534bdSAlex Bennée len = term - p;
368842b42dfSAlex Bennée
36956e534bdSAlex Bennée /* Is it the main target xml? */
370842b42dfSAlex Bennée if (strncmp(p, "target.xml", len) == 0) {
37156e534bdSAlex Bennée if (!process->target_xml) {
3726d8f77a6SAkihiko Odaki g_autoptr(GPtrArray) xml = g_ptr_array_new_with_free_func(g_free);
373842b42dfSAlex Bennée
3746d8f77a6SAkihiko Odaki g_ptr_array_add(
3756d8f77a6SAkihiko Odaki xml,
3766d8f77a6SAkihiko Odaki g_strdup("<?xml version=\"1.0\"?>"
377842b42dfSAlex Bennée "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
3786d8f77a6SAkihiko Odaki "<target>"));
379842b42dfSAlex Bennée
38056e534bdSAlex Bennée if (cc->gdb_arch_name) {
3816d8f77a6SAkihiko Odaki g_ptr_array_add(
3826d8f77a6SAkihiko Odaki xml,
3836d8f77a6SAkihiko Odaki g_markup_printf_escaped("<architecture>%s</architecture>",
3846d8f77a6SAkihiko Odaki cc->gdb_arch_name(cpu)));
38556e534bdSAlex Bennée }
38673c392c2SAkihiko Odaki for (guint i = 0; i < cpu->gdb_regs->len; i++) {
38773c392c2SAkihiko Odaki r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
3886d8f77a6SAkihiko Odaki g_ptr_array_add(
3896d8f77a6SAkihiko Odaki xml,
3906d8f77a6SAkihiko Odaki g_markup_printf_escaped("<xi:include href=\"%s\"/>",
391c494f8f5SAkihiko Odaki r->feature->xmlname));
39256e534bdSAlex Bennée }
3936d8f77a6SAkihiko Odaki g_ptr_array_add(xml, g_strdup("</target>"));
3946d8f77a6SAkihiko Odaki g_ptr_array_add(xml, NULL);
39556e534bdSAlex Bennée
3966d8f77a6SAkihiko Odaki process->target_xml = g_strjoinv(NULL, (void *)xml->pdata);
39756e534bdSAlex Bennée }
3985d1ab242SAkihiko Odaki return process->target_xml;
39956e534bdSAlex Bennée }
400ee59fa1dSAkihiko Odaki /* Is it one of the features? */
401ee59fa1dSAkihiko Odaki for (guint i = 0; i < cpu->gdb_regs->len; i++) {
402ee59fa1dSAkihiko Odaki r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
403ee59fa1dSAkihiko Odaki if (strncmp(p, r->feature->xmlname, len) == 0) {
404ee59fa1dSAkihiko Odaki return r->feature->xml;
405842b42dfSAlex Bennée }
40656e534bdSAlex Bennée }
40756e534bdSAlex Bennée
40856e534bdSAlex Bennée /* failed */
40956e534bdSAlex Bennée return NULL;
410842b42dfSAlex Bennée }
411842b42dfSAlex Bennée
gdb_feature_builder_init(GDBFeatureBuilder * builder,GDBFeature * feature,const char * name,const char * xmlname,int base_reg)412e84f4524SAkihiko Odaki void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
413e84f4524SAkihiko Odaki const char *name, const char *xmlname,
414e84f4524SAkihiko Odaki int base_reg)
415e84f4524SAkihiko Odaki {
416e84f4524SAkihiko Odaki char *header = g_markup_printf_escaped(
417e84f4524SAkihiko Odaki "<?xml version=\"1.0\"?>"
418e84f4524SAkihiko Odaki "<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">"
419e84f4524SAkihiko Odaki "<feature name=\"%s\">",
420e84f4524SAkihiko Odaki name);
421e84f4524SAkihiko Odaki
422e84f4524SAkihiko Odaki builder->feature = feature;
423e84f4524SAkihiko Odaki builder->xml = g_ptr_array_new();
424e84f4524SAkihiko Odaki g_ptr_array_add(builder->xml, header);
425eb37086fSAkihiko Odaki builder->regs = g_ptr_array_new();
426e84f4524SAkihiko Odaki builder->base_reg = base_reg;
427e84f4524SAkihiko Odaki feature->xmlname = xmlname;
428eb37086fSAkihiko Odaki feature->name = name;
429e84f4524SAkihiko Odaki }
430e84f4524SAkihiko Odaki
gdb_feature_builder_append_tag(const GDBFeatureBuilder * builder,const char * format,...)431e84f4524SAkihiko Odaki void gdb_feature_builder_append_tag(const GDBFeatureBuilder *builder,
432e84f4524SAkihiko Odaki const char *format, ...)
433e84f4524SAkihiko Odaki {
434e84f4524SAkihiko Odaki va_list ap;
435e84f4524SAkihiko Odaki va_start(ap, format);
436e84f4524SAkihiko Odaki g_ptr_array_add(builder->xml, g_markup_vprintf_escaped(format, ap));
437e84f4524SAkihiko Odaki va_end(ap);
438e84f4524SAkihiko Odaki }
439e84f4524SAkihiko Odaki
gdb_feature_builder_append_reg(const GDBFeatureBuilder * builder,const char * name,int bitsize,int regnum,const char * type,const char * group)440e84f4524SAkihiko Odaki void gdb_feature_builder_append_reg(const GDBFeatureBuilder *builder,
441e84f4524SAkihiko Odaki const char *name,
442e84f4524SAkihiko Odaki int bitsize,
443e84f4524SAkihiko Odaki int regnum,
444e84f4524SAkihiko Odaki const char *type,
445e84f4524SAkihiko Odaki const char *group)
446e84f4524SAkihiko Odaki {
447eb37086fSAkihiko Odaki if (builder->regs->len <= regnum) {
448eb37086fSAkihiko Odaki g_ptr_array_set_size(builder->regs, regnum + 1);
449e84f4524SAkihiko Odaki }
450e84f4524SAkihiko Odaki
451eb37086fSAkihiko Odaki builder->regs->pdata[regnum] = (gpointer *)name;
452eb37086fSAkihiko Odaki
453e84f4524SAkihiko Odaki if (group) {
454e84f4524SAkihiko Odaki gdb_feature_builder_append_tag(
455e84f4524SAkihiko Odaki builder,
456e84f4524SAkihiko Odaki "<reg name=\"%s\" bitsize=\"%d\" regnum=\"%d\" type=\"%s\" group=\"%s\"/>",
457e84f4524SAkihiko Odaki name, bitsize, builder->base_reg + regnum, type, group);
458e84f4524SAkihiko Odaki } else {
459e84f4524SAkihiko Odaki gdb_feature_builder_append_tag(
460e84f4524SAkihiko Odaki builder,
461e84f4524SAkihiko Odaki "<reg name=\"%s\" bitsize=\"%d\" regnum=\"%d\" type=\"%s\"/>",
462e84f4524SAkihiko Odaki name, bitsize, builder->base_reg + regnum, type);
463e84f4524SAkihiko Odaki }
464e84f4524SAkihiko Odaki }
465e84f4524SAkihiko Odaki
gdb_feature_builder_end(const GDBFeatureBuilder * builder)466e84f4524SAkihiko Odaki void gdb_feature_builder_end(const GDBFeatureBuilder *builder)
467e84f4524SAkihiko Odaki {
468e84f4524SAkihiko Odaki g_ptr_array_add(builder->xml, (void *)"</feature>");
469e84f4524SAkihiko Odaki g_ptr_array_add(builder->xml, NULL);
470e84f4524SAkihiko Odaki
471e84f4524SAkihiko Odaki builder->feature->xml = g_strjoinv(NULL, (void *)builder->xml->pdata);
472e84f4524SAkihiko Odaki
473e84f4524SAkihiko Odaki for (guint i = 0; i < builder->xml->len - 2; i++) {
474e84f4524SAkihiko Odaki g_free(g_ptr_array_index(builder->xml, i));
475e84f4524SAkihiko Odaki }
476e84f4524SAkihiko Odaki
477e84f4524SAkihiko Odaki g_ptr_array_free(builder->xml, TRUE);
478eb37086fSAkihiko Odaki
479eb37086fSAkihiko Odaki builder->feature->num_regs = builder->regs->len;
480eb37086fSAkihiko Odaki builder->feature->regs = (void *)g_ptr_array_free(builder->regs, FALSE);
481e84f4524SAkihiko Odaki }
482e84f4524SAkihiko Odaki
gdb_find_static_feature(const char * xmlname)4831218b68eSAkihiko Odaki const GDBFeature *gdb_find_static_feature(const char *xmlname)
4841218b68eSAkihiko Odaki {
4851218b68eSAkihiko Odaki const GDBFeature *feature;
4861218b68eSAkihiko Odaki
4871218b68eSAkihiko Odaki for (feature = gdb_static_features; feature->xmlname; feature++) {
4881218b68eSAkihiko Odaki if (!strcmp(feature->xmlname, xmlname)) {
4891218b68eSAkihiko Odaki return feature;
4901218b68eSAkihiko Odaki }
4911218b68eSAkihiko Odaki }
4921218b68eSAkihiko Odaki
4931218b68eSAkihiko Odaki g_assert_not_reached();
4941218b68eSAkihiko Odaki }
4951218b68eSAkihiko Odaki
gdb_get_register_list(CPUState * cpu)496c3d0b466SAlex Bennée GArray *gdb_get_register_list(CPUState *cpu)
497c3d0b466SAlex Bennée {
498c3d0b466SAlex Bennée GArray *results = g_array_new(true, true, sizeof(GDBRegDesc));
499c3d0b466SAlex Bennée
500c3d0b466SAlex Bennée /* registers are only available once the CPU is initialised */
501c3d0b466SAlex Bennée if (!cpu->gdb_regs) {
502c3d0b466SAlex Bennée return results;
503c3d0b466SAlex Bennée }
504c3d0b466SAlex Bennée
505c3d0b466SAlex Bennée for (int f = 0; f < cpu->gdb_regs->len; f++) {
506c3d0b466SAlex Bennée GDBRegisterState *r = &g_array_index(cpu->gdb_regs, GDBRegisterState, f);
507c3d0b466SAlex Bennée for (int i = 0; i < r->feature->num_regs; i++) {
508c3d0b466SAlex Bennée const char *name = r->feature->regs[i];
509c3d0b466SAlex Bennée GDBRegDesc desc = {
510c3d0b466SAlex Bennée r->base_reg + i,
511c3d0b466SAlex Bennée name,
512c3d0b466SAlex Bennée r->feature->name
513c3d0b466SAlex Bennée };
514c3d0b466SAlex Bennée g_array_append_val(results, desc);
515c3d0b466SAlex Bennée }
516c3d0b466SAlex Bennée }
517c3d0b466SAlex Bennée
518c3d0b466SAlex Bennée return results;
519c3d0b466SAlex Bennée }
520c3d0b466SAlex Bennée
gdb_read_register(CPUState * cpu,GByteArray * buf,int reg)521c3d0b466SAlex Bennée int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
522842b42dfSAlex Bennée {
523842b42dfSAlex Bennée CPUClass *cc = CPU_GET_CLASS(cpu);
524842b42dfSAlex Bennée GDBRegisterState *r;
525842b42dfSAlex Bennée
526842b42dfSAlex Bennée if (reg < cc->gdb_num_core_regs) {
527842b42dfSAlex Bennée return cc->gdb_read_register(cpu, buf, reg);
528842b42dfSAlex Bennée }
529842b42dfSAlex Bennée
53073c392c2SAkihiko Odaki for (guint i = 0; i < cpu->gdb_regs->len; i++) {
53173c392c2SAkihiko Odaki r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
532c494f8f5SAkihiko Odaki if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
53366260159SAkihiko Odaki return r->get_reg(cpu, buf, reg - r->base_reg);
534842b42dfSAlex Bennée }
535842b42dfSAlex Bennée }
536842b42dfSAlex Bennée return 0;
537842b42dfSAlex Bennée }
538842b42dfSAlex Bennée
gdb_write_register(CPUState * cpu,uint8_t * mem_buf,int reg)539842b42dfSAlex Bennée static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
540842b42dfSAlex Bennée {
541842b42dfSAlex Bennée CPUClass *cc = CPU_GET_CLASS(cpu);
542842b42dfSAlex Bennée GDBRegisterState *r;
543842b42dfSAlex Bennée
544842b42dfSAlex Bennée if (reg < cc->gdb_num_core_regs) {
545842b42dfSAlex Bennée return cc->gdb_write_register(cpu, mem_buf, reg);
546842b42dfSAlex Bennée }
547842b42dfSAlex Bennée
54873c392c2SAkihiko Odaki for (guint i = 0; i < cpu->gdb_regs->len; i++) {
54973c392c2SAkihiko Odaki r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
550c494f8f5SAkihiko Odaki if (r->base_reg <= reg && reg < r->base_reg + r->feature->num_regs) {
55166260159SAkihiko Odaki return r->set_reg(cpu, mem_buf, reg - r->base_reg);
552842b42dfSAlex Bennée }
553842b42dfSAlex Bennée }
554842b42dfSAlex Bennée return 0;
555842b42dfSAlex Bennée }
556842b42dfSAlex 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)557ee59fa1dSAkihiko Odaki static void gdb_register_feature(CPUState *cpu, int base_reg,
558ee59fa1dSAkihiko Odaki gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
559ee59fa1dSAkihiko Odaki const GDBFeature *feature)
560ee59fa1dSAkihiko Odaki {
561ee59fa1dSAkihiko Odaki GDBRegisterState s = {
562ee59fa1dSAkihiko Odaki .base_reg = base_reg,
563ee59fa1dSAkihiko Odaki .get_reg = get_reg,
564ee59fa1dSAkihiko Odaki .set_reg = set_reg,
565ee59fa1dSAkihiko Odaki .feature = feature
566ee59fa1dSAkihiko Odaki };
567ee59fa1dSAkihiko Odaki
568ee59fa1dSAkihiko Odaki g_array_append_val(cpu->gdb_regs, s);
569ee59fa1dSAkihiko Odaki }
570ee59fa1dSAkihiko Odaki
gdb_init_cpu(CPUState * cpu)571ee59fa1dSAkihiko Odaki void gdb_init_cpu(CPUState *cpu)
572ee59fa1dSAkihiko Odaki {
573ee59fa1dSAkihiko Odaki CPUClass *cc = CPU_GET_CLASS(cpu);
574ee59fa1dSAkihiko Odaki const GDBFeature *feature;
575ee59fa1dSAkihiko Odaki
576ee59fa1dSAkihiko Odaki cpu->gdb_regs = g_array_new(false, false, sizeof(GDBRegisterState));
577ee59fa1dSAkihiko Odaki
578ee59fa1dSAkihiko Odaki if (cc->gdb_core_xml_file) {
579ee59fa1dSAkihiko Odaki feature = gdb_find_static_feature(cc->gdb_core_xml_file);
580ee59fa1dSAkihiko Odaki gdb_register_feature(cpu, 0,
581ee59fa1dSAkihiko Odaki cc->gdb_read_register, cc->gdb_write_register,
582ee59fa1dSAkihiko Odaki feature);
583ecd6f6a8SAkihiko Odaki cpu->gdb_num_regs = cpu->gdb_num_g_regs = feature->num_regs;
584ee59fa1dSAkihiko Odaki }
585ee59fa1dSAkihiko Odaki
586ecd6f6a8SAkihiko Odaki if (cc->gdb_num_core_regs) {
587ee59fa1dSAkihiko Odaki cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs;
588ee59fa1dSAkihiko Odaki }
589ecd6f6a8SAkihiko Odaki }
590ee59fa1dSAkihiko Odaki
gdb_register_coprocessor(CPUState * cpu,gdb_get_reg_cb get_reg,gdb_set_reg_cb set_reg,const GDBFeature * feature,int g_pos)591842b42dfSAlex Bennée void gdb_register_coprocessor(CPUState *cpu,
592842b42dfSAlex Bennée gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
593ac1e8671SAkihiko Odaki const GDBFeature *feature, int g_pos)
594842b42dfSAlex Bennée {
595842b42dfSAlex Bennée GDBRegisterState *s;
59673c392c2SAkihiko Odaki guint i;
597ee59fa1dSAkihiko Odaki int base_reg = cpu->gdb_num_regs;
598842b42dfSAlex Bennée
59973c392c2SAkihiko Odaki for (i = 0; i < cpu->gdb_regs->len; i++) {
600842b42dfSAlex Bennée /* Check for duplicates. */
60173c392c2SAkihiko Odaki s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
602c494f8f5SAkihiko Odaki if (s->feature == feature) {
603842b42dfSAlex Bennée return;
60473c392c2SAkihiko Odaki }
60573c392c2SAkihiko Odaki }
606842b42dfSAlex Bennée
607ee59fa1dSAkihiko Odaki gdb_register_feature(cpu, base_reg, get_reg, set_reg, feature);
608842b42dfSAlex Bennée
609842b42dfSAlex Bennée /* Add to end of list. */
610ac1e8671SAkihiko Odaki cpu->gdb_num_regs += feature->num_regs;
611842b42dfSAlex Bennée if (g_pos) {
612ee59fa1dSAkihiko Odaki if (g_pos != base_reg) {
613842b42dfSAlex Bennée error_report("Error: Bad gdb register numbering for '%s', "
614ee59fa1dSAkihiko Odaki "expected %d got %d", feature->xml, g_pos, base_reg);
615842b42dfSAlex Bennée } else {
616842b42dfSAlex Bennée cpu->gdb_num_g_regs = cpu->gdb_num_regs;
617842b42dfSAlex Bennée }
618842b42dfSAlex Bennée }
619842b42dfSAlex Bennée }
620842b42dfSAlex Bennée
gdb_unregister_coprocessor_all(CPUState * cpu)621242da180SSalil Mehta void gdb_unregister_coprocessor_all(CPUState *cpu)
622242da180SSalil Mehta {
623242da180SSalil Mehta /*
624242da180SSalil Mehta * Safe to nuke everything. GDBRegisterState::xml is static const char so
625242da180SSalil Mehta * it won't be freed
626242da180SSalil Mehta */
627242da180SSalil Mehta g_array_free(cpu->gdb_regs, true);
628242da180SSalil Mehta
629242da180SSalil Mehta cpu->gdb_regs = NULL;
630242da180SSalil Mehta cpu->gdb_num_regs = 0;
631242da180SSalil Mehta cpu->gdb_num_g_regs = 0;
632242da180SSalil Mehta }
633242da180SSalil Mehta
gdb_process_breakpoint_remove_all(GDBProcess * p)634842b42dfSAlex Bennée static void gdb_process_breakpoint_remove_all(GDBProcess *p)
635842b42dfSAlex Bennée {
636a3fcc111SIlya Leoshkevich CPUState *cpu = gdb_get_first_cpu_in_process(p);
637842b42dfSAlex Bennée
638842b42dfSAlex Bennée while (cpu) {
639ae7467b1SAlex Bennée gdb_breakpoint_remove_all(cpu);
640842b42dfSAlex Bennée cpu = gdb_next_cpu_in_process(cpu);
641842b42dfSAlex Bennée }
642842b42dfSAlex Bennée }
643842b42dfSAlex Bennée
644842b42dfSAlex Bennée
gdb_set_cpu_pc(vaddr pc)645b428ad12SAlex Bennée static void gdb_set_cpu_pc(vaddr pc)
646842b42dfSAlex Bennée {
647842b42dfSAlex Bennée CPUState *cpu = gdbserver_state.c_cpu;
648842b42dfSAlex Bennée
649842b42dfSAlex Bennée cpu_synchronize_state(cpu);
650842b42dfSAlex Bennée cpu_set_pc(cpu, pc);
651842b42dfSAlex Bennée }
652842b42dfSAlex Bennée
gdb_append_thread_id(CPUState * cpu,GString * buf)65336e067b2SAlex Bennée void gdb_append_thread_id(CPUState *cpu, GString *buf)
654842b42dfSAlex Bennée {
655842b42dfSAlex Bennée if (gdbserver_state.multiprocess) {
656842b42dfSAlex Bennée g_string_append_printf(buf, "p%02x.%02x",
65736e067b2SAlex Bennée gdb_get_cpu_pid(cpu), gdb_get_cpu_index(cpu));
658842b42dfSAlex Bennée } else {
65936e067b2SAlex Bennée g_string_append_printf(buf, "%02x", gdb_get_cpu_index(cpu));
660842b42dfSAlex Bennée }
661842b42dfSAlex Bennée }
662842b42dfSAlex Bennée
read_thread_id(const char * buf,const char ** end_buf,uint32_t * pid,uint32_t * tid)663842b42dfSAlex Bennée static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf,
664842b42dfSAlex Bennée uint32_t *pid, uint32_t *tid)
665842b42dfSAlex Bennée {
666842b42dfSAlex Bennée unsigned long p, t;
667842b42dfSAlex Bennée int ret;
668842b42dfSAlex Bennée
669842b42dfSAlex Bennée if (*buf == 'p') {
670842b42dfSAlex Bennée buf++;
671842b42dfSAlex Bennée ret = qemu_strtoul(buf, &buf, 16, &p);
672842b42dfSAlex Bennée
673842b42dfSAlex Bennée if (ret) {
674842b42dfSAlex Bennée return GDB_READ_THREAD_ERR;
675842b42dfSAlex Bennée }
676842b42dfSAlex Bennée
677842b42dfSAlex Bennée /* Skip '.' */
678842b42dfSAlex Bennée buf++;
679842b42dfSAlex Bennée } else {
6806c78de6eSMatheus Tavares Bernardino p = 0;
681842b42dfSAlex Bennée }
682842b42dfSAlex Bennée
683842b42dfSAlex Bennée ret = qemu_strtoul(buf, &buf, 16, &t);
684842b42dfSAlex Bennée
685842b42dfSAlex Bennée if (ret) {
686842b42dfSAlex Bennée return GDB_READ_THREAD_ERR;
687842b42dfSAlex Bennée }
688842b42dfSAlex Bennée
689842b42dfSAlex Bennée *end_buf = buf;
690842b42dfSAlex Bennée
691842b42dfSAlex Bennée if (p == -1) {
692842b42dfSAlex Bennée return GDB_ALL_PROCESSES;
693842b42dfSAlex Bennée }
694842b42dfSAlex Bennée
695842b42dfSAlex Bennée if (pid) {
696842b42dfSAlex Bennée *pid = p;
697842b42dfSAlex Bennée }
698842b42dfSAlex Bennée
699842b42dfSAlex Bennée if (t == -1) {
700842b42dfSAlex Bennée return GDB_ALL_THREADS;
701842b42dfSAlex Bennée }
702842b42dfSAlex Bennée
703842b42dfSAlex Bennée if (tid) {
704842b42dfSAlex Bennée *tid = t;
705842b42dfSAlex Bennée }
706842b42dfSAlex Bennée
707842b42dfSAlex Bennée return GDB_ONE_THREAD;
708842b42dfSAlex Bennée }
709842b42dfSAlex Bennée
710842b42dfSAlex Bennée /**
711842b42dfSAlex Bennée * gdb_handle_vcont - Parses and handles a vCont packet.
712842b42dfSAlex Bennée * returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is
713842b42dfSAlex Bennée * a format error, 0 on success.
714842b42dfSAlex Bennée */
gdb_handle_vcont(const char * p)715842b42dfSAlex Bennée static int gdb_handle_vcont(const char *p)
716842b42dfSAlex Bennée {
717842b42dfSAlex Bennée int res, signal = 0;
718842b42dfSAlex Bennée char cur_action;
719842b42dfSAlex Bennée unsigned long tmp;
720842b42dfSAlex Bennée uint32_t pid, tid;
721842b42dfSAlex Bennée GDBProcess *process;
722842b42dfSAlex Bennée CPUState *cpu;
723842b42dfSAlex Bennée GDBThreadIdKind kind;
7247ea0c33dSAlex Bennée unsigned int max_cpus = gdb_get_max_cpus();
725842b42dfSAlex Bennée /* uninitialised CPUs stay 0 */
7262261b73cSAlex Bennée g_autofree char *newstates = g_new0(char, max_cpus);
727842b42dfSAlex Bennée
728842b42dfSAlex Bennée /* mark valid CPUs with 1 */
729842b42dfSAlex Bennée CPU_FOREACH(cpu) {
730842b42dfSAlex Bennée newstates[cpu->cpu_index] = 1;
731842b42dfSAlex Bennée }
732842b42dfSAlex Bennée
733842b42dfSAlex Bennée /*
734842b42dfSAlex Bennée * res keeps track of what error we are returning, with -ENOTSUP meaning
735842b42dfSAlex Bennée * that the command is unknown or unsupported, thus returning an empty
736842b42dfSAlex Bennée * packet, while -EINVAL and -ERANGE cause an E22 packet, due to invalid,
737842b42dfSAlex Bennée * or incorrect parameters passed.
738842b42dfSAlex Bennée */
739842b42dfSAlex Bennée res = 0;
740761e3c10SMatheus Branco Borella
741761e3c10SMatheus Branco Borella /*
742761e3c10SMatheus Branco Borella * target_count and last_target keep track of how many CPUs we are going to
743761e3c10SMatheus Branco Borella * step or resume, and a pointer to the state structure of one of them,
744ac2786f0SMichael Tokarev * respectively
745761e3c10SMatheus Branco Borella */
746761e3c10SMatheus Branco Borella int target_count = 0;
747761e3c10SMatheus Branco Borella CPUState *last_target = NULL;
748761e3c10SMatheus Branco Borella
749842b42dfSAlex Bennée while (*p) {
750842b42dfSAlex Bennée if (*p++ != ';') {
7512261b73cSAlex Bennée return -ENOTSUP;
752842b42dfSAlex Bennée }
753842b42dfSAlex Bennée
754842b42dfSAlex Bennée cur_action = *p++;
755842b42dfSAlex Bennée if (cur_action == 'C' || cur_action == 'S') {
756842b42dfSAlex Bennée cur_action = qemu_tolower(cur_action);
757842b42dfSAlex Bennée res = qemu_strtoul(p, &p, 16, &tmp);
758842b42dfSAlex Bennée if (res) {
7592261b73cSAlex Bennée return res;
760842b42dfSAlex Bennée }
761842b42dfSAlex Bennée signal = gdb_signal_to_target(tmp);
762842b42dfSAlex Bennée } else if (cur_action != 'c' && cur_action != 's') {
763842b42dfSAlex Bennée /* unknown/invalid/unsupported command */
7642261b73cSAlex Bennée return -ENOTSUP;
765842b42dfSAlex Bennée }
766842b42dfSAlex Bennée
767842b42dfSAlex Bennée if (*p == '\0' || *p == ';') {
768842b42dfSAlex Bennée /*
769842b42dfSAlex Bennée * No thread specifier, action is on "all threads". The
770842b42dfSAlex Bennée * specification is unclear regarding the process to act on. We
771842b42dfSAlex Bennée * choose all processes.
772842b42dfSAlex Bennée */
773842b42dfSAlex Bennée kind = GDB_ALL_PROCESSES;
774842b42dfSAlex Bennée } else if (*p++ == ':') {
775842b42dfSAlex Bennée kind = read_thread_id(p, &p, &pid, &tid);
776842b42dfSAlex Bennée } else {
7772261b73cSAlex Bennée return -ENOTSUP;
778842b42dfSAlex Bennée }
779842b42dfSAlex Bennée
780842b42dfSAlex Bennée switch (kind) {
781842b42dfSAlex Bennée case GDB_READ_THREAD_ERR:
7822261b73cSAlex Bennée return -EINVAL;
783842b42dfSAlex Bennée
784842b42dfSAlex Bennée case GDB_ALL_PROCESSES:
785842b42dfSAlex Bennée cpu = gdb_first_attached_cpu();
786842b42dfSAlex Bennée while (cpu) {
787842b42dfSAlex Bennée if (newstates[cpu->cpu_index] == 1) {
788842b42dfSAlex Bennée newstates[cpu->cpu_index] = cur_action;
789761e3c10SMatheus Branco Borella
790761e3c10SMatheus Branco Borella target_count++;
791761e3c10SMatheus Branco Borella last_target = cpu;
792842b42dfSAlex Bennée }
793842b42dfSAlex Bennée
794842b42dfSAlex Bennée cpu = gdb_next_attached_cpu(cpu);
795842b42dfSAlex Bennée }
796842b42dfSAlex Bennée break;
797842b42dfSAlex Bennée
798842b42dfSAlex Bennée case GDB_ALL_THREADS:
799842b42dfSAlex Bennée process = gdb_get_process(pid);
800842b42dfSAlex Bennée
801842b42dfSAlex Bennée if (!process->attached) {
8022261b73cSAlex Bennée return -EINVAL;
803842b42dfSAlex Bennée }
804842b42dfSAlex Bennée
805a3fcc111SIlya Leoshkevich cpu = gdb_get_first_cpu_in_process(process);
806842b42dfSAlex Bennée while (cpu) {
807842b42dfSAlex Bennée if (newstates[cpu->cpu_index] == 1) {
808842b42dfSAlex Bennée newstates[cpu->cpu_index] = cur_action;
809761e3c10SMatheus Branco Borella
810761e3c10SMatheus Branco Borella target_count++;
811761e3c10SMatheus Branco Borella last_target = cpu;
812842b42dfSAlex Bennée }
813842b42dfSAlex Bennée
814842b42dfSAlex Bennée cpu = gdb_next_cpu_in_process(cpu);
815842b42dfSAlex Bennée }
816842b42dfSAlex Bennée break;
817842b42dfSAlex Bennée
818842b42dfSAlex Bennée case GDB_ONE_THREAD:
819842b42dfSAlex Bennée cpu = gdb_get_cpu(pid, tid);
820842b42dfSAlex Bennée
821842b42dfSAlex Bennée /* invalid CPU/thread specified */
822842b42dfSAlex Bennée if (!cpu) {
8232261b73cSAlex Bennée return -EINVAL;
824842b42dfSAlex Bennée }
825842b42dfSAlex Bennée
826842b42dfSAlex Bennée /* only use if no previous match occourred */
827842b42dfSAlex Bennée if (newstates[cpu->cpu_index] == 1) {
828842b42dfSAlex Bennée newstates[cpu->cpu_index] = cur_action;
829761e3c10SMatheus Branco Borella
830761e3c10SMatheus Branco Borella target_count++;
831761e3c10SMatheus Branco Borella last_target = cpu;
832842b42dfSAlex Bennée }
833842b42dfSAlex Bennée break;
834842b42dfSAlex Bennée }
835842b42dfSAlex Bennée }
8362261b73cSAlex Bennée
837761e3c10SMatheus Branco Borella /*
838761e3c10SMatheus Branco Borella * if we're about to resume a specific set of CPUs/threads, make it so that
839761e3c10SMatheus Branco Borella * in case execution gets interrupted, we can send GDB a stop reply with a
840761e3c10SMatheus Branco Borella * correct value. it doesn't really matter which CPU we tell GDB the signal
841761e3c10SMatheus Branco Borella * happened in (VM pauses stop all of them anyway), so long as it is one of
842761e3c10SMatheus Branco Borella * the ones we resumed/single stepped here.
843761e3c10SMatheus Branco Borella */
844761e3c10SMatheus Branco Borella if (target_count > 0) {
845761e3c10SMatheus Branco Borella gdbserver_state.c_cpu = last_target;
846761e3c10SMatheus Branco Borella }
847761e3c10SMatheus Branco Borella
848842b42dfSAlex Bennée gdbserver_state.signal = signal;
849842b42dfSAlex Bennée gdb_continue_partial(newstates);
850842b42dfSAlex Bennée return res;
851842b42dfSAlex Bennée }
852842b42dfSAlex Bennée
cmd_next_param(const char * param,const char delimiter)853842b42dfSAlex Bennée static const char *cmd_next_param(const char *param, const char delimiter)
854842b42dfSAlex Bennée {
855842b42dfSAlex Bennée static const char all_delimiters[] = ",;:=";
856842b42dfSAlex Bennée char curr_delimiters[2] = {0};
857842b42dfSAlex Bennée const char *delimiters;
858842b42dfSAlex Bennée
859842b42dfSAlex Bennée if (delimiter == '?') {
860842b42dfSAlex Bennée delimiters = all_delimiters;
861842b42dfSAlex Bennée } else if (delimiter == '0') {
862842b42dfSAlex Bennée return strchr(param, '\0');
863842b42dfSAlex Bennée } else if (delimiter == '.' && *param) {
864842b42dfSAlex Bennée return param + 1;
865842b42dfSAlex Bennée } else {
866842b42dfSAlex Bennée curr_delimiters[0] = delimiter;
867842b42dfSAlex Bennée delimiters = curr_delimiters;
868842b42dfSAlex Bennée }
869842b42dfSAlex Bennée
870842b42dfSAlex Bennée param += strcspn(param, delimiters);
871842b42dfSAlex Bennée if (*param) {
872842b42dfSAlex Bennée param++;
873842b42dfSAlex Bennée }
874842b42dfSAlex Bennée return param;
875842b42dfSAlex Bennée }
876842b42dfSAlex Bennée
cmd_parse_params(const char * data,const char * schema,GArray * params)877842b42dfSAlex Bennée static int cmd_parse_params(const char *data, const char *schema,
878842b42dfSAlex Bennée GArray *params)
879842b42dfSAlex Bennée {
880842b42dfSAlex Bennée const char *curr_schema, *curr_data;
881842b42dfSAlex Bennée
882842b42dfSAlex Bennée g_assert(schema);
883842b42dfSAlex Bennée g_assert(params->len == 0);
884842b42dfSAlex Bennée
885842b42dfSAlex Bennée curr_schema = schema;
886842b42dfSAlex Bennée curr_data = data;
887842b42dfSAlex Bennée while (curr_schema[0] && curr_schema[1] && *curr_data) {
888842b42dfSAlex Bennée GdbCmdVariant this_param;
889842b42dfSAlex Bennée
890842b42dfSAlex Bennée switch (curr_schema[0]) {
891842b42dfSAlex Bennée case 'l':
892842b42dfSAlex Bennée if (qemu_strtoul(curr_data, &curr_data, 16,
893842b42dfSAlex Bennée &this_param.val_ul)) {
894842b42dfSAlex Bennée return -EINVAL;
895842b42dfSAlex Bennée }
896842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]);
897842b42dfSAlex Bennée g_array_append_val(params, this_param);
898842b42dfSAlex Bennée break;
899842b42dfSAlex Bennée case 'L':
900842b42dfSAlex Bennée if (qemu_strtou64(curr_data, &curr_data, 16,
901842b42dfSAlex Bennée (uint64_t *)&this_param.val_ull)) {
902842b42dfSAlex Bennée return -EINVAL;
903842b42dfSAlex Bennée }
904842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]);
905842b42dfSAlex Bennée g_array_append_val(params, this_param);
906842b42dfSAlex Bennée break;
907842b42dfSAlex Bennée case 's':
908842b42dfSAlex Bennée this_param.data = curr_data;
909842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]);
910842b42dfSAlex Bennée g_array_append_val(params, this_param);
911842b42dfSAlex Bennée break;
912842b42dfSAlex Bennée case 'o':
913842b42dfSAlex Bennée this_param.opcode = *(uint8_t *)curr_data;
914842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]);
915842b42dfSAlex Bennée g_array_append_val(params, this_param);
916842b42dfSAlex Bennée break;
917842b42dfSAlex Bennée case 't':
918842b42dfSAlex Bennée this_param.thread_id.kind =
919842b42dfSAlex Bennée read_thread_id(curr_data, &curr_data,
920842b42dfSAlex Bennée &this_param.thread_id.pid,
921842b42dfSAlex Bennée &this_param.thread_id.tid);
922842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]);
923842b42dfSAlex Bennée g_array_append_val(params, this_param);
924842b42dfSAlex Bennée break;
925842b42dfSAlex Bennée case '?':
926842b42dfSAlex Bennée curr_data = cmd_next_param(curr_data, curr_schema[1]);
927842b42dfSAlex Bennée break;
928842b42dfSAlex Bennée default:
929842b42dfSAlex Bennée return -EINVAL;
930842b42dfSAlex Bennée }
931842b42dfSAlex Bennée curr_schema += 2;
932842b42dfSAlex Bennée }
933842b42dfSAlex Bennée
934842b42dfSAlex Bennée return 0;
935842b42dfSAlex Bennée }
936842b42dfSAlex Bennée
startswith(const char * string,const char * pattern)937842b42dfSAlex Bennée static inline int startswith(const char *string, const char *pattern)
938842b42dfSAlex Bennée {
939842b42dfSAlex Bennée return !strncmp(string, pattern, strlen(pattern));
940842b42dfSAlex Bennée }
941842b42dfSAlex Bennée
process_string_cmd(const char * data,const GdbCmdParseEntry * cmds,int num_cmds)9420ef6b12eSGustavo Romero static bool process_string_cmd(const char *data,
943842b42dfSAlex Bennée const GdbCmdParseEntry *cmds, int num_cmds)
944842b42dfSAlex Bennée {
945842b42dfSAlex Bennée int i;
946842b42dfSAlex Bennée g_autoptr(GArray) params = g_array_new(false, true, sizeof(GdbCmdVariant));
947842b42dfSAlex Bennée
948842b42dfSAlex Bennée if (!cmds) {
9490ef6b12eSGustavo Romero return false;
950842b42dfSAlex Bennée }
951842b42dfSAlex Bennée
952842b42dfSAlex Bennée for (i = 0; i < num_cmds; i++) {
953842b42dfSAlex Bennée const GdbCmdParseEntry *cmd = &cmds[i];
9542be4d5dbSGustavo Romero void *user_ctx = NULL;
955842b42dfSAlex Bennée g_assert(cmd->handler && cmd->cmd);
956842b42dfSAlex Bennée
957842b42dfSAlex Bennée if ((cmd->cmd_startswith && !startswith(data, cmd->cmd)) ||
958842b42dfSAlex Bennée (!cmd->cmd_startswith && strcmp(cmd->cmd, data))) {
959842b42dfSAlex Bennée continue;
960842b42dfSAlex Bennée }
961842b42dfSAlex Bennée
962842b42dfSAlex Bennée if (cmd->schema) {
963842b42dfSAlex Bennée if (cmd_parse_params(&data[strlen(cmd->cmd)],
964842b42dfSAlex Bennée cmd->schema, params)) {
9650ef6b12eSGustavo Romero return false;
966842b42dfSAlex Bennée }
967842b42dfSAlex Bennée }
968842b42dfSAlex Bennée
9692be4d5dbSGustavo Romero if (cmd->need_cpu_context) {
9702be4d5dbSGustavo Romero user_ctx = (void *)gdbserver_state.g_cpu;
9712be4d5dbSGustavo Romero }
9722be4d5dbSGustavo Romero
97375837005SMatheus Tavares Bernardino gdbserver_state.allow_stop_reply = cmd->allow_stop_reply;
9742be4d5dbSGustavo Romero cmd->handler(params, user_ctx);
9750ef6b12eSGustavo Romero return true;
976842b42dfSAlex Bennée }
977842b42dfSAlex Bennée
9780ef6b12eSGustavo Romero return false;
979842b42dfSAlex Bennée }
980842b42dfSAlex Bennée
run_cmd_parser(const char * data,const GdbCmdParseEntry * cmd)981842b42dfSAlex Bennée static void run_cmd_parser(const char *data, const GdbCmdParseEntry *cmd)
982842b42dfSAlex Bennée {
983842b42dfSAlex Bennée if (!data) {
984842b42dfSAlex Bennée return;
985842b42dfSAlex Bennée }
986842b42dfSAlex Bennée
987842b42dfSAlex Bennée g_string_set_size(gdbserver_state.str_buf, 0);
988842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.mem_buf, 0);
989842b42dfSAlex Bennée
990842b42dfSAlex Bennée /* In case there was an error during the command parsing we must
991842b42dfSAlex Bennée * send a NULL packet to indicate the command is not supported */
9920ef6b12eSGustavo Romero if (!process_string_cmd(data, cmd, 1)) {
99336e067b2SAlex Bennée gdb_put_packet("");
994842b42dfSAlex Bennée }
995842b42dfSAlex Bennée }
996842b42dfSAlex Bennée
handle_detach(GArray * params,void * user_ctx)997842b42dfSAlex Bennée static void handle_detach(GArray *params, void *user_ctx)
998842b42dfSAlex Bennée {
999842b42dfSAlex Bennée GDBProcess *process;
1000842b42dfSAlex Bennée uint32_t pid = 1;
1001842b42dfSAlex Bennée
1002842b42dfSAlex Bennée if (gdbserver_state.multiprocess) {
1003842b42dfSAlex Bennée if (!params->len) {
100436e067b2SAlex Bennée gdb_put_packet("E22");
1005842b42dfSAlex Bennée return;
1006842b42dfSAlex Bennée }
1007842b42dfSAlex Bennée
1008133f202bSGustavo Romero pid = gdb_get_cmd_param(params, 0)->val_ul;
1009842b42dfSAlex Bennée }
1010842b42dfSAlex Bennée
1011539cb4ecSIlya Leoshkevich #ifdef CONFIG_USER_ONLY
1012539cb4ecSIlya Leoshkevich if (gdb_handle_detach_user(pid)) {
1013539cb4ecSIlya Leoshkevich return;
1014539cb4ecSIlya Leoshkevich }
1015539cb4ecSIlya Leoshkevich #endif
1016539cb4ecSIlya Leoshkevich
1017842b42dfSAlex Bennée process = gdb_get_process(pid);
1018842b42dfSAlex Bennée gdb_process_breakpoint_remove_all(process);
1019842b42dfSAlex Bennée process->attached = false;
1020842b42dfSAlex Bennée
1021842b42dfSAlex Bennée if (pid == gdb_get_cpu_pid(gdbserver_state.c_cpu)) {
1022842b42dfSAlex Bennée gdbserver_state.c_cpu = gdb_first_attached_cpu();
1023842b42dfSAlex Bennée }
1024842b42dfSAlex Bennée
1025842b42dfSAlex Bennée if (pid == gdb_get_cpu_pid(gdbserver_state.g_cpu)) {
1026842b42dfSAlex Bennée gdbserver_state.g_cpu = gdb_first_attached_cpu();
1027842b42dfSAlex Bennée }
1028842b42dfSAlex Bennée
1029842b42dfSAlex Bennée if (!gdbserver_state.c_cpu) {
1030842b42dfSAlex Bennée /* No more process attached */
1031c566080cSAlex Bennée gdb_disable_syscalls();
1032842b42dfSAlex Bennée gdb_continue();
1033842b42dfSAlex Bennée }
103436e067b2SAlex Bennée gdb_put_packet("OK");
1035842b42dfSAlex Bennée }
1036842b42dfSAlex Bennée
handle_thread_alive(GArray * params,void * user_ctx)1037842b42dfSAlex Bennée static void handle_thread_alive(GArray *params, void *user_ctx)
1038842b42dfSAlex Bennée {
1039842b42dfSAlex Bennée CPUState *cpu;
1040842b42dfSAlex Bennée
1041842b42dfSAlex Bennée if (!params->len) {
104236e067b2SAlex Bennée gdb_put_packet("E22");
1043842b42dfSAlex Bennée return;
1044842b42dfSAlex Bennée }
1045842b42dfSAlex Bennée
1046133f202bSGustavo Romero if (gdb_get_cmd_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) {
104736e067b2SAlex Bennée gdb_put_packet("E22");
1048842b42dfSAlex Bennée return;
1049842b42dfSAlex Bennée }
1050842b42dfSAlex Bennée
1051133f202bSGustavo Romero cpu = gdb_get_cpu(gdb_get_cmd_param(params, 0)->thread_id.pid,
1052133f202bSGustavo Romero gdb_get_cmd_param(params, 0)->thread_id.tid);
1053842b42dfSAlex Bennée if (!cpu) {
105436e067b2SAlex Bennée gdb_put_packet("E22");
1055842b42dfSAlex Bennée return;
1056842b42dfSAlex Bennée }
1057842b42dfSAlex Bennée
105836e067b2SAlex Bennée gdb_put_packet("OK");
1059842b42dfSAlex Bennée }
1060842b42dfSAlex Bennée
handle_continue(GArray * params,void * user_ctx)1061842b42dfSAlex Bennée static void handle_continue(GArray *params, void *user_ctx)
1062842b42dfSAlex Bennée {
1063842b42dfSAlex Bennée if (params->len) {
1064133f202bSGustavo Romero gdb_set_cpu_pc(gdb_get_cmd_param(params, 0)->val_ull);
1065842b42dfSAlex Bennée }
1066842b42dfSAlex Bennée
1067842b42dfSAlex Bennée gdbserver_state.signal = 0;
1068842b42dfSAlex Bennée gdb_continue();
1069842b42dfSAlex Bennée }
1070842b42dfSAlex Bennée
handle_cont_with_sig(GArray * params,void * user_ctx)1071842b42dfSAlex Bennée static void handle_cont_with_sig(GArray *params, void *user_ctx)
1072842b42dfSAlex Bennée {
1073842b42dfSAlex Bennée unsigned long signal = 0;
1074842b42dfSAlex Bennée
1075842b42dfSAlex Bennée /*
1076842b42dfSAlex Bennée * Note: C sig;[addr] is currently unsupported and we simply
1077842b42dfSAlex Bennée * omit the addr parameter
1078842b42dfSAlex Bennée */
1079842b42dfSAlex Bennée if (params->len) {
1080133f202bSGustavo Romero signal = gdb_get_cmd_param(params, 0)->val_ul;
1081842b42dfSAlex Bennée }
1082842b42dfSAlex Bennée
1083842b42dfSAlex Bennée gdbserver_state.signal = gdb_signal_to_target(signal);
1084842b42dfSAlex Bennée if (gdbserver_state.signal == -1) {
1085842b42dfSAlex Bennée gdbserver_state.signal = 0;
1086842b42dfSAlex Bennée }
1087842b42dfSAlex Bennée gdb_continue();
1088842b42dfSAlex Bennée }
1089842b42dfSAlex Bennée
handle_set_thread(GArray * params,void * user_ctx)1090842b42dfSAlex Bennée static void handle_set_thread(GArray *params, void *user_ctx)
1091842b42dfSAlex Bennée {
1092e454f2feSIlya Leoshkevich uint32_t pid, tid;
1093842b42dfSAlex Bennée CPUState *cpu;
1094842b42dfSAlex Bennée
1095842b42dfSAlex Bennée if (params->len != 2) {
109636e067b2SAlex Bennée gdb_put_packet("E22");
1097842b42dfSAlex Bennée return;
1098842b42dfSAlex Bennée }
1099842b42dfSAlex Bennée
1100133f202bSGustavo Romero if (gdb_get_cmd_param(params, 1)->thread_id.kind == GDB_READ_THREAD_ERR) {
110136e067b2SAlex Bennée gdb_put_packet("E22");
1102842b42dfSAlex Bennée return;
1103842b42dfSAlex Bennée }
1104842b42dfSAlex Bennée
1105133f202bSGustavo Romero if (gdb_get_cmd_param(params, 1)->thread_id.kind != GDB_ONE_THREAD) {
110636e067b2SAlex Bennée gdb_put_packet("OK");
1107842b42dfSAlex Bennée return;
1108842b42dfSAlex Bennée }
1109842b42dfSAlex Bennée
1110133f202bSGustavo Romero pid = gdb_get_cmd_param(params, 1)->thread_id.pid;
1111133f202bSGustavo Romero tid = gdb_get_cmd_param(params, 1)->thread_id.tid;
1112e454f2feSIlya Leoshkevich #ifdef CONFIG_USER_ONLY
1113e454f2feSIlya Leoshkevich if (gdb_handle_set_thread_user(pid, tid)) {
1114e454f2feSIlya Leoshkevich return;
1115e454f2feSIlya Leoshkevich }
1116e454f2feSIlya Leoshkevich #endif
1117e454f2feSIlya Leoshkevich cpu = gdb_get_cpu(pid, tid);
1118842b42dfSAlex Bennée if (!cpu) {
111936e067b2SAlex Bennée gdb_put_packet("E22");
1120842b42dfSAlex Bennée return;
1121842b42dfSAlex Bennée }
1122842b42dfSAlex Bennée
1123842b42dfSAlex Bennée /*
1124842b42dfSAlex Bennée * Note: This command is deprecated and modern gdb's will be using the
1125842b42dfSAlex Bennée * vCont command instead.
1126842b42dfSAlex Bennée */
1127133f202bSGustavo Romero switch (gdb_get_cmd_param(params, 0)->opcode) {
1128842b42dfSAlex Bennée case 'c':
1129842b42dfSAlex Bennée gdbserver_state.c_cpu = cpu;
113036e067b2SAlex Bennée gdb_put_packet("OK");
1131842b42dfSAlex Bennée break;
1132842b42dfSAlex Bennée case 'g':
1133842b42dfSAlex Bennée gdbserver_state.g_cpu = cpu;
113436e067b2SAlex Bennée gdb_put_packet("OK");
1135842b42dfSAlex Bennée break;
1136842b42dfSAlex Bennée default:
113736e067b2SAlex Bennée gdb_put_packet("E22");
1138842b42dfSAlex Bennée break;
1139842b42dfSAlex Bennée }
1140842b42dfSAlex Bennée }
1141842b42dfSAlex Bennée
handle_insert_bp(GArray * params,void * user_ctx)1142842b42dfSAlex Bennée static void handle_insert_bp(GArray *params, void *user_ctx)
1143842b42dfSAlex Bennée {
1144842b42dfSAlex Bennée int res;
1145842b42dfSAlex Bennée
1146842b42dfSAlex Bennée if (params->len != 3) {
114736e067b2SAlex Bennée gdb_put_packet("E22");
1148842b42dfSAlex Bennée return;
1149842b42dfSAlex Bennée }
1150842b42dfSAlex Bennée
1151ae7467b1SAlex Bennée res = gdb_breakpoint_insert(gdbserver_state.c_cpu,
1152133f202bSGustavo Romero gdb_get_cmd_param(params, 0)->val_ul,
1153133f202bSGustavo Romero gdb_get_cmd_param(params, 1)->val_ull,
1154133f202bSGustavo Romero gdb_get_cmd_param(params, 2)->val_ull);
1155842b42dfSAlex Bennée if (res >= 0) {
115636e067b2SAlex Bennée gdb_put_packet("OK");
1157842b42dfSAlex Bennée return;
1158842b42dfSAlex Bennée } else if (res == -ENOSYS) {
115936e067b2SAlex Bennée gdb_put_packet("");
1160842b42dfSAlex Bennée return;
1161842b42dfSAlex Bennée }
1162842b42dfSAlex Bennée
116336e067b2SAlex Bennée gdb_put_packet("E22");
1164842b42dfSAlex Bennée }
1165842b42dfSAlex Bennée
handle_remove_bp(GArray * params,void * user_ctx)1166842b42dfSAlex Bennée static void handle_remove_bp(GArray *params, void *user_ctx)
1167842b42dfSAlex Bennée {
1168842b42dfSAlex Bennée int res;
1169842b42dfSAlex Bennée
1170842b42dfSAlex Bennée if (params->len != 3) {
117136e067b2SAlex Bennée gdb_put_packet("E22");
1172842b42dfSAlex Bennée return;
1173842b42dfSAlex Bennée }
1174842b42dfSAlex Bennée
1175ae7467b1SAlex Bennée res = gdb_breakpoint_remove(gdbserver_state.c_cpu,
1176133f202bSGustavo Romero gdb_get_cmd_param(params, 0)->val_ul,
1177133f202bSGustavo Romero gdb_get_cmd_param(params, 1)->val_ull,
1178133f202bSGustavo Romero gdb_get_cmd_param(params, 2)->val_ull);
1179842b42dfSAlex Bennée if (res >= 0) {
118036e067b2SAlex Bennée gdb_put_packet("OK");
1181842b42dfSAlex Bennée return;
1182842b42dfSAlex Bennée } else if (res == -ENOSYS) {
118336e067b2SAlex Bennée gdb_put_packet("");
1184842b42dfSAlex Bennée return;
1185842b42dfSAlex Bennée }
1186842b42dfSAlex Bennée
118736e067b2SAlex Bennée gdb_put_packet("E22");
1188842b42dfSAlex Bennée }
1189842b42dfSAlex Bennée
1190842b42dfSAlex Bennée /*
1191842b42dfSAlex Bennée * handle_set/get_reg
1192842b42dfSAlex Bennée *
1193842b42dfSAlex Bennée * Older gdb are really dumb, and don't use 'G/g' if 'P/p' is available.
1194842b42dfSAlex Bennée * This works, but can be very slow. Anything new enough to understand
1195842b42dfSAlex Bennée * XML also knows how to use this properly. However to use this we
1196842b42dfSAlex Bennée * need to define a local XML file as well as be talking to a
1197842b42dfSAlex Bennée * reasonably modern gdb. Responding with an empty packet will cause
1198842b42dfSAlex Bennée * the remote gdb to fallback to older methods.
1199842b42dfSAlex Bennée */
1200842b42dfSAlex Bennée
handle_set_reg(GArray * params,void * user_ctx)1201842b42dfSAlex Bennée static void handle_set_reg(GArray *params, void *user_ctx)
1202842b42dfSAlex Bennée {
1203842b42dfSAlex Bennée int reg_size;
1204842b42dfSAlex Bennée
1205842b42dfSAlex Bennée if (params->len != 2) {
120636e067b2SAlex Bennée gdb_put_packet("E22");
1207842b42dfSAlex Bennée return;
1208842b42dfSAlex Bennée }
1209842b42dfSAlex Bennée
1210133f202bSGustavo Romero reg_size = strlen(gdb_get_cmd_param(params, 1)->data) / 2;
1211133f202bSGustavo Romero gdb_hextomem(gdbserver_state.mem_buf, gdb_get_cmd_param(params, 1)->data, reg_size);
1212842b42dfSAlex Bennée gdb_write_register(gdbserver_state.g_cpu, gdbserver_state.mem_buf->data,
1213133f202bSGustavo Romero gdb_get_cmd_param(params, 0)->val_ull);
121436e067b2SAlex Bennée gdb_put_packet("OK");
1215842b42dfSAlex Bennée }
1216842b42dfSAlex Bennée
handle_get_reg(GArray * params,void * user_ctx)1217842b42dfSAlex Bennée static void handle_get_reg(GArray *params, void *user_ctx)
1218842b42dfSAlex Bennée {
1219842b42dfSAlex Bennée int reg_size;
1220842b42dfSAlex Bennée
1221842b42dfSAlex Bennée if (!params->len) {
122236e067b2SAlex Bennée gdb_put_packet("E14");
1223842b42dfSAlex Bennée return;
1224842b42dfSAlex Bennée }
1225842b42dfSAlex Bennée
1226842b42dfSAlex Bennée reg_size = gdb_read_register(gdbserver_state.g_cpu,
1227842b42dfSAlex Bennée gdbserver_state.mem_buf,
1228133f202bSGustavo Romero gdb_get_cmd_param(params, 0)->val_ull);
1229842b42dfSAlex Bennée if (!reg_size) {
123036e067b2SAlex Bennée gdb_put_packet("E14");
1231842b42dfSAlex Bennée return;
1232842b42dfSAlex Bennée } else {
1233842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.mem_buf, reg_size);
1234842b42dfSAlex Bennée }
1235842b42dfSAlex Bennée
123636e067b2SAlex Bennée gdb_memtohex(gdbserver_state.str_buf,
123736e067b2SAlex Bennée gdbserver_state.mem_buf->data, reg_size);
123836e067b2SAlex Bennée gdb_put_strbuf();
1239842b42dfSAlex Bennée }
1240842b42dfSAlex Bennée
handle_write_mem(GArray * params,void * user_ctx)1241842b42dfSAlex Bennée static void handle_write_mem(GArray *params, void *user_ctx)
1242842b42dfSAlex Bennée {
1243842b42dfSAlex Bennée if (params->len != 3) {
124436e067b2SAlex Bennée gdb_put_packet("E22");
1245842b42dfSAlex Bennée return;
1246842b42dfSAlex Bennée }
1247842b42dfSAlex Bennée
124836e067b2SAlex Bennée /* gdb_hextomem() reads 2*len bytes */
1249133f202bSGustavo Romero if (gdb_get_cmd_param(params, 1)->val_ull >
1250133f202bSGustavo Romero strlen(gdb_get_cmd_param(params, 2)->data) / 2) {
125136e067b2SAlex Bennée gdb_put_packet("E22");
1252842b42dfSAlex Bennée return;
1253842b42dfSAlex Bennée }
1254842b42dfSAlex Bennée
1255133f202bSGustavo Romero gdb_hextomem(gdbserver_state.mem_buf, gdb_get_cmd_param(params, 2)->data,
1256133f202bSGustavo Romero gdb_get_cmd_param(params, 1)->val_ull);
1257589a5867SAlex Bennée if (gdb_target_memory_rw_debug(gdbserver_state.g_cpu,
1258133f202bSGustavo Romero gdb_get_cmd_param(params, 0)->val_ull,
1259842b42dfSAlex Bennée gdbserver_state.mem_buf->data,
1260842b42dfSAlex Bennée gdbserver_state.mem_buf->len, true)) {
126136e067b2SAlex Bennée gdb_put_packet("E14");
1262842b42dfSAlex Bennée return;
1263842b42dfSAlex Bennée }
1264842b42dfSAlex Bennée
126536e067b2SAlex Bennée gdb_put_packet("OK");
1266842b42dfSAlex Bennée }
1267842b42dfSAlex Bennée
handle_read_mem(GArray * params,void * user_ctx)1268842b42dfSAlex Bennée static void handle_read_mem(GArray *params, void *user_ctx)
1269842b42dfSAlex Bennée {
1270842b42dfSAlex Bennée if (params->len != 2) {
127136e067b2SAlex Bennée gdb_put_packet("E22");
1272842b42dfSAlex Bennée return;
1273842b42dfSAlex Bennée }
1274842b42dfSAlex Bennée
127536e067b2SAlex Bennée /* gdb_memtohex() doubles the required space */
1276133f202bSGustavo Romero if (gdb_get_cmd_param(params, 1)->val_ull > MAX_PACKET_LENGTH / 2) {
127736e067b2SAlex Bennée gdb_put_packet("E22");
1278842b42dfSAlex Bennée return;
1279842b42dfSAlex Bennée }
1280842b42dfSAlex Bennée
1281842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.mem_buf,
1282133f202bSGustavo Romero gdb_get_cmd_param(params, 1)->val_ull);
1283842b42dfSAlex Bennée
1284589a5867SAlex Bennée if (gdb_target_memory_rw_debug(gdbserver_state.g_cpu,
1285133f202bSGustavo Romero gdb_get_cmd_param(params, 0)->val_ull,
1286842b42dfSAlex Bennée gdbserver_state.mem_buf->data,
1287842b42dfSAlex Bennée gdbserver_state.mem_buf->len, false)) {
128836e067b2SAlex Bennée gdb_put_packet("E14");
1289842b42dfSAlex Bennée return;
1290842b42dfSAlex Bennée }
1291842b42dfSAlex Bennée
129236e067b2SAlex Bennée gdb_memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data,
1293842b42dfSAlex Bennée gdbserver_state.mem_buf->len);
129436e067b2SAlex Bennée gdb_put_strbuf();
1295842b42dfSAlex Bennée }
1296842b42dfSAlex Bennée
handle_write_all_regs(GArray * params,void * user_ctx)1297842b42dfSAlex Bennée static void handle_write_all_regs(GArray *params, void *user_ctx)
1298842b42dfSAlex Bennée {
1299379b42e8SAlex Bennée int reg_id;
1300379b42e8SAlex Bennée size_t len;
1301842b42dfSAlex Bennée uint8_t *registers;
1302842b42dfSAlex Bennée int reg_size;
1303842b42dfSAlex Bennée
1304842b42dfSAlex Bennée if (!params->len) {
1305842b42dfSAlex Bennée return;
1306842b42dfSAlex Bennée }
1307842b42dfSAlex Bennée
1308842b42dfSAlex Bennée cpu_synchronize_state(gdbserver_state.g_cpu);
1309133f202bSGustavo Romero len = strlen(gdb_get_cmd_param(params, 0)->data) / 2;
1310133f202bSGustavo Romero gdb_hextomem(gdbserver_state.mem_buf, gdb_get_cmd_param(params, 0)->data, len);
1311842b42dfSAlex Bennée registers = gdbserver_state.mem_buf->data;
1312379b42e8SAlex Bennée for (reg_id = 0;
1313379b42e8SAlex Bennée reg_id < gdbserver_state.g_cpu->gdb_num_g_regs && len > 0;
1314379b42e8SAlex Bennée reg_id++) {
1315379b42e8SAlex Bennée reg_size = gdb_write_register(gdbserver_state.g_cpu, registers, reg_id);
1316842b42dfSAlex Bennée len -= reg_size;
1317842b42dfSAlex Bennée registers += reg_size;
1318842b42dfSAlex Bennée }
131936e067b2SAlex Bennée gdb_put_packet("OK");
1320842b42dfSAlex Bennée }
1321842b42dfSAlex Bennée
handle_read_all_regs(GArray * params,void * user_ctx)1322842b42dfSAlex Bennée static void handle_read_all_regs(GArray *params, void *user_ctx)
1323842b42dfSAlex Bennée {
1324379b42e8SAlex Bennée int reg_id;
1325379b42e8SAlex Bennée size_t len;
1326842b42dfSAlex Bennée
1327842b42dfSAlex Bennée cpu_synchronize_state(gdbserver_state.g_cpu);
1328842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.mem_buf, 0);
1329842b42dfSAlex Bennée len = 0;
1330379b42e8SAlex Bennée for (reg_id = 0; reg_id < gdbserver_state.g_cpu->gdb_num_g_regs; reg_id++) {
1331842b42dfSAlex Bennée len += gdb_read_register(gdbserver_state.g_cpu,
1332842b42dfSAlex Bennée gdbserver_state.mem_buf,
1333379b42e8SAlex Bennée reg_id);
1334842b42dfSAlex Bennée }
1335842b42dfSAlex Bennée g_assert(len == gdbserver_state.mem_buf->len);
1336842b42dfSAlex Bennée
133736e067b2SAlex Bennée gdb_memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, len);
133836e067b2SAlex Bennée gdb_put_strbuf();
1339842b42dfSAlex Bennée }
1340842b42dfSAlex Bennée
1341842b42dfSAlex Bennée
handle_step(GArray * params,void * user_ctx)1342842b42dfSAlex Bennée static void handle_step(GArray *params, void *user_ctx)
1343842b42dfSAlex Bennée {
1344842b42dfSAlex Bennée if (params->len) {
1345133f202bSGustavo Romero gdb_set_cpu_pc(gdb_get_cmd_param(params, 0)->val_ull);
1346842b42dfSAlex Bennée }
1347842b42dfSAlex Bennée
1348842b42dfSAlex Bennée cpu_single_step(gdbserver_state.c_cpu, gdbserver_state.sstep_flags);
1349842b42dfSAlex Bennée gdb_continue();
1350842b42dfSAlex Bennée }
1351842b42dfSAlex Bennée
handle_backward(GArray * params,void * user_ctx)1352842b42dfSAlex Bennée static void handle_backward(GArray *params, void *user_ctx)
1353842b42dfSAlex Bennée {
1354505601d5SAlex Bennée if (!gdb_can_reverse()) {
135536e067b2SAlex Bennée gdb_put_packet("E22");
1356842b42dfSAlex Bennée }
1357842b42dfSAlex Bennée if (params->len == 1) {
1358133f202bSGustavo Romero switch (gdb_get_cmd_param(params, 0)->opcode) {
1359842b42dfSAlex Bennée case 's':
1360842b42dfSAlex Bennée if (replay_reverse_step()) {
1361842b42dfSAlex Bennée gdb_continue();
1362842b42dfSAlex Bennée } else {
136336e067b2SAlex Bennée gdb_put_packet("E14");
1364842b42dfSAlex Bennée }
1365842b42dfSAlex Bennée return;
1366842b42dfSAlex Bennée case 'c':
1367842b42dfSAlex Bennée if (replay_reverse_continue()) {
1368842b42dfSAlex Bennée gdb_continue();
1369842b42dfSAlex Bennée } else {
137036e067b2SAlex Bennée gdb_put_packet("E14");
1371842b42dfSAlex Bennée }
1372842b42dfSAlex Bennée return;
1373842b42dfSAlex Bennée }
1374842b42dfSAlex Bennée }
1375842b42dfSAlex Bennée
1376842b42dfSAlex Bennée /* Default invalid command */
137736e067b2SAlex Bennée gdb_put_packet("");
1378842b42dfSAlex Bennée }
1379842b42dfSAlex Bennée
handle_v_cont_query(GArray * params,void * user_ctx)1380842b42dfSAlex Bennée static void handle_v_cont_query(GArray *params, void *user_ctx)
1381842b42dfSAlex Bennée {
138236e067b2SAlex Bennée gdb_put_packet("vCont;c;C;s;S");
1383842b42dfSAlex Bennée }
1384842b42dfSAlex Bennée
handle_v_cont(GArray * params,void * user_ctx)1385842b42dfSAlex Bennée static void handle_v_cont(GArray *params, void *user_ctx)
1386842b42dfSAlex Bennée {
1387842b42dfSAlex Bennée int res;
1388842b42dfSAlex Bennée
1389842b42dfSAlex Bennée if (!params->len) {
1390842b42dfSAlex Bennée return;
1391842b42dfSAlex Bennée }
1392842b42dfSAlex Bennée
1393133f202bSGustavo Romero res = gdb_handle_vcont(gdb_get_cmd_param(params, 0)->data);
1394842b42dfSAlex Bennée if ((res == -EINVAL) || (res == -ERANGE)) {
139536e067b2SAlex Bennée gdb_put_packet("E22");
1396842b42dfSAlex Bennée } else if (res) {
139736e067b2SAlex Bennée gdb_put_packet("");
1398842b42dfSAlex Bennée }
1399842b42dfSAlex Bennée }
1400842b42dfSAlex Bennée
handle_v_attach(GArray * params,void * user_ctx)1401842b42dfSAlex Bennée static void handle_v_attach(GArray *params, void *user_ctx)
1402842b42dfSAlex Bennée {
1403842b42dfSAlex Bennée GDBProcess *process;
1404842b42dfSAlex Bennée CPUState *cpu;
1405842b42dfSAlex Bennée
1406842b42dfSAlex Bennée g_string_assign(gdbserver_state.str_buf, "E22");
1407842b42dfSAlex Bennée if (!params->len) {
1408842b42dfSAlex Bennée goto cleanup;
1409842b42dfSAlex Bennée }
1410842b42dfSAlex Bennée
1411133f202bSGustavo Romero process = gdb_get_process(gdb_get_cmd_param(params, 0)->val_ul);
1412842b42dfSAlex Bennée if (!process) {
1413842b42dfSAlex Bennée goto cleanup;
1414842b42dfSAlex Bennée }
1415842b42dfSAlex Bennée
1416a3fcc111SIlya Leoshkevich cpu = gdb_get_first_cpu_in_process(process);
1417842b42dfSAlex Bennée if (!cpu) {
1418842b42dfSAlex Bennée goto cleanup;
1419842b42dfSAlex Bennée }
1420842b42dfSAlex Bennée
1421842b42dfSAlex Bennée process->attached = true;
1422842b42dfSAlex Bennée gdbserver_state.g_cpu = cpu;
1423842b42dfSAlex Bennée gdbserver_state.c_cpu = cpu;
1424842b42dfSAlex Bennée
142575837005SMatheus Tavares Bernardino if (gdbserver_state.allow_stop_reply) {
1426842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
1427842b42dfSAlex Bennée gdb_append_thread_id(cpu, gdbserver_state.str_buf);
1428842b42dfSAlex Bennée g_string_append_c(gdbserver_state.str_buf, ';');
142975837005SMatheus Tavares Bernardino gdbserver_state.allow_stop_reply = false;
1430842b42dfSAlex Bennée cleanup:
143136e067b2SAlex Bennée gdb_put_strbuf();
1432842b42dfSAlex Bennée }
143375837005SMatheus Tavares Bernardino }
1434842b42dfSAlex Bennée
handle_v_kill(GArray * params,void * user_ctx)1435842b42dfSAlex Bennée static void handle_v_kill(GArray *params, void *user_ctx)
1436842b42dfSAlex Bennée {
1437842b42dfSAlex Bennée /* Kill the target */
143836e067b2SAlex Bennée gdb_put_packet("OK");
1439842b42dfSAlex Bennée error_report("QEMU: Terminated via GDBstub");
1440842b42dfSAlex Bennée gdb_exit(0);
1441e216256aSClément Chigot gdb_qemu_exit(0);
1442842b42dfSAlex Bennée }
1443842b42dfSAlex Bennée
1444842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_v_commands_table[] = {
1445842b42dfSAlex Bennée /* Order is important if has same prefix */
1446842b42dfSAlex Bennée {
1447842b42dfSAlex Bennée .handler = handle_v_cont_query,
1448842b42dfSAlex Bennée .cmd = "Cont?",
14493b6c27d8SGustavo Romero .cmd_startswith = true
1450842b42dfSAlex Bennée },
1451842b42dfSAlex Bennée {
1452842b42dfSAlex Bennée .handler = handle_v_cont,
1453842b42dfSAlex Bennée .cmd = "Cont",
14543b6c27d8SGustavo Romero .cmd_startswith = true,
145575837005SMatheus Tavares Bernardino .allow_stop_reply = true,
1456842b42dfSAlex Bennée .schema = "s0"
1457842b42dfSAlex Bennée },
1458842b42dfSAlex Bennée {
1459842b42dfSAlex Bennée .handler = handle_v_attach,
1460842b42dfSAlex Bennée .cmd = "Attach;",
14613b6c27d8SGustavo Romero .cmd_startswith = true,
146275837005SMatheus Tavares Bernardino .allow_stop_reply = true,
1463842b42dfSAlex Bennée .schema = "l0"
1464842b42dfSAlex Bennée },
1465842b42dfSAlex Bennée {
1466842b42dfSAlex Bennée .handler = handle_v_kill,
1467842b42dfSAlex Bennée .cmd = "Kill;",
14683b6c27d8SGustavo Romero .cmd_startswith = true
1469842b42dfSAlex Bennée },
1470e282010bSIlya Leoshkevich #ifdef CONFIG_USER_ONLY
1471e282010bSIlya Leoshkevich /*
1472e282010bSIlya Leoshkevich * Host I/O Packets. See [1] for details.
1473e282010bSIlya Leoshkevich * [1] https://sourceware.org/gdb/onlinedocs/gdb/Host-I_002fO-Packets.html
1474e282010bSIlya Leoshkevich */
1475e282010bSIlya Leoshkevich {
1476e282010bSIlya Leoshkevich .handler = gdb_handle_v_file_open,
1477e282010bSIlya Leoshkevich .cmd = "File:open:",
14783b6c27d8SGustavo Romero .cmd_startswith = true,
1479e282010bSIlya Leoshkevich .schema = "s,L,L0"
1480e282010bSIlya Leoshkevich },
1481e282010bSIlya Leoshkevich {
1482e282010bSIlya Leoshkevich .handler = gdb_handle_v_file_close,
1483e282010bSIlya Leoshkevich .cmd = "File:close:",
14843b6c27d8SGustavo Romero .cmd_startswith = true,
1485e282010bSIlya Leoshkevich .schema = "l0"
1486e282010bSIlya Leoshkevich },
1487e282010bSIlya Leoshkevich {
1488e282010bSIlya Leoshkevich .handler = gdb_handle_v_file_pread,
1489e282010bSIlya Leoshkevich .cmd = "File:pread:",
14903b6c27d8SGustavo Romero .cmd_startswith = true,
1491e282010bSIlya Leoshkevich .schema = "l,L,L0"
1492e282010bSIlya Leoshkevich },
1493e282010bSIlya Leoshkevich {
1494e282010bSIlya Leoshkevich .handler = gdb_handle_v_file_readlink,
1495e282010bSIlya Leoshkevich .cmd = "File:readlink:",
14963b6c27d8SGustavo Romero .cmd_startswith = true,
1497e282010bSIlya Leoshkevich .schema = "s0"
1498e282010bSIlya Leoshkevich },
1499e282010bSIlya Leoshkevich #endif
1500842b42dfSAlex Bennée };
1501842b42dfSAlex Bennée
handle_v_commands(GArray * params,void * user_ctx)1502842b42dfSAlex Bennée static void handle_v_commands(GArray *params, void *user_ctx)
1503842b42dfSAlex Bennée {
1504842b42dfSAlex Bennée if (!params->len) {
1505842b42dfSAlex Bennée return;
1506842b42dfSAlex Bennée }
1507842b42dfSAlex Bennée
1508133f202bSGustavo Romero if (!process_string_cmd(gdb_get_cmd_param(params, 0)->data,
1509842b42dfSAlex Bennée gdb_v_commands_table,
1510842b42dfSAlex Bennée ARRAY_SIZE(gdb_v_commands_table))) {
151136e067b2SAlex Bennée gdb_put_packet("");
1512842b42dfSAlex Bennée }
1513842b42dfSAlex Bennée }
1514842b42dfSAlex Bennée
handle_query_qemu_sstepbits(GArray * params,void * user_ctx)1515842b42dfSAlex Bennée static void handle_query_qemu_sstepbits(GArray *params, void *user_ctx)
1516842b42dfSAlex Bennée {
1517842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "ENABLE=%x", SSTEP_ENABLE);
1518842b42dfSAlex Bennée
1519842b42dfSAlex Bennée if (gdbserver_state.supported_sstep_flags & SSTEP_NOIRQ) {
1520842b42dfSAlex Bennée g_string_append_printf(gdbserver_state.str_buf, ",NOIRQ=%x",
1521842b42dfSAlex Bennée SSTEP_NOIRQ);
1522842b42dfSAlex Bennée }
1523842b42dfSAlex Bennée
1524842b42dfSAlex Bennée if (gdbserver_state.supported_sstep_flags & SSTEP_NOTIMER) {
1525842b42dfSAlex Bennée g_string_append_printf(gdbserver_state.str_buf, ",NOTIMER=%x",
1526842b42dfSAlex Bennée SSTEP_NOTIMER);
1527842b42dfSAlex Bennée }
1528842b42dfSAlex Bennée
152936e067b2SAlex Bennée gdb_put_strbuf();
1530842b42dfSAlex Bennée }
1531842b42dfSAlex Bennée
handle_set_qemu_sstep(GArray * params,void * user_ctx)1532842b42dfSAlex Bennée static void handle_set_qemu_sstep(GArray *params, void *user_ctx)
1533842b42dfSAlex Bennée {
1534842b42dfSAlex Bennée int new_sstep_flags;
1535842b42dfSAlex Bennée
1536842b42dfSAlex Bennée if (!params->len) {
1537842b42dfSAlex Bennée return;
1538842b42dfSAlex Bennée }
1539842b42dfSAlex Bennée
1540133f202bSGustavo Romero new_sstep_flags = gdb_get_cmd_param(params, 0)->val_ul;
1541842b42dfSAlex Bennée
1542842b42dfSAlex Bennée if (new_sstep_flags & ~gdbserver_state.supported_sstep_flags) {
154336e067b2SAlex Bennée gdb_put_packet("E22");
1544842b42dfSAlex Bennée return;
1545842b42dfSAlex Bennée }
1546842b42dfSAlex Bennée
1547842b42dfSAlex Bennée gdbserver_state.sstep_flags = new_sstep_flags;
154836e067b2SAlex Bennée gdb_put_packet("OK");
1549842b42dfSAlex Bennée }
1550842b42dfSAlex Bennée
handle_query_qemu_sstep(GArray * params,void * user_ctx)1551842b42dfSAlex Bennée static void handle_query_qemu_sstep(GArray *params, void *user_ctx)
1552842b42dfSAlex Bennée {
1553842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "0x%x",
1554842b42dfSAlex Bennée gdbserver_state.sstep_flags);
155536e067b2SAlex Bennée gdb_put_strbuf();
1556842b42dfSAlex Bennée }
1557842b42dfSAlex Bennée
handle_query_curr_tid(GArray * params,void * user_ctx)1558842b42dfSAlex Bennée static void handle_query_curr_tid(GArray *params, void *user_ctx)
1559842b42dfSAlex Bennée {
1560842b42dfSAlex Bennée CPUState *cpu;
1561842b42dfSAlex Bennée GDBProcess *process;
1562842b42dfSAlex Bennée
1563842b42dfSAlex Bennée /*
1564842b42dfSAlex Bennée * "Current thread" remains vague in the spec, so always return
1565842b42dfSAlex Bennée * the first thread of the current process (gdb returns the
1566842b42dfSAlex Bennée * first thread).
1567842b42dfSAlex Bennée */
1568842b42dfSAlex Bennée process = gdb_get_cpu_process(gdbserver_state.g_cpu);
1569a3fcc111SIlya Leoshkevich cpu = gdb_get_first_cpu_in_process(process);
1570842b42dfSAlex Bennée g_string_assign(gdbserver_state.str_buf, "QC");
1571842b42dfSAlex Bennée gdb_append_thread_id(cpu, gdbserver_state.str_buf);
157236e067b2SAlex Bennée gdb_put_strbuf();
1573842b42dfSAlex Bennée }
1574842b42dfSAlex Bennée
handle_query_threads(GArray * params,void * user_ctx)1575842b42dfSAlex Bennée static void handle_query_threads(GArray *params, void *user_ctx)
1576842b42dfSAlex Bennée {
1577842b42dfSAlex Bennée if (!gdbserver_state.query_cpu) {
157836e067b2SAlex Bennée gdb_put_packet("l");
1579842b42dfSAlex Bennée return;
1580842b42dfSAlex Bennée }
1581842b42dfSAlex Bennée
1582842b42dfSAlex Bennée g_string_assign(gdbserver_state.str_buf, "m");
1583842b42dfSAlex Bennée gdb_append_thread_id(gdbserver_state.query_cpu, gdbserver_state.str_buf);
158436e067b2SAlex Bennée gdb_put_strbuf();
1585842b42dfSAlex Bennée gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu);
1586842b42dfSAlex Bennée }
1587842b42dfSAlex Bennée
handle_query_first_threads(GArray * params,void * user_ctx)1588842b42dfSAlex Bennée static void handle_query_first_threads(GArray *params, void *user_ctx)
1589842b42dfSAlex Bennée {
1590842b42dfSAlex Bennée gdbserver_state.query_cpu = gdb_first_attached_cpu();
1591842b42dfSAlex Bennée handle_query_threads(params, user_ctx);
1592842b42dfSAlex Bennée }
1593842b42dfSAlex Bennée
handle_query_thread_extra(GArray * params,void * user_ctx)1594842b42dfSAlex Bennée static void handle_query_thread_extra(GArray *params, void *user_ctx)
1595842b42dfSAlex Bennée {
1596842b42dfSAlex Bennée g_autoptr(GString) rs = g_string_new(NULL);
1597842b42dfSAlex Bennée CPUState *cpu;
1598842b42dfSAlex Bennée
1599842b42dfSAlex Bennée if (!params->len ||
1600133f202bSGustavo Romero gdb_get_cmd_param(params, 0)->thread_id.kind == GDB_READ_THREAD_ERR) {
160136e067b2SAlex Bennée gdb_put_packet("E22");
1602842b42dfSAlex Bennée return;
1603842b42dfSAlex Bennée }
1604842b42dfSAlex Bennée
1605133f202bSGustavo Romero cpu = gdb_get_cpu(gdb_get_cmd_param(params, 0)->thread_id.pid,
1606133f202bSGustavo Romero gdb_get_cmd_param(params, 0)->thread_id.tid);
1607842b42dfSAlex Bennée if (!cpu) {
1608842b42dfSAlex Bennée return;
1609842b42dfSAlex Bennée }
1610842b42dfSAlex Bennée
1611842b42dfSAlex Bennée cpu_synchronize_state(cpu);
1612842b42dfSAlex Bennée
1613842b42dfSAlex Bennée if (gdbserver_state.multiprocess && (gdbserver_state.process_num > 1)) {
1614842b42dfSAlex Bennée /* Print the CPU model and name in multiprocess mode */
1615842b42dfSAlex Bennée ObjectClass *oc = object_get_class(OBJECT(cpu));
1616842b42dfSAlex Bennée const char *cpu_model = object_class_get_name(oc);
1617842b42dfSAlex Bennée const char *cpu_name =
1618842b42dfSAlex Bennée object_get_canonical_path_component(OBJECT(cpu));
1619842b42dfSAlex Bennée g_string_printf(rs, "%s %s [%s]", cpu_model, cpu_name,
1620842b42dfSAlex Bennée cpu->halted ? "halted " : "running");
1621842b42dfSAlex Bennée } else {
1622842b42dfSAlex Bennée g_string_printf(rs, "CPU#%d [%s]", cpu->cpu_index,
1623842b42dfSAlex Bennée cpu->halted ? "halted " : "running");
1624842b42dfSAlex Bennée }
1625842b42dfSAlex Bennée trace_gdbstub_op_extra_info(rs->str);
162636e067b2SAlex Bennée gdb_memtohex(gdbserver_state.str_buf, (uint8_t *)rs->str, rs->len);
162736e067b2SAlex Bennée gdb_put_strbuf();
1628842b42dfSAlex Bennée }
1629842b42dfSAlex Bennée
163060f4ce8eSGustavo Romero
1631e8122a71SAlex Bennée static char **extra_query_flags;
1632e8122a71SAlex Bennée
gdb_extend_qsupported_features(char * qflags)1633e8122a71SAlex Bennée void gdb_extend_qsupported_features(char *qflags)
1634e8122a71SAlex Bennée {
1635e8122a71SAlex Bennée if (!extra_query_flags) {
1636e8122a71SAlex Bennée extra_query_flags = g_new0(char *, 2);
1637e8122a71SAlex Bennée extra_query_flags[0] = g_strdup(qflags);
1638e8122a71SAlex Bennée } else if (!g_strv_contains((const gchar * const *) extra_query_flags,
1639e8122a71SAlex Bennée qflags)) {
1640e8122a71SAlex Bennée int len = g_strv_length(extra_query_flags);
1641e8122a71SAlex Bennée extra_query_flags = g_realloc_n(extra_query_flags, len + 2,
1642e8122a71SAlex Bennée sizeof(char *));
1643e8122a71SAlex Bennée extra_query_flags[len] = g_strdup(qflags);
1644e8122a71SAlex Bennée }
164560f4ce8eSGustavo Romero }
164660f4ce8eSGustavo Romero
handle_query_supported(GArray * params,void * user_ctx)1647842b42dfSAlex Bennée static void handle_query_supported(GArray *params, void *user_ctx)
1648842b42dfSAlex Bennée {
1649842b42dfSAlex Bennée CPUClass *cc;
1650842b42dfSAlex Bennée
1651842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "PacketSize=%x", MAX_PACKET_LENGTH);
1652842b42dfSAlex Bennée cc = CPU_GET_CLASS(first_cpu);
1653842b42dfSAlex Bennée if (cc->gdb_core_xml_file) {
1654842b42dfSAlex Bennée g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+");
1655842b42dfSAlex Bennée }
1656842b42dfSAlex Bennée
1657505601d5SAlex Bennée if (gdb_can_reverse()) {
1658842b42dfSAlex Bennée g_string_append(gdbserver_state.str_buf,
1659842b42dfSAlex Bennée ";ReverseStep+;ReverseContinue+");
1660842b42dfSAlex Bennée }
1661842b42dfSAlex Bennée
1662e282010bSIlya Leoshkevich #if defined(CONFIG_USER_ONLY)
1663e282010bSIlya Leoshkevich #if defined(CONFIG_LINUX)
166459272469SPhilippe Mathieu-Daudé if (get_task_state(gdbserver_state.c_cpu)) {
1665842b42dfSAlex Bennée g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
1666842b42dfSAlex Bennée }
1667046f143cSIlya Leoshkevich g_string_append(gdbserver_state.str_buf, ";QCatchSyscalls+");
16689ae5801dSGustavo Romero
16699ae5801dSGustavo Romero g_string_append(gdbserver_state.str_buf, ";qXfer:siginfo:read+");
1670842b42dfSAlex Bennée #endif
1671e282010bSIlya Leoshkevich g_string_append(gdbserver_state.str_buf, ";qXfer:exec-file:read+");
1672e282010bSIlya Leoshkevich #endif
1673842b42dfSAlex Bennée
16746d923112SIlya Leoshkevich if (params->len) {
1675133f202bSGustavo Romero const char *gdb_supported = gdb_get_cmd_param(params, 0)->data;
16766d923112SIlya Leoshkevich
16776d923112SIlya Leoshkevich if (strstr(gdb_supported, "multiprocess+")) {
1678842b42dfSAlex Bennée gdbserver_state.multiprocess = true;
1679842b42dfSAlex Bennée }
16806d923112SIlya Leoshkevich #if defined(CONFIG_USER_ONLY)
16816d923112SIlya Leoshkevich gdb_handle_query_supported_user(gdb_supported);
16826d923112SIlya Leoshkevich #endif
16836d923112SIlya Leoshkevich }
1684842b42dfSAlex Bennée
1685842b42dfSAlex Bennée g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
168660f4ce8eSGustavo Romero
1687e8122a71SAlex Bennée if (extra_query_flags) {
1688e8122a71SAlex Bennée int extras = g_strv_length(extra_query_flags);
1689e8122a71SAlex Bennée for (int i = 0; i < extras; i++) {
1690e8122a71SAlex Bennée g_string_append(gdbserver_state.str_buf, extra_query_flags[i]);
1691e8122a71SAlex Bennée }
169260f4ce8eSGustavo Romero }
169360f4ce8eSGustavo Romero
169436e067b2SAlex Bennée gdb_put_strbuf();
1695842b42dfSAlex Bennée }
1696842b42dfSAlex Bennée
handle_query_xfer_features(GArray * params,void * user_ctx)1697842b42dfSAlex Bennée static void handle_query_xfer_features(GArray *params, void *user_ctx)
1698842b42dfSAlex Bennée {
1699842b42dfSAlex Bennée GDBProcess *process;
1700842b42dfSAlex Bennée CPUClass *cc;
1701842b42dfSAlex Bennée unsigned long len, total_len, addr;
1702842b42dfSAlex Bennée const char *xml;
1703842b42dfSAlex Bennée const char *p;
1704842b42dfSAlex Bennée
1705842b42dfSAlex Bennée if (params->len < 3) {
170636e067b2SAlex Bennée gdb_put_packet("E22");
1707842b42dfSAlex Bennée return;
1708842b42dfSAlex Bennée }
1709842b42dfSAlex Bennée
1710842b42dfSAlex Bennée process = gdb_get_cpu_process(gdbserver_state.g_cpu);
1711842b42dfSAlex Bennée cc = CPU_GET_CLASS(gdbserver_state.g_cpu);
1712842b42dfSAlex Bennée if (!cc->gdb_core_xml_file) {
171336e067b2SAlex Bennée gdb_put_packet("");
1714842b42dfSAlex Bennée return;
1715842b42dfSAlex Bennée }
1716842b42dfSAlex Bennée
1717133f202bSGustavo Romero p = gdb_get_cmd_param(params, 0)->data;
1718842b42dfSAlex Bennée xml = get_feature_xml(p, &p, process);
1719842b42dfSAlex Bennée if (!xml) {
172036e067b2SAlex Bennée gdb_put_packet("E00");
1721842b42dfSAlex Bennée return;
1722842b42dfSAlex Bennée }
1723842b42dfSAlex Bennée
1724133f202bSGustavo Romero addr = gdb_get_cmd_param(params, 1)->val_ul;
1725133f202bSGustavo Romero len = gdb_get_cmd_param(params, 2)->val_ul;
1726842b42dfSAlex Bennée total_len = strlen(xml);
1727842b42dfSAlex Bennée if (addr > total_len) {
172836e067b2SAlex Bennée gdb_put_packet("E00");
1729842b42dfSAlex Bennée return;
1730842b42dfSAlex Bennée }
1731842b42dfSAlex Bennée
1732842b42dfSAlex Bennée if (len > (MAX_PACKET_LENGTH - 5) / 2) {
1733842b42dfSAlex Bennée len = (MAX_PACKET_LENGTH - 5) / 2;
1734842b42dfSAlex Bennée }
1735842b42dfSAlex Bennée
1736842b42dfSAlex Bennée if (len < total_len - addr) {
1737842b42dfSAlex Bennée g_string_assign(gdbserver_state.str_buf, "m");
173836e067b2SAlex Bennée gdb_memtox(gdbserver_state.str_buf, xml + addr, len);
1739842b42dfSAlex Bennée } else {
1740842b42dfSAlex Bennée g_string_assign(gdbserver_state.str_buf, "l");
174136e067b2SAlex Bennée gdb_memtox(gdbserver_state.str_buf, xml + addr, total_len - addr);
1742842b42dfSAlex Bennée }
1743842b42dfSAlex Bennée
174436e067b2SAlex Bennée gdb_put_packet_binary(gdbserver_state.str_buf->str,
1745842b42dfSAlex Bennée gdbserver_state.str_buf->len, true);
1746842b42dfSAlex Bennée }
1747842b42dfSAlex Bennée
handle_query_qemu_supported(GArray * params,void * user_ctx)1748842b42dfSAlex Bennée static void handle_query_qemu_supported(GArray *params, void *user_ctx)
1749842b42dfSAlex Bennée {
1750842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "sstepbits;sstep");
1751842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY
1752842b42dfSAlex Bennée g_string_append(gdbserver_state.str_buf, ";PhyMemMode");
1753842b42dfSAlex Bennée #endif
175436e067b2SAlex Bennée gdb_put_strbuf();
1755842b42dfSAlex Bennée }
1756842b42dfSAlex Bennée
1757842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
1758842b42dfSAlex Bennée /* Order is important if has same prefix */
1759842b42dfSAlex Bennée {
1760842b42dfSAlex Bennée .handler = handle_query_qemu_sstepbits,
1761842b42dfSAlex Bennée .cmd = "qemu.sstepbits",
1762842b42dfSAlex Bennée },
1763842b42dfSAlex Bennée {
1764842b42dfSAlex Bennée .handler = handle_query_qemu_sstep,
1765842b42dfSAlex Bennée .cmd = "qemu.sstep",
1766842b42dfSAlex Bennée },
1767842b42dfSAlex Bennée {
1768842b42dfSAlex Bennée .handler = handle_set_qemu_sstep,
1769842b42dfSAlex Bennée .cmd = "qemu.sstep=",
17703b6c27d8SGustavo Romero .cmd_startswith = true,
1771842b42dfSAlex Bennée .schema = "l0"
1772842b42dfSAlex Bennée },
1773842b42dfSAlex Bennée };
1774842b42dfSAlex Bennée
1775e8122a71SAlex Bennée /**
1776e8122a71SAlex Bennée * extend_table() - extend one of the command tables
1777e8122a71SAlex Bennée * @table: the command table to extend (or NULL)
1778e8122a71SAlex Bennée * @extensions: a list of GdbCmdParseEntry pointers
1779e8122a71SAlex Bennée *
1780e8122a71SAlex Bennée * The entries themselves should be pointers to static const
1781e8122a71SAlex Bennée * GdbCmdParseEntry entries. If the entry is already in the table we
1782e8122a71SAlex Bennée * skip adding it again.
1783e8122a71SAlex Bennée *
1784e8122a71SAlex Bennée * Returns (a potentially freshly allocated) GPtrArray of GdbCmdParseEntry
1785e8122a71SAlex Bennée */
extend_table(GPtrArray * table,GPtrArray * extensions)1786e8122a71SAlex Bennée static GPtrArray *extend_table(GPtrArray *table, GPtrArray *extensions)
178760f4ce8eSGustavo Romero {
1788e8122a71SAlex Bennée if (!table) {
1789e8122a71SAlex Bennée table = g_ptr_array_new();
1790e8122a71SAlex Bennée }
179160f4ce8eSGustavo Romero
1792e8122a71SAlex Bennée for (int i = 0; i < extensions->len; i++) {
1793e8122a71SAlex Bennée gpointer entry = g_ptr_array_index(extensions, i);
1794e8122a71SAlex Bennée if (!g_ptr_array_find(table, entry, NULL)) {
1795e8122a71SAlex Bennée g_ptr_array_add(table, entry);
179660f4ce8eSGustavo Romero }
179760f4ce8eSGustavo Romero }
179860f4ce8eSGustavo Romero
1799e8122a71SAlex Bennée return table;
1800e8122a71SAlex Bennée }
1801e8122a71SAlex Bennée
1802e8122a71SAlex Bennée /**
1803e8122a71SAlex Bennée * process_extended_table() - run through an extended command table
1804e8122a71SAlex Bennée * @table: the command table to check
1805e8122a71SAlex Bennée * @data: parameters
1806e8122a71SAlex Bennée *
1807e8122a71SAlex Bennée * returns true if the command was found and executed
1808e8122a71SAlex Bennée */
process_extended_table(GPtrArray * table,const char * data)1809e8122a71SAlex Bennée static bool process_extended_table(GPtrArray *table, const char *data)
1810e8122a71SAlex Bennée {
1811e8122a71SAlex Bennée for (int i = 0; i < table->len; i++) {
1812e8122a71SAlex Bennée const GdbCmdParseEntry *entry = g_ptr_array_index(table, i);
1813e8122a71SAlex Bennée if (process_string_cmd(data, entry, 1)) {
181460f4ce8eSGustavo Romero return true;
181560f4ce8eSGustavo Romero }
1816e8122a71SAlex Bennée }
1817e8122a71SAlex Bennée return false;
1818e8122a71SAlex Bennée }
181960f4ce8eSGustavo Romero
1820e8122a71SAlex Bennée
1821e8122a71SAlex Bennée /* Ptr to GdbCmdParseEntry */
1822e8122a71SAlex Bennée static GPtrArray *extended_query_table;
1823e8122a71SAlex Bennée
gdb_extend_query_table(GPtrArray * new_queries)1824e8122a71SAlex Bennée void gdb_extend_query_table(GPtrArray *new_queries)
182560f4ce8eSGustavo Romero {
1826e8122a71SAlex Bennée extended_query_table = extend_table(extended_query_table, new_queries);
182760f4ce8eSGustavo Romero }
182860f4ce8eSGustavo Romero
1829842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_gen_query_table[] = {
1830842b42dfSAlex Bennée {
1831842b42dfSAlex Bennée .handler = handle_query_curr_tid,
1832842b42dfSAlex Bennée .cmd = "C",
1833842b42dfSAlex Bennée },
1834842b42dfSAlex Bennée {
1835842b42dfSAlex Bennée .handler = handle_query_threads,
1836842b42dfSAlex Bennée .cmd = "sThreadInfo",
1837842b42dfSAlex Bennée },
1838842b42dfSAlex Bennée {
1839842b42dfSAlex Bennée .handler = handle_query_first_threads,
1840842b42dfSAlex Bennée .cmd = "fThreadInfo",
1841842b42dfSAlex Bennée },
1842842b42dfSAlex Bennée {
1843842b42dfSAlex Bennée .handler = handle_query_thread_extra,
1844842b42dfSAlex Bennée .cmd = "ThreadExtraInfo,",
18453b6c27d8SGustavo Romero .cmd_startswith = true,
1846842b42dfSAlex Bennée .schema = "t0"
1847842b42dfSAlex Bennée },
1848842b42dfSAlex Bennée #ifdef CONFIG_USER_ONLY
1849842b42dfSAlex Bennée {
1850d96bf49bSAlex Bennée .handler = gdb_handle_query_offsets,
1851842b42dfSAlex Bennée .cmd = "Offsets",
1852842b42dfSAlex Bennée },
1853842b42dfSAlex Bennée #else
1854842b42dfSAlex Bennée {
1855b6fa2ec2SAlex Bennée .handler = gdb_handle_query_rcmd,
1856842b42dfSAlex Bennée .cmd = "Rcmd,",
18573b6c27d8SGustavo Romero .cmd_startswith = true,
1858842b42dfSAlex Bennée .schema = "s0"
1859842b42dfSAlex Bennée },
1860842b42dfSAlex Bennée #endif
1861842b42dfSAlex Bennée {
1862842b42dfSAlex Bennée .handler = handle_query_supported,
1863842b42dfSAlex Bennée .cmd = "Supported:",
18643b6c27d8SGustavo Romero .cmd_startswith = true,
1865842b42dfSAlex Bennée .schema = "s0"
1866842b42dfSAlex Bennée },
1867842b42dfSAlex Bennée {
1868842b42dfSAlex Bennée .handler = handle_query_supported,
1869842b42dfSAlex Bennée .cmd = "Supported",
1870842b42dfSAlex Bennée .schema = "s0"
1871842b42dfSAlex Bennée },
1872842b42dfSAlex Bennée {
1873842b42dfSAlex Bennée .handler = handle_query_xfer_features,
1874842b42dfSAlex Bennée .cmd = "Xfer:features:read:",
18753b6c27d8SGustavo Romero .cmd_startswith = true,
1876842b42dfSAlex Bennée .schema = "s:l,l0"
1877842b42dfSAlex Bennée },
1878e282010bSIlya Leoshkevich #if defined(CONFIG_USER_ONLY)
1879e282010bSIlya Leoshkevich #if defined(CONFIG_LINUX)
1880842b42dfSAlex Bennée {
1881d96bf49bSAlex Bennée .handler = gdb_handle_query_xfer_auxv,
1882842b42dfSAlex Bennée .cmd = "Xfer:auxv:read::",
18833b6c27d8SGustavo Romero .cmd_startswith = true,
1884842b42dfSAlex Bennée .schema = "l,l0"
1885842b42dfSAlex Bennée },
18869ae5801dSGustavo Romero {
18879ae5801dSGustavo Romero .handler = gdb_handle_query_xfer_siginfo,
18889ae5801dSGustavo Romero .cmd = "Xfer:siginfo:read::",
18893b6c27d8SGustavo Romero .cmd_startswith = true,
18909ae5801dSGustavo Romero .schema = "l,l0"
18919ae5801dSGustavo Romero },
1892842b42dfSAlex Bennée #endif
1893842b42dfSAlex Bennée {
1894e282010bSIlya Leoshkevich .handler = gdb_handle_query_xfer_exec_file,
1895e282010bSIlya Leoshkevich .cmd = "Xfer:exec-file:read:",
18963b6c27d8SGustavo Romero .cmd_startswith = true,
1897e282010bSIlya Leoshkevich .schema = "l:l,l0"
1898e282010bSIlya Leoshkevich },
1899e282010bSIlya Leoshkevich #endif
1900e282010bSIlya Leoshkevich {
19018a2025b3SAlex Bennée .handler = gdb_handle_query_attached,
1902842b42dfSAlex Bennée .cmd = "Attached:",
19033b6c27d8SGustavo Romero .cmd_startswith = true
1904842b42dfSAlex Bennée },
1905842b42dfSAlex Bennée {
19068a2025b3SAlex Bennée .handler = gdb_handle_query_attached,
1907842b42dfSAlex Bennée .cmd = "Attached",
1908842b42dfSAlex Bennée },
1909842b42dfSAlex Bennée {
1910842b42dfSAlex Bennée .handler = handle_query_qemu_supported,
1911842b42dfSAlex Bennée .cmd = "qemu.Supported",
1912842b42dfSAlex Bennée },
1913842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY
1914842b42dfSAlex Bennée {
1915589a5867SAlex Bennée .handler = gdb_handle_query_qemu_phy_mem_mode,
1916842b42dfSAlex Bennée .cmd = "qemu.PhyMemMode",
1917842b42dfSAlex Bennée },
1918842b42dfSAlex Bennée #endif
1919842b42dfSAlex Bennée };
1920842b42dfSAlex Bennée
1921e8122a71SAlex Bennée /* Ptr to GdbCmdParseEntry */
1922e8122a71SAlex Bennée static GPtrArray *extended_set_table;
192360f4ce8eSGustavo Romero
gdb_extend_set_table(GPtrArray * new_set)1924e8122a71SAlex Bennée void gdb_extend_set_table(GPtrArray *new_set)
1925e8122a71SAlex Bennée {
1926e8122a71SAlex Bennée extended_set_table = extend_table(extended_set_table, new_set);
192760f4ce8eSGustavo Romero }
192860f4ce8eSGustavo Romero
1929842b42dfSAlex Bennée static const GdbCmdParseEntry gdb_gen_set_table[] = {
1930842b42dfSAlex Bennée /* Order is important if has same prefix */
1931842b42dfSAlex Bennée {
1932842b42dfSAlex Bennée .handler = handle_set_qemu_sstep,
1933842b42dfSAlex Bennée .cmd = "qemu.sstep:",
19343b6c27d8SGustavo Romero .cmd_startswith = true,
1935842b42dfSAlex Bennée .schema = "l0"
1936842b42dfSAlex Bennée },
1937842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY
1938842b42dfSAlex Bennée {
1939589a5867SAlex Bennée .handler = gdb_handle_set_qemu_phy_mem_mode,
1940842b42dfSAlex Bennée .cmd = "qemu.PhyMemMode:",
19413b6c27d8SGustavo Romero .cmd_startswith = true,
1942842b42dfSAlex Bennée .schema = "l0"
1943842b42dfSAlex Bennée },
1944842b42dfSAlex Bennée #endif
1945046f143cSIlya Leoshkevich #if defined(CONFIG_USER_ONLY)
1946046f143cSIlya Leoshkevich {
1947046f143cSIlya Leoshkevich .handler = gdb_handle_set_catch_syscalls,
1948046f143cSIlya Leoshkevich .cmd = "CatchSyscalls:",
19493b6c27d8SGustavo Romero .cmd_startswith = true,
1950046f143cSIlya Leoshkevich .schema = "s0",
1951046f143cSIlya Leoshkevich },
1952046f143cSIlya Leoshkevich #endif
1953842b42dfSAlex Bennée };
1954842b42dfSAlex Bennée
handle_gen_query(GArray * params,void * user_ctx)1955842b42dfSAlex Bennée static void handle_gen_query(GArray *params, void *user_ctx)
1956842b42dfSAlex Bennée {
1957e8122a71SAlex Bennée const char *data;
1958e8122a71SAlex Bennée
1959842b42dfSAlex Bennée if (!params->len) {
1960842b42dfSAlex Bennée return;
1961842b42dfSAlex Bennée }
1962842b42dfSAlex Bennée
1963e8122a71SAlex Bennée data = gdb_get_cmd_param(params, 0)->data;
1964e8122a71SAlex Bennée
1965e8122a71SAlex Bennée if (process_string_cmd(data,
1966842b42dfSAlex Bennée gdb_gen_query_set_common_table,
1967842b42dfSAlex Bennée ARRAY_SIZE(gdb_gen_query_set_common_table))) {
1968842b42dfSAlex Bennée return;
1969842b42dfSAlex Bennée }
1970842b42dfSAlex Bennée
1971e8122a71SAlex Bennée if (process_string_cmd(data,
1972842b42dfSAlex Bennée gdb_gen_query_table,
1973842b42dfSAlex Bennée ARRAY_SIZE(gdb_gen_query_table))) {
197460f4ce8eSGustavo Romero return;
1975842b42dfSAlex Bennée }
197660f4ce8eSGustavo Romero
197760f4ce8eSGustavo Romero if (extended_query_table &&
1978e8122a71SAlex Bennée process_extended_table(extended_query_table, data)) {
197960f4ce8eSGustavo Romero return;
198060f4ce8eSGustavo Romero }
198160f4ce8eSGustavo Romero
198260f4ce8eSGustavo Romero /* Can't handle query, return Empty response. */
198360f4ce8eSGustavo Romero gdb_put_packet("");
1984842b42dfSAlex Bennée }
1985842b42dfSAlex Bennée
handle_gen_set(GArray * params,void * user_ctx)1986842b42dfSAlex Bennée static void handle_gen_set(GArray *params, void *user_ctx)
1987842b42dfSAlex Bennée {
1988e8122a71SAlex Bennée const char *data;
1989e8122a71SAlex Bennée
1990842b42dfSAlex Bennée if (!params->len) {
1991842b42dfSAlex Bennée return;
1992842b42dfSAlex Bennée }
1993842b42dfSAlex Bennée
1994e8122a71SAlex Bennée data = gdb_get_cmd_param(params, 0)->data;
1995e8122a71SAlex Bennée
1996e8122a71SAlex Bennée if (process_string_cmd(data,
1997842b42dfSAlex Bennée gdb_gen_query_set_common_table,
1998842b42dfSAlex Bennée ARRAY_SIZE(gdb_gen_query_set_common_table))) {
1999842b42dfSAlex Bennée return;
2000842b42dfSAlex Bennée }
2001842b42dfSAlex Bennée
2002e8122a71SAlex Bennée if (process_string_cmd(data,
2003842b42dfSAlex Bennée gdb_gen_set_table,
2004842b42dfSAlex Bennée ARRAY_SIZE(gdb_gen_set_table))) {
200560f4ce8eSGustavo Romero return;
2006842b42dfSAlex Bennée }
200760f4ce8eSGustavo Romero
200860f4ce8eSGustavo Romero if (extended_set_table &&
2009e8122a71SAlex Bennée process_extended_table(extended_set_table, data)) {
201060f4ce8eSGustavo Romero return;
201160f4ce8eSGustavo Romero }
201260f4ce8eSGustavo Romero
201360f4ce8eSGustavo Romero /* Can't handle set, return Empty response. */
201460f4ce8eSGustavo Romero gdb_put_packet("");
2015842b42dfSAlex Bennée }
2016842b42dfSAlex Bennée
handle_target_halt(GArray * params,void * user_ctx)2017842b42dfSAlex Bennée static void handle_target_halt(GArray *params, void *user_ctx)
2018842b42dfSAlex Bennée {
201975837005SMatheus Tavares Bernardino if (gdbserver_state.allow_stop_reply) {
2020842b42dfSAlex Bennée g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
2021842b42dfSAlex Bennée gdb_append_thread_id(gdbserver_state.c_cpu, gdbserver_state.str_buf);
2022842b42dfSAlex Bennée g_string_append_c(gdbserver_state.str_buf, ';');
202336e067b2SAlex Bennée gdb_put_strbuf();
202475837005SMatheus Tavares Bernardino gdbserver_state.allow_stop_reply = false;
202575837005SMatheus Tavares Bernardino }
2026842b42dfSAlex Bennée /*
2027842b42dfSAlex Bennée * Remove all the breakpoints when this query is issued,
2028842b42dfSAlex Bennée * because gdb is doing an initial connect and the state
2029842b42dfSAlex Bennée * should be cleaned up.
2030842b42dfSAlex Bennée */
2031ae7467b1SAlex Bennée gdb_breakpoint_remove_all(gdbserver_state.c_cpu);
2032842b42dfSAlex Bennée }
2033842b42dfSAlex Bennée
gdb_handle_packet(const char * line_buf)2034842b42dfSAlex Bennée static int gdb_handle_packet(const char *line_buf)
2035842b42dfSAlex Bennée {
2036842b42dfSAlex Bennée const GdbCmdParseEntry *cmd_parser = NULL;
2037842b42dfSAlex Bennée
2038842b42dfSAlex Bennée trace_gdbstub_io_command(line_buf);
2039842b42dfSAlex Bennée
2040842b42dfSAlex Bennée switch (line_buf[0]) {
2041842b42dfSAlex Bennée case '!':
204236e067b2SAlex Bennée gdb_put_packet("OK");
2043842b42dfSAlex Bennée break;
2044842b42dfSAlex Bennée case '?':
2045842b42dfSAlex Bennée {
2046842b42dfSAlex Bennée static const GdbCmdParseEntry target_halted_cmd_desc = {
2047842b42dfSAlex Bennée .handler = handle_target_halt,
2048842b42dfSAlex Bennée .cmd = "?",
20493b6c27d8SGustavo Romero .cmd_startswith = true,
205075837005SMatheus Tavares Bernardino .allow_stop_reply = true,
2051842b42dfSAlex Bennée };
2052842b42dfSAlex Bennée cmd_parser = &target_halted_cmd_desc;
2053842b42dfSAlex Bennée }
2054842b42dfSAlex Bennée break;
2055842b42dfSAlex Bennée case 'c':
2056842b42dfSAlex Bennée {
2057842b42dfSAlex Bennée static const GdbCmdParseEntry continue_cmd_desc = {
2058842b42dfSAlex Bennée .handler = handle_continue,
2059842b42dfSAlex Bennée .cmd = "c",
20603b6c27d8SGustavo Romero .cmd_startswith = true,
206175837005SMatheus Tavares Bernardino .allow_stop_reply = true,
2062842b42dfSAlex Bennée .schema = "L0"
2063842b42dfSAlex Bennée };
2064842b42dfSAlex Bennée cmd_parser = &continue_cmd_desc;
2065842b42dfSAlex Bennée }
2066842b42dfSAlex Bennée break;
2067842b42dfSAlex Bennée case 'C':
2068842b42dfSAlex Bennée {
2069842b42dfSAlex Bennée static const GdbCmdParseEntry cont_with_sig_cmd_desc = {
2070842b42dfSAlex Bennée .handler = handle_cont_with_sig,
2071842b42dfSAlex Bennée .cmd = "C",
20723b6c27d8SGustavo Romero .cmd_startswith = true,
207375837005SMatheus Tavares Bernardino .allow_stop_reply = true,
2074842b42dfSAlex Bennée .schema = "l0"
2075842b42dfSAlex Bennée };
2076842b42dfSAlex Bennée cmd_parser = &cont_with_sig_cmd_desc;
2077842b42dfSAlex Bennée }
2078842b42dfSAlex Bennée break;
2079842b42dfSAlex Bennée case 'v':
2080842b42dfSAlex Bennée {
2081842b42dfSAlex Bennée static const GdbCmdParseEntry v_cmd_desc = {
2082842b42dfSAlex Bennée .handler = handle_v_commands,
2083842b42dfSAlex Bennée .cmd = "v",
20843b6c27d8SGustavo Romero .cmd_startswith = true,
2085842b42dfSAlex Bennée .schema = "s0"
2086842b42dfSAlex Bennée };
2087842b42dfSAlex Bennée cmd_parser = &v_cmd_desc;
2088842b42dfSAlex Bennée }
2089842b42dfSAlex Bennée break;
2090842b42dfSAlex Bennée case 'k':
2091842b42dfSAlex Bennée /* Kill the target */
2092842b42dfSAlex Bennée error_report("QEMU: Terminated via GDBstub");
2093842b42dfSAlex Bennée gdb_exit(0);
2094e216256aSClément Chigot gdb_qemu_exit(0);
2095e216256aSClément Chigot break;
2096842b42dfSAlex Bennée case 'D':
2097842b42dfSAlex Bennée {
2098842b42dfSAlex Bennée static const GdbCmdParseEntry detach_cmd_desc = {
2099842b42dfSAlex Bennée .handler = handle_detach,
2100842b42dfSAlex Bennée .cmd = "D",
21013b6c27d8SGustavo Romero .cmd_startswith = true,
2102842b42dfSAlex Bennée .schema = "?.l0"
2103842b42dfSAlex Bennée };
2104842b42dfSAlex Bennée cmd_parser = &detach_cmd_desc;
2105842b42dfSAlex Bennée }
2106842b42dfSAlex Bennée break;
2107842b42dfSAlex Bennée case 's':
2108842b42dfSAlex Bennée {
2109842b42dfSAlex Bennée static const GdbCmdParseEntry step_cmd_desc = {
2110842b42dfSAlex Bennée .handler = handle_step,
2111842b42dfSAlex Bennée .cmd = "s",
21123b6c27d8SGustavo Romero .cmd_startswith = true,
211375837005SMatheus Tavares Bernardino .allow_stop_reply = true,
2114842b42dfSAlex Bennée .schema = "L0"
2115842b42dfSAlex Bennée };
2116842b42dfSAlex Bennée cmd_parser = &step_cmd_desc;
2117842b42dfSAlex Bennée }
2118842b42dfSAlex Bennée break;
2119842b42dfSAlex Bennée case 'b':
2120842b42dfSAlex Bennée {
2121842b42dfSAlex Bennée static const GdbCmdParseEntry backward_cmd_desc = {
2122842b42dfSAlex Bennée .handler = handle_backward,
2123842b42dfSAlex Bennée .cmd = "b",
21243b6c27d8SGustavo Romero .cmd_startswith = true,
21253b72d681SNicholas Piggin .allow_stop_reply = true,
2126842b42dfSAlex Bennée .schema = "o0"
2127842b42dfSAlex Bennée };
2128842b42dfSAlex Bennée cmd_parser = &backward_cmd_desc;
2129842b42dfSAlex Bennée }
2130842b42dfSAlex Bennée break;
2131842b42dfSAlex Bennée case 'F':
2132842b42dfSAlex Bennée {
2133842b42dfSAlex Bennée static const GdbCmdParseEntry file_io_cmd_desc = {
2134c566080cSAlex Bennée .handler = gdb_handle_file_io,
2135842b42dfSAlex Bennée .cmd = "F",
21363b6c27d8SGustavo Romero .cmd_startswith = true,
2137842b42dfSAlex Bennée .schema = "L,L,o0"
2138842b42dfSAlex Bennée };
2139842b42dfSAlex Bennée cmd_parser = &file_io_cmd_desc;
2140842b42dfSAlex Bennée }
2141842b42dfSAlex Bennée break;
2142842b42dfSAlex Bennée case 'g':
2143842b42dfSAlex Bennée {
2144842b42dfSAlex Bennée static const GdbCmdParseEntry read_all_regs_cmd_desc = {
2145842b42dfSAlex Bennée .handler = handle_read_all_regs,
2146842b42dfSAlex Bennée .cmd = "g",
21473b6c27d8SGustavo Romero .cmd_startswith = true
2148842b42dfSAlex Bennée };
2149842b42dfSAlex Bennée cmd_parser = &read_all_regs_cmd_desc;
2150842b42dfSAlex Bennée }
2151842b42dfSAlex Bennée break;
2152842b42dfSAlex Bennée case 'G':
2153842b42dfSAlex Bennée {
2154842b42dfSAlex Bennée static const GdbCmdParseEntry write_all_regs_cmd_desc = {
2155842b42dfSAlex Bennée .handler = handle_write_all_regs,
2156842b42dfSAlex Bennée .cmd = "G",
21573b6c27d8SGustavo Romero .cmd_startswith = true,
2158842b42dfSAlex Bennée .schema = "s0"
2159842b42dfSAlex Bennée };
2160842b42dfSAlex Bennée cmd_parser = &write_all_regs_cmd_desc;
2161842b42dfSAlex Bennée }
2162842b42dfSAlex Bennée break;
2163842b42dfSAlex Bennée case 'm':
2164842b42dfSAlex Bennée {
2165842b42dfSAlex Bennée static const GdbCmdParseEntry read_mem_cmd_desc = {
2166842b42dfSAlex Bennée .handler = handle_read_mem,
2167842b42dfSAlex Bennée .cmd = "m",
21683b6c27d8SGustavo Romero .cmd_startswith = true,
2169842b42dfSAlex Bennée .schema = "L,L0"
2170842b42dfSAlex Bennée };
2171842b42dfSAlex Bennée cmd_parser = &read_mem_cmd_desc;
2172842b42dfSAlex Bennée }
2173842b42dfSAlex Bennée break;
2174842b42dfSAlex Bennée case 'M':
2175842b42dfSAlex Bennée {
2176842b42dfSAlex Bennée static const GdbCmdParseEntry write_mem_cmd_desc = {
2177842b42dfSAlex Bennée .handler = handle_write_mem,
2178842b42dfSAlex Bennée .cmd = "M",
21793b6c27d8SGustavo Romero .cmd_startswith = true,
2180842b42dfSAlex Bennée .schema = "L,L:s0"
2181842b42dfSAlex Bennée };
2182842b42dfSAlex Bennée cmd_parser = &write_mem_cmd_desc;
2183842b42dfSAlex Bennée }
2184842b42dfSAlex Bennée break;
2185842b42dfSAlex Bennée case 'p':
2186842b42dfSAlex Bennée {
2187842b42dfSAlex Bennée static const GdbCmdParseEntry get_reg_cmd_desc = {
2188842b42dfSAlex Bennée .handler = handle_get_reg,
2189842b42dfSAlex Bennée .cmd = "p",
21903b6c27d8SGustavo Romero .cmd_startswith = true,
2191842b42dfSAlex Bennée .schema = "L0"
2192842b42dfSAlex Bennée };
2193842b42dfSAlex Bennée cmd_parser = &get_reg_cmd_desc;
2194842b42dfSAlex Bennée }
2195842b42dfSAlex Bennée break;
2196842b42dfSAlex Bennée case 'P':
2197842b42dfSAlex Bennée {
2198842b42dfSAlex Bennée static const GdbCmdParseEntry set_reg_cmd_desc = {
2199842b42dfSAlex Bennée .handler = handle_set_reg,
2200842b42dfSAlex Bennée .cmd = "P",
22013b6c27d8SGustavo Romero .cmd_startswith = true,
2202842b42dfSAlex Bennée .schema = "L?s0"
2203842b42dfSAlex Bennée };
2204842b42dfSAlex Bennée cmd_parser = &set_reg_cmd_desc;
2205842b42dfSAlex Bennée }
2206842b42dfSAlex Bennée break;
2207842b42dfSAlex Bennée case 'Z':
2208842b42dfSAlex Bennée {
2209842b42dfSAlex Bennée static const GdbCmdParseEntry insert_bp_cmd_desc = {
2210842b42dfSAlex Bennée .handler = handle_insert_bp,
2211842b42dfSAlex Bennée .cmd = "Z",
22123b6c27d8SGustavo Romero .cmd_startswith = true,
2213842b42dfSAlex Bennée .schema = "l?L?L0"
2214842b42dfSAlex Bennée };
2215842b42dfSAlex Bennée cmd_parser = &insert_bp_cmd_desc;
2216842b42dfSAlex Bennée }
2217842b42dfSAlex Bennée break;
2218842b42dfSAlex Bennée case 'z':
2219842b42dfSAlex Bennée {
2220842b42dfSAlex Bennée static const GdbCmdParseEntry remove_bp_cmd_desc = {
2221842b42dfSAlex Bennée .handler = handle_remove_bp,
2222842b42dfSAlex Bennée .cmd = "z",
22233b6c27d8SGustavo Romero .cmd_startswith = true,
2224842b42dfSAlex Bennée .schema = "l?L?L0"
2225842b42dfSAlex Bennée };
2226842b42dfSAlex Bennée cmd_parser = &remove_bp_cmd_desc;
2227842b42dfSAlex Bennée }
2228842b42dfSAlex Bennée break;
2229842b42dfSAlex Bennée case 'H':
2230842b42dfSAlex Bennée {
2231842b42dfSAlex Bennée static const GdbCmdParseEntry set_thread_cmd_desc = {
2232842b42dfSAlex Bennée .handler = handle_set_thread,
2233842b42dfSAlex Bennée .cmd = "H",
22343b6c27d8SGustavo Romero .cmd_startswith = true,
2235842b42dfSAlex Bennée .schema = "o.t0"
2236842b42dfSAlex Bennée };
2237842b42dfSAlex Bennée cmd_parser = &set_thread_cmd_desc;
2238842b42dfSAlex Bennée }
2239842b42dfSAlex Bennée break;
2240842b42dfSAlex Bennée case 'T':
2241842b42dfSAlex Bennée {
2242842b42dfSAlex Bennée static const GdbCmdParseEntry thread_alive_cmd_desc = {
2243842b42dfSAlex Bennée .handler = handle_thread_alive,
2244842b42dfSAlex Bennée .cmd = "T",
22453b6c27d8SGustavo Romero .cmd_startswith = true,
2246842b42dfSAlex Bennée .schema = "t0"
2247842b42dfSAlex Bennée };
2248842b42dfSAlex Bennée cmd_parser = &thread_alive_cmd_desc;
2249842b42dfSAlex Bennée }
2250842b42dfSAlex Bennée break;
2251842b42dfSAlex Bennée case 'q':
2252842b42dfSAlex Bennée {
2253842b42dfSAlex Bennée static const GdbCmdParseEntry gen_query_cmd_desc = {
2254842b42dfSAlex Bennée .handler = handle_gen_query,
2255842b42dfSAlex Bennée .cmd = "q",
22563b6c27d8SGustavo Romero .cmd_startswith = true,
2257842b42dfSAlex Bennée .schema = "s0"
2258842b42dfSAlex Bennée };
2259842b42dfSAlex Bennée cmd_parser = &gen_query_cmd_desc;
2260842b42dfSAlex Bennée }
2261842b42dfSAlex Bennée break;
2262842b42dfSAlex Bennée case 'Q':
2263842b42dfSAlex Bennée {
2264842b42dfSAlex Bennée static const GdbCmdParseEntry gen_set_cmd_desc = {
2265842b42dfSAlex Bennée .handler = handle_gen_set,
2266842b42dfSAlex Bennée .cmd = "Q",
22673b6c27d8SGustavo Romero .cmd_startswith = true,
2268842b42dfSAlex Bennée .schema = "s0"
2269842b42dfSAlex Bennée };
2270842b42dfSAlex Bennée cmd_parser = &gen_set_cmd_desc;
2271842b42dfSAlex Bennée }
2272842b42dfSAlex Bennée break;
2273842b42dfSAlex Bennée default:
2274842b42dfSAlex Bennée /* put empty packet */
227536e067b2SAlex Bennée gdb_put_packet("");
2276842b42dfSAlex Bennée break;
2277842b42dfSAlex Bennée }
2278842b42dfSAlex Bennée
2279842b42dfSAlex Bennée if (cmd_parser) {
2280842b42dfSAlex Bennée run_cmd_parser(line_buf, cmd_parser);
2281842b42dfSAlex Bennée }
2282842b42dfSAlex Bennée
2283842b42dfSAlex Bennée return RS_IDLE;
2284842b42dfSAlex Bennée }
2285842b42dfSAlex Bennée
gdb_set_stop_cpu(CPUState * cpu)2286842b42dfSAlex Bennée void gdb_set_stop_cpu(CPUState *cpu)
2287842b42dfSAlex Bennée {
2288842b42dfSAlex Bennée GDBProcess *p = gdb_get_cpu_process(cpu);
2289842b42dfSAlex Bennée
2290842b42dfSAlex Bennée if (!p->attached) {
2291842b42dfSAlex Bennée /*
2292842b42dfSAlex Bennée * Having a stop CPU corresponding to a process that is not attached
2293842b42dfSAlex Bennée * confuses GDB. So we ignore the request.
2294842b42dfSAlex Bennée */
2295842b42dfSAlex Bennée return;
2296842b42dfSAlex Bennée }
2297842b42dfSAlex Bennée
2298842b42dfSAlex Bennée gdbserver_state.c_cpu = cpu;
2299842b42dfSAlex Bennée gdbserver_state.g_cpu = cpu;
2300842b42dfSAlex Bennée }
2301842b42dfSAlex Bennée
gdb_read_byte(uint8_t ch)230236e067b2SAlex Bennée void gdb_read_byte(uint8_t ch)
2303842b42dfSAlex Bennée {
2304842b42dfSAlex Bennée uint8_t reply;
2305842b42dfSAlex Bennée
230675837005SMatheus Tavares Bernardino gdbserver_state.allow_stop_reply = false;
2307842b42dfSAlex Bennée #ifndef CONFIG_USER_ONLY
2308842b42dfSAlex Bennée if (gdbserver_state.last_packet->len) {
2309842b42dfSAlex Bennée /* Waiting for a response to the last packet. If we see the start
2310842b42dfSAlex Bennée of a new command then abandon the previous response. */
2311842b42dfSAlex Bennée if (ch == '-') {
2312842b42dfSAlex Bennée trace_gdbstub_err_got_nack();
231336e067b2SAlex Bennée gdb_put_buffer(gdbserver_state.last_packet->data,
2314842b42dfSAlex Bennée gdbserver_state.last_packet->len);
2315842b42dfSAlex Bennée } else if (ch == '+') {
2316842b42dfSAlex Bennée trace_gdbstub_io_got_ack();
2317842b42dfSAlex Bennée } else {
2318842b42dfSAlex Bennée trace_gdbstub_io_got_unexpected(ch);
2319842b42dfSAlex Bennée }
2320842b42dfSAlex Bennée
2321842b42dfSAlex Bennée if (ch == '+' || ch == '$') {
2322842b42dfSAlex Bennée g_byte_array_set_size(gdbserver_state.last_packet, 0);
2323842b42dfSAlex Bennée }
2324842b42dfSAlex Bennée if (ch != '$')
2325842b42dfSAlex Bennée return;
2326842b42dfSAlex Bennée }
2327842b42dfSAlex Bennée if (runstate_is_running()) {
2328108e8180SNicholas Piggin /*
2329108e8180SNicholas Piggin * When the CPU is running, we cannot do anything except stop
2330108e8180SNicholas Piggin * it when receiving a char. This is expected on a Ctrl-C in the
2331108e8180SNicholas Piggin * gdb client. Because we are in all-stop mode, gdb sends a
2332108e8180SNicholas Piggin * 0x03 byte which is not a usual packet, so we handle it specially
2333108e8180SNicholas Piggin * here, but it does expect a stop reply.
2334108e8180SNicholas Piggin */
2335108e8180SNicholas Piggin if (ch != 0x03) {
23363869eb7eSAlex Bennée trace_gdbstub_err_unexpected_runpkt(ch);
23373869eb7eSAlex Bennée } else {
2338108e8180SNicholas Piggin gdbserver_state.allow_stop_reply = true;
23393869eb7eSAlex Bennée }
2340842b42dfSAlex Bennée vm_stop(RUN_STATE_PAUSED);
2341842b42dfSAlex Bennée } else
2342842b42dfSAlex Bennée #endif
2343842b42dfSAlex Bennée {
2344842b42dfSAlex Bennée switch(gdbserver_state.state) {
2345842b42dfSAlex Bennée case RS_IDLE:
2346842b42dfSAlex Bennée if (ch == '$') {
2347842b42dfSAlex Bennée /* start of command packet */
2348842b42dfSAlex Bennée gdbserver_state.line_buf_index = 0;
2349842b42dfSAlex Bennée gdbserver_state.line_sum = 0;
2350842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE;
2351f1b0f894SAlex Bennée } else if (ch == '+') {
2352f1b0f894SAlex Bennée /*
2353f1b0f894SAlex Bennée * do nothing, gdb may preemptively send out ACKs on
2354f1b0f894SAlex Bennée * initial connection
2355f1b0f894SAlex Bennée */
2356842b42dfSAlex Bennée } else {
2357842b42dfSAlex Bennée trace_gdbstub_err_garbage(ch);
2358842b42dfSAlex Bennée }
2359842b42dfSAlex Bennée break;
2360842b42dfSAlex Bennée case RS_GETLINE:
2361842b42dfSAlex Bennée if (ch == '}') {
2362842b42dfSAlex Bennée /* start escape sequence */
2363842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE_ESC;
2364842b42dfSAlex Bennée gdbserver_state.line_sum += ch;
2365842b42dfSAlex Bennée } else if (ch == '*') {
2366842b42dfSAlex Bennée /* start run length encoding sequence */
2367842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE_RLE;
2368842b42dfSAlex Bennée gdbserver_state.line_sum += ch;
2369842b42dfSAlex Bennée } else if (ch == '#') {
2370842b42dfSAlex Bennée /* end of command, start of checksum*/
2371842b42dfSAlex Bennée gdbserver_state.state = RS_CHKSUM1;
2372842b42dfSAlex Bennée } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {
2373842b42dfSAlex Bennée trace_gdbstub_err_overrun();
2374842b42dfSAlex Bennée gdbserver_state.state = RS_IDLE;
2375842b42dfSAlex Bennée } else {
2376842b42dfSAlex Bennée /* unescaped command character */
2377842b42dfSAlex Bennée gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch;
2378842b42dfSAlex Bennée gdbserver_state.line_sum += ch;
2379842b42dfSAlex Bennée }
2380842b42dfSAlex Bennée break;
2381842b42dfSAlex Bennée case RS_GETLINE_ESC:
2382842b42dfSAlex Bennée if (ch == '#') {
2383842b42dfSAlex Bennée /* unexpected end of command in escape sequence */
2384842b42dfSAlex Bennée gdbserver_state.state = RS_CHKSUM1;
2385842b42dfSAlex Bennée } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {
2386842b42dfSAlex Bennée /* command buffer overrun */
2387842b42dfSAlex Bennée trace_gdbstub_err_overrun();
2388842b42dfSAlex Bennée gdbserver_state.state = RS_IDLE;
2389842b42dfSAlex Bennée } else {
2390842b42dfSAlex Bennée /* parse escaped character and leave escape state */
2391842b42dfSAlex Bennée gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch ^ 0x20;
2392842b42dfSAlex Bennée gdbserver_state.line_sum += ch;
2393842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE;
2394842b42dfSAlex Bennée }
2395842b42dfSAlex Bennée break;
2396842b42dfSAlex Bennée case RS_GETLINE_RLE:
2397842b42dfSAlex Bennée /*
2398842b42dfSAlex Bennée * Run-length encoding is explained in "Debugging with GDB /
2399842b42dfSAlex Bennée * Appendix E GDB Remote Serial Protocol / Overview".
2400842b42dfSAlex Bennée */
2401842b42dfSAlex Bennée if (ch < ' ' || ch == '#' || ch == '$' || ch > 126) {
2402842b42dfSAlex Bennée /* invalid RLE count encoding */
2403842b42dfSAlex Bennée trace_gdbstub_err_invalid_repeat(ch);
2404842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE;
2405842b42dfSAlex Bennée } else {
2406842b42dfSAlex Bennée /* decode repeat length */
2407842b42dfSAlex Bennée int repeat = ch - ' ' + 3;
2408842b42dfSAlex Bennée if (gdbserver_state.line_buf_index + repeat >= sizeof(gdbserver_state.line_buf) - 1) {
2409842b42dfSAlex Bennée /* that many repeats would overrun the command buffer */
2410842b42dfSAlex Bennée trace_gdbstub_err_overrun();
2411842b42dfSAlex Bennée gdbserver_state.state = RS_IDLE;
2412842b42dfSAlex Bennée } else if (gdbserver_state.line_buf_index < 1) {
2413842b42dfSAlex Bennée /* got a repeat but we have nothing to repeat */
2414842b42dfSAlex Bennée trace_gdbstub_err_invalid_rle();
2415842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE;
2416842b42dfSAlex Bennée } else {
2417842b42dfSAlex Bennée /* repeat the last character */
2418842b42dfSAlex Bennée memset(gdbserver_state.line_buf + gdbserver_state.line_buf_index,
2419842b42dfSAlex Bennée gdbserver_state.line_buf[gdbserver_state.line_buf_index - 1], repeat);
2420842b42dfSAlex Bennée gdbserver_state.line_buf_index += repeat;
2421842b42dfSAlex Bennée gdbserver_state.line_sum += ch;
2422842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE;
2423842b42dfSAlex Bennée }
2424842b42dfSAlex Bennée }
2425842b42dfSAlex Bennée break;
2426842b42dfSAlex Bennée case RS_CHKSUM1:
2427842b42dfSAlex Bennée /* get high hex digit of checksum */
2428842b42dfSAlex Bennée if (!isxdigit(ch)) {
2429842b42dfSAlex Bennée trace_gdbstub_err_checksum_invalid(ch);
2430842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE;
2431842b42dfSAlex Bennée break;
2432842b42dfSAlex Bennée }
2433842b42dfSAlex Bennée gdbserver_state.line_buf[gdbserver_state.line_buf_index] = '\0';
2434842b42dfSAlex Bennée gdbserver_state.line_csum = fromhex(ch) << 4;
2435842b42dfSAlex Bennée gdbserver_state.state = RS_CHKSUM2;
2436842b42dfSAlex Bennée break;
2437842b42dfSAlex Bennée case RS_CHKSUM2:
2438842b42dfSAlex Bennée /* get low hex digit of checksum */
2439842b42dfSAlex Bennée if (!isxdigit(ch)) {
2440842b42dfSAlex Bennée trace_gdbstub_err_checksum_invalid(ch);
2441842b42dfSAlex Bennée gdbserver_state.state = RS_GETLINE;
2442842b42dfSAlex Bennée break;
2443842b42dfSAlex Bennée }
2444842b42dfSAlex Bennée gdbserver_state.line_csum |= fromhex(ch);
2445842b42dfSAlex Bennée
2446842b42dfSAlex Bennée if (gdbserver_state.line_csum != (gdbserver_state.line_sum & 0xff)) {
2447842b42dfSAlex Bennée trace_gdbstub_err_checksum_incorrect(gdbserver_state.line_sum, gdbserver_state.line_csum);
2448842b42dfSAlex Bennée /* send NAK reply */
2449842b42dfSAlex Bennée reply = '-';
245036e067b2SAlex Bennée gdb_put_buffer(&reply, 1);
2451842b42dfSAlex Bennée gdbserver_state.state = RS_IDLE;
2452842b42dfSAlex Bennée } else {
2453842b42dfSAlex Bennée /* send ACK reply */
2454842b42dfSAlex Bennée reply = '+';
245536e067b2SAlex Bennée gdb_put_buffer(&reply, 1);
2456842b42dfSAlex Bennée gdbserver_state.state = gdb_handle_packet(gdbserver_state.line_buf);
2457842b42dfSAlex Bennée }
2458842b42dfSAlex Bennée break;
2459842b42dfSAlex Bennée default:
2460842b42dfSAlex Bennée abort();
2461842b42dfSAlex Bennée }
2462842b42dfSAlex Bennée }
2463842b42dfSAlex Bennée }
2464842b42dfSAlex Bennée
2465842b42dfSAlex Bennée /*
2466842b42dfSAlex Bennée * Create the process that will contain all the "orphan" CPUs (that are not
2467842b42dfSAlex Bennée * part of a CPU cluster). Note that if this process contains no CPUs, it won't
2468842b42dfSAlex Bennée * be attachable and thus will be invisible to the user.
2469842b42dfSAlex Bennée */
gdb_create_default_process(GDBState * s)247036e067b2SAlex Bennée void gdb_create_default_process(GDBState *s)
2471842b42dfSAlex Bennée {
2472842b42dfSAlex Bennée GDBProcess *process;
2473dc14a7a6SIlya Leoshkevich int pid;
2474842b42dfSAlex Bennée
2475dc14a7a6SIlya Leoshkevich #ifdef CONFIG_USER_ONLY
2476dc14a7a6SIlya Leoshkevich assert(gdbserver_state.process_num == 0);
2477dc14a7a6SIlya Leoshkevich pid = getpid();
2478dc14a7a6SIlya Leoshkevich #else
2479842b42dfSAlex Bennée if (gdbserver_state.process_num) {
2480dc14a7a6SIlya Leoshkevich pid = s->processes[s->process_num - 1].pid;
2481dc14a7a6SIlya Leoshkevich } else {
2482dc14a7a6SIlya Leoshkevich pid = 0;
2483842b42dfSAlex Bennée }
2484dc14a7a6SIlya Leoshkevich /* We need an available PID slot for this process */
2485dc14a7a6SIlya Leoshkevich assert(pid < UINT32_MAX);
2486dc14a7a6SIlya Leoshkevich pid++;
2487dc14a7a6SIlya Leoshkevich #endif
2488842b42dfSAlex Bennée
2489842b42dfSAlex Bennée s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
2490842b42dfSAlex Bennée process = &s->processes[s->process_num - 1];
2491dc14a7a6SIlya Leoshkevich process->pid = pid;
2492842b42dfSAlex Bennée process->attached = false;
249356e534bdSAlex Bennée process->target_xml = NULL;
2494842b42dfSAlex Bennée }
2495842b42dfSAlex Bennée
2496