gdb/gdbserver/
[deliverable/binutils-gdb.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 }
This page took 0.048479 seconds and 4 git commands to generate.