From c566080cd37fe328077a3c49d7fd248ce2a06bfe Mon Sep 17 00:00:00 2001 From: =?utf8?q?Alex=20Benn=C3=A9e?= Date: Thu, 2 Mar 2023 18:57:57 -0800 Subject: [PATCH] gdbstub: move syscall handling to new file MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Our GDB syscall support is the last chunk of code that needs target specific support so move it to a new file. We take the opportunity to move the syscall state into its own singleton instance and add in a few helpers for the main gdbstub to interact with the module. I also moved the gdb_exit() declaration into syscalls.h as it feels pretty related and most of the callers of it treat it as such. Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230302190846.2593720-22-alex.bennee@linaro.org> Message-Id: <20230303025805.625589-22-richard.henderson@linaro.org> --- bsd-user/freebsd/os-syscall.c | 2 + gdbstub/gdbstub.c | 177 +------------------ gdbstub/internals.h | 8 +- gdbstub/meson.build | 4 + gdbstub/softmmu.c | 7 +- gdbstub/syscalls.c | 235 +++++++++++++++++++++++++ gdbstub/user.c | 1 + include/exec/gdbstub.h | 190 +++++--------------- include/{exec/gdbstub.h => gdbstub/syscalls.h} | 54 ++---- linux-user/exit.c | 2 +- semihosting/arm-compat-semi.c | 1 + semihosting/guestfd.c | 2 +- semihosting/syscalls.c | 2 +- softmmu/runstate.c | 2 +- target/m68k/m68k-semi.c | 2 +- target/mips/tcg/sysemu/mips-semi.c | 2 +- target/nios2/nios2-semi.c | 2 +- 17 files changed, 323 insertions(+), 370 deletions(-) create mode 100644 gdbstub/syscalls.c rewrite include/exec/gdbstub.h (71%) copy include/{exec/gdbstub.h => gdbstub/syscalls.h} (72%) diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 179a20c304..c8f998ecec 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -38,6 +38,8 @@ #include #include +#include "include/gdbstub/syscalls.h" + #include "qemu.h" #include "signal-common.h" #include "user/syscall-trace.h" diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index f1504af44f..e264ed04e7 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -29,6 +29,7 @@ #include "qemu/module.h" #include "trace.h" #include "exec/gdbstub.h" +#include "gdbstub/syscalls.h" #ifdef CONFIG_USER_ONLY #include "gdbstub/user.h" #else @@ -38,7 +39,6 @@ #include "sysemu/hw_accel.h" #include "sysemu/runstate.h" -#include "semihosting/semihost.h" #include "exec/exec-all.h" #include "exec/replay-core.h" #include "exec/tb-flush.h" @@ -78,41 +78,6 @@ void gdb_init_gdbserver_state(void) bool gdb_has_xml; -/* - * Return true if there is a GDB currently connected to the stub - * and attached to a CPU - */ -static bool gdb_attached(void) -{ - return gdbserver_state.init && gdbserver_state.c_cpu; -} - -static enum { - GDB_SYS_UNKNOWN, - GDB_SYS_ENABLED, - GDB_SYS_DISABLED, -} gdb_syscall_mode; - -/* Decide if either remote gdb syscalls or native file IO should be used. */ -int use_gdb_syscalls(void) -{ - SemihostingTarget target = semihosting_get_target(); - if (target == SEMIHOSTING_TARGET_NATIVE) { - /* -semihosting-config target=native */ - return false; - } else if (target == SEMIHOSTING_TARGET_GDB) { - /* -semihosting-config target=gdb */ - return true; - } - - /* -semihosting-config target=auto */ - /* On the first call check if gdb is connected and remember. */ - if (gdb_syscall_mode == GDB_SYS_UNKNOWN) { - gdb_syscall_mode = gdb_attached() ? GDB_SYS_ENABLED : GDB_SYS_DISABLED; - } - return gdb_syscall_mode == GDB_SYS_ENABLED; -} - /* writes 2*len+1 bytes in buf */ void gdb_memtohex(GString *buf, const uint8_t *mem, int len) { @@ -922,7 +887,7 @@ static void handle_detach(GArray *params, void *user_ctx) if (!gdbserver_state.c_cpu) { /* No more process attached */ - gdb_syscall_mode = GDB_SYS_DISABLED; + gdb_disable_syscalls(); gdb_continue(); } gdb_put_packet("OK"); @@ -1235,60 +1200,6 @@ static void handle_read_all_regs(GArray *params, void *user_ctx) gdb_put_strbuf(); } -static void handle_file_io(GArray *params, void *user_ctx) -{ - if (params->len >= 1 && gdbserver_state.current_syscall_cb) { - uint64_t ret; - int err; - - ret = get_param(params, 0)->val_ull; - if (params->len >= 2) { - err = get_param(params, 1)->val_ull; - } else { - err = 0; - } - - /* Convert GDB error numbers back to host error numbers. */ -#define E(X) case GDB_E##X: err = E##X; break - switch (err) { - case 0: - break; - E(PERM); - E(NOENT); - E(INTR); - E(BADF); - E(ACCES); - E(FAULT); - E(BUSY); - E(EXIST); - E(NODEV); - E(NOTDIR); - E(ISDIR); - E(INVAL); - E(NFILE); - E(MFILE); - E(FBIG); - E(NOSPC); - E(SPIPE); - E(ROFS); - E(NAMETOOLONG); - default: - err = EINVAL; - break; - } -#undef E - - gdbserver_state.current_syscall_cb(gdbserver_state.c_cpu, ret, err); - gdbserver_state.current_syscall_cb = NULL; - } - - if (params->len >= 3 && get_param(params, 2)->opcode == (uint8_t)'C') { - gdb_put_packet("T02"); - return; - } - - gdb_continue(); -} static void handle_step(GArray *params, void *user_ctx) { @@ -1894,7 +1805,7 @@ static int gdb_handle_packet(const char *line_buf) case 'F': { static const GdbCmdParseEntry file_io_cmd_desc = { - .handler = handle_file_io, + .handler = gdb_handle_file_io, .cmd = "F", .cmd_startswith = 1, .schema = "L,L,o0" @@ -2062,88 +1973,6 @@ void gdb_set_stop_cpu(CPUState *cpu) gdbserver_state.g_cpu = cpu; } -/* Send a gdb syscall request. - This accepts limited printf-style format specifiers, specifically: - %x - target_ulong argument printed in hex. - %lx - 64-bit argument printed in hex. - %s - string pointer (target_ulong) and length (int) pair. */ -void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va) -{ - char *p; - char *p_end; - target_ulong addr; - uint64_t i64; - - if (!gdb_attached()) { - return; - } - - gdbserver_state.current_syscall_cb = cb; -#ifndef CONFIG_USER_ONLY - vm_stop(RUN_STATE_DEBUG); -#endif - p = &gdbserver_state.syscall_buf[0]; - p_end = &gdbserver_state.syscall_buf[sizeof(gdbserver_state.syscall_buf)]; - *(p++) = 'F'; - while (*fmt) { - if (*fmt == '%') { - fmt++; - switch (*fmt++) { - case 'x': - addr = va_arg(va, target_ulong); - p += snprintf(p, p_end - p, TARGET_FMT_lx, addr); - break; - case 'l': - if (*(fmt++) != 'x') - goto bad_format; - i64 = va_arg(va, uint64_t); - p += snprintf(p, p_end - p, "%" PRIx64, i64); - break; - case 's': - addr = va_arg(va, target_ulong); - p += snprintf(p, p_end - p, TARGET_FMT_lx "/%x", - addr, va_arg(va, int)); - break; - default: - bad_format: - error_report("gdbstub: Bad syscall format string '%s'", - fmt - 1); - break; - } - } else { - *(p++) = *(fmt++); - } - } - *p = 0; -#ifdef CONFIG_USER_ONLY - gdb_put_packet(gdbserver_state.syscall_buf); - /* Return control to gdb for it to process the syscall request. - * Since the protocol requires that gdb hands control back to us - * using a "here are the results" F packet, we don't need to check - * gdb_handlesig's return value (which is the signal to deliver if - * execution was resumed via a continue packet). - */ - gdb_handlesig(gdbserver_state.c_cpu, 0); -#else - /* In this case wait to send the syscall packet until notification that - the CPU has stopped. This must be done because if the packet is sent - now the reply from the syscall request could be received while the CPU - is still in the running state, which can cause packets to be dropped - and state transition 'T' packets to be sent while the syscall is still - being processed. */ - qemu_cpu_kick(gdbserver_state.c_cpu); -#endif -} - -void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) -{ - va_list va; - - va_start(va, fmt); - gdb_do_syscallv(cb, fmt, va); - va_end(va); -} - void gdb_read_byte(uint8_t ch) { uint8_t reply; diff --git a/gdbstub/internals.h b/gdbstub/internals.h index be0eef4850..8db61f7fb4 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -61,8 +61,6 @@ typedef struct GDBState { bool multiprocess; GDBProcess *processes; int process_num; - char syscall_buf[256]; - gdb_syscall_complete_cb current_syscall_cb; GString *str_buf; GByteArray *mem_buf; int sstep_flags; @@ -191,6 +189,12 @@ void gdb_handle_query_attached(GArray *params, void *user_ctx); /* both */ void gdb_handle_query_qemu_phy_mem_mode(GArray *params, void *user_ctx); void gdb_handle_set_qemu_phy_mem_mode(GArray *params, void *user_ctx); +/* sycall handling */ +void gdb_handle_file_io(GArray *params, void *user_ctx); +bool gdb_handled_syscall(void); +void gdb_disable_syscalls(void); +void gdb_syscall_reset(void); + /* * Break/Watch point support - there is an implementation for softmmu * and user mode. diff --git a/gdbstub/meson.build b/gdbstub/meson.build index 773bd4b9c9..c876222b9c 100644 --- a/gdbstub/meson.build +++ b/gdbstub/meson.build @@ -5,6 +5,10 @@ # specific_ss.add(files('gdbstub.c')) + +# These have to built to the target ABI +specific_ss.add(files('syscalls.c')) + softmmu_ss.add(files('softmmu.c')) user_ss.add(files('user.c')) diff --git a/gdbstub/softmmu.c b/gdbstub/softmmu.c index d2863d0663..d3152fb6e7 100644 --- a/gdbstub/softmmu.c +++ b/gdbstub/softmmu.c @@ -15,6 +15,7 @@ #include "qemu/error-report.h" #include "qemu/cutils.h" #include "exec/gdbstub.h" +#include "gdbstub/syscalls.h" #include "exec/hwaddr.h" #include "exec/tb-flush.h" #include "sysemu/cpus.h" @@ -113,9 +114,9 @@ static void gdb_vm_state_change(void *opaque, bool running, RunState state) if (running || gdbserver_state.state == RS_INACTIVE) { return; } + /* Is there a GDB syscall waiting to be sent? */ - if (gdbserver_state.current_syscall_cb) { - gdb_put_packet(gdbserver_state.syscall_buf); + if (gdb_handled_syscall()) { return; } @@ -384,7 +385,7 @@ int gdbserver_start(const char *device) } gdbserver_state.state = chr ? RS_IDLE : RS_INACTIVE; gdbserver_system_state.mon_chr = mon_chr; - gdbserver_state.current_syscall_cb = NULL; + gdb_syscall_reset(); return 0; } diff --git a/gdbstub/syscalls.c b/gdbstub/syscalls.c new file mode 100644 index 0000000000..46537938d5 --- /dev/null +++ b/gdbstub/syscalls.c @@ -0,0 +1,235 @@ +/* + * GDB Syscall Handling + * + * GDB can execute syscalls on the guests behalf, currently used by + * the various semihosting extensions. As this interfaces with a guest + * ABI we need to build it per-guest (although in reality its a 32 or + * 64 bit target_ulong that is the only difference). + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2023 Linaro Ltd + * + * SPDX-License-Identifier: LGPL-2.0+ + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "cpu.h" +#include "semihosting/semihost.h" +#include "sysemu/runstate.h" +#include "gdbstub/user.h" +#include "gdbstub/syscalls.h" +#include "trace.h" +#include "internals.h" + +/* Syscall specific state */ +typedef struct { + char syscall_buf[256]; + gdb_syscall_complete_cb current_syscall_cb; +} GDBSyscallState; + +static GDBSyscallState gdbserver_syscall_state; + +/* + * Return true if there is a GDB currently connected to the stub + * and attached to a CPU + */ +static bool gdb_attached(void) +{ + return gdbserver_state.init && gdbserver_state.c_cpu; +} + +static enum { + GDB_SYS_UNKNOWN, + GDB_SYS_ENABLED, + GDB_SYS_DISABLED, +} gdb_syscall_mode; + +/* Decide if either remote gdb syscalls or native file IO should be used. */ +int use_gdb_syscalls(void) +{ + SemihostingTarget target = semihosting_get_target(); + if (target == SEMIHOSTING_TARGET_NATIVE) { + /* -semihosting-config target=native */ + return false; + } else if (target == SEMIHOSTING_TARGET_GDB) { + /* -semihosting-config target=gdb */ + return true; + } + + /* -semihosting-config target=auto */ + /* On the first call check if gdb is connected and remember. */ + if (gdb_syscall_mode == GDB_SYS_UNKNOWN) { + gdb_syscall_mode = gdb_attached() ? GDB_SYS_ENABLED : GDB_SYS_DISABLED; + } + return gdb_syscall_mode == GDB_SYS_ENABLED; +} + +/* called when the stub detaches */ +void gdb_disable_syscalls(void) +{ + gdb_syscall_mode = GDB_SYS_DISABLED; +} + +void gdb_syscall_reset(void) +{ + gdbserver_syscall_state.current_syscall_cb = NULL; +} + +bool gdb_handled_syscall(void) +{ + if (gdbserver_syscall_state.current_syscall_cb) { + gdb_put_packet(gdbserver_syscall_state.syscall_buf); + return true; + } + + return false; +} + +/* + * Send a gdb syscall request. + * This accepts limited printf-style format specifiers, specifically: + * %x - target_ulong argument printed in hex. + * %lx - 64-bit argument printed in hex. + * %s - string pointer (target_ulong) and length (int) pair. + */ +void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va) +{ + char *p; + char *p_end; + target_ulong addr; + uint64_t i64; + + if (!gdb_attached()) { + return; + } + + gdbserver_syscall_state.current_syscall_cb = cb; +#ifndef CONFIG_USER_ONLY + vm_stop(RUN_STATE_DEBUG); +#endif + p = &gdbserver_syscall_state.syscall_buf[0]; + p_end = &gdbserver_syscall_state.syscall_buf[sizeof(gdbserver_syscall_state.syscall_buf)]; + *(p++) = 'F'; + while (*fmt) { + if (*fmt == '%') { + fmt++; + switch (*fmt++) { + case 'x': + addr = va_arg(va, target_ulong); + p += snprintf(p, p_end - p, TARGET_FMT_lx, addr); + break; + case 'l': + if (*(fmt++) != 'x') { + goto bad_format; + } + i64 = va_arg(va, uint64_t); + p += snprintf(p, p_end - p, "%" PRIx64, i64); + break; + case 's': + addr = va_arg(va, target_ulong); + p += snprintf(p, p_end - p, TARGET_FMT_lx "/%x", + addr, va_arg(va, int)); + break; + default: + bad_format: + error_report("gdbstub: Bad syscall format string '%s'", + fmt - 1); + break; + } + } else { + *(p++) = *(fmt++); + } + } + *p = 0; +#ifdef CONFIG_USER_ONLY + gdb_put_packet(gdbserver_syscall_state.syscall_buf); + /* + * Return control to gdb for it to process the syscall request. + * Since the protocol requires that gdb hands control back to us + * using a "here are the results" F packet, we don't need to check + * gdb_handlesig's return value (which is the signal to deliver if + * execution was resumed via a continue packet). + */ + gdb_handlesig(gdbserver_state.c_cpu, 0); +#else + /* + * In this case wait to send the syscall packet until notification that + * the CPU has stopped. This must be done because if the packet is sent + * now the reply from the syscall request could be received while the CPU + * is still in the running state, which can cause packets to be dropped + * and state transition 'T' packets to be sent while the syscall is still + * being processed. + */ + qemu_cpu_kick(gdbserver_state.c_cpu); +#endif +} + +void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + gdb_do_syscallv(cb, fmt, va); + va_end(va); +} + +/* + * GDB Command Handlers + */ + +void gdb_handle_file_io(GArray *params, void *user_ctx) +{ + if (params->len >= 1 && gdbserver_syscall_state.current_syscall_cb) { + uint64_t ret; + int err; + + ret = get_param(params, 0)->val_ull; + if (params->len >= 2) { + err = get_param(params, 1)->val_ull; + } else { + err = 0; + } + + /* Convert GDB error numbers back to host error numbers. */ +#define E(X) case GDB_E##X: err = E##X; break + switch (err) { + case 0: + break; + E(PERM); + E(NOENT); + E(INTR); + E(BADF); + E(ACCES); + E(FAULT); + E(BUSY); + E(EXIST); + E(NODEV); + E(NOTDIR); + E(ISDIR); + E(INVAL); + E(NFILE); + E(MFILE); + E(FBIG); + E(NOSPC); + E(SPIPE); + E(ROFS); + E(NAMETOOLONG); + default: + err = EINVAL; + break; + } +#undef E + + gdbserver_syscall_state.current_syscall_cb(gdbserver_state.c_cpu, + ret, err); + gdbserver_syscall_state.current_syscall_cb = NULL; + } + + if (params->len >= 3 && get_param(params, 2)->opcode == (uint8_t)'C') { + gdb_put_packet("T02"); + return; + } + + gdb_continue(); +} diff --git a/gdbstub/user.c b/gdbstub/user.c index 3f6183e66a..3da410e221 100644 --- a/gdbstub/user.c +++ b/gdbstub/user.c @@ -15,6 +15,7 @@ #include "exec/hwaddr.h" #include "exec/tb-flush.h" #include "exec/gdbstub.h" +#include "gdbstub/syscalls.h" #include "gdbstub/user.h" #include "hw/core/cpu.h" #include "trace.h" diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h dissimilarity index 71% index bb8a3928dd..7d743fe1e9 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -1,146 +1,44 @@ -#ifndef GDBSTUB_H -#define GDBSTUB_H - -#define DEFAULT_GDBSTUB_PORT "1234" - -/* GDB breakpoint/watchpoint types */ -#define GDB_BREAKPOINT_SW 0 -#define GDB_BREAKPOINT_HW 1 -#define GDB_WATCHPOINT_WRITE 2 -#define GDB_WATCHPOINT_READ 3 -#define GDB_WATCHPOINT_ACCESS 4 - -/* For gdb file i/o remote protocol open flags. */ -#define GDB_O_RDONLY 0 -#define GDB_O_WRONLY 1 -#define GDB_O_RDWR 2 -#define GDB_O_APPEND 8 -#define GDB_O_CREAT 0x200 -#define GDB_O_TRUNC 0x400 -#define GDB_O_EXCL 0x800 - -/* For gdb file i/o remote protocol errno values */ -#define GDB_EPERM 1 -#define GDB_ENOENT 2 -#define GDB_EINTR 4 -#define GDB_EBADF 9 -#define GDB_EACCES 13 -#define GDB_EFAULT 14 -#define GDB_EBUSY 16 -#define GDB_EEXIST 17 -#define GDB_ENODEV 19 -#define GDB_ENOTDIR 20 -#define GDB_EISDIR 21 -#define GDB_EINVAL 22 -#define GDB_ENFILE 23 -#define GDB_EMFILE 24 -#define GDB_EFBIG 27 -#define GDB_ENOSPC 28 -#define GDB_ESPIPE 29 -#define GDB_EROFS 30 -#define GDB_ENAMETOOLONG 91 -#define GDB_EUNKNOWN 9999 - -/* For gdb file i/o remote protocol lseek whence. */ -#define GDB_SEEK_SET 0 -#define GDB_SEEK_CUR 1 -#define GDB_SEEK_END 2 - -/* For gdb file i/o stat/fstat. */ -typedef uint32_t gdb_mode_t; -typedef uint32_t gdb_time_t; - -struct gdb_stat { - uint32_t gdb_st_dev; /* device */ - uint32_t gdb_st_ino; /* inode */ - gdb_mode_t gdb_st_mode; /* protection */ - uint32_t gdb_st_nlink; /* number of hard links */ - uint32_t gdb_st_uid; /* user ID of owner */ - uint32_t gdb_st_gid; /* group ID of owner */ - uint32_t gdb_st_rdev; /* device type (if inode device) */ - uint64_t gdb_st_size; /* total size, in bytes */ - uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */ - uint64_t gdb_st_blocks; /* number of blocks allocated */ - gdb_time_t gdb_st_atime; /* time of last access */ - gdb_time_t gdb_st_mtime; /* time of last modification */ - gdb_time_t gdb_st_ctime; /* time of last change */ -} QEMU_PACKED; - -struct gdb_timeval { - gdb_time_t tv_sec; /* second */ - uint64_t tv_usec; /* microsecond */ -} QEMU_PACKED; - -typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, uint64_t ret, int err); - -/** - * gdb_do_syscall: - * @cb: function to call when the system call has completed - * @fmt: gdb syscall format string - * ...: list of arguments to interpolate into @fmt - * - * Send a GDB syscall request. This function will return immediately; - * the callback function will be called later when the remote system - * call has completed. - * - * @fmt should be in the 'call-id,parameter,parameter...' format documented - * for the F request packet in the GDB remote protocol. A limited set of - * printf-style format specifiers is supported: - * %x - target_ulong argument printed in hex - * %lx - 64-bit argument printed in hex - * %s - string pointer (target_ulong) and length (int) pair - */ -void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...); -/** - * gdb_do_syscallv: - * @cb: function to call when the system call has completed - * @fmt: gdb syscall format string - * @va: arguments to interpolate into @fmt - * - * As gdb_do_syscall, but taking a va_list rather than a variable - * argument list. - */ -void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va); -int use_gdb_syscalls(void); - -/* Get or set a register. Returns the size of the register. */ -typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg); -typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg); -void gdb_register_coprocessor(CPUState *cpu, - gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg, - int num_regs, const char *xml, int g_pos); - -/** - * gdbserver_start: start the gdb server - * @port_or_device: connection spec for gdb - * - * For CONFIG_USER this is either a tcp port or a path to a fifo. For - * system emulation you can use a full chardev spec for your gdbserver - * port. - */ -int gdbserver_start(const char *port_or_device); - -/** - * gdb_exit: exit gdb session, reporting inferior status - * @code: exit code reported - * - * This closes the session and sends a final packet to GDB reporting - * the exit status of the program. It also cleans up any connections - * detritus before returning. - */ -void gdb_exit(int code); - -void gdb_set_stop_cpu(CPUState *cpu); - -/** - * gdb_has_xml: - * This is an ugly hack to cope with both new and old gdb. - * If gdb sends qXfer:features:read then assume we're talking to a newish - * gdb that understands target descriptions. - */ -extern bool gdb_has_xml; - -/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ -extern const char *const xml_builtin[][2]; - -#endif +#ifndef GDBSTUB_H +#define GDBSTUB_H + +#define DEFAULT_GDBSTUB_PORT "1234" + +/* GDB breakpoint/watchpoint types */ +#define GDB_BREAKPOINT_SW 0 +#define GDB_BREAKPOINT_HW 1 +#define GDB_WATCHPOINT_WRITE 2 +#define GDB_WATCHPOINT_READ 3 +#define GDB_WATCHPOINT_ACCESS 4 + + +/* Get or set a register. Returns the size of the register. */ +typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg); +typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg); +void gdb_register_coprocessor(CPUState *cpu, + gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg, + int num_regs, const char *xml, int g_pos); + +/** + * gdbserver_start: start the gdb server + * @port_or_device: connection spec for gdb + * + * For CONFIG_USER this is either a tcp port or a path to a fifo. For + * system emulation you can use a full chardev spec for your gdbserver + * port. + */ +int gdbserver_start(const char *port_or_device); + +void gdb_set_stop_cpu(CPUState *cpu); + +/** + * gdb_has_xml: + * This is an ugly hack to cope with both new and old gdb. + * If gdb sends qXfer:features:read then assume we're talking to a newish + * gdb that understands target descriptions. + */ +extern bool gdb_has_xml; + +/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ +extern const char *const xml_builtin[][2]; + +#endif diff --git a/include/exec/gdbstub.h b/include/gdbstub/syscalls.h similarity index 72% copy from include/exec/gdbstub.h copy to include/gdbstub/syscalls.h index bb8a3928dd..5851a2c706 100644 --- a/include/exec/gdbstub.h +++ b/include/gdbstub/syscalls.h @@ -1,14 +1,13 @@ -#ifndef GDBSTUB_H -#define GDBSTUB_H - -#define DEFAULT_GDBSTUB_PORT "1234" +/* + * GDB Syscall support + * + * Copyright (c) 2023 Linaro Ltd + * + * SPDX-License-Identifier: LGPL-2.0+ + */ -/* GDB breakpoint/watchpoint types */ -#define GDB_BREAKPOINT_SW 0 -#define GDB_BREAKPOINT_HW 1 -#define GDB_WATCHPOINT_WRITE 2 -#define GDB_WATCHPOINT_READ 3 -#define GDB_WATCHPOINT_ACCESS 4 +#ifndef _SYSCALLS_H_ +#define _SYSCALLS_H_ /* For gdb file i/o remote protocol open flags. */ #define GDB_O_RDONLY 0 @@ -91,6 +90,7 @@ typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, uint64_t ret, int err); * %s - string pointer (target_ulong) and length (int) pair */ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...); + /** * gdb_do_syscallv: * @cb: function to call when the system call has completed @@ -101,24 +101,15 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...); * argument list. */ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va); -int use_gdb_syscalls(void); - -/* Get or set a register. Returns the size of the register. */ -typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg); -typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg); -void gdb_register_coprocessor(CPUState *cpu, - gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg, - int num_regs, const char *xml, int g_pos); /** - * gdbserver_start: start the gdb server - * @port_or_device: connection spec for gdb + * use_gdb_syscalls() - report if GDB should be used for syscalls * - * For CONFIG_USER this is either a tcp port or a path to a fifo. For - * system emulation you can use a full chardev spec for your gdbserver - * port. + * This is mostly driven by the semihosting mode the user configures + * but assuming GDB is allowed by that we report true if GDB is + * connected to the stub. */ -int gdbserver_start(const char *port_or_device); +int use_gdb_syscalls(void); /** * gdb_exit: exit gdb session, reporting inferior status @@ -130,17 +121,4 @@ int gdbserver_start(const char *port_or_device); */ void gdb_exit(int code); -void gdb_set_stop_cpu(CPUState *cpu); - -/** - * gdb_has_xml: - * This is an ugly hack to cope with both new and old gdb. - * If gdb sends qXfer:features:read then assume we're talking to a newish - * gdb that understands target descriptions. - */ -extern bool gdb_has_xml; - -/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ -extern const char *const xml_builtin[][2]; - -#endif +#endif /* _SYSCALLS_H_ */ diff --git a/linux-user/exit.c b/linux-user/exit.c index 607b6da9fc..fd49d76f45 100644 --- a/linux-user/exit.c +++ b/linux-user/exit.c @@ -18,7 +18,7 @@ */ #include "qemu/osdep.h" #include "accel/tcg/perf.h" -#include "exec/gdbstub.h" +#include "gdbstub/syscalls.h" #include "qemu.h" #include "user-internals.h" #ifdef CONFIG_GPROF diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c index 62d8bae97f..564fe17f75 100644 --- a/semihosting/arm-compat-semi.c +++ b/semihosting/arm-compat-semi.c @@ -34,6 +34,7 @@ #include "qemu/osdep.h" #include "qemu/timer.h" #include "exec/gdbstub.h" +#include "gdbstub/syscalls.h" #include "semihosting/semihost.h" #include "semihosting/console.h" #include "semihosting/common-semi.h" diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c index b05c52f26f..acb86b50dd 100644 --- a/semihosting/guestfd.c +++ b/semihosting/guestfd.c @@ -9,7 +9,7 @@ */ #include "qemu/osdep.h" -#include "exec/gdbstub.h" +#include "gdbstub/syscalls.h" #include "semihosting/semihost.h" #include "semihosting/guestfd.h" #ifdef CONFIG_USER_ONLY diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c index d69078899a..42080ffdda 100644 --- a/semihosting/syscalls.c +++ b/semihosting/syscalls.c @@ -7,8 +7,8 @@ */ #include "qemu/osdep.h" -#include "exec/gdbstub.h" #include "cpu.h" +#include "gdbstub/syscalls.h" #include "semihosting/guestfd.h" #include "semihosting/syscalls.h" #include "semihosting/console.h" diff --git a/softmmu/runstate.c b/softmmu/runstate.c index 9b3611d56d..d1e04586db 100644 --- a/softmmu/runstate.c +++ b/softmmu/runstate.c @@ -30,7 +30,7 @@ #include "crypto/cipher.h" #include "crypto/init.h" #include "exec/cpu-common.h" -#include "exec/gdbstub.h" +#include "gdbstub/syscalls.h" #include "hw/boards.h" #include "migration/misc.h" #include "migration/postcopy-ram.h" diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c index f753710d7d..88ad9ba814 100644 --- a/target/m68k/m68k-semi.c +++ b/target/m68k/m68k-semi.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/gdbstub.h" +#include "gdbstub/syscalls.h" #include "gdbstub/helpers.h" #include "semihosting/syscalls.h" #include "semihosting/softmmu-uaccess.h" diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c index 4e6e759057..f3735df7b9 100644 --- a/target/mips/tcg/sysemu/mips-semi.c +++ b/target/mips/tcg/sysemu/mips-semi.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "qemu/log.h" -#include "exec/gdbstub.h" +#include "gdbstub/syscalls.h" #include "gdbstub/helpers.h" #include "semihosting/softmmu-uaccess.h" #include "semihosting/semihost.h" diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c index 113b3f22aa..3738774976 100644 --- a/target/nios2/nios2-semi.c +++ b/target/nios2/nios2-semi.c @@ -23,7 +23,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/gdbstub.h" +#include "gdbstub/syscalls.h" #include "gdbstub/helpers.h" #include "semihosting/syscalls.h" #include "semihosting/softmmu-uaccess.h" -- 2.11.4.GIT