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