daily update
[external/binutils.git] / gdb / gdbserver / hostio.c
1 /* Host file transfer support for gdbserver.
2    Copyright (C) 2007, 2008, 2009, 2010 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     return -1;
138
139   *data_len = output_index;
140   return 0;
141 }
142
143 static int
144 require_comma (char **pp)
145 {
146   if (**pp == ',')
147     {
148       (*pp)++;
149       return 0;
150     }
151   else
152     return -1;
153 }
154
155 static int
156 require_end (char *p)
157 {
158   if (*p == '\0')
159     return 0;
160   else
161     return -1;
162 }
163
164 static int
165 require_valid_fd (int fd)
166 {
167   struct fd_list *fd_ptr;
168
169   for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next)
170     if (fd_ptr->fd == fd)
171       return 0;
172
173   return -1;
174 }
175
176 /* Fill in own_buf with the last hostio error packet, however it
177    suitable for the target.  */
178 static void
179 hostio_error (char *own_buf)
180 {
181   the_target->hostio_last_error (own_buf);
182 }
183
184 static void
185 hostio_packet_error (char *own_buf)
186 {
187   sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
188 }
189
190 static void
191 hostio_reply (char *own_buf, int result)
192 {
193   sprintf (own_buf, "F%x", result);
194 }
195
196 static int
197 hostio_reply_with_data (char *own_buf, char *buffer, int len,
198                         int *new_packet_len)
199 {
200   int input_index, output_index, out_maxlen;
201
202   sprintf (own_buf, "F%x;", len);
203   output_index = strlen (own_buf);
204
205   out_maxlen = PBUFSIZ;
206
207   for (input_index = 0; input_index < len; input_index++)
208     {
209       char b = buffer[input_index];
210
211       if (b == '$' || b == '#' || b == '}' || b == '*')
212         {
213           /* These must be escaped.  */
214           if (output_index + 2 > out_maxlen)
215             break;
216           own_buf[output_index++] = '}';
217           own_buf[output_index++] = b ^ 0x20;
218         }
219       else
220         {
221           if (output_index + 1 > out_maxlen)
222             break;
223           own_buf[output_index++] = b;
224         }
225     }
226
227   *new_packet_len = output_index;
228   return input_index;
229 }
230
231 static int
232 fileio_open_flags_to_host (int fileio_open_flags, int *open_flags_p)
233 {
234   int open_flags = 0;
235
236   if (fileio_open_flags & ~FILEIO_O_SUPPORTED)
237     return -1;
238
239   if (fileio_open_flags & FILEIO_O_CREAT)
240     open_flags |= O_CREAT;
241   if (fileio_open_flags & FILEIO_O_EXCL)
242     open_flags |= O_EXCL;
243   if (fileio_open_flags & FILEIO_O_TRUNC)
244     open_flags |= O_TRUNC;
245   if (fileio_open_flags & FILEIO_O_APPEND)
246     open_flags |= O_APPEND;
247   if (fileio_open_flags & FILEIO_O_RDONLY)
248     open_flags |= O_RDONLY;
249   if (fileio_open_flags & FILEIO_O_WRONLY)
250     open_flags |= O_WRONLY;
251   if (fileio_open_flags & FILEIO_O_RDWR)
252     open_flags |= O_RDWR;
253 /* On systems supporting binary and text mode, always open files in
254    binary mode. */
255 #ifdef O_BINARY
256   open_flags |= O_BINARY;
257 #endif
258
259   *open_flags_p = open_flags;
260   return 0;
261 }
262
263 static void
264 handle_open (char *own_buf)
265 {
266   char filename[PATH_MAX];
267   char *p;
268   int fileio_flags, mode, flags, fd;
269   struct fd_list *new_fd;
270
271   p = own_buf + strlen ("vFile:open:");
272
273   if (require_filename (&p, filename)
274       || require_comma (&p)
275       || require_int (&p, &fileio_flags)
276       || require_comma (&p)
277       || require_int (&p, &mode)
278       || require_end (p)
279       || fileio_open_flags_to_host (fileio_flags, &flags))
280     {
281       hostio_packet_error (own_buf);
282       return;
283     }
284
285   /* We do not need to convert MODE, since the fileio protocol
286      uses the standard values.  */
287   fd = open (filename, flags, mode);
288
289   if (fd == -1)
290     {
291       hostio_error (own_buf);
292       return;
293     }
294
295   /* Record the new file descriptor.  */
296   new_fd = xmalloc (sizeof (struct fd_list));
297   new_fd->fd = fd;
298   new_fd->next = open_fds;
299   open_fds = new_fd;
300
301   hostio_reply (own_buf, fd);
302 }
303
304 static void
305 handle_pread (char *own_buf, int *new_packet_len)
306 {
307   int fd, ret, len, offset, bytes_sent;
308   char *p, *data;
309
310   p = own_buf + strlen ("vFile:pread:");
311
312   if (require_int (&p, &fd)
313       || require_comma (&p)
314       || require_valid_fd (fd)
315       || require_int (&p, &len)
316       || require_comma (&p)
317       || require_int (&p, &offset)
318       || require_end (p))
319     {
320       hostio_packet_error (own_buf);
321       return;
322     }
323
324   data = xmalloc (len);
325 #ifdef HAVE_PREAD
326   ret = pread (fd, data, len, offset);
327 #else
328   ret = lseek (fd, offset, SEEK_SET);
329   if (ret != -1)
330     ret = read (fd, data, len);
331 #endif
332
333   if (ret == -1)
334     {
335       hostio_error (own_buf);
336       free (data);
337       return;
338     }
339
340   bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len);
341
342   /* If we were using read, and the data did not all fit in the reply,
343      we would have to back up using lseek here.  With pread it does
344      not matter.  But we still have a problem; the return value in the
345      packet might be wrong, so we must fix it.  This time it will
346      definitely fit.  */
347   if (bytes_sent < ret)
348     bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent,
349                                          new_packet_len);
350
351   free (data);
352 }
353
354 static void
355 handle_pwrite (char *own_buf, int packet_len)
356 {
357   int fd, ret, len, offset;
358   char *p, *data;
359
360   p = own_buf + strlen ("vFile:pwrite:");
361
362   if (require_int (&p, &fd)
363       || require_comma (&p)
364       || require_valid_fd (fd)
365       || require_int (&p, &offset)
366       || require_comma (&p)
367       || require_data (p, packet_len - (p - own_buf), &data, &len))
368     {
369       hostio_packet_error (own_buf);
370       return;
371     }
372
373 #ifdef HAVE_PWRITE
374   ret = pwrite (fd, data, len, offset);
375 #else
376   ret = lseek (fd, offset, SEEK_SET);
377   if (ret != -1)
378     ret = write (fd, data, len);
379 #endif
380
381   if (ret == -1)
382     {
383       hostio_error (own_buf);
384       free (data);
385       return;
386     }
387
388   hostio_reply (own_buf, ret);
389   free (data);
390 }
391
392 static void
393 handle_close (char *own_buf)
394 {
395   int fd, ret;
396   char *p;
397   struct fd_list **open_fd_p, *old_fd;
398
399   p = own_buf + strlen ("vFile:close:");
400
401   if (require_int (&p, &fd)
402       || require_valid_fd (fd)
403       || require_end (p))
404     {
405       hostio_packet_error (own_buf);
406       return;
407     }
408
409   ret = close (fd);
410
411   if (ret == -1)
412     {
413       hostio_error (own_buf);
414       return;
415     }
416
417   open_fd_p = &open_fds;
418   while (*open_fd_p && (*open_fd_p)->fd != fd)
419     open_fd_p = &(*open_fd_p)->next;
420
421   old_fd = *open_fd_p;
422   *open_fd_p = (*open_fd_p)->next;
423   free (old_fd);
424
425   hostio_reply (own_buf, ret);
426 }
427
428 static void
429 handle_unlink (char *own_buf)
430 {
431   char filename[PATH_MAX];
432   char *p;
433   int ret;
434
435   p = own_buf + strlen ("vFile:unlink:");
436
437   if (require_filename (&p, filename)
438       || require_end (p))
439     {
440       hostio_packet_error (own_buf);
441       return;
442     }
443
444   ret = unlink (filename);
445
446   if (ret == -1)
447     {
448       hostio_error (own_buf);
449       return;
450     }
451
452   hostio_reply (own_buf, ret);
453 }
454
455 /* Handle all the 'F' file transfer packets.  */
456
457 int
458 handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
459 {
460   if (strncmp (own_buf, "vFile:open:", 11) == 0)
461     handle_open (own_buf);
462   else if (strncmp (own_buf, "vFile:pread:", 11) == 0)
463     handle_pread (own_buf, new_packet_len);
464   else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0)
465     handle_pwrite (own_buf, packet_len);
466   else if (strncmp (own_buf, "vFile:close:", 12) == 0)
467     handle_close (own_buf);
468   else if (strncmp (own_buf, "vFile:unlink:", 13) == 0)
469     handle_unlink (own_buf);
470   else
471     return 0;
472
473   return 1;
474 }