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