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