* tui/tui-regs.c (tui_display_register): Add comment about
[deliverable/binutils-gdb.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 }
This page took 0.040033 seconds and 4 git commands to generate.