ChangeLog:
[deliverable/binutils-gdb.git] / gdb / gdbserver / hostio.c
CommitLineData
a6b151f1 1/* Host file transfer support for gdbserver.
0b302171 2 Copyright (C) 2007-2012 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)
9130f83e 137 {
8040bd49 138 free (*data);
9130f83e
MS
139 return -1;
140 }
a6b151f1
DJ
141
142 *data_len = output_index;
143 return 0;
144}
145
146static int
147require_comma (char **pp)
148{
149 if (**pp == ',')
150 {
151 (*pp)++;
152 return 0;
153 }
154 else
155 return -1;
156}
157
158static int
159require_end (char *p)
160{
161 if (*p == '\0')
162 return 0;
163 else
164 return -1;
165}
166
167static int
168require_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
59a016f0
PA
179/* Fill in own_buf with the last hostio error packet, however it
180 suitable for the target. */
a6b151f1 181static void
59a016f0 182hostio_error (char *own_buf)
a6b151f1 183{
59a016f0 184 the_target->hostio_last_error (own_buf);
a6b151f1
DJ
185}
186
187static void
188hostio_packet_error (char *own_buf)
189{
59a016f0 190 sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
a6b151f1
DJ
191}
192
193static void
194hostio_reply (char *own_buf, int result)
195{
196 sprintf (own_buf, "F%x", result);
197}
198
199static int
200hostio_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
234static int
235fileio_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
266static void
267handle_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 {
59a016f0 294 hostio_error (own_buf);
a6b151f1
DJ
295 return;
296 }
297
298 /* Record the new file descriptor. */
bca929d3 299 new_fd = xmalloc (sizeof (struct fd_list));
a6b151f1
DJ
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
307static void
308handle_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
bca929d3 327 data = xmalloc (len);
4e799345 328#ifdef HAVE_PREAD
a6b151f1 329 ret = pread (fd, data, len, offset);
4e799345
DJ
330#else
331 ret = lseek (fd, offset, SEEK_SET);
332 if (ret != -1)
333 ret = read (fd, data, len);
334#endif
a6b151f1
DJ
335
336 if (ret == -1)
337 {
59a016f0 338 hostio_error (own_buf);
a6b151f1
DJ
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
357static void
358handle_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
4e799345 376#ifdef HAVE_PWRITE
a6b151f1 377 ret = pwrite (fd, data, len, offset);
4e799345
DJ
378#else
379 ret = lseek (fd, offset, SEEK_SET);
380 if (ret != -1)
381 ret = write (fd, data, len);
382#endif
a6b151f1
DJ
383
384 if (ret == -1)
385 {
59a016f0 386 hostio_error (own_buf);
a6b151f1
DJ
387 free (data);
388 return;
389 }
390
391 hostio_reply (own_buf, ret);
392 free (data);
393}
394
395static void
396handle_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 {
59a016f0 416 hostio_error (own_buf);
a6b151f1
DJ
417 return;
418 }
419
420 open_fd_p = &open_fds;
588eebee
MS
421 /* We know that fd is in the list, thanks to require_valid_fd. */
422 while ((*open_fd_p)->fd != fd)
a6b151f1
DJ
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
432static void
433handle_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 {
59a016f0 452 hostio_error (own_buf);
a6b151f1
DJ
453 return;
454 }
455
456 hostio_reply (own_buf, ret);
457}
458
b9e7b9c3
UW
459static void
460handle_readlink (char *own_buf, int *new_packet_len)
461{
462 char filename[PATH_MAX], linkname[PATH_MAX];
463 char *p;
464 int ret, bytes_sent;
465
466 p = own_buf + strlen ("vFile:readlink:");
467
468 if (require_filename (&p, filename)
469 || require_end (p))
470 {
471 hostio_packet_error (own_buf);
472 return;
473 }
474
475 ret = readlink (filename, linkname, sizeof linkname);
476 if (ret == -1)
477 {
478 hostio_error (own_buf);
479 return;
480 }
481
482 bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len);
483
484 /* If the response does not fit into a single packet, do not attempt
485 to return a partial response, but simply fail. */
486 if (bytes_sent < ret)
487 sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG);
488}
489
a6b151f1
DJ
490/* Handle all the 'F' file transfer packets. */
491
492int
493handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
494{
495 if (strncmp (own_buf, "vFile:open:", 11) == 0)
496 handle_open (own_buf);
497 else if (strncmp (own_buf, "vFile:pread:", 11) == 0)
498 handle_pread (own_buf, new_packet_len);
499 else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0)
500 handle_pwrite (own_buf, packet_len);
501 else if (strncmp (own_buf, "vFile:close:", 12) == 0)
502 handle_close (own_buf);
503 else if (strncmp (own_buf, "vFile:unlink:", 13) == 0)
504 handle_unlink (own_buf);
b9e7b9c3
UW
505 else if (strncmp (own_buf, "vFile:readlink:", 15) == 0)
506 handle_readlink (own_buf, new_packet_len);
a6b151f1
DJ
507 else
508 return 0;
509
510 return 1;
511}
This page took 0.340778 seconds and 4 git commands to generate.