Don't assume File-I/O mode bits match the host's format
[deliverable/binutils-gdb.git] / gdb / gdbserver / hostio.c
CommitLineData
a6b151f1 1/* Host file transfer support for gdbserver.
32d0add0 2 Copyright (C) 2007-2015 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"
533b0600 23#include "hostio.h"
a6b151f1 24
a6b151f1
DJ
25#include <fcntl.h>
26#include <limits.h>
27#include <unistd.h>
aa9e327f
GB
28#include <sys/types.h>
29#include <sys/stat.h>
7823a941 30#include "fileio.h"
a6b151f1
DJ
31
32extern int remote_debug;
33
34struct fd_list
35{
36 int fd;
37 struct fd_list *next;
38};
39
40static struct fd_list *open_fds;
41
42static int
43safe_fromhex (char a, int *nibble)
44{
45 if (a >= '0' && a <= '9')
46 *nibble = a - '0';
47 else if (a >= 'a' && a <= 'f')
48 *nibble = a - 'a' + 10;
49 else if (a >= 'A' && a <= 'F')
50 *nibble = a - 'A' + 10;
51 else
52 return -1;
53
54 return 0;
55}
56
d5749ee7
PA
57/* Filenames are hex encoded, so the maximum we can handle is half the
58 packet buffer size. Cap to PATH_MAX, if it is shorter. */
59#if !defined (PATH_MAX) || (PATH_MAX > (PBUFSIZ / 2 + 1))
60# define HOSTIO_PATH_MAX (PBUFSIZ / 2 + 1)
61#else
62# define HOSTIO_PATH_MAX PATH_MAX
63#endif
64
a6b151f1
DJ
65static int
66require_filename (char **pp, char *filename)
67{
68 int count;
69 char *p;
70
71 p = *pp;
72 count = 0;
73
74 while (*p && *p != ',')
75 {
76 int nib1, nib2;
77
78 /* Don't allow overflow. */
d5749ee7 79 if (count >= HOSTIO_PATH_MAX - 1)
a6b151f1
DJ
80 return -1;
81
82 if (safe_fromhex (p[0], &nib1)
83 || safe_fromhex (p[1], &nib2))
84 return -1;
85
86 filename[count++] = nib1 * 16 + nib2;
87 p += 2;
88 }
89
90 filename[count] = '\0';
91 *pp = p;
92 return 0;
93}
94
95static int
96require_int (char **pp, int *value)
97{
98 char *p;
99 int count;
100
101 p = *pp;
102 *value = 0;
103 count = 0;
104
105 while (*p && *p != ',')
106 {
107 int nib;
108
109 /* Don't allow overflow. */
110 if (count >= 7)
111 return -1;
112
113 if (safe_fromhex (p[0], &nib))
114 return -1;
115 *value = *value * 16 + nib;
116 p++;
117 count++;
118 }
119
120 *pp = p;
121 return 0;
122}
123
124static int
125require_data (char *p, int p_len, char **data, int *data_len)
126{
127 int input_index, output_index, escaped;
128
bca929d3 129 *data = xmalloc (p_len);
a6b151f1
DJ
130
131 output_index = 0;
132 escaped = 0;
133 for (input_index = 0; input_index < p_len; input_index++)
134 {
135 char b = p[input_index];
136
137 if (escaped)
138 {
139 (*data)[output_index++] = b ^ 0x20;
140 escaped = 0;
141 }
142 else if (b == '}')
143 escaped = 1;
144 else
145 (*data)[output_index++] = b;
146 }
147
148 if (escaped)
9130f83e 149 {
8040bd49 150 free (*data);
9130f83e
MS
151 return -1;
152 }
a6b151f1
DJ
153
154 *data_len = output_index;
155 return 0;
156}
157
158static int
159require_comma (char **pp)
160{
161 if (**pp == ',')
162 {
163 (*pp)++;
164 return 0;
165 }
166 else
167 return -1;
168}
169
170static int
171require_end (char *p)
172{
173 if (*p == '\0')
174 return 0;
175 else
176 return -1;
177}
178
179static int
180require_valid_fd (int fd)
181{
182 struct fd_list *fd_ptr;
183
184 for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next)
185 if (fd_ptr->fd == fd)
186 return 0;
187
188 return -1;
189}
190
59a016f0
PA
191/* Fill in own_buf with the last hostio error packet, however it
192 suitable for the target. */
a6b151f1 193static void
59a016f0 194hostio_error (char *own_buf)
a6b151f1 195{
59a016f0 196 the_target->hostio_last_error (own_buf);
a6b151f1
DJ
197}
198
199static void
200hostio_packet_error (char *own_buf)
201{
59a016f0 202 sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
a6b151f1
DJ
203}
204
205static void
206hostio_reply (char *own_buf, int result)
207{
208 sprintf (own_buf, "F%x", result);
209}
210
211static int
212hostio_reply_with_data (char *own_buf, char *buffer, int len,
213 int *new_packet_len)
214{
215 int input_index, output_index, out_maxlen;
216
217 sprintf (own_buf, "F%x;", len);
218 output_index = strlen (own_buf);
219
220 out_maxlen = PBUFSIZ;
221
222 for (input_index = 0; input_index < len; input_index++)
223 {
224 char b = buffer[input_index];
225
226 if (b == '$' || b == '#' || b == '}' || b == '*')
227 {
228 /* These must be escaped. */
229 if (output_index + 2 > out_maxlen)
230 break;
231 own_buf[output_index++] = '}';
232 own_buf[output_index++] = b ^ 0x20;
233 }
234 else
235 {
236 if (output_index + 1 > out_maxlen)
237 break;
238 own_buf[output_index++] = b;
239 }
240 }
241
242 *new_packet_len = output_index;
243 return input_index;
244}
245
a6b151f1
DJ
246static void
247handle_open (char *own_buf)
248{
d5749ee7 249 char filename[HOSTIO_PATH_MAX];
a6b151f1 250 char *p;
3ac2e371
GB
251 int fileio_flags, fileio_mode, flags, fd;
252 mode_t mode;
a6b151f1
DJ
253 struct fd_list *new_fd;
254
255 p = own_buf + strlen ("vFile:open:");
256
257 if (require_filename (&p, filename)
258 || require_comma (&p)
259 || require_int (&p, &fileio_flags)
260 || require_comma (&p)
3ac2e371 261 || require_int (&p, &fileio_mode)
a6b151f1 262 || require_end (p)
3ac2e371
GB
263 || fileio_to_host_openflags (fileio_flags, &flags)
264 || fileio_to_host_mode (fileio_mode, &mode))
a6b151f1
DJ
265 {
266 hostio_packet_error (own_buf);
267 return;
268 }
269
270 /* We do not need to convert MODE, since the fileio protocol
271 uses the standard values. */
272 fd = open (filename, flags, mode);
273
274 if (fd == -1)
275 {
59a016f0 276 hostio_error (own_buf);
a6b151f1
DJ
277 return;
278 }
279
280 /* Record the new file descriptor. */
bca929d3 281 new_fd = xmalloc (sizeof (struct fd_list));
a6b151f1
DJ
282 new_fd->fd = fd;
283 new_fd->next = open_fds;
284 open_fds = new_fd;
285
286 hostio_reply (own_buf, fd);
287}
288
289static void
290handle_pread (char *own_buf, int *new_packet_len)
291{
292 int fd, ret, len, offset, bytes_sent;
293 char *p, *data;
294
295 p = own_buf + strlen ("vFile:pread:");
296
297 if (require_int (&p, &fd)
298 || require_comma (&p)
299 || require_valid_fd (fd)
300 || require_int (&p, &len)
301 || require_comma (&p)
302 || require_int (&p, &offset)
303 || require_end (p))
304 {
305 hostio_packet_error (own_buf);
306 return;
307 }
308
bca929d3 309 data = xmalloc (len);
4e799345 310#ifdef HAVE_PREAD
a6b151f1 311 ret = pread (fd, data, len, offset);
4e799345 312#else
7c3270ae 313 ret = -1;
4e799345 314#endif
7c3270ae
UW
315 /* If we have no pread or it failed for this file, use lseek/read. */
316 if (ret == -1)
317 {
318 ret = lseek (fd, offset, SEEK_SET);
319 if (ret != -1)
320 ret = read (fd, data, len);
321 }
a6b151f1
DJ
322
323 if (ret == -1)
324 {
59a016f0 325 hostio_error (own_buf);
a6b151f1
DJ
326 free (data);
327 return;
328 }
329
330 bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len);
331
332 /* If we were using read, and the data did not all fit in the reply,
333 we would have to back up using lseek here. With pread it does
334 not matter. But we still have a problem; the return value in the
335 packet might be wrong, so we must fix it. This time it will
336 definitely fit. */
337 if (bytes_sent < ret)
338 bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent,
339 new_packet_len);
340
341 free (data);
342}
343
344static void
345handle_pwrite (char *own_buf, int packet_len)
346{
347 int fd, ret, len, offset;
348 char *p, *data;
349
350 p = own_buf + strlen ("vFile:pwrite:");
351
352 if (require_int (&p, &fd)
353 || require_comma (&p)
354 || require_valid_fd (fd)
355 || require_int (&p, &offset)
356 || require_comma (&p)
357 || require_data (p, packet_len - (p - own_buf), &data, &len))
358 {
359 hostio_packet_error (own_buf);
360 return;
361 }
362
4e799345 363#ifdef HAVE_PWRITE
a6b151f1 364 ret = pwrite (fd, data, len, offset);
4e799345 365#else
7c3270ae 366 ret = -1;
4e799345 367#endif
7c3270ae
UW
368 /* If we have no pwrite or it failed for this file, use lseek/write. */
369 if (ret == -1)
370 {
371 ret = lseek (fd, offset, SEEK_SET);
372 if (ret != -1)
373 ret = write (fd, data, len);
374 }
a6b151f1
DJ
375
376 if (ret == -1)
377 {
59a016f0 378 hostio_error (own_buf);
a6b151f1
DJ
379 free (data);
380 return;
381 }
382
383 hostio_reply (own_buf, ret);
384 free (data);
385}
386
aa9e327f
GB
387static void
388handle_fstat (char *own_buf, int *new_packet_len)
389{
390 int fd, bytes_sent;
391 char *p;
392 struct stat st;
393 struct fio_stat fst;
394
395 p = own_buf + strlen ("vFile:fstat:");
396
397 if (require_int (&p, &fd)
398 || require_valid_fd (fd)
399 || require_end (p))
400 {
401 hostio_packet_error (own_buf);
402 return;
403 }
404
405 if (fstat (fd, &st) == -1)
406 {
407 hostio_error (own_buf);
408 return;
409 }
410
7823a941 411 host_to_fileio_stat (&st, &fst);
aa9e327f
GB
412
413 bytes_sent = hostio_reply_with_data (own_buf,
414 (char *) &fst, sizeof (fst),
415 new_packet_len);
416
417 /* If the response does not fit into a single packet, do not attempt
418 to return a partial response, but simply fail. */
419 if (bytes_sent < sizeof (fst))
420 write_enn (own_buf);
421}
422
a6b151f1
DJ
423static void
424handle_close (char *own_buf)
425{
426 int fd, ret;
427 char *p;
428 struct fd_list **open_fd_p, *old_fd;
429
430 p = own_buf + strlen ("vFile:close:");
431
432 if (require_int (&p, &fd)
433 || require_valid_fd (fd)
434 || require_end (p))
435 {
436 hostio_packet_error (own_buf);
437 return;
438 }
439
440 ret = close (fd);
441
442 if (ret == -1)
443 {
59a016f0 444 hostio_error (own_buf);
a6b151f1
DJ
445 return;
446 }
447
448 open_fd_p = &open_fds;
588eebee
MS
449 /* We know that fd is in the list, thanks to require_valid_fd. */
450 while ((*open_fd_p)->fd != fd)
a6b151f1
DJ
451 open_fd_p = &(*open_fd_p)->next;
452
453 old_fd = *open_fd_p;
454 *open_fd_p = (*open_fd_p)->next;
455 free (old_fd);
456
457 hostio_reply (own_buf, ret);
458}
459
460static void
461handle_unlink (char *own_buf)
462{
d5749ee7 463 char filename[HOSTIO_PATH_MAX];
a6b151f1
DJ
464 char *p;
465 int ret;
466
467 p = own_buf + strlen ("vFile:unlink:");
468
469 if (require_filename (&p, filename)
470 || require_end (p))
471 {
472 hostio_packet_error (own_buf);
473 return;
474 }
475
476 ret = unlink (filename);
477
478 if (ret == -1)
479 {
59a016f0 480 hostio_error (own_buf);
a6b151f1
DJ
481 return;
482 }
483
484 hostio_reply (own_buf, ret);
485}
486
b9e7b9c3
UW
487static void
488handle_readlink (char *own_buf, int *new_packet_len)
489{
d5749ee7 490 char filename[HOSTIO_PATH_MAX], linkname[HOSTIO_PATH_MAX];
b9e7b9c3
UW
491 char *p;
492 int ret, bytes_sent;
493
494 p = own_buf + strlen ("vFile:readlink:");
495
496 if (require_filename (&p, filename)
497 || require_end (p))
498 {
499 hostio_packet_error (own_buf);
500 return;
501 }
502
0270a750 503 ret = readlink (filename, linkname, sizeof (linkname) - 1);
b9e7b9c3
UW
504 if (ret == -1)
505 {
506 hostio_error (own_buf);
507 return;
508 }
509
510 bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len);
511
512 /* If the response does not fit into a single packet, do not attempt
513 to return a partial response, but simply fail. */
514 if (bytes_sent < ret)
515 sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG);
516}
517
a6b151f1
DJ
518/* Handle all the 'F' file transfer packets. */
519
520int
521handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
522{
61012eef 523 if (startswith (own_buf, "vFile:open:"))
a6b151f1 524 handle_open (own_buf);
61012eef 525 else if (startswith (own_buf, "vFile:pread:"))
a6b151f1 526 handle_pread (own_buf, new_packet_len);
61012eef 527 else if (startswith (own_buf, "vFile:pwrite:"))
a6b151f1 528 handle_pwrite (own_buf, packet_len);
aa9e327f
GB
529 else if (startswith (own_buf, "vFile:fstat:"))
530 handle_fstat (own_buf, new_packet_len);
61012eef 531 else if (startswith (own_buf, "vFile:close:"))
a6b151f1 532 handle_close (own_buf);
61012eef 533 else if (startswith (own_buf, "vFile:unlink:"))
a6b151f1 534 handle_unlink (own_buf);
61012eef 535 else if (startswith (own_buf, "vFile:readlink:"))
b9e7b9c3 536 handle_readlink (own_buf, new_packet_len);
a6b151f1
DJ
537 else
538 return 0;
539
540 return 1;
541}
This page took 0.610321 seconds and 4 git commands to generate.