blob: 43231e695e847cfe9f26f405051c8f8f043b9ff6 [file] [log] [blame]
Alex Bennéed96bf492023-03-02 18:57:47 -08001/*
2 * Target specific user-mode handling
3 *
4 * Copyright (c) 2003-2005 Fabrice Bellard
5 * Copyright (c) 2022 Linaro Ltd
6 *
Philippe Mathieu-Daudéb14d0642024-09-11 17:12:04 +02007 * SPDX-License-Identifier: LGPL-2.0-or-later
Alex Bennéed96bf492023-03-02 18:57:47 -08008 */
9
10#include "qemu/osdep.h"
11#include "exec/gdbstub.h"
Gustavo Romero133f2022024-07-05 09:40:38 +010012#include "gdbstub/commands.h"
Alex Bennéed96bf492023-03-02 18:57:47 -080013#include "qemu.h"
14#include "internals.h"
Ilya Leoshkeviche2820102023-06-30 19:04:21 +010015#ifdef CONFIG_LINUX
16#include "linux-user/loader.h"
17#include "linux-user/qemu.h"
18#endif
Alex Bennéed96bf492023-03-02 18:57:47 -080019
20/*
21 * Map target signal numbers to GDB protocol signal numbers and vice
22 * versa. For user emulation's currently supported systems, we can
23 * assume most signals are defined.
24 */
25
26static int gdb_signal_table[] = {
27 0,
28 TARGET_SIGHUP,
29 TARGET_SIGINT,
30 TARGET_SIGQUIT,
31 TARGET_SIGILL,
32 TARGET_SIGTRAP,
33 TARGET_SIGABRT,
34 -1, /* SIGEMT */
35 TARGET_SIGFPE,
36 TARGET_SIGKILL,
37 TARGET_SIGBUS,
38 TARGET_SIGSEGV,
39 TARGET_SIGSYS,
40 TARGET_SIGPIPE,
41 TARGET_SIGALRM,
42 TARGET_SIGTERM,
43 TARGET_SIGURG,
44 TARGET_SIGSTOP,
45 TARGET_SIGTSTP,
46 TARGET_SIGCONT,
47 TARGET_SIGCHLD,
48 TARGET_SIGTTIN,
49 TARGET_SIGTTOU,
50 TARGET_SIGIO,
51 TARGET_SIGXCPU,
52 TARGET_SIGXFSZ,
53 TARGET_SIGVTALRM,
54 TARGET_SIGPROF,
55 TARGET_SIGWINCH,
56 -1, /* SIGLOST */
57 TARGET_SIGUSR1,
58 TARGET_SIGUSR2,
59#ifdef TARGET_SIGPWR
60 TARGET_SIGPWR,
61#else
62 -1,
63#endif
64 -1, /* SIGPOLL */
65 -1,
66 -1,
67 -1,
68 -1,
69 -1,
70 -1,
71 -1,
72 -1,
73 -1,
74 -1,
75 -1,
76#ifdef __SIGRTMIN
77 __SIGRTMIN + 1,
78 __SIGRTMIN + 2,
79 __SIGRTMIN + 3,
80 __SIGRTMIN + 4,
81 __SIGRTMIN + 5,
82 __SIGRTMIN + 6,
83 __SIGRTMIN + 7,
84 __SIGRTMIN + 8,
85 __SIGRTMIN + 9,
86 __SIGRTMIN + 10,
87 __SIGRTMIN + 11,
88 __SIGRTMIN + 12,
89 __SIGRTMIN + 13,
90 __SIGRTMIN + 14,
91 __SIGRTMIN + 15,
92 __SIGRTMIN + 16,
93 __SIGRTMIN + 17,
94 __SIGRTMIN + 18,
95 __SIGRTMIN + 19,
96 __SIGRTMIN + 20,
97 __SIGRTMIN + 21,
98 __SIGRTMIN + 22,
99 __SIGRTMIN + 23,
100 __SIGRTMIN + 24,
101 __SIGRTMIN + 25,
102 __SIGRTMIN + 26,
103 __SIGRTMIN + 27,
104 __SIGRTMIN + 28,
105 __SIGRTMIN + 29,
106 __SIGRTMIN + 30,
107 __SIGRTMIN + 31,
108 -1, /* SIGCANCEL */
109 __SIGRTMIN,
110 __SIGRTMIN + 32,
111 __SIGRTMIN + 33,
112 __SIGRTMIN + 34,
113 __SIGRTMIN + 35,
114 __SIGRTMIN + 36,
115 __SIGRTMIN + 37,
116 __SIGRTMIN + 38,
117 __SIGRTMIN + 39,
118 __SIGRTMIN + 40,
119 __SIGRTMIN + 41,
120 __SIGRTMIN + 42,
121 __SIGRTMIN + 43,
122 __SIGRTMIN + 44,
123 __SIGRTMIN + 45,
124 __SIGRTMIN + 46,
125 __SIGRTMIN + 47,
126 __SIGRTMIN + 48,
127 __SIGRTMIN + 49,
128 __SIGRTMIN + 50,
129 __SIGRTMIN + 51,
130 __SIGRTMIN + 52,
131 __SIGRTMIN + 53,
132 __SIGRTMIN + 54,
133 __SIGRTMIN + 55,
134 __SIGRTMIN + 56,
135 __SIGRTMIN + 57,
136 __SIGRTMIN + 58,
137 __SIGRTMIN + 59,
138 __SIGRTMIN + 60,
139 __SIGRTMIN + 61,
140 __SIGRTMIN + 62,
141 __SIGRTMIN + 63,
142 __SIGRTMIN + 64,
143 __SIGRTMIN + 65,
144 __SIGRTMIN + 66,
145 __SIGRTMIN + 67,
146 __SIGRTMIN + 68,
147 __SIGRTMIN + 69,
148 __SIGRTMIN + 70,
149 __SIGRTMIN + 71,
150 __SIGRTMIN + 72,
151 __SIGRTMIN + 73,
152 __SIGRTMIN + 74,
153 __SIGRTMIN + 75,
154 __SIGRTMIN + 76,
155 __SIGRTMIN + 77,
156 __SIGRTMIN + 78,
157 __SIGRTMIN + 79,
158 __SIGRTMIN + 80,
159 __SIGRTMIN + 81,
160 __SIGRTMIN + 82,
161 __SIGRTMIN + 83,
162 __SIGRTMIN + 84,
163 __SIGRTMIN + 85,
164 __SIGRTMIN + 86,
165 __SIGRTMIN + 87,
166 __SIGRTMIN + 88,
167 __SIGRTMIN + 89,
168 __SIGRTMIN + 90,
169 __SIGRTMIN + 91,
170 __SIGRTMIN + 92,
171 __SIGRTMIN + 93,
172 __SIGRTMIN + 94,
173 __SIGRTMIN + 95,
174 -1, /* SIGINFO */
175 -1, /* UNKNOWN */
176 -1, /* DEFAULT */
177 -1,
178 -1,
179 -1,
180 -1,
181 -1,
182 -1
183#endif
184};
185
186int gdb_signal_to_target(int sig)
187{
188 if (sig < ARRAY_SIZE(gdb_signal_table)) {
189 return gdb_signal_table[sig];
190 } else {
191 return -1;
192 }
193}
194
195int gdb_target_signal_to_gdb(int sig)
196{
197 int i;
198 for (i = 0; i < ARRAY_SIZE(gdb_signal_table); i++) {
199 if (gdb_signal_table[i] == sig) {
200 return i;
201 }
202 }
203 return GDB_SIGNAL_UNKNOWN;
204}
205
206int gdb_get_cpu_index(CPUState *cpu)
207{
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +0000208 TaskState *ts = get_task_state(cpu);
Alex Bennéed96bf492023-03-02 18:57:47 -0800209 return ts ? ts->ts_tid : -1;
210}
211
212/*
213 * User-mode specific command helpers
214 */
215
216void gdb_handle_query_offsets(GArray *params, void *user_ctx)
217{
218 TaskState *ts;
219
Philippe Mathieu-Daudé59272462024-04-25 11:12:19 +0200220 ts = get_task_state(gdbserver_state.c_cpu);
Alex Bennéed96bf492023-03-02 18:57:47 -0800221 g_string_printf(gdbserver_state.str_buf,
222 "Text=" TARGET_ABI_FMT_lx
223 ";Data=" TARGET_ABI_FMT_lx
224 ";Bss=" TARGET_ABI_FMT_lx,
225 ts->info->code_offset,
226 ts->info->data_offset,
227 ts->info->data_offset);
228 gdb_put_strbuf();
229}
230
231#if defined(CONFIG_LINUX)
232/* Partial user only duplicate of helper in gdbstub.c */
233static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
234 uint8_t *buf, int len, bool is_write)
235{
Philippe Mathieu-Daudé0368d8d2025-01-21 12:11:35 +0100236 if (cpu->cc->memory_rw_debug) {
237 return cpu->cc->memory_rw_debug(cpu, addr, buf, len, is_write);
Alex Bennéed96bf492023-03-02 18:57:47 -0800238 }
239 return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
240}
241
242void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx)
243{
244 TaskState *ts;
245 unsigned long offset, len, saved_auxv, auxv_len;
246
247 if (params->len < 2) {
248 gdb_put_packet("E22");
249 return;
250 }
251
Gustavo Romero133f2022024-07-05 09:40:38 +0100252 offset = gdb_get_cmd_param(params, 0)->val_ul;
253 len = gdb_get_cmd_param(params, 1)->val_ul;
Philippe Mathieu-Daudé59272462024-04-25 11:12:19 +0200254 ts = get_task_state(gdbserver_state.c_cpu);
Alex Bennéed96bf492023-03-02 18:57:47 -0800255 saved_auxv = ts->info->saved_auxv;
256 auxv_len = ts->info->auxv_len;
257
258 if (offset >= auxv_len) {
259 gdb_put_packet("E00");
260 return;
261 }
262
263 if (len > (MAX_PACKET_LENGTH - 5) / 2) {
264 len = (MAX_PACKET_LENGTH - 5) / 2;
265 }
266
267 if (len < auxv_len - offset) {
268 g_string_assign(gdbserver_state.str_buf, "m");
269 } else {
270 g_string_assign(gdbserver_state.str_buf, "l");
271 len = auxv_len - offset;
272 }
273
274 g_byte_array_set_size(gdbserver_state.mem_buf, len);
275 if (target_memory_rw_debug(gdbserver_state.g_cpu, saved_auxv + offset,
276 gdbserver_state.mem_buf->data, len, false)) {
277 gdb_put_packet("E14");
278 return;
279 }
280
281 gdb_memtox(gdbserver_state.str_buf,
282 (const char *)gdbserver_state.mem_buf->data, len);
283 gdb_put_packet_binary(gdbserver_state.str_buf->str,
284 gdbserver_state.str_buf->len, true);
285}
286#endif
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100287
288static const char *get_filename_param(GArray *params, int i)
289{
Gustavo Romero133f2022024-07-05 09:40:38 +0100290 const char *hex_filename = gdb_get_cmd_param(params, i)->data;
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100291 gdb_hextomem(gdbserver_state.mem_buf, hex_filename,
292 strlen(hex_filename) / 2);
293 g_byte_array_append(gdbserver_state.mem_buf, (const guint8 *)"", 1);
294 return (const char *)gdbserver_state.mem_buf->data;
295}
296
297static void hostio_reply_with_data(const void *buf, size_t n)
298{
299 g_string_printf(gdbserver_state.str_buf, "F%zx;", n);
300 gdb_memtox(gdbserver_state.str_buf, buf, n);
301 gdb_put_packet_binary(gdbserver_state.str_buf->str,
302 gdbserver_state.str_buf->len, true);
303}
304
305void gdb_handle_v_file_open(GArray *params, void *user_ctx)
306{
307 const char *filename = get_filename_param(params, 0);
Gustavo Romero133f2022024-07-05 09:40:38 +0100308 uint64_t flags = gdb_get_cmd_param(params, 1)->val_ull;
309 uint64_t mode = gdb_get_cmd_param(params, 2)->val_ull;
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100310
311#ifdef CONFIG_LINUX
Richard Hendersonb77af262023-09-13 17:22:49 -0700312 int fd = do_guest_openat(cpu_env(gdbserver_state.g_cpu), 0, filename,
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100313 flags, mode, false);
314#else
315 int fd = open(filename, flags, mode);
316#endif
317 if (fd < 0) {
Dominik 'Disconnect3d' Czarnota8b647bd2025-01-20 23:28:58 +0100318 g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100319 } else {
Dominik 'Disconnect3d' Czarnota8b647bd2025-01-20 23:28:58 +0100320 g_string_printf(gdbserver_state.str_buf, "F%x", fd);
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100321 }
322 gdb_put_strbuf();
323}
324
325void gdb_handle_v_file_close(GArray *params, void *user_ctx)
326{
Gustavo Romero133f2022024-07-05 09:40:38 +0100327 int fd = gdb_get_cmd_param(params, 0)->val_ul;
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100328
329 if (close(fd) == -1) {
Dominik 'Disconnect3d' Czarnota8b647bd2025-01-20 23:28:58 +0100330 g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100331 gdb_put_strbuf();
332 return;
333 }
334
335 gdb_put_packet("F00");
336}
337
338void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
339{
Gustavo Romero133f2022024-07-05 09:40:38 +0100340 int fd = gdb_get_cmd_param(params, 0)->val_ul;
341 size_t count = gdb_get_cmd_param(params, 1)->val_ull;
342 off_t offset = gdb_get_cmd_param(params, 2)->val_ull;
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100343
344 size_t bufsiz = MIN(count, BUFSIZ);
345 g_autofree char *buf = g_try_malloc(bufsiz);
346 if (buf == NULL) {
347 gdb_put_packet("E12");
348 return;
349 }
350
351 ssize_t n = pread(fd, buf, bufsiz, offset);
352 if (n < 0) {
Dominik 'Disconnect3d' Czarnota8b647bd2025-01-20 23:28:58 +0100353 g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100354 gdb_put_strbuf();
355 return;
356 }
357 hostio_reply_with_data(buf, n);
358}
359
360void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
361{
362 const char *filename = get_filename_param(params, 0);
363
364 g_autofree char *buf = g_try_malloc(BUFSIZ);
365 if (buf == NULL) {
366 gdb_put_packet("E12");
367 return;
368 }
369
370#ifdef CONFIG_LINUX
371 ssize_t n = do_guest_readlink(filename, buf, BUFSIZ);
372#else
373 ssize_t n = readlink(filename, buf, BUFSIZ);
374#endif
375 if (n < 0) {
Dominik 'Disconnect3d' Czarnota8b647bd2025-01-20 23:28:58 +0100376 g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100377 gdb_put_strbuf();
378 return;
379 }
380 hostio_reply_with_data(buf, n);
381}
382
383void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
384{
Gustavo Romero133f2022024-07-05 09:40:38 +0100385 uint32_t pid = gdb_get_cmd_param(params, 0)->val_ul;
386 uint32_t offset = gdb_get_cmd_param(params, 1)->val_ul;
387 uint32_t length = gdb_get_cmd_param(params, 2)->val_ul;
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100388
389 GDBProcess *process = gdb_get_process(pid);
390 if (!process) {
391 gdb_put_packet("E00");
392 return;
393 }
394
395 CPUState *cpu = gdb_get_first_cpu_in_process(process);
396 if (!cpu) {
397 gdb_put_packet("E00");
398 return;
399 }
400
Ilya Leoshkeviche4e5cb42024-03-05 12:09:39 +0000401 TaskState *ts = get_task_state(cpu);
Ilya Leoshkeviche2820102023-06-30 19:04:21 +0100402 if (!ts || !ts->bprm || !ts->bprm->filename) {
403 gdb_put_packet("E00");
404 return;
405 }
406
407 size_t total_length = strlen(ts->bprm->filename);
408 if (offset > total_length) {
409 gdb_put_packet("E00");
410 return;
411 }
412 if (offset + length > total_length) {
413 length = total_length - offset;
414 }
415
416 g_string_printf(gdbserver_state.str_buf, "l%.*s", length,
417 ts->bprm->filename + offset);
418 gdb_put_strbuf();
419}
Ilya Leoshkevich4aad0962024-02-07 16:38:08 +0000420
421int gdb_target_sigtrap(void)
422{
423 return TARGET_SIGTRAP;
424}