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