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"
12 #include "gdbstub/commands.h"
14 #include "internals.h"
16 #include "linux-user/loader.h"
17 #include "linux-user/qemu.h"
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.
26 static int gdb_signal_table
[] = {
186 int gdb_signal_to_target(int sig
)
188 if (sig
< ARRAY_SIZE(gdb_signal_table
)) {
189 return gdb_signal_table
[sig
];
195 int gdb_target_signal_to_gdb(int sig
)
198 for (i
= 0; i
< ARRAY_SIZE(gdb_signal_table
); i
++) {
199 if (gdb_signal_table
[i
] == sig
) {
203 return GDB_SIGNAL_UNKNOWN
;
206 int gdb_get_cpu_index(CPUState
*cpu
)
208 TaskState
*ts
= get_task_state(cpu
);
209 return ts
? ts
->ts_tid
: -1;
213 * User-mode specific command helpers
216 void gdb_handle_query_offsets(GArray
*params
, void *user_ctx
)
220 ts
= get_task_state(gdbserver_state
.c_cpu
);
221 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
);
231 #if defined(CONFIG_LINUX)
232 /* Partial user only duplicate of helper in gdbstub.c */
233 static inline int target_memory_rw_debug(CPUState
*cpu
, target_ulong addr
,
234 uint8_t *buf
, int len
, bool is_write
)
237 cc
= CPU_GET_CLASS(cpu
);
238 if (cc
->memory_rw_debug
) {
239 return cc
->memory_rw_debug(cpu
, addr
, buf
, len
, is_write
);
241 return cpu_memory_rw_debug(cpu
, addr
, buf
, len
, is_write
);
244 void gdb_handle_query_xfer_auxv(GArray
*params
, void *user_ctx
)
247 unsigned long offset
, len
, saved_auxv
, auxv_len
;
249 if (params
->len
< 2) {
250 gdb_put_packet("E22");
254 offset
= gdb_get_cmd_param(params
, 0)->val_ul
;
255 len
= gdb_get_cmd_param(params
, 1)->val_ul
;
256 ts
= get_task_state(gdbserver_state
.c_cpu
);
257 saved_auxv
= ts
->info
->saved_auxv
;
258 auxv_len
= ts
->info
->auxv_len
;
260 if (offset
>= auxv_len
) {
261 gdb_put_packet("E00");
265 if (len
> (MAX_PACKET_LENGTH
- 5) / 2) {
266 len
= (MAX_PACKET_LENGTH
- 5) / 2;
269 if (len
< auxv_len
- offset
) {
270 g_string_assign(gdbserver_state
.str_buf
, "m");
272 g_string_assign(gdbserver_state
.str_buf
, "l");
273 len
= auxv_len
- offset
;
276 g_byte_array_set_size(gdbserver_state
.mem_buf
, len
);
277 if (target_memory_rw_debug(gdbserver_state
.g_cpu
, saved_auxv
+ offset
,
278 gdbserver_state
.mem_buf
->data
, len
, false)) {
279 gdb_put_packet("E14");
283 gdb_memtox(gdbserver_state
.str_buf
,
284 (const char *)gdbserver_state
.mem_buf
->data
, len
);
285 gdb_put_packet_binary(gdbserver_state
.str_buf
->str
,
286 gdbserver_state
.str_buf
->len
, true);
290 static const char *get_filename_param(GArray
*params
, int i
)
292 const char *hex_filename
= gdb_get_cmd_param(params
, i
)->data
;
293 gdb_hextomem(gdbserver_state
.mem_buf
, hex_filename
,
294 strlen(hex_filename
) / 2);
295 g_byte_array_append(gdbserver_state
.mem_buf
, (const guint8
*)"", 1);
296 return (const char *)gdbserver_state
.mem_buf
->data
;
299 static void hostio_reply_with_data(const void *buf
, size_t n
)
301 g_string_printf(gdbserver_state
.str_buf
, "F%zx;", n
);
302 gdb_memtox(gdbserver_state
.str_buf
, buf
, n
);
303 gdb_put_packet_binary(gdbserver_state
.str_buf
->str
,
304 gdbserver_state
.str_buf
->len
, true);
307 void gdb_handle_v_file_open(GArray
*params
, void *user_ctx
)
309 const char *filename
= get_filename_param(params
, 0);
310 uint64_t flags
= gdb_get_cmd_param(params
, 1)->val_ull
;
311 uint64_t mode
= gdb_get_cmd_param(params
, 2)->val_ull
;
314 int fd
= do_guest_openat(cpu_env(gdbserver_state
.g_cpu
), 0, filename
,
317 int fd
= open(filename
, flags
, mode
);
320 g_string_printf(gdbserver_state
.str_buf
, "F-1,%d", errno
);
322 g_string_printf(gdbserver_state
.str_buf
, "F%d", fd
);
327 void gdb_handle_v_file_close(GArray
*params
, void *user_ctx
)
329 int fd
= gdb_get_cmd_param(params
, 0)->val_ul
;
331 if (close(fd
) == -1) {
332 g_string_printf(gdbserver_state
.str_buf
, "F-1,%d", errno
);
337 gdb_put_packet("F00");
340 void gdb_handle_v_file_pread(GArray
*params
, void *user_ctx
)
342 int fd
= gdb_get_cmd_param(params
, 0)->val_ul
;
343 size_t count
= gdb_get_cmd_param(params
, 1)->val_ull
;
344 off_t offset
= gdb_get_cmd_param(params
, 2)->val_ull
;
346 size_t bufsiz
= MIN(count
, BUFSIZ
);
347 g_autofree
char *buf
= g_try_malloc(bufsiz
);
349 gdb_put_packet("E12");
353 ssize_t n
= pread(fd
, buf
, bufsiz
, offset
);
355 g_string_printf(gdbserver_state
.str_buf
, "F-1,%d", errno
);
359 hostio_reply_with_data(buf
, n
);
362 void gdb_handle_v_file_readlink(GArray
*params
, void *user_ctx
)
364 const char *filename
= get_filename_param(params
, 0);
366 g_autofree
char *buf
= g_try_malloc(BUFSIZ
);
368 gdb_put_packet("E12");
373 ssize_t n
= do_guest_readlink(filename
, buf
, BUFSIZ
);
375 ssize_t n
= readlink(filename
, buf
, BUFSIZ
);
378 g_string_printf(gdbserver_state
.str_buf
, "F-1,%d", errno
);
382 hostio_reply_with_data(buf
, n
);
385 void gdb_handle_query_xfer_exec_file(GArray
*params
, void *user_ctx
)
387 uint32_t pid
= gdb_get_cmd_param(params
, 0)->val_ul
;
388 uint32_t offset
= gdb_get_cmd_param(params
, 1)->val_ul
;
389 uint32_t length
= gdb_get_cmd_param(params
, 2)->val_ul
;
391 GDBProcess
*process
= gdb_get_process(pid
);
393 gdb_put_packet("E00");
397 CPUState
*cpu
= gdb_get_first_cpu_in_process(process
);
399 gdb_put_packet("E00");
403 TaskState
*ts
= get_task_state(cpu
);
404 if (!ts
|| !ts
->bprm
|| !ts
->bprm
->filename
) {
405 gdb_put_packet("E00");
409 size_t total_length
= strlen(ts
->bprm
->filename
);
410 if (offset
> total_length
) {
411 gdb_put_packet("E00");
414 if (offset
+ length
> total_length
) {
415 length
= total_length
- offset
;
418 g_string_printf(gdbserver_state
.str_buf
, "l%.*s", length
,
419 ts
->bprm
->filename
+ offset
);
423 int gdb_target_sigtrap(void)
425 return TARGET_SIGTRAP
;