xref: /netbsd-src/external/gpl3/gdb/dist/gdbserver/hostio.cc (revision 06dfa8449cb5e76c0044ec0f3badf7d5180af0f5)
1 /* Host file transfer support for gdbserver.
2    Copyright (C) 2007-2020 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 #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 in own_buf with the last hostio error packet, however it
195    suitable for the target.  */
196 static void
197 hostio_error (char *own_buf)
198 {
199   the_target->hostio_last_error (own_buf);
200 }
201 
202 static void
203 hostio_packet_error (char *own_buf)
204 {
205   sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
206 }
207 
208 static void
209 hostio_reply (char *own_buf, int result)
210 {
211   sprintf (own_buf, "F%x", result);
212 }
213 
214 static int
215 hostio_reply_with_data (char *own_buf, char *buffer, int len,
216 			int *new_packet_len)
217 {
218   int input_index, output_index, out_maxlen;
219 
220   sprintf (own_buf, "F%x;", len);
221   output_index = strlen (own_buf);
222 
223   out_maxlen = PBUFSIZ;
224 
225   for (input_index = 0; input_index < len; input_index++)
226     {
227       char b = buffer[input_index];
228 
229       if (b == '$' || b == '#' || b == '}' || b == '*')
230 	{
231 	  /* These must be escaped.  */
232 	  if (output_index + 2 > out_maxlen)
233 	    break;
234 	  own_buf[output_index++] = '}';
235 	  own_buf[output_index++] = b ^ 0x20;
236 	}
237       else
238 	{
239 	  if (output_index + 1 > out_maxlen)
240 	    break;
241 	  own_buf[output_index++] = b;
242 	}
243     }
244 
245   *new_packet_len = output_index;
246   return input_index;
247 }
248 
249 /* Process ID of inferior whose filesystem hostio functions
250    that take FILENAME arguments will use.  Zero means to use
251    our own filesystem.  */
252 
253 static int hostio_fs_pid;
254 
255 /* See hostio.h.  */
256 
257 void
258 hostio_handle_new_gdb_connection (void)
259 {
260   hostio_fs_pid = 0;
261 }
262 
263 /* Handle a "vFile:setfs:" packet.  */
264 
265 static void
266 handle_setfs (char *own_buf)
267 {
268   char *p;
269   int pid;
270 
271   /* If the target doesn't have any of the in-filesystem-of methods
272      then there's no point in GDB sending "vFile:setfs:" packets.  We
273      reply with an empty packet (i.e. we pretend we don't understand
274      "vFile:setfs:") and that should stop GDB sending any more.  */
275   if (!the_target->supports_multifs ())
276     {
277       own_buf[0] = '\0';
278       return;
279     }
280 
281   p = own_buf + strlen ("vFile:setfs:");
282 
283   if (require_int (&p, &pid)
284       || pid < 0
285       || require_end (p))
286     {
287       hostio_packet_error (own_buf);
288       return;
289     }
290 
291   hostio_fs_pid = pid;
292 
293   hostio_reply (own_buf, 0);
294 }
295 
296 static void
297 handle_open (char *own_buf)
298 {
299   char filename[HOSTIO_PATH_MAX];
300   char *p;
301   int fileio_flags, fileio_mode, flags, fd;
302   mode_t mode;
303   struct fd_list *new_fd;
304 
305   p = own_buf + strlen ("vFile:open:");
306 
307   if (require_filename (&p, filename)
308       || require_comma (&p)
309       || require_int (&p, &fileio_flags)
310       || require_comma (&p)
311       || require_int (&p, &fileio_mode)
312       || require_end (p)
313       || fileio_to_host_openflags (fileio_flags, &flags)
314       || fileio_to_host_mode (fileio_mode, &mode))
315     {
316       hostio_packet_error (own_buf);
317       return;
318     }
319 
320   /* We do not need to convert MODE, since the fileio protocol
321      uses the standard values.  */
322   if (hostio_fs_pid != 0)
323     fd = the_target->multifs_open (hostio_fs_pid, filename, flags, mode);
324   else
325     fd = open (filename, flags, mode);
326 
327   if (fd == -1)
328     {
329       hostio_error (own_buf);
330       return;
331     }
332 
333   /* Record the new file descriptor.  */
334   new_fd = XNEW (struct fd_list);
335   new_fd->fd = fd;
336   new_fd->next = open_fds;
337   open_fds = new_fd;
338 
339   hostio_reply (own_buf, fd);
340 }
341 
342 static void
343 handle_pread (char *own_buf, int *new_packet_len)
344 {
345   int fd, ret, len, offset, bytes_sent;
346   char *p, *data;
347   static int max_reply_size = -1;
348 
349   p = own_buf + strlen ("vFile:pread:");
350 
351   if (require_int (&p, &fd)
352       || require_comma (&p)
353       || require_valid_fd (fd)
354       || require_int (&p, &len)
355       || require_comma (&p)
356       || require_int (&p, &offset)
357       || require_end (p))
358     {
359       hostio_packet_error (own_buf);
360       return;
361     }
362 
363   /* Do not attempt to read more than the maximum number of bytes
364      hostio_reply_with_data can fit in a packet.  We may still read
365      too much because of escaping, but this is handled below.  */
366   if (max_reply_size == -1)
367     {
368       sprintf (own_buf, "F%x;", PBUFSIZ);
369       max_reply_size = PBUFSIZ - strlen (own_buf);
370     }
371   if (len > max_reply_size)
372     len = max_reply_size;
373 
374   data = (char *) xmalloc (len);
375 #ifdef HAVE_PREAD
376   ret = pread (fd, data, len, offset);
377 #else
378   ret = -1;
379 #endif
380   /* If we have no pread or it failed for this file, use lseek/read.  */
381   if (ret == -1)
382     {
383       ret = lseek (fd, offset, SEEK_SET);
384       if (ret != -1)
385 	ret = read (fd, data, len);
386     }
387 
388   if (ret == -1)
389     {
390       hostio_error (own_buf);
391       free (data);
392       return;
393     }
394 
395   bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len);
396 
397   /* If we were using read, and the data did not all fit in the reply,
398      we would have to back up using lseek here.  With pread it does
399      not matter.  But we still have a problem; the return value in the
400      packet might be wrong, so we must fix it.  This time it will
401      definitely fit.  */
402   if (bytes_sent < ret)
403     bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent,
404 					 new_packet_len);
405 
406   free (data);
407 }
408 
409 static void
410 handle_pwrite (char *own_buf, int packet_len)
411 {
412   int fd, ret, len, offset;
413   char *p, *data;
414 
415   p = own_buf + strlen ("vFile:pwrite:");
416 
417   if (require_int (&p, &fd)
418       || require_comma (&p)
419       || require_valid_fd (fd)
420       || require_int (&p, &offset)
421       || require_comma (&p)
422       || require_data (p, packet_len - (p - own_buf), &data, &len))
423     {
424       hostio_packet_error (own_buf);
425       return;
426     }
427 
428 #ifdef HAVE_PWRITE
429   ret = pwrite (fd, data, len, offset);
430 #else
431   ret = -1;
432 #endif
433   /* If we have no pwrite or it failed for this file, use lseek/write.  */
434   if (ret == -1)
435     {
436       ret = lseek (fd, offset, SEEK_SET);
437       if (ret != -1)
438 	ret = write (fd, data, len);
439     }
440 
441   if (ret == -1)
442     {
443       hostio_error (own_buf);
444       free (data);
445       return;
446     }
447 
448   hostio_reply (own_buf, ret);
449   free (data);
450 }
451 
452 static void
453 handle_fstat (char *own_buf, int *new_packet_len)
454 {
455   int fd, bytes_sent;
456   char *p;
457   struct stat st;
458   struct fio_stat fst;
459 
460   p = own_buf + strlen ("vFile:fstat:");
461 
462   if (require_int (&p, &fd)
463       || require_valid_fd (fd)
464       || require_end (p))
465     {
466       hostio_packet_error (own_buf);
467       return;
468     }
469 
470   if (fstat (fd, &st) == -1)
471     {
472       hostio_error (own_buf);
473       return;
474     }
475 
476   host_to_fileio_stat (&st, &fst);
477 
478   bytes_sent = hostio_reply_with_data (own_buf,
479 				       (char *) &fst, sizeof (fst),
480 				       new_packet_len);
481 
482   /* If the response does not fit into a single packet, do not attempt
483      to return a partial response, but simply fail.  */
484   if (bytes_sent < sizeof (fst))
485     write_enn (own_buf);
486 }
487 
488 static void
489 handle_close (char *own_buf)
490 {
491   int fd, ret;
492   char *p;
493   struct fd_list **open_fd_p, *old_fd;
494 
495   p = own_buf + strlen ("vFile:close:");
496 
497   if (require_int (&p, &fd)
498       || require_valid_fd (fd)
499       || require_end (p))
500     {
501       hostio_packet_error (own_buf);
502       return;
503     }
504 
505   ret = close (fd);
506 
507   if (ret == -1)
508     {
509       hostio_error (own_buf);
510       return;
511     }
512 
513   open_fd_p = &open_fds;
514   /* We know that fd is in the list, thanks to require_valid_fd.  */
515   while ((*open_fd_p)->fd != fd)
516     open_fd_p = &(*open_fd_p)->next;
517 
518   old_fd = *open_fd_p;
519   *open_fd_p = (*open_fd_p)->next;
520   free (old_fd);
521 
522   hostio_reply (own_buf, ret);
523 }
524 
525 static void
526 handle_unlink (char *own_buf)
527 {
528   char filename[HOSTIO_PATH_MAX];
529   char *p;
530   int ret;
531 
532   p = own_buf + strlen ("vFile:unlink:");
533 
534   if (require_filename (&p, filename)
535       || require_end (p))
536     {
537       hostio_packet_error (own_buf);
538       return;
539     }
540 
541   if (hostio_fs_pid != 0)
542     ret = the_target->multifs_unlink (hostio_fs_pid, filename);
543   else
544     ret = unlink (filename);
545 
546   if (ret == -1)
547     {
548       hostio_error (own_buf);
549       return;
550     }
551 
552   hostio_reply (own_buf, ret);
553 }
554 
555 static void
556 handle_readlink (char *own_buf, int *new_packet_len)
557 {
558   char filename[HOSTIO_PATH_MAX], linkname[HOSTIO_PATH_MAX];
559   char *p;
560   int ret, bytes_sent;
561 
562   p = own_buf + strlen ("vFile:readlink:");
563 
564   if (require_filename (&p, filename)
565       || require_end (p))
566     {
567       hostio_packet_error (own_buf);
568       return;
569     }
570 
571   if (hostio_fs_pid != 0)
572     ret = the_target->multifs_readlink (hostio_fs_pid, filename,
573 					linkname,
574 					sizeof (linkname) - 1);
575   else
576     ret = readlink (filename, linkname, sizeof (linkname) - 1);
577 
578   if (ret == -1)
579     {
580       hostio_error (own_buf);
581       return;
582     }
583 
584   bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len);
585 
586   /* If the response does not fit into a single packet, do not attempt
587      to return a partial response, but simply fail.  */
588   if (bytes_sent < ret)
589     sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG);
590 }
591 
592 /* Handle all the 'F' file transfer packets.  */
593 
594 int
595 handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
596 {
597   if (startswith (own_buf, "vFile:open:"))
598     handle_open (own_buf);
599   else if (startswith (own_buf, "vFile:pread:"))
600     handle_pread (own_buf, new_packet_len);
601   else if (startswith (own_buf, "vFile:pwrite:"))
602     handle_pwrite (own_buf, packet_len);
603   else if (startswith (own_buf, "vFile:fstat:"))
604     handle_fstat (own_buf, new_packet_len);
605   else if (startswith (own_buf, "vFile:close:"))
606     handle_close (own_buf);
607   else if (startswith (own_buf, "vFile:unlink:"))
608     handle_unlink (own_buf);
609   else if (startswith (own_buf, "vFile:readlink:"))
610     handle_readlink (own_buf, new_packet_len);
611   else if (startswith (own_buf, "vFile:setfs:"))
612     handle_setfs (own_buf);
613   else
614     return 0;
615 
616   return 1;
617 }
618