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