X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sim%2Fcommon%2Fsyscall.c;h=d6607229156c96efe08a215b66357328166665a4;hb=128e85e3ab36b8e30f6612fb50de3cbb4ede6824;hp=e0a3b880b84c26a061b8e3a2400ce6c5f78cda49;hpb=5b64ad42d36e6d487e1f7287d37fbc243a178e72;p=deliverable%2Fbinutils-gdb.git diff --git a/sim/common/syscall.c b/sim/common/syscall.c index e0a3b880b8..d660722915 100644 --- a/sim/common/syscall.c +++ b/sim/common/syscall.c @@ -1,12 +1,12 @@ /* Remote target system call support. - Copyright 1997, 1998 Free Software Foundation, Inc. + Copyright 1997-2016 Free Software Foundation, Inc. Contributed by Cygnus Solutions. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,8 +15,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ /* This interface isn't intended to be specific to any particular kind of remote (hardware, simulator, whatever). As such, support for it @@ -29,15 +28,16 @@ #endif #include "ansidecl.h" #include "libiberty.h" -#ifdef ANSI_PROTOTYPES #include -#else -#include -#endif #include #ifdef HAVE_STDLIB_H #include #endif +#ifdef HAVE_STRING_H +#include +#elif defined (HAVE_STRINGS_H) +#include +#endif #ifdef HAVE_UNISTD_H #include #endif @@ -46,7 +46,7 @@ #include #include #include -#include "callback.h" +#include "gdb/callback.h" #include "targ-vals.h" #ifndef ENOSYS @@ -68,16 +68,16 @@ #define TWORD long #define TADDR unsigned long +/* Path to be prepended to syscalls with absolute paths, and to be + chdir:ed at startup, if not empty. */ +char *simulator_sysroot = ""; + /* Utility of cb_syscall to fetch a path name or other string from the target. The result is 0 for success or a host errno value. */ -static int -get_string (cb, sc, buf, buflen, addr) - host_callback *cb; - CB_SYSCALL *sc; - char *buf; - int buflen; - TADDR addr; +int +cb_get_string (host_callback *cb, CB_SYSCALL *sc, char *buf, int buflen, + TADDR addr) { char *p, *pend; @@ -88,7 +88,7 @@ get_string (cb, sc, buf, buflen, addr) path name along with the syscall request, and cache the file name somewhere (or otherwise tweak this as desired). */ unsigned int count = (*sc->read_mem) (cb, sc, addr, p, 1); - + if (count != 1) return EINVAL; if (*p == 0) @@ -101,22 +101,36 @@ get_string (cb, sc, buf, buflen, addr) /* Utility of cb_syscall to fetch a path name. The buffer is malloc'd and the address is stored in BUFP. - The result is that of get_string. + The result is that of get_string, but prepended with + simulator_sysroot if the string starts with '/'. If an error occurs, no buffer is left malloc'd. */ static int -get_path (cb, sc, addr, bufp) - host_callback *cb; - CB_SYSCALL *sc; - TADDR addr; - char **bufp; +get_path (host_callback *cb, CB_SYSCALL *sc, TADDR addr, char **bufp) { char *buf = xmalloc (MAX_PATH_LEN); int result; + int sysroot_len = strlen (simulator_sysroot); - result = get_string (cb, sc, buf, MAX_PATH_LEN, addr); + result = cb_get_string (cb, sc, buf, MAX_PATH_LEN - sysroot_len, addr); if (result == 0) - *bufp = buf; + { + /* Prepend absolute paths with simulator_sysroot. Relative paths + are supposed to be relative to a chdir within that path, but at + this point unknown where. */ + if (simulator_sysroot[0] != '\0' && *buf == '/') + { + /* Considering expected rareness of syscalls with absolute + file paths (compared to relative file paths and insn + execution), it does not seem worthwhile to rearrange things + to get rid of the string moves here; we'd need at least an + extra call to check the initial '/' in the path. */ + memmove (buf + sysroot_len, buf, sysroot_len); + memcpy (buf, simulator_sysroot, sysroot_len); + } + + *bufp = buf; + } else free (buf); return result; @@ -125,9 +139,7 @@ get_path (cb, sc, addr, bufp) /* Perform a system call on behalf of the target. */ CB_RC -cb_syscall (cb, sc) - host_callback *cb; - CB_SYSCALL *sc; +cb_syscall (host_callback *cb, CB_SYSCALL *sc) { TWORD result = 0, errcode = 0; @@ -228,7 +240,7 @@ cb_syscall (cb, sc) #endif /* wip */ case CB_SYS_exit : - /* Caller must catch and handle. */ + /* Caller must catch and handle; see sim_syscall as an example. */ break; case CB_SYS_open : @@ -269,7 +281,7 @@ cb_syscall (cb, sc) while (count > 0) { - if (fd == 0) + if (cb_is_stdin (cb, fd)) result = (int) (*cb->read_stdin) (cb, buf, (count < FILE_XFR_SIZE ? count : FILE_XFR_SIZE)); @@ -322,12 +334,12 @@ cb_syscall (cb, sc) errcode = EINVAL; goto FinishSyscall; } - if (fd == 1) + if (cb_is_stdout (cb, fd)) { result = (int) (*cb->write_stdout) (cb, buf, bytes_read); (*cb->flush_stdout) (cb); } - else if (fd == 2) + else if (cb_is_stderr (cb, fd)) { result = (int) (*cb->write_stderr) (cb, buf, bytes_read); (*cb->flush_stderr) (cb); @@ -373,6 +385,63 @@ cb_syscall (cb, sc) } break; + case CB_SYS_truncate : + { + char *path; + long len = sc->arg2; + + errcode = get_path (cb, sc, sc->arg1, &path); + if (errcode != 0) + { + result = -1; + errcode = EFAULT; + goto FinishSyscall; + } + result = (*cb->truncate) (cb, path, len); + free (path); + if (result < 0) + goto ErrorFinish; + } + break; + + case CB_SYS_ftruncate : + { + int fd = sc->arg1; + long len = sc->arg2; + + result = (*cb->ftruncate) (cb, fd, len); + if (result < 0) + goto ErrorFinish; + } + break; + + case CB_SYS_rename : + { + char *path1, *path2; + + errcode = get_path (cb, sc, sc->arg1, &path1); + if (errcode != 0) + { + result = -1; + errcode = EFAULT; + goto FinishSyscall; + } + errcode = get_path (cb, sc, sc->arg2, &path2); + if (errcode != 0) + { + result = -1; + errcode = EFAULT; + free (path1); + goto FinishSyscall; + } + result = (*cb->rename) (cb, path1, path2); + free (path1); + free (path2); + if (result < 0) + goto ErrorFinish; + } + break; + case CB_SYS_stat : { char *path,*buf; @@ -386,7 +455,7 @@ cb_syscall (cb, sc) result = -1; goto FinishSyscall; } - result = (*cb->stat) (cb, path, &statbuf); + result = (*cb->to_stat) (cb, path, &statbuf); free (path); if (result < 0) goto ErrorFinish; @@ -419,7 +488,7 @@ cb_syscall (cb, sc) struct stat statbuf; TADDR addr = sc->arg2; - result = (*cb->fstat) (cb, sc->arg1, &statbuf); + result = (*cb->to_fstat) (cb, sc->arg1, &statbuf); if (result < 0) goto ErrorFinish; buflen = cb_host_to_target_stat (cb, NULL, NULL); @@ -444,6 +513,77 @@ cb_syscall (cb, sc) } break; + case CB_SYS_lstat : + { + char *path, *buf; + int buflen; + struct stat statbuf; + TADDR addr = sc->arg2; + + errcode = get_path (cb, sc, sc->arg1, &path); + if (errcode != 0) + { + result = -1; + goto FinishSyscall; + } + result = (*cb->to_lstat) (cb, path, &statbuf); + free (path); + if (result < 0) + goto ErrorFinish; + + buflen = cb_host_to_target_stat (cb, NULL, NULL); + buf = xmalloc (buflen); + if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen) + { + /* The translation failed. This is due to an internal + host program error, not the target's fault. + Unfortunately, it's hard to test this case, so there's no + test-case for this execution path. */ + free (buf); + errcode = ENOSYS; + result = -1; + goto FinishSyscall; + } + + if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen) + { + free (buf); + errcode = EINVAL; + result = -1; + goto FinishSyscall; + } + + free (buf); + } + break; + + case CB_SYS_pipe : + { + int p[2]; + char *target_p = xcalloc (1, cb->target_sizeof_int * 2); + + result = (*cb->pipe) (cb, p); + if (result != 0) + goto ErrorFinish; + + cb_store_target_endian (cb, target_p, cb->target_sizeof_int, p[0]); + cb_store_target_endian (cb, target_p + cb->target_sizeof_int, + cb->target_sizeof_int, p[1]); + if ((*sc->write_mem) (cb, sc, sc->arg1, target_p, + cb->target_sizeof_int * 2) + != cb->target_sizeof_int * 2) + { + /* Close the pipe fd:s. */ + (*cb->close) (cb, p[0]); + (*cb->close) (cb, p[1]); + errcode = EFAULT; + result = -1; + } + + free (target_p); + } + break; + case CB_SYS_time : { /* FIXME: May wish to change CB_SYS_time to something else.