]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - sim/common/syscall.c
sim: convert old style prototypes
[thirdparty/binutils-gdb.git] / sim / common / syscall.c
index e0a3b880b84c26a061b8e3a2400ce6c5f78cda49..397cd80c504422c4cd5d25c860dfa796054a9fb1 100644 (file)
@@ -1,12 +1,12 @@
 /* Remote target system call support.
-   Copyright 1997, 1998 Free Software Foundation, Inc.
+   Copyright 1997-2014 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 <http://www.gnu.org/licenses/>.  */
 
 /* This interface isn't intended to be specific to any particular kind
    of remote (hardware, simulator, whatever).  As such, support for it
    supported.  */
 
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+#include "cconfig.h"
 #endif
 #include "ansidecl.h"
 #include "libiberty.h"
-#ifdef ANSI_PROTOTYPES
 #include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
 #include <stdio.h>
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#elif defined (HAVE_STRINGS_H)
+#include <strings.h>
+#endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -46,7 +46,7 @@
 #include <time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include "callback.h"
+#include "gdb/callback.h"
 #include "targ-vals.h"
 
 #ifndef ENOSYS
 #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;
 
@@ -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;
@@ -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->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.