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