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