* syscall.c (cb_syscall) <case CB_SYS_pipe>: New case.
[deliverable/binutils-gdb.git] / sim / common / syscall.c
1 /* Remote target system call support.
2 Copyright 1997, 1998, 2002, 2004 Free Software Foundation, Inc.
3 Contributed by Cygnus Solutions.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GAS; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 /* This interface isn't intended to be specific to any particular kind
22 of remote (hardware, simulator, whatever). As such, support for it
23 (e.g. sim/common/callback.c) should *not* live in the simulator source
24 tree, nor should it live in the gdb source tree. K&R C must be
25 supported. */
26
27 #ifdef HAVE_CONFIG_H
28 #include "cconfig.h"
29 #endif
30 #include "ansidecl.h"
31 #include "libiberty.h"
32 #ifdef ANSI_PROTOTYPES
33 #include <stdarg.h>
34 #else
35 #include <varargs.h>
36 #endif
37 #include <stdio.h>
38 #ifdef HAVE_STDLIB_H
39 #include <stdlib.h>
40 #endif
41 #ifdef HAVE_STRING_H
42 #include <string.h>
43 #elif defined (HAVE_STRINGS_H)
44 #include <strings.h>
45 #endif
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <time.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include "gdb/callback.h"
55 #include "targ-vals.h"
56
57 #ifndef ENOSYS
58 #define ENOSYS EINVAL
59 #endif
60 #ifndef ENAMETOOLONG
61 #define ENAMETOOLONG EINVAL
62 #endif
63
64 /* Maximum length of a path name. */
65 #ifndef MAX_PATH_LEN
66 #define MAX_PATH_LEN 1024
67 #endif
68
69 /* When doing file read/writes, do this many bytes at a time. */
70 #define FILE_XFR_SIZE 4096
71
72 /* FIXME: for now, need to consider target word size. */
73 #define TWORD long
74 #define TADDR unsigned long
75
76 /* Path to be prepended to syscalls with absolute paths, and to be
77 chdir:ed at startup, if not empty. */
78 char *simulator_sysroot = "";
79
80 /* Utility of cb_syscall to fetch a path name or other string from the target.
81 The result is 0 for success or a host errno value. */
82
83 static int
84 get_string (cb, sc, buf, buflen, addr)
85 host_callback *cb;
86 CB_SYSCALL *sc;
87 char *buf;
88 int buflen;
89 TADDR addr;
90 {
91 char *p, *pend;
92
93 for (p = buf, pend = buf + buflen; p < pend; ++p, ++addr)
94 {
95 /* No, it isn't expected that this would cause one transaction with
96 the remote target for each byte. The target could send the
97 path name along with the syscall request, and cache the file
98 name somewhere (or otherwise tweak this as desired). */
99 unsigned int count = (*sc->read_mem) (cb, sc, addr, p, 1);
100
101 if (count != 1)
102 return EINVAL;
103 if (*p == 0)
104 break;
105 }
106 if (p == pend)
107 return ENAMETOOLONG;
108 return 0;
109 }
110
111 /* Utility of cb_syscall to fetch a path name.
112 The buffer is malloc'd and the address is stored in BUFP.
113 The result is that of get_string, but prepended with
114 simulator_sysroot if the string starts with '/'.
115 If an error occurs, no buffer is left malloc'd. */
116
117 static int
118 get_path (cb, sc, addr, bufp)
119 host_callback *cb;
120 CB_SYSCALL *sc;
121 TADDR addr;
122 char **bufp;
123 {
124 char *buf = xmalloc (MAX_PATH_LEN);
125 int result;
126 int sysroot_len = strlen (simulator_sysroot);
127
128 result = get_string (cb, sc, buf, MAX_PATH_LEN - sysroot_len, addr);
129 if (result == 0)
130 {
131 /* Prepend absolute paths with simulator_sysroot. Relative paths
132 are supposed to be relative to a chdir within that path, but at
133 this point unknown where. */
134 if (simulator_sysroot[0] != '\0' && *buf == '/')
135 {
136 /* Considering expected rareness of syscalls with absolute
137 file paths (compared to relative file paths and insn
138 execution), it does not seem worthwhile to rearrange things
139 to get rid of the string moves here; we'd need at least an
140 extra call to check the initial '/' in the path. */
141 memmove (buf + sysroot_len, buf, sysroot_len);
142 memcpy (buf, simulator_sysroot, sysroot_len);
143 }
144
145 *bufp = buf;
146 }
147 else
148 free (buf);
149 return result;
150 }
151
152 /* Perform a system call on behalf of the target. */
153
154 CB_RC
155 cb_syscall (cb, sc)
156 host_callback *cb;
157 CB_SYSCALL *sc;
158 {
159 TWORD result = 0, errcode = 0;
160
161 if (sc->magic != CB_SYSCALL_MAGIC)
162 abort ();
163
164 switch (cb_target_to_host_syscall (cb, sc->func))
165 {
166 #if 0 /* FIXME: wip */
167 case CB_SYS_argvlen :
168 {
169 /* Compute how much space is required to store the argv,envp
170 strings so that the program can allocate the space and then
171 call SYS_argv to fetch the values. */
172 int addr_size = cb->addr_size;
173 int argc,envc,arglen,envlen;
174 const char **argv = cb->init_argv;
175 const char **envp = cb->init_envp;
176
177 argc = arglen = 0;
178 if (argv)
179 {
180 for ( ; argv[argc]; ++argc)
181 arglen += strlen (argv[argc]) + 1;
182 }
183 envc = envlen = 0;
184 if (envp)
185 {
186 for ( ; envp[envc]; ++envc)
187 envlen += strlen (envp[envc]) + 1;
188 }
189 result = arglen + envlen;
190 break;
191 }
192
193 case CB_SYS_argv :
194 {
195 /* Pointer to target's buffer. */
196 TADDR tbuf = sc->arg1;
197 /* Buffer size. */
198 int bufsize = sc->arg2;
199 /* Q is the target address of where all the strings go. */
200 TADDR q;
201 int word_size = cb->word_size;
202 int i,argc,envc,len;
203 const char **argv = cb->init_argv;
204 const char **envp = cb->init_envp;
205
206 argc = 0;
207 if (argv)
208 {
209 for ( ; argv[argc]; ++argc)
210 {
211 int len = strlen (argv[argc]);
212 int written = (*sc->write_mem) (cb, sc, tbuf, argv[argc], len + 1);
213 if (written != len)
214 {
215 result = -1;
216 errcode = EINVAL;
217 goto FinishSyscall;
218 }
219 tbuf = len + 1;
220 }
221 }
222 if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
223 {
224 result = -1;
225 errcode = EINVAL;
226 goto FinishSyscall;
227 }
228 tbuf++;
229 envc = 0;
230 if (envp)
231 {
232 for ( ; envp[envc]; ++envc)
233 {
234 int len = strlen (envp[envc]);
235 int written = (*sc->write_mem) (cb, sc, tbuf, envp[envc], len + 1);
236 if (written != len)
237 {
238 result = -1;
239 errcode = EINVAL;
240 goto FinishSyscall;
241 }
242 tbuf = len + 1;
243 }
244 }
245 if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1)
246 {
247 result = -1;
248 errcode = EINVAL;
249 goto FinishSyscall;
250 }
251 result = argc;
252 sc->result2 = envc;
253 break;
254 }
255 #endif /* wip */
256
257 case CB_SYS_exit :
258 /* Caller must catch and handle. */
259 break;
260
261 case CB_SYS_open :
262 {
263 char *path;
264
265 errcode = get_path (cb, sc, sc->arg1, &path);
266 if (errcode != 0)
267 {
268 result = -1;
269 goto FinishSyscall;
270 }
271 result = (*cb->open) (cb, path, sc->arg2 /*, sc->arg3*/);
272 free (path);
273 if (result < 0)
274 goto ErrorFinish;
275 }
276 break;
277
278 case CB_SYS_close :
279 result = (*cb->close) (cb, sc->arg1);
280 if (result < 0)
281 goto ErrorFinish;
282 break;
283
284 case CB_SYS_read :
285 {
286 /* ??? Perfect handling of error conditions may require only one
287 call to cb->read. One can't assume all the data is
288 contiguously stored in host memory so that would require
289 malloc'ing/free'ing the space. Maybe later. */
290 char buf[FILE_XFR_SIZE];
291 int fd = sc->arg1;
292 TADDR addr = sc->arg2;
293 size_t count = sc->arg3;
294 size_t bytes_read = 0;
295 int bytes_written;
296
297 while (count > 0)
298 {
299 if (fd == 0)
300 result = (int) (*cb->read_stdin) (cb, buf,
301 (count < FILE_XFR_SIZE
302 ? count : FILE_XFR_SIZE));
303 else
304 result = (int) (*cb->read) (cb, fd, buf,
305 (count < FILE_XFR_SIZE
306 ? count : FILE_XFR_SIZE));
307 if (result == -1)
308 goto ErrorFinish;
309 if (result == 0) /* EOF */
310 break;
311 bytes_written = (*sc->write_mem) (cb, sc, addr, buf, result);
312 if (bytes_written != result)
313 {
314 result = -1;
315 errcode = EINVAL;
316 goto FinishSyscall;
317 }
318 bytes_read += result;
319 count -= result;
320 addr += result;
321 /* If this is a short read, don't go back for more */
322 if (result != FILE_XFR_SIZE)
323 break;
324 }
325 result = bytes_read;
326 }
327 break;
328
329 case CB_SYS_write :
330 {
331 /* ??? Perfect handling of error conditions may require only one
332 call to cb->write. One can't assume all the data is
333 contiguously stored in host memory so that would require
334 malloc'ing/free'ing the space. Maybe later. */
335 char buf[FILE_XFR_SIZE];
336 int fd = sc->arg1;
337 TADDR addr = sc->arg2;
338 size_t count = sc->arg3;
339 int bytes_read;
340 size_t bytes_written = 0;
341
342 while (count > 0)
343 {
344 int bytes_to_read = count < FILE_XFR_SIZE ? count : FILE_XFR_SIZE;
345 bytes_read = (*sc->read_mem) (cb, sc, addr, buf, bytes_to_read);
346 if (bytes_read != bytes_to_read)
347 {
348 result = -1;
349 errcode = EINVAL;
350 goto FinishSyscall;
351 }
352 if (fd == 1)
353 {
354 result = (int) (*cb->write_stdout) (cb, buf, bytes_read);
355 (*cb->flush_stdout) (cb);
356 }
357 else if (fd == 2)
358 {
359 result = (int) (*cb->write_stderr) (cb, buf, bytes_read);
360 (*cb->flush_stderr) (cb);
361 }
362 else
363 result = (int) (*cb->write) (cb, fd, buf, bytes_read);
364 if (result == -1)
365 goto ErrorFinish;
366 bytes_written += result;
367 count -= result;
368 addr += result;
369 }
370 result = bytes_written;
371 }
372 break;
373
374 case CB_SYS_lseek :
375 {
376 int fd = sc->arg1;
377 unsigned long offset = sc->arg2;
378 int whence = sc->arg3;
379
380 result = (*cb->lseek) (cb, fd, offset, whence);
381 if (result < 0)
382 goto ErrorFinish;
383 }
384 break;
385
386 case CB_SYS_unlink :
387 {
388 char *path;
389
390 errcode = get_path (cb, sc, sc->arg1, &path);
391 if (errcode != 0)
392 {
393 result = -1;
394 goto FinishSyscall;
395 }
396 result = (*cb->unlink) (cb, path);
397 free (path);
398 if (result < 0)
399 goto ErrorFinish;
400 }
401 break;
402
403 case CB_SYS_truncate :
404 {
405 char *path;
406 long len = sc->arg2;
407
408 errcode = get_path (cb, sc, sc->arg1, &path);
409 if (errcode != 0)
410 {
411 result = -1;
412 errcode = EFAULT;
413 goto FinishSyscall;
414 }
415 result = (*cb->truncate) (cb, path, len);
416 free (path);
417 if (result < 0)
418 goto ErrorFinish;
419 }
420 break;
421
422 case CB_SYS_ftruncate :
423 {
424 int fd = sc->arg1;
425 long len = sc->arg2;
426
427 result = (*cb->ftruncate) (cb, fd, len);
428 if (result < 0)
429 goto ErrorFinish;
430 }
431 break;
432
433 case CB_SYS_rename :
434 {
435 char *path1, *path2;
436
437 errcode = get_path (cb, sc, sc->arg1, &path1);
438 if (errcode != 0)
439 {
440 result = -1;
441 errcode = EFAULT;
442 goto FinishSyscall;
443 }
444 errcode = get_path (cb, sc, sc->arg2, &path2);
445 if (errcode != 0)
446 {
447 result = -1;
448 errcode = EFAULT;
449 free (path1);
450 goto FinishSyscall;
451 }
452 result = (*cb->rename) (cb, path1, path2);
453 free (path1);
454 free (path2);
455 if (result < 0)
456 goto ErrorFinish;
457 }
458 break;
459
460 case CB_SYS_stat :
461 {
462 char *path,*buf;
463 int buflen;
464 struct stat statbuf;
465 TADDR addr = sc->arg2;
466
467 errcode = get_path (cb, sc, sc->arg1, &path);
468 if (errcode != 0)
469 {
470 result = -1;
471 goto FinishSyscall;
472 }
473 result = (*cb->stat) (cb, path, &statbuf);
474 free (path);
475 if (result < 0)
476 goto ErrorFinish;
477 buflen = cb_host_to_target_stat (cb, NULL, NULL);
478 buf = xmalloc (buflen);
479 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
480 {
481 /* The translation failed. This is due to an internal
482 host program error, not the target's fault. */
483 free (buf);
484 errcode = ENOSYS;
485 result = -1;
486 goto FinishSyscall;
487 }
488 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
489 {
490 free (buf);
491 errcode = EINVAL;
492 result = -1;
493 goto FinishSyscall;
494 }
495 free (buf);
496 }
497 break;
498
499 case CB_SYS_fstat :
500 {
501 char *buf;
502 int buflen;
503 struct stat statbuf;
504 TADDR addr = sc->arg2;
505
506 result = (*cb->fstat) (cb, sc->arg1, &statbuf);
507 if (result < 0)
508 goto ErrorFinish;
509 buflen = cb_host_to_target_stat (cb, NULL, NULL);
510 buf = xmalloc (buflen);
511 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
512 {
513 /* The translation failed. This is due to an internal
514 host program error, not the target's fault. */
515 free (buf);
516 errcode = ENOSYS;
517 result = -1;
518 goto FinishSyscall;
519 }
520 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
521 {
522 free (buf);
523 errcode = EINVAL;
524 result = -1;
525 goto FinishSyscall;
526 }
527 free (buf);
528 }
529 break;
530
531 case CB_SYS_lstat :
532 {
533 char *path, *buf;
534 int buflen;
535 struct stat statbuf;
536 TADDR addr = sc->arg2;
537
538 errcode = get_path (cb, sc, sc->arg1, &path);
539 if (errcode != 0)
540 {
541 result = -1;
542 goto FinishSyscall;
543 }
544 result = (*cb->lstat) (cb, path, &statbuf);
545 free (path);
546 if (result < 0)
547 goto ErrorFinish;
548
549 buflen = cb_host_to_target_stat (cb, NULL, NULL);
550 buf = xmalloc (buflen);
551 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
552 {
553 /* The translation failed. This is due to an internal
554 host program error, not the target's fault.
555 Unfortunately, it's hard to test this case, so there's no
556 test-case for this execution path. */
557 free (buf);
558 errcode = ENOSYS;
559 result = -1;
560 goto FinishSyscall;
561 }
562
563 if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen)
564 {
565 free (buf);
566 errcode = EINVAL;
567 result = -1;
568 goto FinishSyscall;
569 }
570
571 free (buf);
572 }
573 break;
574
575 case CB_SYS_pipe :
576 {
577 int p[2];
578 char *target_p = xcalloc (1, cb->target_sizeof_int * 2);
579
580 result = (*cb->pipe) (cb, p);
581 if (result != 0)
582 goto ErrorFinish;
583
584 cb_store_target_endian (cb, target_p, cb->target_sizeof_int, p[0]);
585 cb_store_target_endian (cb, target_p + cb->target_sizeof_int,
586 cb->target_sizeof_int, p[1]);
587 if ((*sc->write_mem) (cb, sc, sc->arg1, target_p,
588 cb->target_sizeof_int * 2)
589 != cb->target_sizeof_int * 2)
590 {
591 /* Close the pipe fd:s. */
592 (*cb->close) (cb, p[0]);
593 (*cb->close) (cb, p[1]);
594 errcode = EFAULT;
595 result = -1;
596 }
597
598 free (target_p);
599 }
600 break;
601
602 case CB_SYS_time :
603 {
604 /* FIXME: May wish to change CB_SYS_time to something else.
605 We might also want gettimeofday or times, but if system calls
606 can be built on others, we can keep the number we have to support
607 here down. */
608 time_t t = (*cb->time) (cb, (time_t *) 0);
609 result = t;
610 /* It is up to target code to process the argument to time(). */
611 }
612 break;
613
614 case CB_SYS_chdir :
615 case CB_SYS_chmod :
616 case CB_SYS_utime :
617 /* fall through for now */
618
619 default :
620 result = -1;
621 errcode = ENOSYS;
622 break;
623 }
624
625 FinishSyscall:
626 sc->result = result;
627 if (errcode == 0)
628 sc->errcode = 0;
629 else
630 sc->errcode = cb_host_to_target_errno (cb, errcode);
631 return CB_RC_OK;
632
633 ErrorFinish:
634 sc->result = result;
635 sc->errcode = (*cb->get_errno) (cb);
636 return CB_RC_OK;
637 }
This page took 0.061389 seconds and 4 git commands to generate.