]> Git Repo - binutils.git/blob - gdbserver/hostio.cc
Automatic date update in version.in
[binutils.git] / gdbserver / hostio.cc
1 /* Host file transfer support for gdbserver.
2    Copyright (C) 2007-2022 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 "gdbsupport/fileio.h"
23 #include "hostio.h"
24
25 #include <fcntl.h>
26 #include <limits.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include "gdbsupport/fileio.h"
31
32 struct fd_list
33 {
34   int fd;
35   struct fd_list *next;
36 };
37
38 static struct fd_list *open_fds;
39
40 static int
41 safe_fromhex (char a, int *nibble)
42 {
43   if (a >= '0' && a <= '9')
44     *nibble = a - '0';
45   else if (a >= 'a' && a <= 'f')
46     *nibble = a - 'a' + 10;
47   else if (a >= 'A' && a <= 'F')
48     *nibble = a - 'A' + 10;
49   else
50     return -1;
51
52   return 0;
53 }
54
55 /* Filenames are hex encoded, so the maximum we can handle is half the
56    packet buffer size.  Cap to PATH_MAX, if it is shorter.  */
57 #if !defined (PATH_MAX) || (PATH_MAX > (PBUFSIZ / 2 + 1))
58 #  define HOSTIO_PATH_MAX (PBUFSIZ / 2 + 1)
59 #else
60 #  define HOSTIO_PATH_MAX PATH_MAX
61 #endif
62
63 static int
64 require_filename (char **pp, char *filename)
65 {
66   int count;
67   char *p;
68
69   p = *pp;
70   count = 0;
71
72   while (*p && *p != ',')
73     {
74       int nib1, nib2;
75
76       /* Don't allow overflow.  */
77       if (count >= HOSTIO_PATH_MAX - 1)
78         return -1;
79
80       if (safe_fromhex (p[0], &nib1)
81           || safe_fromhex (p[1], &nib2))
82         return -1;
83
84       filename[count++] = nib1 * 16 + nib2;
85       p += 2;
86     }
87
88   filename[count] = '\0';
89   *pp = p;
90   return 0;
91 }
92
93 static int
94 require_int (char **pp, int *value)
95 {
96   char *p;
97   int count, firstdigit;
98
99   p = *pp;
100   *value = 0;
101   count = 0;
102   firstdigit = -1;
103
104   while (*p && *p != ',')
105     {
106       int nib;
107
108       if (safe_fromhex (p[0], &nib))
109         return -1;
110
111       if (firstdigit == -1)
112         firstdigit = nib;
113
114       /* Don't allow overflow.  */
115       if (count >= 8 || (count == 7 && firstdigit >= 0x8))
116         return -1;
117
118       *value = *value * 16 + nib;
119       p++;
120       count++;
121     }
122
123   *pp = p;
124   return 0;
125 }
126
127 static int
128 require_data (char *p, int p_len, char **data, int *data_len)
129 {
130   int input_index, output_index, escaped;
131
132   *data = (char *) xmalloc (p_len);
133
134   output_index = 0;
135   escaped = 0;
136   for (input_index = 0; input_index < p_len; input_index++)
137     {
138       char b = p[input_index];
139
140       if (escaped)
141         {
142           (*data)[output_index++] = b ^ 0x20;
143           escaped = 0;
144         }
145       else if (b == '}')
146         escaped = 1;
147       else
148         (*data)[output_index++] = b;
149     }
150
151   if (escaped)
152     {
153       free (*data);
154       return -1;
155     }
156
157   *data_len = output_index;
158   return 0;
159 }
160
161 static int
162 require_comma (char **pp)
163 {
164   if (**pp == ',')
165     {
166       (*pp)++;
167       return 0;
168     }
169   else
170     return -1;
171 }
172
173 static int
174 require_end (char *p)
175 {
176   if (*p == '\0')
177     return 0;
178   else
179     return -1;
180 }
181
182 static int
183 require_valid_fd (int fd)
184 {
185   struct fd_list *fd_ptr;
186
187   for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next)
188     if (fd_ptr->fd == fd)
189       return 0;
190
191   return -1;
192 }
193
194 /* Fill BUF with an hostio error packet representing the last hostio
195    error, from errno.  */
196
197 static void
198 hostio_error (char *own_buf)
199 {
200   int fileio_error = host_to_fileio_error (errno);
201   sprintf (own_buf, "F-1,%x", fileio_error);
202 }
203
204 static void
205 hostio_packet_error (char *own_buf)
206 {
207   sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
208 }
209
210 static void
211 hostio_reply (char *own_buf, int result)
212 {
213   sprintf (own_buf, "F%x", result);
214 }
215
216 static int
217 hostio_reply_with_data (char *own_buf, char *buffer, int len,
218                         int *new_packet_len)
219 {
220   int input_index, output_index, out_maxlen;
221
222   sprintf (own_buf, "F%x;", len);
223   output_index = strlen (own_buf);
224
225   out_maxlen = PBUFSIZ;
226
227   for (input_index = 0; input_index < len; input_index++)
228     {
229       char b = buffer[input_index];
230
231       if (b == '$' || b == '#' || b == '}' || b == '*')
232         {
233           /* These must be escaped.  */
234           if (output_index + 2 > out_maxlen)
235             break;
236           own_buf[output_index++] = '}';
237           own_buf[output_index++] = b ^ 0x20;
238         }
239       else
240         {
241           if (output_index + 1 > out_maxlen)
242             break;
243           own_buf[output_index++] = b;
244         }
245     }
246
247   *new_packet_len = output_index;
248   return input_index;
249 }
250
251 /* Process ID of inferior whose filesystem hostio functions
252    that take FILENAME arguments will use.  Zero means to use
253    our own filesystem.  */
254
255 static int hostio_fs_pid;
256
257 /* See hostio.h.  */
258
259 void
260 hostio_handle_new_gdb_connection (void)
261 {
262   hostio_fs_pid = 0;
263 }
264
265 /* Handle a "vFile:setfs:" packet.  */
266
267 static void
268 handle_setfs (char *own_buf)
269 {
270   char *p;
271   int pid;
272
273   /* If the target doesn't have any of the in-filesystem-of methods
274      then there's no point in GDB sending "vFile:setfs:" packets.  We
275      reply with an empty packet (i.e. we pretend we don't understand
276      "vFile:setfs:") and that should stop GDB sending any more.  */
277   if (!the_target->supports_multifs ())
278     {
279       own_buf[0] = '\0';
280       return;
281     }
282
283   p = own_buf + strlen ("vFile:setfs:");
284
285   if (require_int (&p, &pid)
286       || pid < 0
287       || require_end (p))
288     {
289       hostio_packet_error (own_buf);
290       return;
291     }
292
293   hostio_fs_pid = pid;
294
295   hostio_reply (own_buf, 0);
296 }
297
298 static void
299 handle_open (char *own_buf)
300 {
301   char filename[HOSTIO_PATH_MAX];
302   char *p;
303   int fileio_flags, fileio_mode, flags, fd;
304   mode_t mode;
305   struct fd_list *new_fd;
306
307   p = own_buf + strlen ("vFile:open:");
308
309   if (require_filename (&p, filename)
310       || require_comma (&p)
311       || require_int (&p, &fileio_flags)
312       || require_comma (&p)
313       || require_int (&p, &fileio_mode)
314       || require_end (p)
315       || fileio_to_host_openflags (fileio_flags, &flags)
316       || fileio_to_host_mode (fileio_mode, &mode))
317     {
318       hostio_packet_error (own_buf);
319       return;
320     }
321
322   /* We do not need to convert MODE, since the fileio protocol
323      uses the standard values.  */
324   if (hostio_fs_pid != 0)
325     fd = the_target->multifs_open (hostio_fs_pid, filename, flags, mode);
326   else
327     fd = open (filename, flags, mode);
328
329   if (fd == -1)
330     {
331       hostio_error (own_buf);
332       return;
333     }
334
335   /* Record the new file descriptor.  */
336   new_fd = XNEW (struct fd_list);
337   new_fd->fd = fd;
338   new_fd->next = open_fds;
339   open_fds = new_fd;
340
341   hostio_reply (own_buf, fd);
342 }
343
344 static void
345 handle_pread (char *own_buf, int *new_packet_len)
346 {
347   int fd, ret, len, offset, bytes_sent;
348   char *p, *data;
349   static int max_reply_size = -1;
350
351   p = own_buf + strlen ("vFile:pread:");
352
353   if (require_int (&p, &fd)
354       || require_comma (&p)
355       || require_valid_fd (fd)
356       || require_int (&p, &len)
357       || require_comma (&p)
358       || require_int (&p, &offset)
359       || require_end (p))
360     {
361       hostio_packet_error (own_buf);
362       return;
363     }
364
365   /* Do not attempt to read more than the maximum number of bytes
366      hostio_reply_with_data can fit in a packet.  We may still read
367      too much because of escaping, but this is handled below.  */
368   if (max_reply_size == -1)
369     {
370       sprintf (own_buf, "F%x;", PBUFSIZ);
371       max_reply_size = PBUFSIZ - strlen (own_buf);
372     }
373   if (len > max_reply_size)
374     len = max_reply_size;
375
376   data = (char *) xmalloc (len);
377 #ifdef HAVE_PREAD
378   ret = pread (fd, data, len, offset);
379 #else
380   ret = -1;
381 #endif
382   /* If we have no pread or it failed for this file, use lseek/read.  */
383   if (ret == -1)
384     {
385       ret = lseek (fd, offset, SEEK_SET);
386       if (ret != -1)
387         ret = read (fd, data, len);
388     }
389
390   if (ret == -1)
391     {
392       hostio_error (own_buf);
393       free (data);
394       return;
395     }
396
397   bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len);
398
399   /* If we were using read, and the data did not all fit in the reply,
400      we would have to back up using lseek here.  With pread it does
401      not matter.  But we still have a problem; the return value in the
402      packet might be wrong, so we must fix it.  This time it will
403      definitely fit.  */
404   if (bytes_sent < ret)
405     bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent,
406                                          new_packet_len);
407
408   free (data);
409 }
410
411 static void
412 handle_pwrite (char *own_buf, int packet_len)
413 {
414   int fd, ret, len, offset;
415   char *p, *data;
416
417   p = own_buf + strlen ("vFile:pwrite:");
418
419   if (require_int (&p, &fd)
420       || require_comma (&p)
421       || require_valid_fd (fd)
422       || require_int (&p, &offset)
423       || require_comma (&p)
424       || require_data (p, packet_len - (p - own_buf), &data, &len))
425     {
426       hostio_packet_error (own_buf);
427       return;
428     }
429
430 #ifdef HAVE_PWRITE
431   ret = pwrite (fd, data, len, offset);
432 #else
433   ret = -1;
434 #endif
435   /* If we have no pwrite or it failed for this file, use lseek/write.  */
436   if (ret == -1)
437     {
438       ret = lseek (fd, offset, SEEK_SET);
439       if (ret != -1)
440         ret = write (fd, data, len);
441     }
442
443   if (ret == -1)
444     {
445       hostio_error (own_buf);
446       free (data);
447       return;
448     }
449
450   hostio_reply (own_buf, ret);
451   free (data);
452 }
453
454 static void
455 handle_fstat (char *own_buf, int *new_packet_len)
456 {
457   int fd, bytes_sent;
458   char *p;
459   struct stat st;
460   struct fio_stat fst;
461
462   p = own_buf + strlen ("vFile:fstat:");
463
464   if (require_int (&p, &fd)
465       || require_valid_fd (fd)
466       || require_end (p))
467     {
468       hostio_packet_error (own_buf);
469       return;
470     }
471
472   if (fstat (fd, &st) == -1)
473     {
474       hostio_error (own_buf);
475       return;
476     }
477
478   host_to_fileio_stat (&st, &fst);
479
480   bytes_sent = hostio_reply_with_data (own_buf,
481                                        (char *) &fst, sizeof (fst),
482                                        new_packet_len);
483
484   /* If the response does not fit into a single packet, do not attempt
485      to return a partial response, but simply fail.  */
486   if (bytes_sent < sizeof (fst))
487     write_enn (own_buf);
488 }
489
490 static void
491 handle_close (char *own_buf)
492 {
493   int fd, ret;
494   char *p;
495   struct fd_list **open_fd_p, *old_fd;
496
497   p = own_buf + strlen ("vFile:close:");
498
499   if (require_int (&p, &fd)
500       || require_valid_fd (fd)
501       || require_end (p))
502     {
503       hostio_packet_error (own_buf);
504       return;
505     }
506
507   ret = close (fd);
508
509   if (ret == -1)
510     {
511       hostio_error (own_buf);
512       return;
513     }
514
515   open_fd_p = &open_fds;
516   /* We know that fd is in the list, thanks to require_valid_fd.  */
517   while ((*open_fd_p)->fd != fd)
518     open_fd_p = &(*open_fd_p)->next;
519
520   old_fd = *open_fd_p;
521   *open_fd_p = (*open_fd_p)->next;
522   free (old_fd);
523
524   hostio_reply (own_buf, ret);
525 }
526
527 static void
528 handle_unlink (char *own_buf)
529 {
530   char filename[HOSTIO_PATH_MAX];
531   char *p;
532   int ret;
533
534   p = own_buf + strlen ("vFile:unlink:");
535
536   if (require_filename (&p, filename)
537       || require_end (p))
538     {
539       hostio_packet_error (own_buf);
540       return;
541     }
542
543   if (hostio_fs_pid != 0)
544     ret = the_target->multifs_unlink (hostio_fs_pid, filename);
545   else
546     ret = unlink (filename);
547
548   if (ret == -1)
549     {
550       hostio_error (own_buf);
551       return;
552     }
553
554   hostio_reply (own_buf, ret);
555 }
556
557 static void
558 handle_readlink (char *own_buf, int *new_packet_len)
559 {
560   char filename[HOSTIO_PATH_MAX], linkname[HOSTIO_PATH_MAX];
561   char *p;
562   int ret, bytes_sent;
563
564   p = own_buf + strlen ("vFile:readlink:");
565
566   if (require_filename (&p, filename)
567       || require_end (p))
568     {
569       hostio_packet_error (own_buf);
570       return;
571     }
572
573   if (hostio_fs_pid != 0)
574     ret = the_target->multifs_readlink (hostio_fs_pid, filename,
575                                         linkname,
576                                         sizeof (linkname) - 1);
577   else
578     ret = readlink (filename, linkname, sizeof (linkname) - 1);
579
580   if (ret == -1)
581     {
582       hostio_error (own_buf);
583       return;
584     }
585
586   bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len);
587
588   /* If the response does not fit into a single packet, do not attempt
589      to return a partial response, but simply fail.  */
590   if (bytes_sent < ret)
591     sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG);
592 }
593
594 /* Handle all the 'F' file transfer packets.  */
595
596 int
597 handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
598 {
599   if (startswith (own_buf, "vFile:open:"))
600     handle_open (own_buf);
601   else if (startswith (own_buf, "vFile:pread:"))
602     handle_pread (own_buf, new_packet_len);
603   else if (startswith (own_buf, "vFile:pwrite:"))
604     handle_pwrite (own_buf, packet_len);
605   else if (startswith (own_buf, "vFile:fstat:"))
606     handle_fstat (own_buf, new_packet_len);
607   else if (startswith (own_buf, "vFile:close:"))
608     handle_close (own_buf);
609   else if (startswith (own_buf, "vFile:unlink:"))
610     handle_unlink (own_buf);
611   else if (startswith (own_buf, "vFile:readlink:"))
612     handle_readlink (own_buf, new_packet_len);
613   else if (startswith (own_buf, "vFile:setfs:"))
614     handle_setfs (own_buf);
615   else
616     return 0;
617
618   return 1;
619 }
This page took 0.056502 seconds and 4 git commands to generate.