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