* linux-low.c (linux_remove_process): Add `detaching' parameter.
[deliverable/binutils-gdb.git] / gdb / gdbserver / hostio.c
CommitLineData
a6b151f1 1/* Host file transfer support for gdbserver.
0fb0cc75 2 Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
a6b151f1
DJ
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
32de4b9d 10 the Free Software Foundation; either version 3 of the License, or
a6b151f1
DJ
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
32de4b9d 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
a6b151f1
DJ
20
21#include "server.h"
22#include "gdb/fileio.h"
23
a6b151f1
DJ
24#include <fcntl.h>
25#include <limits.h>
26#include <unistd.h>
27
28extern int remote_debug;
29
30struct fd_list
31{
32 int fd;
33 struct fd_list *next;
34};
35
36static struct fd_list *open_fds;
37
38static int
39safe_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
53static int
54require_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
83static int
84require_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
112static int
113require_data (char *p, int p_len, char **data, int *data_len)
114{
115 int input_index, output_index, escaped;
116
bca929d3 117 *data = xmalloc (p_len);
a6b151f1
DJ
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
143static int
144require_comma (char **pp)
145{
146 if (**pp == ',')
147 {
148 (*pp)++;
149 return 0;
150 }
151 else
152 return -1;
153}
154
155static int
156require_end (char *p)
157{
158 if (*p == '\0')
159 return 0;
160 else
161 return -1;
162}
163
164static int
165require_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
59a016f0
PA
176/* Fill in own_buf with the last hostio error packet, however it
177 suitable for the target. */
a6b151f1 178static void
59a016f0 179hostio_error (char *own_buf)
a6b151f1 180{
59a016f0 181 the_target->hostio_last_error (own_buf);
a6b151f1
DJ
182}
183
184static void
185hostio_packet_error (char *own_buf)
186{
59a016f0 187 sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
a6b151f1
DJ
188}
189
190static void
191hostio_reply (char *own_buf, int result)
192{
193 sprintf (own_buf, "F%x", result);
194}
195
196static int
197hostio_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
231static int
232fileio_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
263static void
264handle_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 {
59a016f0 291 hostio_error (own_buf);
a6b151f1
DJ
292 return;
293 }
294
295 /* Record the new file descriptor. */
bca929d3 296 new_fd = xmalloc (sizeof (struct fd_list));
a6b151f1
DJ
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
304static void
305handle_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
bca929d3 324 data = xmalloc (len);
4e799345 325#ifdef HAVE_PREAD
a6b151f1 326 ret = pread (fd, data, len, offset);
4e799345
DJ
327#else
328 ret = lseek (fd, offset, SEEK_SET);
329 if (ret != -1)
330 ret = read (fd, data, len);
331#endif
a6b151f1
DJ
332
333 if (ret == -1)
334 {
59a016f0 335 hostio_error (own_buf);
a6b151f1
DJ
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
354static void
355handle_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
4e799345 373#ifdef HAVE_PWRITE
a6b151f1 374 ret = pwrite (fd, data, len, offset);
4e799345
DJ
375#else
376 ret = lseek (fd, offset, SEEK_SET);
377 if (ret != -1)
378 ret = write (fd, data, len);
379#endif
a6b151f1
DJ
380
381 if (ret == -1)
382 {
59a016f0 383 hostio_error (own_buf);
a6b151f1
DJ
384 free (data);
385 return;
386 }
387
388 hostio_reply (own_buf, ret);
389 free (data);
390}
391
392static void
393handle_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 {
59a016f0 413 hostio_error (own_buf);
a6b151f1
DJ
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
428static void
429handle_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 {
59a016f0 448 hostio_error (own_buf);
a6b151f1
DJ
449 return;
450 }
451
452 hostio_reply (own_buf, ret);
453}
454
455/* Handle all the 'F' file transfer packets. */
456
457int
458handle_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.237559 seconds and 4 git commands to generate.