xref: /openbmc/qemu/gdbstub/user-target.c (revision 2f95279a)
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+
8  */
9 
10 #include "qemu/osdep.h"
11 #include "exec/gdbstub.h"
12 #include "qemu.h"
13 #include "internals.h"
14 #ifdef CONFIG_LINUX
15 #include "linux-user/loader.h"
16 #include "linux-user/qemu.h"
17 #endif
18 
19 /*
20  * Map target signal numbers to GDB protocol signal numbers and vice
21  * versa.  For user emulation's currently supported systems, we can
22  * assume most signals are defined.
23  */
24 
25 static int gdb_signal_table[] = {
26     0,
27     TARGET_SIGHUP,
28     TARGET_SIGINT,
29     TARGET_SIGQUIT,
30     TARGET_SIGILL,
31     TARGET_SIGTRAP,
32     TARGET_SIGABRT,
33     -1, /* SIGEMT */
34     TARGET_SIGFPE,
35     TARGET_SIGKILL,
36     TARGET_SIGBUS,
37     TARGET_SIGSEGV,
38     TARGET_SIGSYS,
39     TARGET_SIGPIPE,
40     TARGET_SIGALRM,
41     TARGET_SIGTERM,
42     TARGET_SIGURG,
43     TARGET_SIGSTOP,
44     TARGET_SIGTSTP,
45     TARGET_SIGCONT,
46     TARGET_SIGCHLD,
47     TARGET_SIGTTIN,
48     TARGET_SIGTTOU,
49     TARGET_SIGIO,
50     TARGET_SIGXCPU,
51     TARGET_SIGXFSZ,
52     TARGET_SIGVTALRM,
53     TARGET_SIGPROF,
54     TARGET_SIGWINCH,
55     -1, /* SIGLOST */
56     TARGET_SIGUSR1,
57     TARGET_SIGUSR2,
58 #ifdef TARGET_SIGPWR
59     TARGET_SIGPWR,
60 #else
61     -1,
62 #endif
63     -1, /* SIGPOLL */
64     -1,
65     -1,
66     -1,
67     -1,
68     -1,
69     -1,
70     -1,
71     -1,
72     -1,
73     -1,
74     -1,
75 #ifdef __SIGRTMIN
76     __SIGRTMIN + 1,
77     __SIGRTMIN + 2,
78     __SIGRTMIN + 3,
79     __SIGRTMIN + 4,
80     __SIGRTMIN + 5,
81     __SIGRTMIN + 6,
82     __SIGRTMIN + 7,
83     __SIGRTMIN + 8,
84     __SIGRTMIN + 9,
85     __SIGRTMIN + 10,
86     __SIGRTMIN + 11,
87     __SIGRTMIN + 12,
88     __SIGRTMIN + 13,
89     __SIGRTMIN + 14,
90     __SIGRTMIN + 15,
91     __SIGRTMIN + 16,
92     __SIGRTMIN + 17,
93     __SIGRTMIN + 18,
94     __SIGRTMIN + 19,
95     __SIGRTMIN + 20,
96     __SIGRTMIN + 21,
97     __SIGRTMIN + 22,
98     __SIGRTMIN + 23,
99     __SIGRTMIN + 24,
100     __SIGRTMIN + 25,
101     __SIGRTMIN + 26,
102     __SIGRTMIN + 27,
103     __SIGRTMIN + 28,
104     __SIGRTMIN + 29,
105     __SIGRTMIN + 30,
106     __SIGRTMIN + 31,
107     -1, /* SIGCANCEL */
108     __SIGRTMIN,
109     __SIGRTMIN + 32,
110     __SIGRTMIN + 33,
111     __SIGRTMIN + 34,
112     __SIGRTMIN + 35,
113     __SIGRTMIN + 36,
114     __SIGRTMIN + 37,
115     __SIGRTMIN + 38,
116     __SIGRTMIN + 39,
117     __SIGRTMIN + 40,
118     __SIGRTMIN + 41,
119     __SIGRTMIN + 42,
120     __SIGRTMIN + 43,
121     __SIGRTMIN + 44,
122     __SIGRTMIN + 45,
123     __SIGRTMIN + 46,
124     __SIGRTMIN + 47,
125     __SIGRTMIN + 48,
126     __SIGRTMIN + 49,
127     __SIGRTMIN + 50,
128     __SIGRTMIN + 51,
129     __SIGRTMIN + 52,
130     __SIGRTMIN + 53,
131     __SIGRTMIN + 54,
132     __SIGRTMIN + 55,
133     __SIGRTMIN + 56,
134     __SIGRTMIN + 57,
135     __SIGRTMIN + 58,
136     __SIGRTMIN + 59,
137     __SIGRTMIN + 60,
138     __SIGRTMIN + 61,
139     __SIGRTMIN + 62,
140     __SIGRTMIN + 63,
141     __SIGRTMIN + 64,
142     __SIGRTMIN + 65,
143     __SIGRTMIN + 66,
144     __SIGRTMIN + 67,
145     __SIGRTMIN + 68,
146     __SIGRTMIN + 69,
147     __SIGRTMIN + 70,
148     __SIGRTMIN + 71,
149     __SIGRTMIN + 72,
150     __SIGRTMIN + 73,
151     __SIGRTMIN + 74,
152     __SIGRTMIN + 75,
153     __SIGRTMIN + 76,
154     __SIGRTMIN + 77,
155     __SIGRTMIN + 78,
156     __SIGRTMIN + 79,
157     __SIGRTMIN + 80,
158     __SIGRTMIN + 81,
159     __SIGRTMIN + 82,
160     __SIGRTMIN + 83,
161     __SIGRTMIN + 84,
162     __SIGRTMIN + 85,
163     __SIGRTMIN + 86,
164     __SIGRTMIN + 87,
165     __SIGRTMIN + 88,
166     __SIGRTMIN + 89,
167     __SIGRTMIN + 90,
168     __SIGRTMIN + 91,
169     __SIGRTMIN + 92,
170     __SIGRTMIN + 93,
171     __SIGRTMIN + 94,
172     __SIGRTMIN + 95,
173     -1, /* SIGINFO */
174     -1, /* UNKNOWN */
175     -1, /* DEFAULT */
176     -1,
177     -1,
178     -1,
179     -1,
180     -1,
181     -1
182 #endif
183 };
184 
185 int gdb_signal_to_target(int sig)
186 {
187     if (sig < ARRAY_SIZE(gdb_signal_table)) {
188         return gdb_signal_table[sig];
189     } else {
190         return -1;
191     }
192 }
193 
194 int gdb_target_signal_to_gdb(int sig)
195 {
196     int i;
197     for (i = 0; i < ARRAY_SIZE(gdb_signal_table); i++) {
198         if (gdb_signal_table[i] == sig) {
199             return i;
200         }
201     }
202     return GDB_SIGNAL_UNKNOWN;
203 }
204 
205 int gdb_get_cpu_index(CPUState *cpu)
206 {
207     TaskState *ts = get_task_state(cpu);
208     return ts ? ts->ts_tid : -1;
209 }
210 
211 /*
212  * User-mode specific command helpers
213  */
214 
215 void gdb_handle_query_offsets(GArray *params, void *user_ctx)
216 {
217     TaskState *ts;
218 
219     ts = get_task_state(gdbserver_state.c_cpu);
220     g_string_printf(gdbserver_state.str_buf,
221                     "Text=" TARGET_ABI_FMT_lx
222                     ";Data=" TARGET_ABI_FMT_lx
223                     ";Bss=" TARGET_ABI_FMT_lx,
224                     ts->info->code_offset,
225                     ts->info->data_offset,
226                     ts->info->data_offset);
227     gdb_put_strbuf();
228 }
229 
230 #if defined(CONFIG_LINUX)
231 /* Partial user only duplicate of helper in gdbstub.c */
232 static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
233                                          uint8_t *buf, int len, bool is_write)
234 {
235     CPUClass *cc;
236     cc = CPU_GET_CLASS(cpu);
237     if (cc->memory_rw_debug) {
238         return 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 = get_param(params, 0)->val_ul;
254     len = get_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 = get_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 = get_param(params, 1)->val_ull;
310     uint64_t mode = get_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         g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
320     } else {
321         g_string_printf(gdbserver_state.str_buf, "F%d", fd);
322     }
323     gdb_put_strbuf();
324 }
325 
326 void gdb_handle_v_file_close(GArray *params, void *user_ctx)
327 {
328     int fd = get_param(params, 0)->val_ul;
329 
330     if (close(fd) == -1) {
331         g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
332         gdb_put_strbuf();
333         return;
334     }
335 
336     gdb_put_packet("F00");
337 }
338 
339 void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
340 {
341     int fd = get_param(params, 0)->val_ul;
342     size_t count = get_param(params, 1)->val_ull;
343     off_t offset = get_param(params, 2)->val_ull;
344 
345     size_t bufsiz = MIN(count, BUFSIZ);
346     g_autofree char *buf = g_try_malloc(bufsiz);
347     if (buf == NULL) {
348         gdb_put_packet("E12");
349         return;
350     }
351 
352     ssize_t n = pread(fd, buf, bufsiz, offset);
353     if (n < 0) {
354         g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
355         gdb_put_strbuf();
356         return;
357     }
358     hostio_reply_with_data(buf, n);
359 }
360 
361 void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
362 {
363     const char *filename = get_filename_param(params, 0);
364 
365     g_autofree char *buf = g_try_malloc(BUFSIZ);
366     if (buf == NULL) {
367         gdb_put_packet("E12");
368         return;
369     }
370 
371 #ifdef CONFIG_LINUX
372     ssize_t n = do_guest_readlink(filename, buf, BUFSIZ);
373 #else
374     ssize_t n = readlink(filename, buf, BUFSIZ);
375 #endif
376     if (n < 0) {
377         g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
378         gdb_put_strbuf();
379         return;
380     }
381     hostio_reply_with_data(buf, n);
382 }
383 
384 void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
385 {
386     uint32_t pid = get_param(params, 0)->val_ul;
387     uint32_t offset = get_param(params, 1)->val_ul;
388     uint32_t length = get_param(params, 2)->val_ul;
389 
390     GDBProcess *process = gdb_get_process(pid);
391     if (!process) {
392         gdb_put_packet("E00");
393         return;
394     }
395 
396     CPUState *cpu = gdb_get_first_cpu_in_process(process);
397     if (!cpu) {
398         gdb_put_packet("E00");
399         return;
400     }
401 
402     TaskState *ts = get_task_state(cpu);
403     if (!ts || !ts->bprm || !ts->bprm->filename) {
404         gdb_put_packet("E00");
405         return;
406     }
407 
408     size_t total_length = strlen(ts->bprm->filename);
409     if (offset > total_length) {
410         gdb_put_packet("E00");
411         return;
412     }
413     if (offset + length > total_length) {
414         length = total_length - offset;
415     }
416 
417     g_string_printf(gdbserver_state.str_buf, "l%.*s", length,
418                     ts->bprm->filename + offset);
419     gdb_put_strbuf();
420 }
421 
422 int gdb_target_sigtrap(void)
423 {
424     return TARGET_SIGTRAP;
425 }
426