Copyright year update in most files of the GDB Project.
[external/binutils.git] / gdb / gdbserver / hostio.c
1 /* Host file transfer support for gdbserver.
2    Copyright (C) 2007-2012 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   /* We know that fd is in the list, thanks to require_valid_fd.  */
422   while ((*open_fd_p)->fd != fd)
423     open_fd_p = &(*open_fd_p)->next;
424
425   old_fd = *open_fd_p;
426   *open_fd_p = (*open_fd_p)->next;
427   free (old_fd);
428
429   hostio_reply (own_buf, ret);
430 }
431
432 static void
433 handle_unlink (char *own_buf)
434 {
435   char filename[PATH_MAX];
436   char *p;
437   int ret;
438
439   p = own_buf + strlen ("vFile:unlink:");
440
441   if (require_filename (&p, filename)
442       || require_end (p))
443     {
444       hostio_packet_error (own_buf);
445       return;
446     }
447
448   ret = unlink (filename);
449
450   if (ret == -1)
451     {
452       hostio_error (own_buf);
453       return;
454     }
455
456   hostio_reply (own_buf, ret);
457 }
458
459 /* Handle all the 'F' file transfer packets.  */
460
461 int
462 handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
463 {
464   if (strncmp (own_buf, "vFile:open:", 11) == 0)
465     handle_open (own_buf);
466   else if (strncmp (own_buf, "vFile:pread:", 11) == 0)
467     handle_pread (own_buf, new_packet_len);
468   else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0)
469     handle_pwrite (own_buf, packet_len);
470   else if (strncmp (own_buf, "vFile:close:", 12) == 0)
471     handle_close (own_buf);
472   else if (strncmp (own_buf, "vFile:unlink:", 13) == 0)
473     handle_unlink (own_buf);
474   else
475     return 0;
476
477   return 1;
478 }