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 */ 24 typedef struct { 25 char syscall_buf[256]; 26 gdb_syscall_complete_cb current_syscall_cb; 27 } GDBSyscallState; 28 29 static 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 */ 35 static bool gdb_attached(void) 36 { 37 return gdbserver_state.init && gdbserver_state.c_cpu; 38 } 39 40 static 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. */ 47 int 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 */ 67 void gdb_disable_syscalls(void) 68 { 69 gdb_syscall_mode = GDB_SYS_DISABLED; 70 } 71 72 void gdb_syscall_reset(void) 73 { 74 gdbserver_syscall_state.current_syscall_cb = NULL; 75 } 76 77 bool 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 */ 94 void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) 95 { 96 char *p, *p_end; 97 va_list va; 98 99 if (!gdb_attached()) { 100 return; 101 } 102 103 gdbserver_syscall_state.current_syscall_cb = cb; 104 va_start(va, fmt); 105 106 p = gdbserver_syscall_state.syscall_buf; 107 p_end = p + sizeof(gdbserver_syscall_state.syscall_buf); 108 *(p++) = 'F'; 109 while (*fmt) { 110 if (*fmt == '%') { 111 uint64_t i64; 112 uint32_t i32; 113 114 fmt++; 115 switch (*fmt++) { 116 case 'x': 117 i32 = va_arg(va, uint32_t); 118 p += snprintf(p, p_end - p, "%" PRIx32, i32); 119 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': 128 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); 131 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; 143 144 va_end(va); 145 gdb_syscall_handling(gdbserver_syscall_state.syscall_buf); 146 } 147 148 /* 149 * GDB Command Handlers 150 */ 151 152 void 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 158 ret = gdb_get_cmd_param(params, 0)->val_ull; 159 if (params->len >= 2) { 160 err = gdb_get_cmd_param(params, 1)->val_ull; 161 } 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 200 if (params->len >= 3 && gdb_get_cmd_param(params, 2)->opcode == (uint8_t)'C') { 201 gdb_put_packet("T02"); 202 return; 203 } 204 205 gdb_continue(); 206 } 207