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