blob: 4e1295b782db5fa05efb8940380563a2ee552840 [file] [log] [blame]
Alex Bennéec5660802023-03-02 18:57:57 -08001/*
2 * GDB Syscall Handling
3 *
4 * GDB can execute syscalls on the guests behalf, currently used by
Richard Henderson2d3d2512023-03-02 18:58:04 -08005 * the various semihosting extensions.
Alex Bennéec5660802023-03-02 18:57:57 -08006 *
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"
Alex Bennéec5660802023-03-02 18:57:57 -080015#include "semihosting/semihost.h"
16#include "sysemu/runstate.h"
17#include "gdbstub/user.h"
18#include "gdbstub/syscalls.h"
Gustavo Romero133f2022024-07-05 09:40:38 +010019#include "gdbstub/commands.h"
Alex Bennéec5660802023-03-02 18:57:57 -080020#include "trace.h"
21#include "internals.h"
22
23/* Syscall specific state */
24typedef struct {
25 char syscall_buf[256];
26 gdb_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{
37 return gdbserver_state.init && gdbserver_state.c_cpu;
38}
39
40static enum {
41 GDB_SYS_UNKNOWN,
42 GDB_SYS_ENABLED,
43 GDB_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{
49 SemihostingTarget target = semihosting_get_target();
50 if (target == SEMIHOSTING_TARGET_NATIVE) {
51 /* -semihosting-config target=native */
52 return false;
53 } else if (target == SEMIHOSTING_TARGET_GDB) {
54 /* -semihosting-config target=gdb */
55 return true;
56 }
57
58 /* -semihosting-config target=auto */
59 /* On the first call check if gdb is connected and remember. */
60 if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
61 gdb_syscall_mode = gdb_attached() ? GDB_SYS_ENABLED : GDB_SYS_DISABLED;
62 }
63 return gdb_syscall_mode == GDB_SYS_ENABLED;
64}
65
66/* called when the stub detaches */
67void gdb_disable_syscalls(void)
68{
69 gdb_syscall_mode = GDB_SYS_DISABLED;
70}
71
72void gdb_syscall_reset(void)
73{
74 gdbserver_syscall_state.current_syscall_cb = NULL;
75}
76
77bool gdb_handled_syscall(void)
78{
79 if (gdbserver_syscall_state.current_syscall_cb) {
80 gdb_put_packet(gdbserver_syscall_state.syscall_buf);
81 return true;
82 }
83
84 return 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 */
Richard Henderson2f70f2d2023-03-02 18:58:02 -080094void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
Alex Bennéec5660802023-03-02 18:57:57 -080095{
Richard Henderson2f70f2d2023-03-02 18:58:02 -080096 char *p, *p_end;
97 va_list va;
Alex Bennéec5660802023-03-02 18:57:57 -080098
99 if (!gdb_attached()) {
100 return;
101 }
102
103 gdbserver_syscall_state.current_syscall_cb = cb;
Richard Henderson2f70f2d2023-03-02 18:58:02 -0800104 va_start(va, fmt);
Alex Bennée131f3872023-03-02 18:58:01 -0800105
Richard Henderson2f70f2d2023-03-02 18:58:02 -0800106 p = gdbserver_syscall_state.syscall_buf;
107 p_end = p + sizeof(gdbserver_syscall_state.syscall_buf);
Alex Bennéec5660802023-03-02 18:57:57 -0800108 *(p++) = 'F';
109 while (*fmt) {
110 if (*fmt == '%') {
Richard Henderson2f70f2d2023-03-02 18:58:02 -0800111 uint64_t i64;
Richard Henderson0820a072023-03-02 18:58:03 -0800112 uint32_t i32;
Richard Henderson2f70f2d2023-03-02 18:58:02 -0800113
Alex Bennéec5660802023-03-02 18:57:57 -0800114 fmt++;
115 switch (*fmt++) {
116 case 'x':
Richard Henderson0820a072023-03-02 18:58:03 -0800117 i32 = va_arg(va, uint32_t);
118 p += snprintf(p, p_end - p, "%" PRIx32, i32);
Alex Bennéec5660802023-03-02 18:57:57 -0800119 break;
120 case 'l':
121 if (*(fmt++) != 'x') {
122 goto bad_format;
123 }
124 i64 = va_arg(va, uint64_t);
125 p += snprintf(p, p_end - p, "%" PRIx64, i64);
126 break;
127 case 's':
Richard Henderson0820a072023-03-02 18:58:03 -0800128 i64 = va_arg(va, uint64_t);
129 i32 = va_arg(va, uint32_t);
130 p += snprintf(p, p_end - p, "%" PRIx64 "/%x" PRIx32, i64, i32);
Alex Bennéec5660802023-03-02 18:57:57 -0800131 break;
132 default:
133 bad_format:
134 error_report("gdbstub: Bad syscall format string '%s'",
135 fmt - 1);
136 break;
137 }
138 } else {
139 *(p++) = *(fmt++);
140 }
141 }
142 *p = 0;
Alex Bennée131f3872023-03-02 18:58:01 -0800143
Alex Bennéec5660802023-03-02 18:57:57 -0800144 va_end(va);
Richard Henderson2f70f2d2023-03-02 18:58:02 -0800145 gdb_syscall_handling(gdbserver_syscall_state.syscall_buf);
Alex Bennéec5660802023-03-02 18:57:57 -0800146}
147
148/*
149 * GDB Command Handlers
150 */
151
152void gdb_handle_file_io(GArray *params, void *user_ctx)
153{
154 if (params->len >= 1 && gdbserver_syscall_state.current_syscall_cb) {
155 uint64_t ret;
156 int err;
157
Gustavo Romero133f2022024-07-05 09:40:38 +0100158 ret = gdb_get_cmd_param(params, 0)->val_ull;
Alex Bennéec5660802023-03-02 18:57:57 -0800159 if (params->len >= 2) {
Gustavo Romero133f2022024-07-05 09:40:38 +0100160 err = gdb_get_cmd_param(params, 1)->val_ull;
Alex Bennéec5660802023-03-02 18:57:57 -0800161 } else {
162 err = 0;
163 }
164
165 /* Convert GDB error numbers back to host error numbers. */
166#define E(X) case GDB_E##X: err = E##X; break
167 switch (err) {
168 case 0:
169 break;
170 E(PERM);
171 E(NOENT);
172 E(INTR);
173 E(BADF);
174 E(ACCES);
175 E(FAULT);
176 E(BUSY);
177 E(EXIST);
178 E(NODEV);
179 E(NOTDIR);
180 E(ISDIR);
181 E(INVAL);
182 E(NFILE);
183 E(MFILE);
184 E(FBIG);
185 E(NOSPC);
186 E(SPIPE);
187 E(ROFS);
188 E(NAMETOOLONG);
189 default:
190 err = EINVAL;
191 break;
192 }
193#undef E
194
195 gdbserver_syscall_state.current_syscall_cb(gdbserver_state.c_cpu,
196 ret, err);
197 gdbserver_syscall_state.current_syscall_cb = NULL;
198 }
199
Gustavo Romero133f2022024-07-05 09:40:38 +0100200 if (params->len >= 3 && gdb_get_cmd_param(params, 2)->opcode == (uint8_t)'C') {
Alex Bennéec5660802023-03-02 18:57:57 -0800201 gdb_put_packet("T02");
202 return;
203 }
204
205 gdb_continue();
206}