2 * Target specific user-mode handling
4 * Copyright (c) 2003-2005 Fabrice Bellard
5 * Copyright (c) 2022 Linaro Ltd
7 * SPDX-License-Identifier: LGPL-2.0+
10 #include "qemu/osdep.h"
11 #include "exec/gdbstub.h"
13 #include "internals.h"
15 #include "linux-user/loader.h"
16 #include "linux-user/qemu.h"
20 * Map target signal numbers to GDB protocol signal numbers and vice
21 * versa. For user emulation's currently supported systems, we can
22 * assume most signals are defined.
25 static int gdb_signal_table[] = {
185 int gdb_signal_to_target(int sig)
187 if (sig < ARRAY_SIZE(gdb_signal_table)) {
188 return gdb_signal_table[sig];
194 int gdb_target_signal_to_gdb(int sig)
197 for (i = 0; i < ARRAY_SIZE(gdb_signal_table); i++) {
198 if (gdb_signal_table[i] == sig) {
202 return GDB_SIGNAL_UNKNOWN;
205 int gdb_get_cpu_index(CPUState *cpu)
207 TaskState *ts = (TaskState *) cpu->opaque;
208 return ts ? ts->ts_tid : -1;
212 * User-mode specific command helpers
215 void gdb_handle_query_offsets(GArray *params, void *user_ctx)
219 ts = gdbserver_state.c_cpu->opaque;
220 g_string_printf(gdbserver_state.str_buf,
221 "Text=" TARGET_ABI_FMT_lx
222 ";Data=" TARGET_ABI_FMT_lx
223 ";Bss=" TARGET_ABI_FMT_lx,
224 ts->info->code_offset,
225 ts->info->data_offset,
226 ts->info->data_offset);
230 #if defined(CONFIG_LINUX)
231 /* Partial user only duplicate of helper in gdbstub.c */
232 static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
233 uint8_t *buf, int len, bool is_write)
236 cc = CPU_GET_CLASS(cpu);
237 if (cc->memory_rw_debug) {
238 return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
240 return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
243 void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx)
246 unsigned long offset, len, saved_auxv, auxv_len;
248 if (params->len < 2) {
249 gdb_put_packet("E22");
253 offset = get_param(params, 0)->val_ul;
254 len = get_param(params, 1)->val_ul;
255 ts = gdbserver_state.c_cpu->opaque;
256 saved_auxv = ts->info->saved_auxv;
257 auxv_len = ts->info->auxv_len;
259 if (offset >= auxv_len) {
260 gdb_put_packet("E00");
264 if (len > (MAX_PACKET_LENGTH - 5) / 2) {
265 len = (MAX_PACKET_LENGTH - 5) / 2;
268 if (len < auxv_len - offset) {
269 g_string_assign(gdbserver_state.str_buf, "m");
271 g_string_assign(gdbserver_state.str_buf, "l");
272 len = auxv_len - offset;
275 g_byte_array_set_size(gdbserver_state.mem_buf, len);
276 if (target_memory_rw_debug(gdbserver_state.g_cpu, saved_auxv + offset,
277 gdbserver_state.mem_buf->data, len, false)) {
278 gdb_put_packet("E14");
282 gdb_memtox(gdbserver_state.str_buf,
283 (const char *)gdbserver_state.mem_buf->data, len);
284 gdb_put_packet_binary(gdbserver_state.str_buf->str,
285 gdbserver_state.str_buf->len, true);
289 static const char *get_filename_param(GArray *params, int i)
291 const char *hex_filename = get_param(params, i)->data;
292 gdb_hextomem(gdbserver_state.mem_buf, hex_filename,
293 strlen(hex_filename) / 2);
294 g_byte_array_append(gdbserver_state.mem_buf, (const guint8 *)"", 1);
295 return (const char *)gdbserver_state.mem_buf->data;
298 static void hostio_reply_with_data(const void *buf, size_t n)
300 g_string_printf(gdbserver_state.str_buf, "F%zx;", n);
301 gdb_memtox(gdbserver_state.str_buf, buf, n);
302 gdb_put_packet_binary(gdbserver_state.str_buf->str,
303 gdbserver_state.str_buf->len, true);
306 void gdb_handle_v_file_open(GArray *params, void *user_ctx)
308 const char *filename = get_filename_param(params, 0);
309 uint64_t flags = get_param(params, 1)->val_ull;
310 uint64_t mode = get_param(params, 2)->val_ull;
313 int fd = do_guest_openat(cpu_env(gdbserver_state.g_cpu), 0, filename,
316 int fd = open(filename, flags, mode);
319 g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
321 g_string_printf(gdbserver_state.str_buf, "F%d", fd);
326 void gdb_handle_v_file_close(GArray *params, void *user_ctx)
328 int fd = get_param(params, 0)->val_ul;
330 if (close(fd) == -1) {
331 g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
336 gdb_put_packet("F00");
339 void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
341 int fd = get_param(params, 0)->val_ul;
342 size_t count = get_param(params, 1)->val_ull;
343 off_t offset = get_param(params, 2)->val_ull;
345 size_t bufsiz = MIN(count, BUFSIZ);
346 g_autofree char *buf = g_try_malloc(bufsiz);
348 gdb_put_packet("E12");
352 ssize_t n = pread(fd, buf, bufsiz, offset);
354 g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
358 hostio_reply_with_data(buf, n);
361 void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
363 const char *filename = get_filename_param(params, 0);
365 g_autofree char *buf = g_try_malloc(BUFSIZ);
367 gdb_put_packet("E12");
372 ssize_t n = do_guest_readlink(filename, buf, BUFSIZ);
374 ssize_t n = readlink(filename, buf, BUFSIZ);
377 g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
381 hostio_reply_with_data(buf, n);
384 void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
386 uint32_t pid = get_param(params, 0)->val_ul;
387 uint32_t offset = get_param(params, 1)->val_ul;
388 uint32_t length = get_param(params, 2)->val_ul;
390 GDBProcess *process = gdb_get_process(pid);
392 gdb_put_packet("E00");
396 CPUState *cpu = gdb_get_first_cpu_in_process(process);
398 gdb_put_packet("E00");
402 TaskState *ts = cpu->opaque;
403 if (!ts || !ts->bprm || !ts->bprm->filename) {
404 gdb_put_packet("E00");
408 size_t total_length = strlen(ts->bprm->filename);
409 if (offset > total_length) {
410 gdb_put_packet("E00");
413 if (offset + length > total_length) {
414 length = total_length - offset;
417 g_string_printf(gdbserver_state.str_buf, "l%.*s", length,
418 ts->bprm->filename + offset);