]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/gdbserver/hostio.c
Update year range in copyright notice of all files owned by the GDB project.
[thirdparty/binutils-gdb.git] / gdb / gdbserver / hostio.c
1 /* Host file transfer support for gdbserver.
2 Copyright (C) 2007-2015 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 #include "hostio.h"
24
25 #include <fcntl.h>
26 #include <limits.h>
27 #include <unistd.h>
28
29 extern int remote_debug;
30
31 struct fd_list
32 {
33 int fd;
34 struct fd_list *next;
35 };
36
37 static struct fd_list *open_fds;
38
39 static int
40 safe_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
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
62 static int
63 require_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. */
76 if (count >= HOSTIO_PATH_MAX - 1)
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
92 static int
93 require_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
121 static int
122 require_data (char *p, int p_len, char **data, int *data_len)
123 {
124 int input_index, output_index, escaped;
125
126 *data = xmalloc (p_len);
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)
146 {
147 free (*data);
148 return -1;
149 }
150
151 *data_len = output_index;
152 return 0;
153 }
154
155 static int
156 require_comma (char **pp)
157 {
158 if (**pp == ',')
159 {
160 (*pp)++;
161 return 0;
162 }
163 else
164 return -1;
165 }
166
167 static int
168 require_end (char *p)
169 {
170 if (*p == '\0')
171 return 0;
172 else
173 return -1;
174 }
175
176 static int
177 require_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
188 /* Fill in own_buf with the last hostio error packet, however it
189 suitable for the target. */
190 static void
191 hostio_error (char *own_buf)
192 {
193 the_target->hostio_last_error (own_buf);
194 }
195
196 static void
197 hostio_packet_error (char *own_buf)
198 {
199 sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
200 }
201
202 static void
203 hostio_reply (char *own_buf, int result)
204 {
205 sprintf (own_buf, "F%x", result);
206 }
207
208 static int
209 hostio_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
243 static int
244 fileio_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
275 static void
276 handle_open (char *own_buf)
277 {
278 char filename[HOSTIO_PATH_MAX];
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 {
303 hostio_error (own_buf);
304 return;
305 }
306
307 /* Record the new file descriptor. */
308 new_fd = xmalloc (sizeof (struct fd_list));
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
316 static void
317 handle_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
336 data = xmalloc (len);
337 #ifdef HAVE_PREAD
338 ret = pread (fd, data, len, offset);
339 #else
340 ret = -1;
341 #endif
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 }
349
350 if (ret == -1)
351 {
352 hostio_error (own_buf);
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
371 static void
372 handle_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
390 #ifdef HAVE_PWRITE
391 ret = pwrite (fd, data, len, offset);
392 #else
393 ret = -1;
394 #endif
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 }
402
403 if (ret == -1)
404 {
405 hostio_error (own_buf);
406 free (data);
407 return;
408 }
409
410 hostio_reply (own_buf, ret);
411 free (data);
412 }
413
414 static void
415 handle_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 {
435 hostio_error (own_buf);
436 return;
437 }
438
439 open_fd_p = &open_fds;
440 /* We know that fd is in the list, thanks to require_valid_fd. */
441 while ((*open_fd_p)->fd != fd)
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
451 static void
452 handle_unlink (char *own_buf)
453 {
454 char filename[HOSTIO_PATH_MAX];
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 {
471 hostio_error (own_buf);
472 return;
473 }
474
475 hostio_reply (own_buf, ret);
476 }
477
478 static void
479 handle_readlink (char *own_buf, int *new_packet_len)
480 {
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 }
508
509 /* Handle all the 'F' file transfer packets. */
510
511 int
512 handle_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);
516 else if (strncmp (own_buf, "vFile:pread:", 11) == 0)
517 handle_pread (own_buf, new_packet_len);
518 else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0)
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);
524 else if (strncmp (own_buf, "vFile:readlink:", 15) == 0)
525 handle_readlink (own_buf, new_packet_len);
526 else
527 return 0;
528
529 return 1;
530 }