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