master
c 429 lines 10.1 KB
Raw
1 /*
2 * Target specific user-mode handling
3 *
4 * Copyright (c) 2003-2005 Fabrice Bellard
5 * Copyright (c) 2022 Linaro Ltd
6 *
7 * SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9
10 #include "qemu/osdep.h"
11 #include "exec/gdbstub.h"
12 #include "gdbstub/commands.h"
13 #include "gdbstub/syscalls.h"
14 #include "qemu.h"
15 #include "internals.h"
16 #ifdef CONFIG_LINUX
17 #include "linux-user/loader.h"
18 #include "linux-user/qemu.h"
19 #endif
20
21 /*
22 * Map target signal numbers to GDB protocol signal numbers and vice
23 * versa. For user emulation's currently supported systems, we can
24 * assume most signals are defined.
25 */
26
27 static int gdb_signal_table[] = {
28 0,
29 TARGET_SIGHUP,
30 TARGET_SIGINT,
31 TARGET_SIGQUIT,
32 TARGET_SIGILL,
33 TARGET_SIGTRAP,
34 TARGET_SIGABRT,
35 -1, /* SIGEMT */
36 TARGET_SIGFPE,
37 TARGET_SIGKILL,
38 TARGET_SIGBUS,
39 TARGET_SIGSEGV,
40 TARGET_SIGSYS,
41 TARGET_SIGPIPE,
42 TARGET_SIGALRM,
43 TARGET_SIGTERM,
44 TARGET_SIGURG,
45 TARGET_SIGSTOP,
46 TARGET_SIGTSTP,
47 TARGET_SIGCONT,
48 TARGET_SIGCHLD,
49 TARGET_SIGTTIN,
50 TARGET_SIGTTOU,
51 TARGET_SIGIO,
52 TARGET_SIGXCPU,
53 TARGET_SIGXFSZ,
54 TARGET_SIGVTALRM,
55 TARGET_SIGPROF,
56 TARGET_SIGWINCH,
57 -1, /* SIGLOST */
58 TARGET_SIGUSR1,
59 TARGET_SIGUSR2,
60 #ifdef TARGET_SIGPWR
61 TARGET_SIGPWR,
62 #else
63 -1,
64 #endif
65 -1, /* SIGPOLL */
66 -1,
67 -1,
68 -1,
69 -1,
70 -1,
71 -1,
72 -1,
73 -1,
74 -1,
75 -1,
76 -1,
77 #ifdef __SIGRTMIN
78 __SIGRTMIN + 1,
79 __SIGRTMIN + 2,
80 __SIGRTMIN + 3,
81 __SIGRTMIN + 4,
82 __SIGRTMIN + 5,
83 __SIGRTMIN + 6,
84 __SIGRTMIN + 7,
85 __SIGRTMIN + 8,
86 __SIGRTMIN + 9,
87 __SIGRTMIN + 10,
88 __SIGRTMIN + 11,
89 __SIGRTMIN + 12,
90 __SIGRTMIN + 13,
91 __SIGRTMIN + 14,
92 __SIGRTMIN + 15,
93 __SIGRTMIN + 16,
94 __SIGRTMIN + 17,
95 __SIGRTMIN + 18,
96 __SIGRTMIN + 19,
97 __SIGRTMIN + 20,
98 __SIGRTMIN + 21,
99 __SIGRTMIN + 22,
100 __SIGRTMIN + 23,
101 __SIGRTMIN + 24,
102 __SIGRTMIN + 25,
103 __SIGRTMIN + 26,
104 __SIGRTMIN + 27,
105 __SIGRTMIN + 28,
106 __SIGRTMIN + 29,
107 __SIGRTMIN + 30,
108 __SIGRTMIN + 31,
109 -1, /* SIGCANCEL */
110 __SIGRTMIN,
111 __SIGRTMIN + 32,
112 __SIGRTMIN + 33,
113 __SIGRTMIN + 34,
114 __SIGRTMIN + 35,
115 __SIGRTMIN + 36,
116 __SIGRTMIN + 37,
117 __SIGRTMIN + 38,
118 __SIGRTMIN + 39,
119 __SIGRTMIN + 40,
120 __SIGRTMIN + 41,
121 __SIGRTMIN + 42,
122 __SIGRTMIN + 43,
123 __SIGRTMIN + 44,
124 __SIGRTMIN + 45,
125 __SIGRTMIN + 46,
126 __SIGRTMIN + 47,
127 __SIGRTMIN + 48,
128 __SIGRTMIN + 49,
129 __SIGRTMIN + 50,
130 __SIGRTMIN + 51,
131 __SIGRTMIN + 52,
132 __SIGRTMIN + 53,
133 __SIGRTMIN + 54,
134 __SIGRTMIN + 55,
135 __SIGRTMIN + 56,
136 __SIGRTMIN + 57,
137 __SIGRTMIN + 58,
138 __SIGRTMIN + 59,
139 __SIGRTMIN + 60,
140 __SIGRTMIN + 61,
141 __SIGRTMIN + 62,
142 __SIGRTMIN + 63,
143 __SIGRTMIN + 64,
144 __SIGRTMIN + 65,
145 __SIGRTMIN + 66,
146 __SIGRTMIN + 67,
147 __SIGRTMIN + 68,
148 __SIGRTMIN + 69,
149 __SIGRTMIN + 70,
150 __SIGRTMIN + 71,
151 __SIGRTMIN + 72,
152 __SIGRTMIN + 73,
153 __SIGRTMIN + 74,
154 __SIGRTMIN + 75,
155 __SIGRTMIN + 76,
156 __SIGRTMIN + 77,
157 __SIGRTMIN + 78,
158 __SIGRTMIN + 79,
159 __SIGRTMIN + 80,
160 __SIGRTMIN + 81,
161 __SIGRTMIN + 82,
162 __SIGRTMIN + 83,
163 __SIGRTMIN + 84,
164 __SIGRTMIN + 85,
165 __SIGRTMIN + 86,
166 __SIGRTMIN + 87,
167 __SIGRTMIN + 88,
168 __SIGRTMIN + 89,
169 __SIGRTMIN + 90,
170 __SIGRTMIN + 91,
171 __SIGRTMIN + 92,
172 __SIGRTMIN + 93,
173 __SIGRTMIN + 94,
174 __SIGRTMIN + 95,
175 -1, /* SIGINFO */
176 -1, /* UNKNOWN */
177 -1, /* DEFAULT */
178 -1,
179 -1,
180 -1,
181 -1,
182 -1,
183 -1
184 #endif
185 };
186
187 int gdb_signal_to_target(int sig)
188 {
189 if (sig < ARRAY_SIZE(gdb_signal_table)) {
190 return gdb_signal_table[sig];
191 } else {
192 return -1;
193 }
194 }
195
196 int gdb_target_signal_to_gdb(int sig)
197 {
198 int i;
199 for (i = 0; i < ARRAY_SIZE(gdb_signal_table); i++) {
200 if (gdb_signal_table[i] == sig) {
201 return i;
202 }
203 }
204 return GDB_SIGNAL_UNKNOWN;
205 }
206
207 int gdb_get_cpu_index(CPUState *cpu)
208 {
209 TaskState *ts = get_task_state(cpu);
210 return ts ? ts->ts_tid : -1;
211 }
212
213 /*
214 * User-mode specific command helpers
215 */
216
217 void gdb_handle_query_offsets(GArray *params, void *user_ctx)
218 {
219 TaskState *ts;
220
221 ts = get_task_state(gdbserver_state.c_cpu);
222 g_string_printf(gdbserver_state.str_buf,
223 "Text=" TARGET_ABI_FMT_lx
224 ";Data=" TARGET_ABI_FMT_lx
225 ";Bss=" TARGET_ABI_FMT_lx,
226 ts->info->code_offset,
227 ts->info->data_offset,
228 ts->info->data_offset);
229 gdb_put_strbuf();
230 }
231
232 #if defined(CONFIG_LINUX)
233 /* Partial user only duplicate of helper in gdbstub.c */
234 static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
235 uint8_t *buf, int len, bool is_write)
236 {
237 if (cpu->cc->memory_rw_debug) {
238 return cpu->cc->memory_rw_debug(cpu, addr, buf, len, is_write);
239 }
240 return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
241 }
242
243 void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx)
244 {
245 TaskState *ts;
246 unsigned long offset, len, saved_auxv, auxv_len;
247
248 if (params->len < 2) {
249 gdb_put_packet("E22");
250 return;
251 }
252
253 offset = gdb_get_cmd_param(params, 0)->val_ul;
254 len = gdb_get_cmd_param(params, 1)->val_ul;
255 ts = get_task_state(gdbserver_state.c_cpu);
256 saved_auxv = ts->info->saved_auxv;
257 auxv_len = ts->info->auxv_len;
258
259 if (offset >= auxv_len) {
260 gdb_put_packet("E00");
261 return;
262 }
263
264 if (len > (MAX_PACKET_LENGTH - 5) / 2) {
265 len = (MAX_PACKET_LENGTH - 5) / 2;
266 }
267
268 if (len < auxv_len - offset) {
269 g_string_assign(gdbserver_state.str_buf, "m");
270 } else {
271 g_string_assign(gdbserver_state.str_buf, "l");
272 len = auxv_len - offset;
273 }
274
275 g_byte_array_set_size(gdbserver_state.mem_buf, len);
276 if (target_memory_rw_debug(gdbserver_state.g_cpu, saved_auxv + offset,
277 gdbserver_state.mem_buf->data, len, false)) {
278 gdb_put_packet("E14");
279 return;
280 }
281
282 gdb_memtox(gdbserver_state.str_buf,
283 (const char *)gdbserver_state.mem_buf->data, len);
284 gdb_put_packet_binary(gdbserver_state.str_buf->str,
285 gdbserver_state.str_buf->len, true);
286 }
287 #endif
288
289 static const char *get_filename_param(GArray *params, int i)
290 {
291 const char *hex_filename = gdb_get_cmd_param(params, i)->data;
292 gdb_hextomem(gdbserver_state.mem_buf, hex_filename,
293 strlen(hex_filename) / 2);
294 g_byte_array_append(gdbserver_state.mem_buf, (const guint8 *)"", 1);
295 return (const char *)gdbserver_state.mem_buf->data;
296 }
297
298 static void hostio_reply_with_data(const void *buf, size_t n)
299 {
300 g_string_printf(gdbserver_state.str_buf, "F%zx;", n);
301 gdb_memtox(gdbserver_state.str_buf, buf, n);
302 gdb_put_packet_binary(gdbserver_state.str_buf->str,
303 gdbserver_state.str_buf->len, true);
304 }
305
306 void gdb_handle_v_file_open(GArray *params, void *user_ctx)
307 {
308 const char *filename = get_filename_param(params, 0);
309 uint64_t flags = gdb_get_cmd_param(params, 1)->val_ull;
310 uint64_t mode = gdb_get_cmd_param(params, 2)->val_ull;
311
312 #ifdef CONFIG_LINUX
313 int fd = do_guest_openat(cpu_env(gdbserver_state.g_cpu), 0, filename,
314 flags, mode, false);
315 #else
316 int fd = open(filename, flags, mode);
317 #endif
318 if (fd < 0) {
319 int gdb_errno = host_to_gdb_errno(errno);
320 g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
321 } else {
322 g_string_printf(gdbserver_state.str_buf, "F%x", fd);
323 }
324 gdb_put_strbuf();
325 }
326
327 void gdb_handle_v_file_close(GArray *params, void *user_ctx)
328 {
329 int fd = gdb_get_cmd_param(params, 0)->val_ul;
330
331 if (close(fd) == -1) {
332 int gdb_errno = host_to_gdb_errno(errno);
333 g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
334 gdb_put_strbuf();
335 return;
336 }
337
338 gdb_put_packet("F00");
339 }
340
341 void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
342 {
343 int fd = gdb_get_cmd_param(params, 0)->val_ul;
344 size_t count = gdb_get_cmd_param(params, 1)->val_ull;
345 off_t offset = gdb_get_cmd_param(params, 2)->val_ull;
346
347 size_t bufsiz = MIN(count, BUFSIZ);
348 g_autofree char *buf = g_try_malloc(bufsiz);
349 if (buf == NULL) {
350 gdb_put_packet("E12");
351 return;
352 }
353
354 ssize_t n = pread(fd, buf, bufsiz, offset);
355 if (n < 0) {
356 int gdb_errno = host_to_gdb_errno(errno);
357 g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
358 gdb_put_strbuf();
359 return;
360 }
361 hostio_reply_with_data(buf, n);
362 }
363
364 void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
365 {
366 const char *filename = get_filename_param(params, 0);
367
368 g_autofree char *buf = g_try_malloc(BUFSIZ);
369 if (buf == NULL) {
370 gdb_put_packet("E12");
371 return;
372 }
373
374 #ifdef CONFIG_LINUX
375 ssize_t n = do_guest_readlink(filename, buf, BUFSIZ);
376 #else
377 ssize_t n = readlink(filename, buf, BUFSIZ);
378 #endif
379 if (n < 0) {
380 int gdb_errno = host_to_gdb_errno(errno);
381 g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
382 gdb_put_strbuf();
383 return;
384 }
385 hostio_reply_with_data(buf, n);
386 }
387
388 void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
389 {
390 uint32_t pid = gdb_get_cmd_param(params, 0)->val_ul;
391 uint32_t offset = gdb_get_cmd_param(params, 1)->val_ul;
392 uint32_t length = gdb_get_cmd_param(params, 2)->val_ul;
393
394 GDBProcess *process = gdb_get_process(pid);
395 if (!process) {
396 gdb_put_packet("E00");
397 return;
398 }
399
400 CPUState *cpu = gdb_get_first_cpu_in_process(process);
401 if (!cpu) {
402 gdb_put_packet("E00");
403 return;
404 }
405
406 TaskState *ts = get_task_state(cpu);
407 if (!ts || !ts->bprm || !ts->bprm->filename) {
408 gdb_put_packet("E00");
409 return;
410 }
411
412 size_t total_length = strlen(ts->bprm->filename);
413 if (offset > total_length) {
414 gdb_put_packet("E00");
415 return;
416 }
417 if (offset + length > total_length) {
418 length = total_length - offset;
419 }
420
421 g_string_printf(gdbserver_state.str_buf, "l%.*s", length,
422 ts->bprm->filename + offset);
423 gdb_put_strbuf();
424 }
425
426 int gdb_target_sigtrap(void)
427 {
428 return TARGET_SIGTRAP;
429 }