GDBserver
/home/stan/gdb/src/gdb/gdbserver/hostio.c
Go to the documentation of this file.
00001 /* Host file transfer support for gdbserver.
00002    Copyright (C) 2007-2013 Free Software Foundation, Inc.
00003 
00004    Contributed by CodeSourcery.
00005 
00006    This file is part of GDB.
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 3 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00020 
00021 #include "server.h"
00022 #include "gdb/fileio.h"
00023 #include "hostio.h"
00024 
00025 #include <fcntl.h>
00026 #include <limits.h>
00027 #include <unistd.h>
00028 
00029 extern int remote_debug;
00030 
00031 struct fd_list
00032 {
00033   int fd;
00034   struct fd_list *next;
00035 };
00036 
00037 static struct fd_list *open_fds;
00038 
00039 static int
00040 safe_fromhex (char a, int *nibble)
00041 {
00042   if (a >= '0' && a <= '9')
00043     *nibble = a - '0';
00044   else if (a >= 'a' && a <= 'f')
00045     *nibble = a - 'a' + 10;
00046   else if (a >= 'A' && a <= 'F')
00047     *nibble = a - 'A' + 10;
00048   else
00049     return -1;
00050 
00051   return 0;
00052 }
00053 
00054 /* Filenames are hex encoded, so the maximum we can handle is half the
00055    packet buffer size.  Cap to PATH_MAX, if it is shorter.  */
00056 #if !defined (PATH_MAX) || (PATH_MAX > (PBUFSIZ / 2 + 1))
00057 #  define HOSTIO_PATH_MAX (PBUFSIZ / 2 + 1)
00058 #else
00059 #  define HOSTIO_PATH_MAX PATH_MAX
00060 #endif
00061 
00062 static int
00063 require_filename (char **pp, char *filename)
00064 {
00065   int count;
00066   char *p;
00067 
00068   p = *pp;
00069   count = 0;
00070 
00071   while (*p && *p != ',')
00072     {
00073       int nib1, nib2;
00074 
00075       /* Don't allow overflow.  */
00076       if (count >= HOSTIO_PATH_MAX - 1)
00077         return -1;
00078 
00079       if (safe_fromhex (p[0], &nib1)
00080           || safe_fromhex (p[1], &nib2))
00081         return -1;
00082 
00083       filename[count++] = nib1 * 16 + nib2;
00084       p += 2;
00085     }
00086 
00087   filename[count] = '\0';
00088   *pp = p;
00089   return 0;
00090 }
00091 
00092 static int
00093 require_int (char **pp, int *value)
00094 {
00095   char *p;
00096   int count;
00097 
00098   p = *pp;
00099   *value = 0;
00100   count = 0;
00101 
00102   while (*p && *p != ',')
00103     {
00104       int nib;
00105 
00106       /* Don't allow overflow.  */
00107       if (count >= 7)
00108         return -1;
00109 
00110       if (safe_fromhex (p[0], &nib))
00111         return -1;
00112       *value = *value * 16 + nib;
00113       p++;
00114       count++;
00115     }
00116 
00117   *pp = p;
00118   return 0;
00119 }
00120 
00121 static int
00122 require_data (char *p, int p_len, char **data, int *data_len)
00123 {
00124   int input_index, output_index, escaped;
00125 
00126   *data = xmalloc (p_len);
00127 
00128   output_index = 0;
00129   escaped = 0;
00130   for (input_index = 0; input_index < p_len; input_index++)
00131     {
00132       char b = p[input_index];
00133 
00134       if (escaped)
00135         {
00136           (*data)[output_index++] = b ^ 0x20;
00137           escaped = 0;
00138         }
00139       else if (b == '}')
00140         escaped = 1;
00141       else
00142         (*data)[output_index++] = b;
00143     }
00144 
00145   if (escaped)
00146     {
00147       free (*data);
00148       return -1;
00149     }
00150 
00151   *data_len = output_index;
00152   return 0;
00153 }
00154 
00155 static int
00156 require_comma (char **pp)
00157 {
00158   if (**pp == ',')
00159     {
00160       (*pp)++;
00161       return 0;
00162     }
00163   else
00164     return -1;
00165 }
00166 
00167 static int
00168 require_end (char *p)
00169 {
00170   if (*p == '\0')
00171     return 0;
00172   else
00173     return -1;
00174 }
00175 
00176 static int
00177 require_valid_fd (int fd)
00178 {
00179   struct fd_list *fd_ptr;
00180 
00181   for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next)
00182     if (fd_ptr->fd == fd)
00183       return 0;
00184 
00185   return -1;
00186 }
00187 
00188 /* Fill in own_buf with the last hostio error packet, however it
00189    suitable for the target.  */
00190 static void
00191 hostio_error (char *own_buf)
00192 {
00193   the_target->hostio_last_error (own_buf);
00194 }
00195 
00196 static void
00197 hostio_packet_error (char *own_buf)
00198 {
00199   sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
00200 }
00201 
00202 static void
00203 hostio_reply (char *own_buf, int result)
00204 {
00205   sprintf (own_buf, "F%x", result);
00206 }
00207 
00208 static int
00209 hostio_reply_with_data (char *own_buf, char *buffer, int len,
00210                         int *new_packet_len)
00211 {
00212   int input_index, output_index, out_maxlen;
00213 
00214   sprintf (own_buf, "F%x;", len);
00215   output_index = strlen (own_buf);
00216 
00217   out_maxlen = PBUFSIZ;
00218 
00219   for (input_index = 0; input_index < len; input_index++)
00220     {
00221       char b = buffer[input_index];
00222 
00223       if (b == '$' || b == '#' || b == '}' || b == '*')
00224         {
00225           /* These must be escaped.  */
00226           if (output_index + 2 > out_maxlen)
00227             break;
00228           own_buf[output_index++] = '}';
00229           own_buf[output_index++] = b ^ 0x20;
00230         }
00231       else
00232         {
00233           if (output_index + 1 > out_maxlen)
00234             break;
00235           own_buf[output_index++] = b;
00236         }
00237     }
00238 
00239   *new_packet_len = output_index;
00240   return input_index;
00241 }
00242 
00243 static int
00244 fileio_open_flags_to_host (int fileio_open_flags, int *open_flags_p)
00245 {
00246   int open_flags = 0;
00247 
00248   if (fileio_open_flags & ~FILEIO_O_SUPPORTED)
00249     return -1;
00250 
00251   if (fileio_open_flags & FILEIO_O_CREAT)
00252     open_flags |= O_CREAT;
00253   if (fileio_open_flags & FILEIO_O_EXCL)
00254     open_flags |= O_EXCL;
00255   if (fileio_open_flags & FILEIO_O_TRUNC)
00256     open_flags |= O_TRUNC;
00257   if (fileio_open_flags & FILEIO_O_APPEND)
00258     open_flags |= O_APPEND;
00259   if (fileio_open_flags & FILEIO_O_RDONLY)
00260     open_flags |= O_RDONLY;
00261   if (fileio_open_flags & FILEIO_O_WRONLY)
00262     open_flags |= O_WRONLY;
00263   if (fileio_open_flags & FILEIO_O_RDWR)
00264     open_flags |= O_RDWR;
00265 /* On systems supporting binary and text mode, always open files in
00266    binary mode. */
00267 #ifdef O_BINARY
00268   open_flags |= O_BINARY;
00269 #endif
00270 
00271   *open_flags_p = open_flags;
00272   return 0;
00273 }
00274 
00275 static void
00276 handle_open (char *own_buf)
00277 {
00278   char filename[HOSTIO_PATH_MAX];
00279   char *p;
00280   int fileio_flags, mode, flags, fd;
00281   struct fd_list *new_fd;
00282 
00283   p = own_buf + strlen ("vFile:open:");
00284 
00285   if (require_filename (&p, filename)
00286       || require_comma (&p)
00287       || require_int (&p, &fileio_flags)
00288       || require_comma (&p)
00289       || require_int (&p, &mode)
00290       || require_end (p)
00291       || fileio_open_flags_to_host (fileio_flags, &flags))
00292     {
00293       hostio_packet_error (own_buf);
00294       return;
00295     }
00296 
00297   /* We do not need to convert MODE, since the fileio protocol
00298      uses the standard values.  */
00299   fd = open (filename, flags, mode);
00300 
00301   if (fd == -1)
00302     {
00303       hostio_error (own_buf);
00304       return;
00305     }
00306 
00307   /* Record the new file descriptor.  */
00308   new_fd = xmalloc (sizeof (struct fd_list));
00309   new_fd->fd = fd;
00310   new_fd->next = open_fds;
00311   open_fds = new_fd;
00312 
00313   hostio_reply (own_buf, fd);
00314 }
00315 
00316 static void
00317 handle_pread (char *own_buf, int *new_packet_len)
00318 {
00319   int fd, ret, len, offset, bytes_sent;
00320   char *p, *data;
00321 
00322   p = own_buf + strlen ("vFile:pread:");
00323 
00324   if (require_int (&p, &fd)
00325       || require_comma (&p)
00326       || require_valid_fd (fd)
00327       || require_int (&p, &len)
00328       || require_comma (&p)
00329       || require_int (&p, &offset)
00330       || require_end (p))
00331     {
00332       hostio_packet_error (own_buf);
00333       return;
00334     }
00335 
00336   data = xmalloc (len);
00337 #ifdef HAVE_PREAD
00338   ret = pread (fd, data, len, offset);
00339 #else
00340   ret = -1;
00341 #endif
00342   /* If we have no pread or it failed for this file, use lseek/read.  */
00343   if (ret == -1)
00344     {
00345       ret = lseek (fd, offset, SEEK_SET);
00346       if (ret != -1)
00347         ret = read (fd, data, len);
00348     }
00349 
00350   if (ret == -1)
00351     {
00352       hostio_error (own_buf);
00353       free (data);
00354       return;
00355     }
00356 
00357   bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len);
00358 
00359   /* If we were using read, and the data did not all fit in the reply,
00360      we would have to back up using lseek here.  With pread it does
00361      not matter.  But we still have a problem; the return value in the
00362      packet might be wrong, so we must fix it.  This time it will
00363      definitely fit.  */
00364   if (bytes_sent < ret)
00365     bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent,
00366                                          new_packet_len);
00367 
00368   free (data);
00369 }
00370 
00371 static void
00372 handle_pwrite (char *own_buf, int packet_len)
00373 {
00374   int fd, ret, len, offset;
00375   char *p, *data;
00376 
00377   p = own_buf + strlen ("vFile:pwrite:");
00378 
00379   if (require_int (&p, &fd)
00380       || require_comma (&p)
00381       || require_valid_fd (fd)
00382       || require_int (&p, &offset)
00383       || require_comma (&p)
00384       || require_data (p, packet_len - (p - own_buf), &data, &len))
00385     {
00386       hostio_packet_error (own_buf);
00387       return;
00388     }
00389 
00390 #ifdef HAVE_PWRITE
00391   ret = pwrite (fd, data, len, offset);
00392 #else
00393   ret = -1;
00394 #endif
00395   /* If we have no pwrite or it failed for this file, use lseek/write.  */
00396   if (ret == -1)
00397     {
00398       ret = lseek (fd, offset, SEEK_SET);
00399       if (ret != -1)
00400         ret = write (fd, data, len);
00401     }
00402 
00403   if (ret == -1)
00404     {
00405       hostio_error (own_buf);
00406       free (data);
00407       return;
00408     }
00409 
00410   hostio_reply (own_buf, ret);
00411   free (data);
00412 }
00413 
00414 static void
00415 handle_close (char *own_buf)
00416 {
00417   int fd, ret;
00418   char *p;
00419   struct fd_list **open_fd_p, *old_fd;
00420 
00421   p = own_buf + strlen ("vFile:close:");
00422 
00423   if (require_int (&p, &fd)
00424       || require_valid_fd (fd)
00425       || require_end (p))
00426     {
00427       hostio_packet_error (own_buf);
00428       return;
00429     }
00430 
00431   ret = close (fd);
00432 
00433   if (ret == -1)
00434     {
00435       hostio_error (own_buf);
00436       return;
00437     }
00438 
00439   open_fd_p = &open_fds;
00440   /* We know that fd is in the list, thanks to require_valid_fd.  */
00441   while ((*open_fd_p)->fd != fd)
00442     open_fd_p = &(*open_fd_p)->next;
00443 
00444   old_fd = *open_fd_p;
00445   *open_fd_p = (*open_fd_p)->next;
00446   free (old_fd);
00447 
00448   hostio_reply (own_buf, ret);
00449 }
00450 
00451 static void
00452 handle_unlink (char *own_buf)
00453 {
00454   char filename[HOSTIO_PATH_MAX];
00455   char *p;
00456   int ret;
00457 
00458   p = own_buf + strlen ("vFile:unlink:");
00459 
00460   if (require_filename (&p, filename)
00461       || require_end (p))
00462     {
00463       hostio_packet_error (own_buf);
00464       return;
00465     }
00466 
00467   ret = unlink (filename);
00468 
00469   if (ret == -1)
00470     {
00471       hostio_error (own_buf);
00472       return;
00473     }
00474 
00475   hostio_reply (own_buf, ret);
00476 }
00477 
00478 static void
00479 handle_readlink (char *own_buf, int *new_packet_len)
00480 {
00481 #if defined (HAVE_READLINK)
00482   char filename[HOSTIO_PATH_MAX], linkname[HOSTIO_PATH_MAX];
00483   char *p;
00484   int ret, bytes_sent;
00485 
00486   p = own_buf + strlen ("vFile:readlink:");
00487 
00488   if (require_filename (&p, filename)
00489       || require_end (p))
00490     {
00491       hostio_packet_error (own_buf);
00492       return;
00493     }
00494 
00495   ret = readlink (filename, linkname, sizeof (linkname) - 1);
00496   if (ret == -1)
00497     {
00498       hostio_error (own_buf);
00499       return;
00500     }
00501 
00502   bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len);
00503 
00504   /* If the response does not fit into a single packet, do not attempt
00505      to return a partial response, but simply fail.  */
00506   if (bytes_sent < ret)
00507     sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG);
00508 #else /* ! HAVE_READLINK */
00509     sprintf (own_buf, "F-1,%x", FILEIO_ENOSYS);
00510 #endif
00511 }
00512 
00513 /* Handle all the 'F' file transfer packets.  */
00514 
00515 int
00516 handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
00517 {
00518   if (strncmp (own_buf, "vFile:open:", 11) == 0)
00519     handle_open (own_buf);
00520   else if (strncmp (own_buf, "vFile:pread:", 11) == 0)
00521     handle_pread (own_buf, new_packet_len);
00522   else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0)
00523     handle_pwrite (own_buf, packet_len);
00524   else if (strncmp (own_buf, "vFile:close:", 12) == 0)
00525     handle_close (own_buf);
00526   else if (strncmp (own_buf, "vFile:unlink:", 13) == 0)
00527     handle_unlink (own_buf);
00528   else if (strncmp (own_buf, "vFile:readlink:", 15) == 0)
00529     handle_readlink (own_buf, new_packet_len);
00530   else
00531     return 0;
00532 
00533   return 1;
00534 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines