]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/gdbserver/hostio.c
Move savestring to common/common-utils.c, make gdbserver use it.
[thirdparty/binutils-gdb.git] / gdb / gdbserver / hostio.c
CommitLineData
a6b151f1 1/* Host file transfer support for gdbserver.
28e7fd62 2 Copyright (C) 2007-2013 Free Software Foundation, Inc.
a6b151f1
DJ
3
4 Contributed by CodeSourcery.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
32de4b9d 10 the Free Software Foundation; either version 3 of the License, or
a6b151f1
DJ
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
32de4b9d 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
a6b151f1
DJ
20
21#include "server.h"
22#include "gdb/fileio.h"
23
a6b151f1
DJ
24#include <fcntl.h>
25#include <limits.h>
26#include <unistd.h>
27
28extern int remote_debug;
29
30struct fd_list
31{
32 int fd;
33 struct fd_list *next;
34};
35
36static struct fd_list *open_fds;
37
38static int
39safe_fromhex (char a, int *nibble)
40{
41 if (a >= '0' && a <= '9')
42 *nibble = a - '0';
43 else if (a >= 'a' && a <= 'f')
44 *nibble = a - 'a' + 10;
45 else if (a >= 'A' && a <= 'F')
46 *nibble = a - 'A' + 10;
47 else
48 return -1;
49
50 return 0;
51}
52
53static int
54require_filename (char **pp, char *filename)
55{
56 int count;
57 char *p;
58
59 p = *pp;
60 count = 0;
61
62 while (*p && *p != ',')
63 {
64 int nib1, nib2;
65
66 /* Don't allow overflow. */
67 if (count >= PATH_MAX - 1)
68 return -1;
69
70 if (safe_fromhex (p[0], &nib1)
71 || safe_fromhex (p[1], &nib2))
72 return -1;
73
74 filename[count++] = nib1 * 16 + nib2;
75 p += 2;
76 }
77
78 filename[count] = '\0';
79 *pp = p;
80 return 0;
81}
82
83static int
84require_int (char **pp, int *value)
85{
86 char *p;
87 int count;
88
89 p = *pp;
90 *value = 0;
91 count = 0;
92
93 while (*p && *p != ',')
94 {
95 int nib;
96
97 /* Don't allow overflow. */
98 if (count >= 7)
99 return -1;
100
101 if (safe_fromhex (p[0], &nib))
102 return -1;
103 *value = *value * 16 + nib;
104 p++;
105 count++;
106 }
107
108 *pp = p;
109 return 0;
110}
111
112static int
113require_data (char *p, int p_len, char **data, int *data_len)
114{
115 int input_index, output_index, escaped;
116
bca929d3 117 *data = xmalloc (p_len);
a6b151f1
DJ
118
119 output_index = 0;
120 escaped = 0;
121 for (input_index = 0; input_index < p_len; input_index++)
122 {
123 char b = p[input_index];
124
125 if (escaped)
126 {
127 (*data)[output_index++] = b ^ 0x20;
128 escaped = 0;
129 }
130 else if (b == '}')
131 escaped = 1;
132 else
133 (*data)[output_index++] = b;
134 }
135
136 if (escaped)
9130f83e 137 {
8040bd49 138 free (*data);
9130f83e
MS
139 return -1;
140 }
a6b151f1
DJ
141
142 *data_len = output_index;
143 return 0;
144}
145
146static int
147require_comma (char **pp)
148{
149 if (**pp == ',')
150 {
151 (*pp)++;
152 return 0;
153 }
154 else
155 return -1;
156}
157
158static int
159require_end (char *p)
160{
161 if (*p == '\0')
162 return 0;
163 else
164 return -1;
165}
166
167static int
168require_valid_fd (int fd)
169{
170 struct fd_list *fd_ptr;
171
172 for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next)
173 if (fd_ptr->fd == fd)
174 return 0;
175
176 return -1;
177}
178
59a016f0
PA
179/* Fill in own_buf with the last hostio error packet, however it
180 suitable for the target. */
a6b151f1 181static void
59a016f0 182hostio_error (char *own_buf)
a6b151f1 183{
59a016f0 184 the_target->hostio_last_error (own_buf);
a6b151f1
DJ
185}
186
187static void
188hostio_packet_error (char *own_buf)
189{
59a016f0 190 sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
a6b151f1
DJ
191}
192
193static void
194hostio_reply (char *own_buf, int result)
195{
196 sprintf (own_buf, "F%x", result);
197}
198
199static int
200hostio_reply_with_data (char *own_buf, char *buffer, int len,
201 int *new_packet_len)
202{
203 int input_index, output_index, out_maxlen;
204
205 sprintf (own_buf, "F%x;", len);
206 output_index = strlen (own_buf);
207
208 out_maxlen = PBUFSIZ;
209
210 for (input_index = 0; input_index < len; input_index++)
211 {
212 char b = buffer[input_index];
213
214 if (b == '$' || b == '#' || b == '}' || b == '*')
215 {
216 /* These must be escaped. */
217 if (output_index + 2 > out_maxlen)
218 break;
219 own_buf[output_index++] = '}';
220 own_buf[output_index++] = b ^ 0x20;
221 }
222 else
223 {
224 if (output_index + 1 > out_maxlen)
225 break;
226 own_buf[output_index++] = b;
227 }
228 }
229
230 *new_packet_len = output_index;
231 return input_index;
232}
233
234static int
235fileio_open_flags_to_host (int fileio_open_flags, int *open_flags_p)
236{
237 int open_flags = 0;
238
239 if (fileio_open_flags & ~FILEIO_O_SUPPORTED)
240 return -1;
241
242 if (fileio_open_flags & FILEIO_O_CREAT)
243 open_flags |= O_CREAT;
244 if (fileio_open_flags & FILEIO_O_EXCL)
245 open_flags |= O_EXCL;
246 if (fileio_open_flags & FILEIO_O_TRUNC)
247 open_flags |= O_TRUNC;
248 if (fileio_open_flags & FILEIO_O_APPEND)
249 open_flags |= O_APPEND;
250 if (fileio_open_flags & FILEIO_O_RDONLY)
251 open_flags |= O_RDONLY;
252 if (fileio_open_flags & FILEIO_O_WRONLY)
253 open_flags |= O_WRONLY;
254 if (fileio_open_flags & FILEIO_O_RDWR)
255 open_flags |= O_RDWR;
256/* On systems supporting binary and text mode, always open files in
257 binary mode. */
258#ifdef O_BINARY
259 open_flags |= O_BINARY;
260#endif
261
262 *open_flags_p = open_flags;
263 return 0;
264}
265
266static void
267handle_open (char *own_buf)
268{
269 char filename[PATH_MAX];
270 char *p;
271 int fileio_flags, mode, flags, fd;
272 struct fd_list *new_fd;
273
274 p = own_buf + strlen ("vFile:open:");
275
276 if (require_filename (&p, filename)
277 || require_comma (&p)
278 || require_int (&p, &fileio_flags)
279 || require_comma (&p)
280 || require_int (&p, &mode)
281 || require_end (p)
282 || fileio_open_flags_to_host (fileio_flags, &flags))
283 {
284 hostio_packet_error (own_buf);
285 return;
286 }
287
288 /* We do not need to convert MODE, since the fileio protocol
289 uses the standard values. */
290 fd = open (filename, flags, mode);
291
292 if (fd == -1)
293 {
59a016f0 294 hostio_error (own_buf);
a6b151f1
DJ
295 return;
296 }
297
298 /* Record the new file descriptor. */
bca929d3 299 new_fd = xmalloc (sizeof (struct fd_list));
a6b151f1
DJ
300 new_fd->fd = fd;
301 new_fd->next = open_fds;
302 open_fds = new_fd;
303
304 hostio_reply (own_buf, fd);
305}
306
307static void
308handle_pread (char *own_buf, int *new_packet_len)
309{
310 int fd, ret, len, offset, bytes_sent;
311 char *p, *data;
312
313 p = own_buf + strlen ("vFile:pread:");
314
315 if (require_int (&p, &fd)
316 || require_comma (&p)
317 || require_valid_fd (fd)
318 || require_int (&p, &len)
319 || require_comma (&p)
320 || require_int (&p, &offset)
321 || require_end (p))
322 {
323 hostio_packet_error (own_buf);
324 return;
325 }
326
bca929d3 327 data = xmalloc (len);
4e799345 328#ifdef HAVE_PREAD
a6b151f1 329 ret = pread (fd, data, len, offset);
4e799345 330#else
7c3270ae 331 ret = -1;
4e799345 332#endif
7c3270ae
UW
333 /* If we have no pread or it failed for this file, use lseek/read. */
334 if (ret == -1)
335 {
336 ret = lseek (fd, offset, SEEK_SET);
337 if (ret != -1)
338 ret = read (fd, data, len);
339 }
a6b151f1
DJ
340
341 if (ret == -1)
342 {
59a016f0 343 hostio_error (own_buf);
a6b151f1
DJ
344 free (data);
345 return;
346 }
347
348 bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len);
349
350 /* If we were using read, and the data did not all fit in the reply,
351 we would have to back up using lseek here. With pread it does
352 not matter. But we still have a problem; the return value in the
353 packet might be wrong, so we must fix it. This time it will
354 definitely fit. */
355 if (bytes_sent < ret)
356 bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent,
357 new_packet_len);
358
359 free (data);
360}
361
362static void
363handle_pwrite (char *own_buf, int packet_len)
364{
365 int fd, ret, len, offset;
366 char *p, *data;
367
368 p = own_buf + strlen ("vFile:pwrite:");
369
370 if (require_int (&p, &fd)
371 || require_comma (&p)
372 || require_valid_fd (fd)
373 || require_int (&p, &offset)
374 || require_comma (&p)
375 || require_data (p, packet_len - (p - own_buf), &data, &len))
376 {
377 hostio_packet_error (own_buf);
378 return;
379 }
380
4e799345 381#ifdef HAVE_PWRITE
a6b151f1 382 ret = pwrite (fd, data, len, offset);
4e799345 383#else
7c3270ae 384 ret = -1;
4e799345 385#endif
7c3270ae
UW
386 /* If we have no pwrite or it failed for this file, use lseek/write. */
387 if (ret == -1)
388 {
389 ret = lseek (fd, offset, SEEK_SET);
390 if (ret != -1)
391 ret = write (fd, data, len);
392 }
a6b151f1
DJ
393
394 if (ret == -1)
395 {
59a016f0 396 hostio_error (own_buf);
a6b151f1
DJ
397 free (data);
398 return;
399 }
400
401 hostio_reply (own_buf, ret);
402 free (data);
403}
404
405static void
406handle_close (char *own_buf)
407{
408 int fd, ret;
409 char *p;
410 struct fd_list **open_fd_p, *old_fd;
411
412 p = own_buf + strlen ("vFile:close:");
413
414 if (require_int (&p, &fd)
415 || require_valid_fd (fd)
416 || require_end (p))
417 {
418 hostio_packet_error (own_buf);
419 return;
420 }
421
422 ret = close (fd);
423
424 if (ret == -1)
425 {
59a016f0 426 hostio_error (own_buf);
a6b151f1
DJ
427 return;
428 }
429
430 open_fd_p = &open_fds;
588eebee
MS
431 /* We know that fd is in the list, thanks to require_valid_fd. */
432 while ((*open_fd_p)->fd != fd)
a6b151f1
DJ
433 open_fd_p = &(*open_fd_p)->next;
434
435 old_fd = *open_fd_p;
436 *open_fd_p = (*open_fd_p)->next;
437 free (old_fd);
438
439 hostio_reply (own_buf, ret);
440}
441
442static void
443handle_unlink (char *own_buf)
444{
445 char filename[PATH_MAX];
446 char *p;
447 int ret;
448
449 p = own_buf + strlen ("vFile:unlink:");
450
451 if (require_filename (&p, filename)
452 || require_end (p))
453 {
454 hostio_packet_error (own_buf);
455 return;
456 }
457
458 ret = unlink (filename);
459
460 if (ret == -1)
461 {
59a016f0 462 hostio_error (own_buf);
a6b151f1
DJ
463 return;
464 }
465
466 hostio_reply (own_buf, ret);
467}
468
b9e7b9c3
UW
469static void
470handle_readlink (char *own_buf, int *new_packet_len)
471{
f8255c2a 472#if defined (HAVE_READLINK)
b9e7b9c3
UW
473 char filename[PATH_MAX], linkname[PATH_MAX];
474 char *p;
475 int ret, bytes_sent;
476
477 p = own_buf + strlen ("vFile:readlink:");
478
479 if (require_filename (&p, filename)
480 || require_end (p))
481 {
482 hostio_packet_error (own_buf);
483 return;
484 }
485
0270a750 486 ret = readlink (filename, linkname, sizeof (linkname) - 1);
b9e7b9c3
UW
487 if (ret == -1)
488 {
489 hostio_error (own_buf);
490 return;
491 }
492
493 bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len);
494
495 /* If the response does not fit into a single packet, do not attempt
496 to return a partial response, but simply fail. */
497 if (bytes_sent < ret)
498 sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG);
f8255c2a
JB
499#else /* ! HAVE_READLINK */
500 sprintf (own_buf, "F-1,%x", FILEIO_ENOSYS);
501#endif
b9e7b9c3
UW
502}
503
a6b151f1
DJ
504/* Handle all the 'F' file transfer packets. */
505
506int
507handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
508{
509 if (strncmp (own_buf, "vFile:open:", 11) == 0)
510 handle_open (own_buf);
511 else if (strncmp (own_buf, "vFile:pread:", 11) == 0)
512 handle_pread (own_buf, new_packet_len);
513 else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0)
514 handle_pwrite (own_buf, packet_len);
515 else if (strncmp (own_buf, "vFile:close:", 12) == 0)
516 handle_close (own_buf);
517 else if (strncmp (own_buf, "vFile:unlink:", 13) == 0)
518 handle_unlink (own_buf);
b9e7b9c3
UW
519 else if (strncmp (own_buf, "vFile:readlink:", 15) == 0)
520 handle_readlink (own_buf, new_packet_len);
a6b151f1
DJ
521 else
522 return 0;
523
524 return 1;
525}