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