qemu
1/*
2* GDB Syscall Handling
3*
4* GDB can execute syscalls on the guests behalf, currently used by
5* the various semihosting extensions.
6*
7* Copyright (c) 2003-2005 Fabrice Bellard
8* Copyright (c) 2023 Linaro Ltd
9*
10* SPDX-License-Identifier: LGPL-2.0+
11*/
12
13#include "qemu/osdep.h"14#include "qemu/error-report.h"15#include "semihosting/semihost.h"16#include "sysemu/runstate.h"17#include "gdbstub/user.h"18#include "gdbstub/syscalls.h"19#include "gdbstub/commands.h"20#include "trace.h"21#include "internals.h"22
23/* Syscall specific state */
24typedef struct {25char syscall_buf[256];26gdb_syscall_complete_cb current_syscall_cb;27} GDBSyscallState;28
29static GDBSyscallState gdbserver_syscall_state;30
31/*
32* Return true if there is a GDB currently connected to the stub
33* and attached to a CPU
34*/
35static bool gdb_attached(void)36{
37return gdbserver_state.init && gdbserver_state.c_cpu;38}
39
40static enum {41GDB_SYS_UNKNOWN,42GDB_SYS_ENABLED,43GDB_SYS_DISABLED,44} gdb_syscall_mode;45
46/* Decide if either remote gdb syscalls or native file IO should be used. */
47int use_gdb_syscalls(void)48{
49SemihostingTarget target = semihosting_get_target();50if (target == SEMIHOSTING_TARGET_NATIVE) {51/* -semihosting-config target=native */52return false;53} else if (target == SEMIHOSTING_TARGET_GDB) {54/* -semihosting-config target=gdb */55return true;56}57
58/* -semihosting-config target=auto */59/* On the first call check if gdb is connected and remember. */60if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {61gdb_syscall_mode = gdb_attached() ? GDB_SYS_ENABLED : GDB_SYS_DISABLED;62}63return gdb_syscall_mode == GDB_SYS_ENABLED;64}
65
66/* called when the stub detaches */
67void gdb_disable_syscalls(void)68{
69gdb_syscall_mode = GDB_SYS_DISABLED;70}
71
72void gdb_syscall_reset(void)73{
74gdbserver_syscall_state.current_syscall_cb = NULL;75}
76
77bool gdb_handled_syscall(void)78{
79if (gdbserver_syscall_state.current_syscall_cb) {80gdb_put_packet(gdbserver_syscall_state.syscall_buf);81return true;82}83
84return false;85}
86
87/*
88* Send a gdb syscall request.
89* This accepts limited printf-style format specifiers, specifically:
90* %x - target_ulong argument printed in hex.
91* %lx - 64-bit argument printed in hex.
92* %s - string pointer (target_ulong) and length (int) pair.
93*/
94void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)95{
96char *p, *p_end;97va_list va;98
99if (!gdb_attached()) {100return;101}102
103gdbserver_syscall_state.current_syscall_cb = cb;104va_start(va, fmt);105
106p = gdbserver_syscall_state.syscall_buf;107p_end = p + sizeof(gdbserver_syscall_state.syscall_buf);108*(p++) = 'F';109while (*fmt) {110if (*fmt == '%') {111uint64_t i64;112uint32_t i32;113
114fmt++;115switch (*fmt++) {116case 'x':117i32 = va_arg(va, uint32_t);118p += snprintf(p, p_end - p, "%" PRIx32, i32);119break;120case 'l':121if (*(fmt++) != 'x') {122goto bad_format;123}124i64 = va_arg(va, uint64_t);125p += snprintf(p, p_end - p, "%" PRIx64, i64);126break;127case 's':128i64 = va_arg(va, uint64_t);129i32 = va_arg(va, uint32_t);130p += snprintf(p, p_end - p, "%" PRIx64 "/%x" PRIx32, i64, i32);131break;132default:133bad_format:134error_report("gdbstub: Bad syscall format string '%s'",135fmt - 1);136break;137}138} else {139*(p++) = *(fmt++);140}141}142*p = 0;143
144va_end(va);145gdb_syscall_handling(gdbserver_syscall_state.syscall_buf);146}
147
148/*
149* GDB Command Handlers
150*/
151
152void gdb_handle_file_io(GArray *params, void *user_ctx)153{
154if (params->len >= 1 && gdbserver_syscall_state.current_syscall_cb) {155uint64_t ret;156int err;157
158ret = gdb_get_cmd_param(params, 0)->val_ull;159if (params->len >= 2) {160err = gdb_get_cmd_param(params, 1)->val_ull;161} else {162err = 0;163}164
165/* Convert GDB error numbers back to host error numbers. */166#define E(X) case GDB_E##X: err = E##X; break167switch (err) {168case 0:169break;170E(PERM);171E(NOENT);172E(INTR);173E(BADF);174E(ACCES);175E(FAULT);176E(BUSY);177E(EXIST);178E(NODEV);179E(NOTDIR);180E(ISDIR);181E(INVAL);182E(NFILE);183E(MFILE);184E(FBIG);185E(NOSPC);186E(SPIPE);187E(ROFS);188E(NAMETOOLONG);189default:190err = EINVAL;191break;192}193#undef E194
195gdbserver_syscall_state.current_syscall_cb(gdbserver_state.c_cpu,196ret, err);197gdbserver_syscall_state.current_syscall_cb = NULL;198}199
200if (params->len >= 3 && gdb_get_cmd_param(params, 2)->opcode == (uint8_t)'C') {201gdb_put_packet("T02");202return;203}204
205gdb_continue();206}
207