gdb/gdbserver/
[external/binutils.git] / gdb / gdbserver / hostio.c
1 /* Host file transfer support for gdbserver.
2    Copyright (C) 2007, 2008, 2009, 2010, 2011 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
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <unistd.h>
27
28 extern int remote_debug;
29
30 struct fd_list
31 {
32   int fd;
33   struct fd_list *next;
34 };
35
36 static struct fd_list *open_fds;
37
38 static int
39 safe_fromhex (char a, int *nibble)
40 {
41   if (a >= '0' && a <= '9')
42     *nibble = a - '0';
43   else if (a >= 'a' && a <= 'f')
44     *nibble = a - 'a' + 10;
45   else if (a >= 'A' && a <= 'F')
46     *nibble = a - 'A' + 10;
47   else
48     return -1;
49
50   return 0;
51 }
52
53 static int
54 require_filename (char **pp, char *filename)
55 {
56   int count;
57   char *p;
58
59   p = *pp;
60   count = 0;
61
62   while (*p && *p != ',')
63     {
64       int nib1, nib2;
65
66       /* Don't allow overflow.  */
67       if (count >= PATH_MAX - 1)
68         return -1;
69
70       if (safe_fromhex (p[0], &nib1)
71           || safe_fromhex (p[1], &nib2))
72         return -1;
73
74       filename[count++] = nib1 * 16 + nib2;
75       p += 2;
76     }
77
78   filename[count] = '\0';
79   *pp = p;
80   return 0;
81 }
82
83 static int
84 require_int (char **pp, int *value)
85 {
86   char *p;
87   int count;
88
89   p = *pp;
90   *value = 0;
91   count = 0;
92
93   while (*p && *p != ',')
94     {
95       int nib;
96
97       /* Don't allow overflow.  */
98       if (count >= 7)
99         return -1;
100
101       if (safe_fromhex (p[0], &nib))
102         return -1;
103       *value = *value * 16 + nib;
104       p++;
105       count++;
106     }
107
108   *pp = p;
109   return 0;
110 }
111
112 static int
113 require_data (char *p, int p_len, char **data, int *data_len)
114 {
115   int input_index, output_index, escaped;
116
117   *data = xmalloc (p_len);
118
119   output_index = 0;
120   escaped = 0;
121   for (input_index = 0; input_index < p_len; input_index++)
122     {
123       char b = p[input_index];
124
125       if (escaped)
126         {
127           (*data)[output_index++] = b ^ 0x20;
128           escaped = 0;
129         }
130       else if (b == '}')
131         escaped = 1;
132       else
133         (*data)[output_index++] = b;
134     }
135
136   if (escaped)
137     {
138       free (data);
139       return -1;
140     }
141
142   *data_len = output_index;
143   return 0;
144 }
145
146 static int
147 require_comma (char **pp)
148 {
149   if (**pp == ',')
150     {
151       (*pp)++;
152       return 0;
153     }
154   else
155     return -1;
156 }
157
158 static int
159 require_end (char *p)
160 {
161   if (*p == '\0')
162     return 0;
163   else
164     return -1;
165 }
166
167 static int
168 require_valid_fd (int fd)
169 {
170   struct fd_list *fd_ptr;
171
172   for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next)
173     if (fd_ptr->fd == fd)
174       return 0;
175
176   return -1;
177 }
178
179 /* Fill in own_buf with the last hostio error packet, however it
180    suitable for the target.  */
181 static void
182 hostio_error (char *own_buf)
183 {
184   the_target->hostio_last_error (own_buf);
185 }
186
187 static void
188 hostio_packet_error (char *own_buf)
189 {
190   sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
191 }
192
193 static void
194 hostio_reply (char *own_buf, int result)
195 {
196   sprintf (own_buf, "F%x", result);
197 }
198
199 static int
200 hostio_reply_with_data (char *own_buf, char *buffer, int len,
201                         int *new_packet_len)
202 {
203   int input_index, output_index, out_maxlen;
204
205   sprintf (own_buf, "F%x;", len);
206   output_index = strlen (own_buf);
207
208   out_maxlen = PBUFSIZ;
209
210   for (input_index = 0; input_index < len; input_index++)
211     {
212       char b = buffer[input_index];
213
214       if (b == '$' || b == '#' || b == '}' || b == '*')
215         {
216           /* These must be escaped.  */
217           if (output_index + 2 > out_maxlen)
218             break;
219           own_buf[output_index++] = '}';
220           own_buf[output_index++] = b ^ 0x20;
221         }
222       else
223         {
224           if (output_index + 1 > out_maxlen)
225             break;
226           own_buf[output_index++] = b;
227         }
228     }
229
230   *new_packet_len = output_index;
231   return input_index;
232 }
233
234 static int
235 fileio_open_flags_to_host (int fileio_open_flags, int *open_flags_p)
236 {
237   int open_flags = 0;
238
239   if (fileio_open_flags & ~FILEIO_O_SUPPORTED)
240     return -1;
241
242   if (fileio_open_flags & FILEIO_O_CREAT)
243     open_flags |= O_CREAT;
244   if (fileio_open_flags & FILEIO_O_EXCL)
245     open_flags |= O_EXCL;
246   if (fileio_open_flags & FILEIO_O_TRUNC)
247     open_flags |= O_TRUNC;
248   if (fileio_open_flags & FILEIO_O_APPEND)
249     open_flags |= O_APPEND;
250   if (fileio_open_flags & FILEIO_O_RDONLY)
251     open_flags |= O_RDONLY;
252   if (fileio_open_flags & FILEIO_O_WRONLY)
253     open_flags |= O_WRONLY;
254   if (fileio_open_flags & FILEIO_O_RDWR)
255     open_flags |= O_RDWR;
256 /* On systems supporting binary and text mode, always open files in
257    binary mode. */
258 #ifdef O_BINARY
259   open_flags |= O_BINARY;
260 #endif
261
262   *open_flags_p = open_flags;
263   return 0;
264 }
265
266 static void
267 handle_open (char *own_buf)
268 {
269   char filename[PATH_MAX];
270   char *p;
271   int fileio_flags, mode, flags, fd;
272   struct fd_list *new_fd;
273
274   p = own_buf + strlen ("vFile:open:");
275
276   if (require_filename (&p, filename)
277       || require_comma (&p)
278       || require_int (&p, &fileio_flags)
279       || require_comma (&p)
280       || require_int (&p, &mode)
281       || require_end (p)
282       || fileio_open_flags_to_host (fileio_flags, &flags))
283     {
284       hostio_packet_error (own_buf);
285       return;
286     }
287
288   /* We do not need to convert MODE, since the fileio protocol
289      uses the standard values.  */
290   fd = open (filename, flags, mode);
291
292   if (fd == -1)
293     {
294       hostio_error (own_buf);
295       return;
296     }
297
298   /* Record the new file descriptor.  */
299   new_fd = xmalloc (sizeof (struct fd_list));
300   new_fd->fd = fd;
301   new_fd->next = open_fds;
302   open_fds = new_fd;
303
304   hostio_reply (own_buf, fd);
305 }
306
307 static void
308 handle_pread (char *own_buf, int *new_packet_len)
309 {
310   int fd, ret, len, offset, bytes_sent;
311   char *p, *data;
312
313   p = own_buf + strlen ("vFile:pread:");
314
315   if (require_int (&p, &fd)
316       || require_comma (&p)
317       || require_valid_fd (fd)
318       || require_int (&p, &len)
319       || require_comma (&p)
320       || require_int (&p, &offset)
321       || require_end (p))
322     {
323       hostio_packet_error (own_buf);
324       return;
325     }
326
327   data = xmalloc (len);
328 #ifdef HAVE_PREAD
329   ret = pread (fd, data, len, offset);
330 #else
331   ret = lseek (fd, offset, SEEK_SET);
332   if (ret != -1)
333     ret = read (fd, data, len);
334 #endif
335
336   if (ret == -1)
337     {
338       hostio_error (own_buf);
339       free (data);
340       return;
341     }
342
343   bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len);
344
345   /* If we were using read, and the data did not all fit in the reply,
346      we would have to back up using lseek here.  With pread it does
347      not matter.  But we still have a problem; the return value in the
348      packet might be wrong, so we must fix it.  This time it will
349      definitely fit.  */
350   if (bytes_sent < ret)
351     bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent,
352                                          new_packet_len);
353
354   free (data);
355 }
356
357 static void
358 handle_pwrite (char *own_buf, int packet_len)
359 {
360   int fd, ret, len, offset;
361   char *p, *data;
362
363   p = own_buf + strlen ("vFile:pwrite:");
364
365   if (require_int (&p, &fd)
366       || require_comma (&p)
367       || require_valid_fd (fd)
368       || require_int (&p, &offset)
369       || require_comma (&p)
370       || require_data (p, packet_len - (p - own_buf), &data, &len))
371     {
372       hostio_packet_error (own_buf);
373       return;
374     }
375
376 #ifdef HAVE_PWRITE
377   ret = pwrite (fd, data, len, offset);
378 #else
379   ret = lseek (fd, offset, SEEK_SET);
380   if (ret != -1)
381     ret = write (fd, data, len);
382 #endif
383
384   if (ret == -1)
385     {
386       hostio_error (own_buf);
387       free (data);
388       return;
389     }
390
391   hostio_reply (own_buf, ret);
392   free (data);
393 }
394
395 static void
396 handle_close (char *own_buf)
397 {
398   int fd, ret;
399   char *p;
400   struct fd_list **open_fd_p, *old_fd;
401
402   p = own_buf + strlen ("vFile:close:");
403
404   if (require_int (&p, &fd)
405       || require_valid_fd (fd)
406       || require_end (p))
407     {
408       hostio_packet_error (own_buf);
409       return;
410     }
411
412   ret = close (fd);
413
414   if (ret == -1)
415     {
416       hostio_error (own_buf);
417       return;
418     }
419
420   open_fd_p = &open_fds;
421   while (*open_fd_p && (*open_fd_p)->fd != fd)
422     open_fd_p = &(*open_fd_p)->next;
423
424   old_fd = *open_fd_p;
425   *open_fd_p = (*open_fd_p)->next;
426   free (old_fd);
427
428   hostio_reply (own_buf, ret);
429 }
430
431 static void
432 handle_unlink (char *own_buf)
433 {
434   char filename[PATH_MAX];
435   char *p;
436   int ret;
437
438   p = own_buf + strlen ("vFile:unlink:");
439
440   if (require_filename (&p, filename)
441       || require_end (p))
442     {
443       hostio_packet_error (own_buf);
444       return;
445     }
446
447   ret = unlink (filename);
448
449   if (ret == -1)
450     {
451       hostio_error (own_buf);
452       return;
453     }
454
455   hostio_reply (own_buf, ret);
456 }
457
458 /* Handle all the 'F' file transfer packets.  */
459
460 int
461 handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
462 {
463   if (strncmp (own_buf, "vFile:open:", 11) == 0)
464     handle_open (own_buf);
465   else if (strncmp (own_buf, "vFile:pread:", 11) == 0)
466     handle_pread (own_buf, new_packet_len);
467   else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0)
468     handle_pwrite (own_buf, packet_len);
469   else if (strncmp (own_buf, "vFile:close:", 12) == 0)
470     handle_close (own_buf);
471   else if (strncmp (own_buf, "vFile:unlink:", 13) == 0)
472     handle_unlink (own_buf);
473   else
474     return 0;
475
476   return 1;
477 }