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