qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall
@ 2019-01-18 21:30 Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 01/49] linux-user: Setup split syscall infrastructure Richard Henderson
                   ` (47 more replies)
  0 siblings, 48 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Since v5, I've split the patches into smaller pieces, and done
a few more syscalls.  But I've also been approaching them in a
more "systematic" way -- taking from the top of the switch.

I've been trying to fix up checkpatch failures as I've moved
code, but I've surely missed some.  I've also been trying to
share code between the "*at" syscalls and their original.

I've tested x86_64->armhf and aarch64->i386 vs LTP.

FYI, as measured by the line count of do_syscall1, this is
about 25% of the total job to be done.


r~


PS: Patch 2/49 is a debugging patch I forgot to remove.
Rather than regenerate the series, I just omitted it here.


Richard Henderson (49):
  linux-user: Setup split syscall infrastructure
  linux-user: Split out open, open_at
  linux-user: Share more code for open and openat
  linux-user: Tidy do_openat loop over fakes
  linux-user: Split out readlink, readlinkat
  linux-user: Split out close
  linux-user: Split out read, write
  linux-user: Reduce regpairs_aligned & target_offset64 ifdefs
  linux-user: Split out readv, writev
  linux-user: Split out pread64, pwrite64
  linux-user: Split out preadv, pwritev
  linux-user: Split out name_to_handle_at, open_by_handle_at
  linux-user: Split out ipc syscalls
  linux-user: Split out memory syscalls
  linux-user: Split out exit
  linux-user: Split out brk
  linux-user: Split out clone, fork, vfork
  linux-user: Split out wait4, waitid, waitpid
  linux-user: Implement rusage argument to waitid
  linux-user: Split out creat
  linux-user: Split out link, linkat
  linux-user: Split out unlink, unlinkat, rmdir
  linux-user: Split out execve
  linux-user: Implement execveat
  linux-user: Split out chdir
  linux-user: Split out time
  linux-user: Split out mknod, mknodat
  linux-user: Split out chmod, fchmod, fchmodat
  linux-user: Split out lseek, llseek
  linux-user: Split out getpid, getppid, getxpid
  linux-user: Split out mount
  linux-user: Split out umount, umount2
  linux-user: Split out stime
  linux-user: Split out alarm, pause
  linux-user: Split out utime, utimes, futimesat
  linux-user: Split out access, faccessat
  linux-user: Split out nice
  linux-user: Split out sync, syncfs
  linux-user: Split out kill
  linux-user: Split out rename, renameat, renameat2
  linux-user: Split out mkdir, mkdirat
  linux-user: Split out dup, dup2, dup3
  linux-user: Split out pipe, pipe2
  linux-user: Split out times
  linux-user: Split out acct
  linux-user: Move syscall_init to the end
  linux-user: Split out ioctl
  linux-user: Split out fcntl, fcntl64

 linux-user/syscall-defs.h      |  240 ++
 linux-user/syscall.h           |  102 +
 linux-user/strace.c            | 1258 +++-------
 linux-user/syscall-fcntl.inc.c |  322 +++
 linux-user/syscall-file.inc.c  | 1229 ++++++++++
 linux-user/syscall-ioctl.inc.c |  873 +++++++
 linux-user/syscall-ipc.inc.c   | 1086 +++++++++
 linux-user/syscall-mem.inc.c   |  244 ++
 linux-user/syscall-proc.inc.c  |  593 +++++
 linux-user/syscall-sig.inc.c   |   41 +
 linux-user/syscall-time.inc.c  |   44 +
 linux-user/syscall.c           | 4128 ++------------------------------
 configure                      |   20 -
 linux-user/strace.list         |  285 ---
 14 files changed, 5376 insertions(+), 5089 deletions(-)
 create mode 100644 linux-user/syscall-defs.h
 create mode 100644 linux-user/syscall.h
 create mode 100644 linux-user/syscall-fcntl.inc.c
 create mode 100644 linux-user/syscall-file.inc.c
 create mode 100644 linux-user/syscall-ioctl.inc.c
 create mode 100644 linux-user/syscall-ipc.inc.c
 create mode 100644 linux-user/syscall-mem.inc.c
 create mode 100644 linux-user/syscall-proc.inc.c
 create mode 100644 linux-user/syscall-sig.inc.c
 create mode 100644 linux-user/syscall-time.inc.c

-- 
2.17.2

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 01/49] linux-user: Setup split syscall infrastructure
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 03/49] linux-user: Split out open, open_at Richard Henderson
                   ` (46 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Defines a unified structure for implementation and strace.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h |  17 ++
 linux-user/syscall.h      |  89 +++++++++
 linux-user/strace.c       | 388 +++++++++++++++++++++++++++-----------
 linux-user/syscall.c      | 103 +++++++++-
 4 files changed, 484 insertions(+), 113 deletions(-)
 create mode 100644 linux-user/syscall-defs.h
 create mode 100644 linux-user/syscall.h

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
new file mode 100644
index 0000000000..8c0490425a
--- /dev/null
+++ b/linux-user/syscall-defs.h
@@ -0,0 +1,17 @@
+/*
+ *  Linux syscall definitions
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
diff --git a/linux-user/syscall.h b/linux-user/syscall.h
new file mode 100644
index 0000000000..43b5dc0684
--- /dev/null
+++ b/linux-user/syscall.h
@@ -0,0 +1,89 @@
+/*
+ *  Linux syscalls internals
+ *  Copyright (c) 2018 Linaro, Limited.
+ *
+ *  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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LINUX_USER_SYSCALL_H
+#define LINUX_USER_SYSCALL_H 1
+
+typedef struct SyscallDef SyscallDef;
+
+/*
+ * This hook extracts max 6 arguments from max 8 input registers.
+ * In the process, register pairs that store 64-bit arguments are merged.
+ * Finally, syscalls are demultipliexed; e.g. the hook for socketcall will
+ * return the SyscallDef for bind, listen, etc.  In the process the hook
+ * may need to read from guest memory, or otherwise validate operands.
+ * On failure, set errno (to a host value) and return NULL;
+ * the (target adjusted) errno will be returned to the guest.
+ */
+typedef const SyscallDef *SyscallArgsFn(const SyscallDef *, int64_t out[6],
+                                        abi_long in[8]);
+
+/* This hook implements the syscall.  */
+typedef abi_long SyscallImplFn(CPUArchState *, int64_t, int64_t, int64_t,
+                               int64_t, int64_t, int64_t);
+
+/* This hook prints the arguments to the syscall for strace.  */
+typedef void SyscallPrintFn(const SyscallDef *, int64_t arg[6]);
+
+/* This hook print the return value from the syscall for strace.  */
+typedef void SyscallPrintRetFn(const SyscallDef *, abi_long);
+
+/*
+ * These flags describe the arguments for the generic fallback to
+ * SyscallPrintFn.  ARG_NONE indicates that the argument is not present.
+ */
+typedef enum {
+    ARG_NONE = 0,
+
+    /* These print as numbers of abi_long.  */
+    ARG_DEC,
+    ARG_HEX,
+    ARG_OCT,
+
+    /* These print as sets of flags.  */
+    ARG_ATDIRFD,
+    ARG_MODEFLAG,
+    ARG_OPENFLAG,
+
+    /* These are interpreted as pointers.  */
+    ARG_PTR,
+    ARG_STR,
+    ARG_BUF,
+
+    /* For a 32-bit host, force printing as a 64-bit operand.  */
+#if TARGET_ABI_BITS == 32
+    ARG_DEC64,
+#else
+    ARG_DEC64 = ARG_DEC,
+#endif
+} SyscallArgType;
+
+struct SyscallDef {
+    const char *name;
+    SyscallArgsFn *args;
+    SyscallImplFn *impl;
+    SyscallPrintFn *print;
+    SyscallPrintRetFn *print_ret;
+    SyscallArgType arg_type[6];
+};
+
+void print_syscall_def(const SyscallDef *def, int64_t args[6]);
+void print_syscall_def_ret(const SyscallDef *def, abi_long ret);
+void print_syscall_ptr_ret(const SyscallDef *def, abi_long ret);
+
+#endif
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 7318392e57..8c467da48e 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -10,6 +10,7 @@
 #include <linux/if_packet.h>
 #include <sched.h>
 #include "qemu.h"
+#include "syscall.h"
 
 int do_strace=0;
 
@@ -796,7 +797,7 @@ UNUSED static struct flags unlinkat_flags[] = {
     FLAG_END,
 };
 
-UNUSED static struct flags mode_flags[] = {
+static struct flags const mode_flags[] = {
     FLAG_GENERIC(S_IFSOCK),
     FLAG_GENERIC(S_IFLNK),
     FLAG_GENERIC(S_IFREG),
@@ -807,14 +808,14 @@ UNUSED static struct flags mode_flags[] = {
     FLAG_END,
 };
 
-UNUSED static struct flags open_access_flags[] = {
+static struct flags const open_access_flags[] = {
     FLAG_TARGET(O_RDONLY),
     FLAG_TARGET(O_WRONLY),
     FLAG_TARGET(O_RDWR),
     FLAG_END,
 };
 
-UNUSED static struct flags open_flags[] = {
+static struct flags const open_flags[] = {
     FLAG_TARGET(O_APPEND),
     FLAG_TARGET(O_CREAT),
     FLAG_TARGET(O_DIRECTORY),
@@ -989,84 +990,86 @@ get_comma(int last)
     return ((last) ? "" : ",");
 }
 
+static int add_flags(char *buf, int size, const struct flags *f,
+                     int flags, bool octal)
+{
+    const char *sep = "";
+    int off = 0;
+
+    if (flags == 0 && f->f_value == 0) {
+        return snprintf(buf, size, "%s", f->f_string);
+    }
+
+    for (; f->f_string != NULL; f++) {
+        if (f->f_value != 0 && (flags & f->f_value) == f->f_value) {
+            off += snprintf(buf + off, size - off, "%s%s", sep, f->f_string);
+            flags &= ~f->f_value;
+            sep = "|";
+        }
+    }
+
+    /* Print rest of the flags as numeric.  */
+    if (flags) {
+        if (octal) {
+            off += snprintf(buf + off, size - off, "%s%#o", sep, flags);
+        } else {
+            off += snprintf(buf + off, size - off, "%s%#x", sep, flags);
+        }
+    }
+    return off;
+}
+
 static void
 print_flags(const struct flags *f, abi_long flags, int last)
 {
-    const char *sep = "";
-    int n;
+    char buf[256];
+    add_flags(buf, sizeof(buf), f, flags, false);
+    gemu_log("%s%s", buf, get_comma(last));
+}
 
-    if ((flags == 0) && (f->f_value == 0)) {
-        gemu_log("%s%s", f->f_string, get_comma(last));
-        return;
-    }
-    for (n = 0; f->f_string != NULL; f++) {
-        if ((f->f_value != 0) && ((flags & f->f_value) == f->f_value)) {
-            gemu_log("%s%s", sep, f->f_string);
-            flags &= ~f->f_value;
-            sep = "|";
-            n++;
-        }
-    }
-
-    if (n > 0) {
-        /* print rest of the flags as numeric */
-        if (flags != 0) {
-            gemu_log("%s%#x%s", sep, (unsigned int)flags, get_comma(last));
-        } else {
-            gemu_log("%s", get_comma(last));
-        }
+static int add_atdirfd(char *buf, int size, int fd)
+{
+    if (fd == AT_FDCWD) {
+        return snprintf(buf, size, "AT_FDCWD");
     } else {
-        /* no string version of flags found, print them in hex then */
-        gemu_log("%#x%s", (unsigned int)flags, get_comma(last));
+        return snprintf(buf, size, "%d", fd);
     }
 }
 
 static void
 print_at_dirfd(abi_long dirfd, int last)
 {
-#ifdef AT_FDCWD
-    if (dirfd == AT_FDCWD) {
-        gemu_log("AT_FDCWD%s", get_comma(last));
-        return;
-    }
-#endif
-    gemu_log("%d%s", (int)dirfd, get_comma(last));
+    char buf[16];
+    add_atdirfd(buf, sizeof(buf), dirfd);
+    gemu_log("%s%s", buf, get_comma(last));
 }
 
 static void
 print_file_mode(abi_long mode, int last)
 {
-    const char *sep = "";
-    const struct flags *m;
+    char buf[256];
+    add_flags(buf, sizeof(buf), mode_flags, mode, true);
+    gemu_log("%s%s", buf, get_comma(last));
+}
 
-    for (m = &mode_flags[0]; m->f_string != NULL; m++) {
-        if ((m->f_value & mode) == m->f_value) {
-            gemu_log("%s%s", m->f_string, sep);
-            sep = "|";
-            mode &= ~m->f_value;
-            break;
-        }
+static int add_open_flags(char *buf, int size, int flags)
+{
+    int off = add_flags(buf, size, open_access_flags,
+                        flags & TARGET_O_ACCMODE, false);
+    flags &= ~TARGET_O_ACCMODE;
+    if (flags == 0 || off + 2 >= size) {
+        return off;
     }
-
-    mode &= ~S_IFMT;
-    /* print rest of the mode as octal */
-    if (mode != 0)
-        gemu_log("%s%#o", sep, (unsigned int)mode);
-
-    gemu_log("%s", get_comma(last));
+    buf[off++] = '|';
+    return off + add_flags(buf + off, size - off, open_flags, flags, true);
 }
 
 static void
 print_open_flags(abi_long flags, int last)
 {
-    print_flags(open_access_flags, flags & TARGET_O_ACCMODE, 1);
-    flags &= ~TARGET_O_ACCMODE;
-    if (flags == 0) {
-        gemu_log("%s", get_comma(last));
-        return;
-    }
-    gemu_log("|");
-    print_flags(open_flags, flags, last);
+    char buf[256];
+    add_open_flags(buf, sizeof(buf), flags);
+    gemu_log("%s%s", buf, get_comma(last));
 }
 
 static void
@@ -1083,48 +1086,86 @@ print_syscall_epilogue(const struct syscallname *sc)
     gemu_log(")");
 }
 
-static void
-print_string(abi_long addr, int last)
+static int add_pointer(char *buf, int size, abi_ulong addr)
 {
-    char *s;
-
-    if ((s = lock_user_string(addr)) != NULL) {
-        gemu_log("\"%s\"%s", s, get_comma(last));
-        unlock_user(s, addr, 0);
+    if (addr) {
+        return snprintf(buf, size, "0x" TARGET_ABI_FMT_lx, addr);
     } else {
-        /* can't get string out of it, so print it as pointer */
-        print_pointer(addr, last);
+        return snprintf(buf, size, "NULL");
     }
 }
 
+static int add_string(char *buf, int size, abi_ulong addr)
+{
+    char *s = lock_user_string(addr);
+    if (s) {
+        /* TODO: Escape special characters within the string.  */
+        /* TODO: Limit the string length for logging.  */
+        int len = snprintf(buf, size, "\"%s\"", s);
+        unlock_user(s, addr, 0);
+        return len;
+    }
+    return add_pointer(buf, size, addr);
+}
+
+static void
+print_string(abi_long addr, int last)
+{
+    char buf[256];
+    add_string(buf, sizeof(buf), addr);
+    gemu_log("%s%s", buf, get_comma(last));
+}
+
 #define MAX_PRINT_BUF 40
+
+static int add_buffer(char *buf, int size, abi_long addr, abi_ulong len)
+{
+    unsigned char *p;
+    int off = 0;
+    abi_ulong i;
+
+    p = lock_user(VERIFY_READ, addr, MIN(len, MAX_PRINT_BUF), 1);
+    if (!p) {
+        return add_pointer(buf, size, addr);
+    }
+
+    buf[0] = '"';
+    off = 1;
+
+    for (i = 0; i < MAX_PRINT_BUF; ++i) {
+        int len;
+
+        if (isprint(p[i])) {
+            buf[off] = p[i];
+            len = 1;
+        } else {
+            len = snprintf(buf + off, size - off, "\\%o", p[i]);
+        }
+        off += len;
+        if (off + 2 >= size) {
+            goto overflow;
+        }
+    }
+    unlock_user(p, addr, 0);
+
+    if (i == len && off + 2 < size) {
+        buf[off] = '"';
+        buf[off + 1] = 0;
+        return off + 1;
+    }
+
+ overflow:
+    off = MIN(off, size - 5);
+    strcpy(buf + off, "...\"");
+    return off + 4;
+}
+
 static void
 print_buf(abi_long addr, abi_long len, int last)
 {
-    uint8_t *s;
-    int i;
-
-    s = lock_user(VERIFY_READ, addr, len, 1);
-    if (s) {
-        gemu_log("\"");
-        for (i = 0; i < MAX_PRINT_BUF && i < len; i++) {
-            if (isprint(s[i])) {
-                gemu_log("%c", s[i]);
-            } else {
-                gemu_log("\\%o", s[i]);
-            }
-        }
-        gemu_log("\"");
-        if (i != len) {
-            gemu_log("...");
-        }
-        if (!last) {
-            gemu_log(",");
-        }
-        unlock_user(s, addr, 0);
-    } else {
-        print_pointer(addr, last);
-    }
+    char buf[256];
+    add_buffer(buf, sizeof(buf), addr, len);
+    gemu_log("%s%s", buf, get_comma(last));
 }
 
 /*
@@ -1143,10 +1184,9 @@ print_raw_param(const char *fmt, abi_long param, int last)
 static void
 print_pointer(abi_long p, int last)
 {
-    if (p == 0)
-        gemu_log("NULL%s", get_comma(last));
-    else
-        gemu_log("0x" TARGET_ABI_FMT_lx "%s", p, get_comma(last));
+    char buf[24];
+    add_pointer(buf, sizeof(buf), p);
+    gemu_log("%s%s", buf, get_comma(last));
 }
 
 /*
@@ -2638,32 +2678,170 @@ print_syscall(int num,
     gemu_log("Unknown syscall %d\n", num);
 }
 
+static void print_syscall_def1(const SyscallDef *def, int64_t args[6])
+{
+    char buf[1024], *b = buf;
+    int i, rest = sizeof(buf);
+
+    /*
+     * Render the argument list into BUF.  This allows us to log the
+     * entire syscall in one write statement at the end.
+     * While this is still not quite as good as separate files, a-la
+     * strace -ff, it can minimize confusion with a multithreaded guest.
+     */
+    buf[0] = 0;
+    for (i = 0; i < 6; ++i) {
+        SyscallArgType type = def->arg_type[i];
+        int64_t arg = args[i];
+        int len;
+
+        if (type == ARG_NONE) {
+            break;
+        }
+
+        /* Validate remaining space.  */
+        if (rest < 4) {
+            goto overflow;
+        }
+
+        /* Add separator.  */
+        if (i > 0) {
+            b[0] = ',';
+            b[1] = ' ';
+            b += 2;
+            rest -= 2;
+        }
+
+        switch (type) {
+#if TARGET_ABI_BITS == 32
+        /*
+         * ??? We don't have TARGET_ABI_FMT_* macros for exactly
+         * what we want here.  For this case it probably makes
+         * most sense to just special case.
+         */
+        case ARG_DEC:
+            len = snprintf(b, rest, "%d", (int32_t)arg);
+            break;
+        case ARG_HEX:
+            len = snprintf(b, rest, "%#x", (uint32_t)arg);
+            break;
+        case ARG_OCT:
+            len = snprintf(b, rest, "%#o", (uint32_t)arg);
+            break;
+        case ARG_DEC64:
+            len = snprintf(b, rest, "%" PRId64, arg);
+            break;
+#else
+        case ARG_DEC:
+            len = snprintf(b, rest, "%" PRId64, arg);
+            break;
+        case ARG_OCT:
+            len = snprintf(b, rest, "%" PRIo64, arg);
+            break;
+        case ARG_HEX:
+            len = snprintf(b, rest, "%" PRIx64, arg);
+            break;
+#endif
+        case ARG_ATDIRFD:
+            len = add_atdirfd(b, rest, arg);
+            break;
+        case ARG_MODEFLAG:
+            len = add_flags(b, rest, mode_flags, arg, true);
+            break;
+        case ARG_OPENFLAG:
+            len = add_open_flags(b, rest, arg);
+            break;
+        case ARG_PTR:
+            len = add_pointer(b, rest, arg);
+            break;
+        case ARG_STR:
+            len = add_string(b, rest, arg);
+            break;
+        case ARG_BUF:
+            len = add_buffer(b, rest, arg, MAX_PRINT_BUF);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+
+        b += len;
+        rest -= len;
+        if (rest == 0) {
+            goto overflow;
+        }
+    }
+    goto done;
+
+ overflow:
+    strcpy(buf + sizeof(buf) - 4, "...");
+ done:
+    gemu_log("%d %s(%s)", getpid(), def->name, buf);
+}
+
+void print_syscall_def(const SyscallDef *def, int64_t args[6])
+{
+    SyscallPrintFn *print = def->print;
+    if (!print) {
+        print = print_syscall_def1;
+    }
+    print(def, args);
+}
+
+static void print_syscall_def_ret1(const SyscallDef *def, abi_long ret)
+{
+    if (is_error(ret)) {
+        const char *errstr = target_strerror(-ret);
+        if (errstr) {
+            gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n",
+                     -ret, errstr);
+        } else {
+            gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld "\n", -ret);
+        }
+    } else {
+        gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
+    }
+}
 
 void
 print_syscall_ret(int num, abi_long ret)
 {
     int i;
-    const char *errstr = NULL;
 
     for(i=0;i<nsyscalls;i++)
         if( scnames[i].nr == num ) {
             if( scnames[i].result != NULL ) {
                 scnames[i].result(&scnames[i],ret);
             } else {
-                if (ret < 0) {
-                    errstr = target_strerror(-ret);
-                }
-                if (errstr) {
-                    gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n",
-                             -ret, errstr);
-                } else {
-                    gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
-                }
+                print_syscall_def_ret1(NULL, ret);
             }
             break;
         }
 }
 
+void print_syscall_ptr_ret(const SyscallDef *def, abi_long ret)
+{
+    if (is_error(ret)) {
+        const char *errstr = target_strerror(-ret);
+        if (errstr) {
+            gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n",
+                     -ret, errstr);
+        } else {
+            gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld "\n", -ret);
+        }
+    } else {
+        gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
+    }
+}
+
+void print_syscall_def_ret(const SyscallDef *def, abi_long ret)
+{
+    SyscallPrintRetFn *print = def->print_ret;
+    if (!print) {
+        print = print_syscall_def_ret1;
+    }
+    print(def, ret);
+}
+
 void print_taken_signal(int target_signum, const target_siginfo_t *tinfo)
 {
     /* Print the strace output for a signal being taken:
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index b5786d4fc1..93377f7586 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -111,6 +111,7 @@
 
 #include "qemu.h"
 #include "fd-trans.h"
+#include "syscall.h"
 
 #ifndef CLONE_IO
 #define CLONE_IO                0x80000000      /* Clone io context */
@@ -11533,12 +11534,70 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     return ret;
 }
 
+/* Emit the signature for a SyscallArgsFn.  */
+#define SYSCALL_ARGS(NAME) \
+    static const SyscallDef *args_##NAME(const SyscallDef *def, \
+                                         int64_t out[6], abi_long in[8])
+
+/* Emit the signature for a SyscallImplFn.  */
+#define SYSCALL_IMPL(NAME) \
+    static abi_long impl_##NAME(CPUArchState *cpu_env, int64_t arg1, \
+                                int64_t arg2, int64_t arg3, int64_t arg4, \
+                                int64_t arg5, int64_t arg6)
+
+
+#undef SYSCALL_IMPL
+#undef SYSCALL_ARGS
+
+/*
+ * Emit a complete SyscallDef structure.
+ */
+#define SYSCALL_DEF_FULL(NAME, ...) \
+    static const SyscallDef def_##NAME = { .name = #NAME, __VA_ARGS__ }
+
+/*
+ * Emit the definition for a "simple" syscall.  Such does not use
+ * SyscallArgsFn and only uses arg_type for strace.
+ */
+#define SYSCALL_DEF(NAME, ...) \
+    SYSCALL_DEF_FULL(NAME, .impl = impl_##NAME, .arg_type = { __VA_ARGS__ })
+
+/* Similarly, but also uses an args hook.  */
+#define SYSCALL_DEF_ARGS(NAME, ...) \
+    SYSCALL_DEF_FULL(NAME, .impl = impl_##NAME, .args = args_##NAME, \
+                     .arg_type = { __VA_ARGS__ })
+
+#include "syscall-defs.h"
+
+#undef SYSCALL_DEF
+#undef SYSCALL_DEF_ARGS
+#undef SYSCALL_DEF_FULL
+
+static const SyscallDef *syscall_table(int num)
+{
+#define SYSCALL_DEF(NAME, ...)  case TARGET_NR_##NAME: return &def_##NAME
+#define SYSCALL_DEF_ARGS(NAME, ...)  SYSCALL_DEF(NAME)
+#define SYSCALL_DEF_FULL(NAME, ...)  SYSCALL_DEF(NAME)
+
+    switch (num) {
+#include "syscall-defs.h"
+    }
+    return NULL;
+
+#undef SYSCALL_DEF
+#undef SYSCALL_DEF_ARGS
+#undef SYSCALL_DEF_FULL
+}
+
 abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                     abi_long arg2, abi_long arg3, abi_long arg4,
                     abi_long arg5, abi_long arg6, abi_long arg7,
                     abi_long arg8)
 {
     CPUState *cpu = ENV_GET_CPU(cpu_env);
+    const SyscallDef *def, *orig_def;
+    abi_long raw_args[8] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 };
+    int64_t  out_args[6] = { arg1, arg2, arg3, arg4, arg5, arg6 };
     abi_long ret;
 
 #ifdef DEBUG_ERESTARTSYS
@@ -11558,16 +11617,44 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4,
                              arg5, arg6, arg7, arg8);
 
-    if (unlikely(do_strace)) {
-        print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
-        ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
-                          arg5, arg6, arg7, arg8);
-        print_syscall_ret(num, ret);
-    } else {
-        ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
-                          arg5, arg6, arg7, arg8);
+    orig_def = def = syscall_table(num);
+    if (def == NULL) {
+        /* Unconverted.  */
+        if (unlikely(do_strace)) {
+            print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
+            ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
+                              arg5, arg6, arg7, arg8);
+            print_syscall_ret(num, ret);
+        } else {
+            ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
+                              arg5, arg6, arg7, arg8);
+        }
+        goto fini;
     }
 
+    if (def->args) {
+        def = def->args(def, out_args, raw_args);
+        if (unlikely(def == NULL)) {
+            ret = -host_to_target_errno(errno);
+            if (unlikely(do_strace)) {
+                print_syscall_def(orig_def, out_args);
+                print_syscall_def_ret(orig_def, ret);
+            }
+            goto fini;
+        }
+    }
+
+    if (unlikely(do_strace)) {
+        print_syscall_def(def, out_args);
+        ret = def->impl(cpu_env, out_args[0], out_args[1], out_args[2],
+                        out_args[3], out_args[4], out_args[5]);
+        print_syscall_def_ret(def, ret);
+    } else {
+        ret = def->impl(cpu_env, out_args[0], out_args[1], out_args[2],
+                        out_args[3], out_args[4], out_args[5]);
+    }
+
+ fini:
     trace_guest_user_syscall_ret(cpu, num, ret);
     return ret;
 }
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 03/49] linux-user: Split out open, open_at
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 01/49] linux-user: Setup split syscall infrastructure Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 04/49] linux-user: Share more code for open and openat Richard Henderson
                   ` (45 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

For the moment, leave a forward declaration for is_proc_myself
until the readlink syscalls are also moved to syscall-file.inc.c.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |   5 +
 linux-user/strace.c           |  35 ----
 linux-user/syscall-file.inc.c | 319 ++++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 282 +-----------------------------
 linux-user/strace.list        |   6 -
 5 files changed, 326 insertions(+), 321 deletions(-)
 create mode 100644 linux-user/syscall-file.inc.c

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 8c0490425a..1f3a9c47ab 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -15,3 +15,8 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
+
+#ifdef TARGET_NR_open
+SYSCALL_DEF(open, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
+#endif
+SYSCALL_DEF(openat, ARG_ATDIRFD, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 8c467da48e..1e4f6c9b53 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -2216,41 +2216,6 @@ print_mq_open(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_open
-static void
-print_open(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    int is_creat = (arg1 & TARGET_O_CREAT);
-
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_open_flags(arg1, (is_creat == 0));
-    if (is_creat)
-        print_file_mode(arg2, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
-#ifdef TARGET_NR_openat
-static void
-print_openat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    int is_creat = (arg2 & TARGET_O_CREAT);
-
-    print_syscall_prologue(name);
-    print_at_dirfd(arg0, 0);
-    print_string(arg1, 0);
-    print_open_flags(arg2, (is_creat == 0));
-    if (is_creat)
-        print_file_mode(arg3, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_mq_unlink
 static void
 print_mq_unlink(const struct syscallname *name,
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
new file mode 100644
index 0000000000..ca777da753
--- /dev/null
+++ b/linux-user/syscall-file.inc.c
@@ -0,0 +1,319 @@
+/*
+ *  Linux file-related syscall implementations
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Helpers for do_openat, manipulating /proc/self/foo.
+ */
+
+static int open_self_cmdline(void *cpu_env, int fd)
+{
+    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
+    struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
+    int i;
+
+    for (i = 0; i < bprm->argc; i++) {
+        size_t len = strlen(bprm->argv[i]) + 1;
+
+        if (write(fd, bprm->argv[i], len) != len) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int open_self_maps(void *cpu_env, int fd)
+{
+    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
+    TaskState *ts = cpu->opaque;
+    FILE *fp;
+    char *line = NULL;
+    size_t len = 0;
+    ssize_t read;
+
+    fp = fopen("/proc/self/maps", "r");
+    if (fp == NULL) {
+        return -1;
+    }
+
+    while ((read = getline(&line, &len, fp)) != -1) {
+        int fields, dev_maj, dev_min, inode;
+        uint64_t min, max, offset;
+        char flag_r, flag_w, flag_x, flag_p;
+        char path[512] = "";
+        fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
+                        " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
+                        &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
+
+        if ((fields < 10) || (fields > 11)) {
+            continue;
+        }
+        if (h2g_valid(min)) {
+            int flags = page_get_flags(h2g(min));
+            max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1;
+            if (page_check_range(h2g(min), max - min, flags) == -1) {
+                continue;
+            }
+            if (h2g(min) == ts->info->stack_limit) {
+                pstrcpy(path, sizeof(path), "      [stack]");
+            }
+            dprintf(fd, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr
+                    " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
+                    h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
+                    flag_x, flag_p, offset, dev_maj, dev_min, inode,
+                    path[0] ? "         " : "", path);
+        }
+    }
+
+    free(line);
+    fclose(fp);
+
+    return 0;
+}
+
+static int open_self_stat(void *cpu_env, int fd)
+{
+    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
+    TaskState *ts = cpu->opaque;
+    abi_ulong start_stack = ts->info->start_stack;
+    int i;
+
+    for (i = 0; i < 44; i++) {
+        char buf[128];
+        int len;
+        uint64_t val = 0;
+
+        if (i == 0) {
+            /* pid */
+            val = getpid();
+            snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
+        } else if (i == 1) {
+            /* app name */
+            snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
+        } else if (i == 27) {
+            /* stack bottom */
+            val = start_stack;
+            snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
+        } else {
+            /* for the rest, there is MasterCard */
+            snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
+        }
+
+        len = strlen(buf);
+        if (write(fd, buf, len) != len) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int open_self_auxv(void *cpu_env, int fd)
+{
+    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
+    TaskState *ts = cpu->opaque;
+    abi_ulong auxv = ts->info->saved_auxv;
+    abi_ulong len = ts->info->auxv_len;
+    char *ptr;
+
+    /*
+     * Auxiliary vector is stored in target process stack.
+     * read in whole auxv vector and copy it to file
+     */
+    ptr = lock_user(VERIFY_READ, auxv, len, 0);
+    if (ptr != NULL) {
+        while (len > 0) {
+            ssize_t r;
+            r = write(fd, ptr, len);
+            if (r <= 0) {
+                break;
+            }
+            len -= r;
+            ptr += r;
+        }
+        lseek(fd, 0, SEEK_SET);
+        unlock_user(ptr, auxv, len);
+    }
+
+    return 0;
+}
+
+static int is_proc_myself(const char *filename, const char *entry)
+{
+    if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
+        filename += strlen("/proc/");
+        if (!strncmp(filename, "self/", strlen("self/"))) {
+            filename += strlen("self/");
+        } else if (*filename >= '1' && *filename <= '9') {
+            char myself[80];
+            snprintf(myself, sizeof(myself), "%d/", getpid());
+            if (!strncmp(filename, myself, strlen(myself))) {
+                filename += strlen(myself);
+            } else {
+                return 0;
+            }
+        } else {
+            return 0;
+        }
+        if (!strcmp(filename, entry)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
+static int is_proc(const char *filename, const char *entry)
+{
+    return strcmp(filename, entry) == 0;
+}
+
+static int open_net_route(void *cpu_env, int fd)
+{
+    FILE *fp;
+    char *line = NULL;
+    size_t len = 0;
+    ssize_t read;
+
+    fp = fopen("/proc/net/route", "r");
+    if (fp == NULL) {
+        return -1;
+    }
+
+    /* read header */
+
+    read = getline(&line, &len, fp);
+    dprintf(fd, "%s", line);
+
+    /* read routes */
+
+    while ((read = getline(&line, &len, fp)) != -1) {
+        char iface[16];
+        uint32_t dest, gw, mask;
+        unsigned int flags, refcnt, use, metric, mtu, window, irtt;
+        sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
+               iface, &dest, &gw, &flags, &refcnt, &use, &metric,
+               &mask, &mtu, &window, &irtt);
+        dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
+                iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
+                metric, tswap32(mask), mtu, window, irtt);
+    }
+
+    free(line);
+    fclose(fp);
+
+    return 0;
+}
+#endif
+
+static int do_openat(void *cpu_env, int dirfd, const char *pathname,
+                     int flags, mode_t mode)
+{
+    struct fake_open {
+        const char *filename;
+        int (*fill)(void *cpu_env, int fd);
+        int (*cmp)(const char *s1, const char *s2);
+    };
+    const struct fake_open *fake_open;
+    static const struct fake_open fakes[] = {
+        { "maps", open_self_maps, is_proc_myself },
+        { "stat", open_self_stat, is_proc_myself },
+        { "auxv", open_self_auxv, is_proc_myself },
+        { "cmdline", open_self_cmdline, is_proc_myself },
+#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
+        { "/proc/net/route", open_net_route, is_proc },
+#endif
+        { NULL, NULL, NULL }
+    };
+
+    if (is_proc_myself(pathname, "exe")) {
+        int execfd = qemu_getauxval(AT_EXECFD);
+        return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
+    }
+
+    for (fake_open = fakes; fake_open->filename; fake_open++) {
+        if (fake_open->cmp(pathname, fake_open->filename)) {
+            break;
+        }
+    }
+
+    if (fake_open->filename) {
+        const char *tmpdir;
+        char filename[PATH_MAX];
+        int fd, r;
+
+        /* create temporary file to map stat to */
+        tmpdir = getenv("TMPDIR");
+        if (!tmpdir) {
+            tmpdir = "/tmp";
+        }
+        snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
+        fd = mkstemp(filename);
+        if (fd < 0) {
+            return fd;
+        }
+        unlink(filename);
+
+        r = fake_open->fill(cpu_env, fd);
+        if (r) {
+            int e = errno;
+            close(fd);
+            errno = e;
+            return r;
+        }
+        lseek(fd, 0, SEEK_SET);
+
+        return fd;
+    }
+
+    return safe_openat(dirfd, path(pathname), flags, mode);
+}
+
+#ifdef TARGET_NR_open
+SYSCALL_IMPL(open)
+{
+    char *p = lock_user_string(arg1);
+    abi_long ret;
+
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
+                              target_to_host_bitmask(arg2, fcntl_flags_tbl),
+                              arg3));
+    fd_trans_unregister(ret);
+    unlock_user(p, arg1, 0);
+    return ret;
+}
+#endif
+
+SYSCALL_IMPL(openat)
+{
+    char *p = lock_user_string(arg2);
+    abi_long ret;
+
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(do_openat(cpu_env, arg1, p,
+                              target_to_host_bitmask(arg3, fcntl_flags_tbl),
+                              arg4));
+    fd_trans_unregister(ret);
+    unlock_user(p, arg2, 0);
+    return ret;
+}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9367574089..32d1a285eb 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6577,266 +6577,7 @@ int host_to_target_waitstatus(int status)
     return status;
 }
 
-static int open_self_cmdline(void *cpu_env, int fd)
-{
-    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
-    struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
-    int i;
-
-    for (i = 0; i < bprm->argc; i++) {
-        size_t len = strlen(bprm->argv[i]) + 1;
-
-        if (write(fd, bprm->argv[i], len) != len) {
-            return -1;
-        }
-    }
-
-    return 0;
-}
-
-static int open_self_maps(void *cpu_env, int fd)
-{
-    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
-    TaskState *ts = cpu->opaque;
-    FILE *fp;
-    char *line = NULL;
-    size_t len = 0;
-    ssize_t read;
-
-    fp = fopen("/proc/self/maps", "r");
-    if (fp == NULL) {
-        return -1;
-    }
-
-    while ((read = getline(&line, &len, fp)) != -1) {
-        int fields, dev_maj, dev_min, inode;
-        uint64_t min, max, offset;
-        char flag_r, flag_w, flag_x, flag_p;
-        char path[512] = "";
-        fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
-                        " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
-                        &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
-
-        if ((fields < 10) || (fields > 11)) {
-            continue;
-        }
-        if (h2g_valid(min)) {
-            int flags = page_get_flags(h2g(min));
-            max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1;
-            if (page_check_range(h2g(min), max - min, flags) == -1) {
-                continue;
-            }
-            if (h2g(min) == ts->info->stack_limit) {
-                pstrcpy(path, sizeof(path), "      [stack]");
-            }
-            dprintf(fd, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr
-                    " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n",
-                    h2g(min), h2g(max - 1) + 1, flag_r, flag_w,
-                    flag_x, flag_p, offset, dev_maj, dev_min, inode,
-                    path[0] ? "         " : "", path);
-        }
-    }
-
-    free(line);
-    fclose(fp);
-
-    return 0;
-}
-
-static int open_self_stat(void *cpu_env, int fd)
-{
-    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
-    TaskState *ts = cpu->opaque;
-    abi_ulong start_stack = ts->info->start_stack;
-    int i;
-
-    for (i = 0; i < 44; i++) {
-      char buf[128];
-      int len;
-      uint64_t val = 0;
-
-      if (i == 0) {
-        /* pid */
-        val = getpid();
-        snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
-      } else if (i == 1) {
-        /* app name */
-        snprintf(buf, sizeof(buf), "(%s) ", ts->bprm->argv[0]);
-      } else if (i == 27) {
-        /* stack bottom */
-        val = start_stack;
-        snprintf(buf, sizeof(buf), "%"PRId64 " ", val);
-      } else {
-        /* for the rest, there is MasterCard */
-        snprintf(buf, sizeof(buf), "0%c", i == 43 ? '\n' : ' ');
-      }
-
-      len = strlen(buf);
-      if (write(fd, buf, len) != len) {
-          return -1;
-      }
-    }
-
-    return 0;
-}
-
-static int open_self_auxv(void *cpu_env, int fd)
-{
-    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
-    TaskState *ts = cpu->opaque;
-    abi_ulong auxv = ts->info->saved_auxv;
-    abi_ulong len = ts->info->auxv_len;
-    char *ptr;
-
-    /*
-     * Auxiliary vector is stored in target process stack.
-     * read in whole auxv vector and copy it to file
-     */
-    ptr = lock_user(VERIFY_READ, auxv, len, 0);
-    if (ptr != NULL) {
-        while (len > 0) {
-            ssize_t r;
-            r = write(fd, ptr, len);
-            if (r <= 0) {
-                break;
-            }
-            len -= r;
-            ptr += r;
-        }
-        lseek(fd, 0, SEEK_SET);
-        unlock_user(ptr, auxv, len);
-    }
-
-    return 0;
-}
-
-static int is_proc_myself(const char *filename, const char *entry)
-{
-    if (!strncmp(filename, "/proc/", strlen("/proc/"))) {
-        filename += strlen("/proc/");
-        if (!strncmp(filename, "self/", strlen("self/"))) {
-            filename += strlen("self/");
-        } else if (*filename >= '1' && *filename <= '9') {
-            char myself[80];
-            snprintf(myself, sizeof(myself), "%d/", getpid());
-            if (!strncmp(filename, myself, strlen(myself))) {
-                filename += strlen(myself);
-            } else {
-                return 0;
-            }
-        } else {
-            return 0;
-        }
-        if (!strcmp(filename, entry)) {
-            return 1;
-        }
-    }
-    return 0;
-}
-
-#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
-static int is_proc(const char *filename, const char *entry)
-{
-    return strcmp(filename, entry) == 0;
-}
-
-static int open_net_route(void *cpu_env, int fd)
-{
-    FILE *fp;
-    char *line = NULL;
-    size_t len = 0;
-    ssize_t read;
-
-    fp = fopen("/proc/net/route", "r");
-    if (fp == NULL) {
-        return -1;
-    }
-
-    /* read header */
-
-    read = getline(&line, &len, fp);
-    dprintf(fd, "%s", line);
-
-    /* read routes */
-
-    while ((read = getline(&line, &len, fp)) != -1) {
-        char iface[16];
-        uint32_t dest, gw, mask;
-        unsigned int flags, refcnt, use, metric, mtu, window, irtt;
-        sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
-                     iface, &dest, &gw, &flags, &refcnt, &use, &metric,
-                     &mask, &mtu, &window, &irtt);
-        dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
-                iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
-                metric, tswap32(mask), mtu, window, irtt);
-    }
-
-    free(line);
-    fclose(fp);
-
-    return 0;
-}
-#endif
-
-static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
-{
-    struct fake_open {
-        const char *filename;
-        int (*fill)(void *cpu_env, int fd);
-        int (*cmp)(const char *s1, const char *s2);
-    };
-    const struct fake_open *fake_open;
-    static const struct fake_open fakes[] = {
-        { "maps", open_self_maps, is_proc_myself },
-        { "stat", open_self_stat, is_proc_myself },
-        { "auxv", open_self_auxv, is_proc_myself },
-        { "cmdline", open_self_cmdline, is_proc_myself },
-#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
-        { "/proc/net/route", open_net_route, is_proc },
-#endif
-        { NULL, NULL, NULL }
-    };
-
-    if (is_proc_myself(pathname, "exe")) {
-        int execfd = qemu_getauxval(AT_EXECFD);
-        return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
-    }
-
-    for (fake_open = fakes; fake_open->filename; fake_open++) {
-        if (fake_open->cmp(pathname, fake_open->filename)) {
-            break;
-        }
-    }
-
-    if (fake_open->filename) {
-        const char *tmpdir;
-        char filename[PATH_MAX];
-        int fd, r;
-
-        /* create temporary file to map stat to */
-        tmpdir = getenv("TMPDIR");
-        if (!tmpdir)
-            tmpdir = "/tmp";
-        snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
-        fd = mkstemp(filename);
-        if (fd < 0) {
-            return fd;
-        }
-        unlink(filename);
-
-        if ((r = fake_open->fill(cpu_env, fd))) {
-            int e = errno;
-            close(fd);
-            errno = e;
-            return r;
-        }
-        lseek(fd, 0, SEEK_SET);
-
-        return fd;
-    }
-
-    return safe_openat(dirfd, path(pathname), flags, mode);
-}
+static int is_proc_myself(const char *filename, const char *entry);
 
 #define TIMER_MAGIC 0x0caf0000
 #define TIMER_MAGIC_MASK 0xffff0000
@@ -7021,26 +6762,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         unlock_user(p, arg2, 0);
         return ret;
 
-#ifdef TARGET_NR_open
-    case TARGET_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            return -TARGET_EFAULT;
-        ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
-                                  target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                                  arg3));
-        fd_trans_unregister(ret);
-        unlock_user(p, arg1, 0);
-        return ret;
-#endif
-    case TARGET_NR_openat:
-        if (!(p = lock_user_string(arg2)))
-            return -TARGET_EFAULT;
-        ret = get_errno(do_openat(cpu_env, arg1, p,
-                                  target_to_host_bitmask(arg3, fcntl_flags_tbl),
-                                  arg4));
-        fd_trans_unregister(ret);
-        unlock_user(p, arg2, 0);
-        return ret;
 #if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
     case TARGET_NR_name_to_handle_at:
         ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
@@ -11545,6 +11266,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
                                 int64_t arg2, int64_t arg3, int64_t arg4, \
                                 int64_t arg5, int64_t arg6)
 
+#include "syscall-file.inc.c"
 
 #undef SYSCALL_IMPL
 #undef SYSCALL_ARGS
diff --git a/linux-user/strace.list b/linux-user/strace.list
index ff8bb19f5f..b2d3e99df7 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -677,12 +677,6 @@
 #ifdef TARGET_NR_olduname
 { TARGET_NR_olduname, "olduname" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_open
-{ TARGET_NR_open, "open" , NULL, print_open, NULL },
-#endif
-#ifdef TARGET_NR_openat
-{ TARGET_NR_openat, "openat" , NULL, print_openat, NULL },
-#endif
 #ifdef TARGET_NR_osf_adjtime
 { TARGET_NR_osf_adjtime, "osf_adjtime" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 04/49] linux-user: Share more code for open and openat
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 01/49] linux-user: Setup split syscall infrastructure Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 03/49] linux-user: Split out open, open_at Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 05/49] linux-user: Tidy do_openat loop over fakes Richard Henderson
                   ` (44 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

The do_openat helper can have all of the code that is not directly
related to the argument ordering of these two syscalls.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-file.inc.c | 69 ++++++++++++++++-------------------
 1 file changed, 31 insertions(+), 38 deletions(-)

diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index ca777da753..ffa70bbea8 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -221,8 +221,8 @@ static int open_net_route(void *cpu_env, int fd)
 }
 #endif
 
-static int do_openat(void *cpu_env, int dirfd, const char *pathname,
-                     int flags, mode_t mode)
+static abi_long do_openat(void *cpu_env, int dirfd, abi_ulong target_path,
+                          int target_flags, mode_t mode)
 {
     struct fake_open {
         const char *filename;
@@ -241,9 +241,20 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname,
         { NULL, NULL, NULL }
     };
 
+    char *pathname = lock_user_string(target_path);
+    int flags = target_to_host_bitmask(target_flags, fcntl_flags_tbl);
+    abi_long ret;
+
+    if (!pathname) {
+        return -TARGET_EFAULT;
+    }
+
     if (is_proc_myself(pathname, "exe")) {
-        int execfd = qemu_getauxval(AT_EXECFD);
-        return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
+        ret = qemu_getauxval(AT_EXECFD);
+        if (ret == 0) {
+            ret = get_errno(safe_openat(dirfd, exec_path, flags, mode));
+        }
+        goto done;
     }
 
     for (fake_open = fakes; fake_open->filename; fake_open++) {
@@ -255,7 +266,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname,
     if (fake_open->filename) {
         const char *tmpdir;
         char filename[PATH_MAX];
-        int fd, r;
+        int fd;
 
         /* create temporary file to map stat to */
         tmpdir = getenv("TMPDIR");
@@ -265,55 +276,37 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname,
         snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
         fd = mkstemp(filename);
         if (fd < 0) {
-            return fd;
+            ret = -TARGET_ENOENT;
+            goto done;
         }
         unlink(filename);
 
-        r = fake_open->fill(cpu_env, fd);
-        if (r) {
-            int e = errno;
+        ret = fake_open->fill(cpu_env, fd);
+        if (ret) {
+            ret = get_errno(ret);
             close(fd);
-            errno = e;
-            return r;
+            goto done;
         }
         lseek(fd, 0, SEEK_SET);
-
-        return fd;
+        ret = fd;
+        goto done;
     }
 
-    return safe_openat(dirfd, path(pathname), flags, mode);
+    ret = get_errno(safe_openat(dirfd, path(pathname), flags, mode));
+ done:
+    fd_trans_unregister(ret);
+    unlock_user(pathname, target_path, 0);
+    return ret;
 }
 
 #ifdef TARGET_NR_open
 SYSCALL_IMPL(open)
 {
-    char *p = lock_user_string(arg1);
-    abi_long ret;
-
-    if (!p) {
-        return -TARGET_EFAULT;
-    }
-    ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
-                              target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                              arg3));
-    fd_trans_unregister(ret);
-    unlock_user(p, arg1, 0);
-    return ret;
+    return do_openat(cpu_env, AT_FDCWD, arg1, arg2, arg3);
 }
 #endif
 
 SYSCALL_IMPL(openat)
 {
-    char *p = lock_user_string(arg2);
-    abi_long ret;
-
-    if (!p) {
-        return -TARGET_EFAULT;
-    }
-    ret = get_errno(do_openat(cpu_env, arg1, p,
-                              target_to_host_bitmask(arg3, fcntl_flags_tbl),
-                              arg4));
-    fd_trans_unregister(ret);
-    unlock_user(p, arg2, 0);
-    return ret;
+    return do_openat(cpu_env, arg1, arg2, arg3, arg4);
 }
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 05/49] linux-user: Tidy do_openat loop over fakes
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (2 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 04/49] linux-user: Share more code for open and openat Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 06/49] linux-user: Split out readlink, readlinkat Richard Henderson
                   ` (43 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Cleaner to use ARRAY_SIZE to loop over elements instead of
using a sentinel within the data structure.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-file.inc.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index ffa70bbea8..f202a4c8f4 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -229,7 +229,6 @@ static abi_long do_openat(void *cpu_env, int dirfd, abi_ulong target_path,
         int (*fill)(void *cpu_env, int fd);
         int (*cmp)(const char *s1, const char *s2);
     };
-    const struct fake_open *fake_open;
     static const struct fake_open fakes[] = {
         { "maps", open_self_maps, is_proc_myself },
         { "stat", open_self_stat, is_proc_myself },
@@ -238,12 +237,12 @@ static abi_long do_openat(void *cpu_env, int dirfd, abi_ulong target_path,
 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
         { "/proc/net/route", open_net_route, is_proc },
 #endif
-        { NULL, NULL, NULL }
     };
 
     char *pathname = lock_user_string(target_path);
     int flags = target_to_host_bitmask(target_flags, fcntl_flags_tbl);
     abi_long ret;
+    size_t i;
 
     if (!pathname) {
         return -TARGET_EFAULT;
@@ -257,17 +256,16 @@ static abi_long do_openat(void *cpu_env, int dirfd, abi_ulong target_path,
         goto done;
     }
 
-    for (fake_open = fakes; fake_open->filename; fake_open++) {
-        if (fake_open->cmp(pathname, fake_open->filename)) {
-            break;
-        }
-    }
-
-    if (fake_open->filename) {
+    for (i = 0; i < ARRAY_SIZE(fakes); ++i) {
+        const struct fake_open *fake_open = &fakes[i];
         const char *tmpdir;
         char filename[PATH_MAX];
         int fd;
 
+        if (!fake_open->cmp(pathname, fake_open->filename)) {
+            continue;
+        }
+
         /* create temporary file to map stat to */
         tmpdir = getenv("TMPDIR");
         if (!tmpdir) {
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 06/49] linux-user: Split out readlink, readlinkat
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (3 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 05/49] linux-user: Tidy do_openat loop over fakes Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 07/49] linux-user: Split out close Richard Henderson
                   ` (42 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Split out a shared implementation for both of these;
unify the best parts of /proc/self/exe checking.

Remove the temporary forward declaration for is_proc_self.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  6 ++++
 linux-user/strace.c           | 29 ------------------
 linux-user/syscall-file.inc.c | 45 ++++++++++++++++++++++++++++
 linux-user/syscall.c          | 55 -----------------------------------
 linux-user/strace.list        |  6 ----
 5 files changed, 51 insertions(+), 90 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 1f3a9c47ab..d1a6c6fa3c 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -20,3 +20,9 @@
 SYSCALL_DEF(open, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
 #endif
 SYSCALL_DEF(openat, ARG_ATDIRFD, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
+#ifdef TARGET_NR_readlink
+SYSCALL_DEF(readlink, ARG_STR, ARG_PTR, ARG_DEC);
+#endif
+#ifdef TARGET_NR_readlinkat
+SYSCALL_DEF(readlinkat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_DEC);
+#endif
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 1e4f6c9b53..4faeb8c031 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -2244,35 +2244,6 @@ print_fstatat64(const struct syscallname *name,
 #define print_newfstatat    print_fstatat64
 #endif
 
-#ifdef TARGET_NR_readlink
-static void
-print_readlink(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_pointer(arg1, 0);
-    print_raw_param("%u", arg2, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
-#ifdef TARGET_NR_readlinkat
-static void
-print_readlinkat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_at_dirfd(arg0, 0);
-    print_string(arg1, 0);
-    print_pointer(arg2, 0);
-    print_raw_param("%u", arg3, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_rename
 static void
 print_rename(const struct syscallname *name,
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index f202a4c8f4..841795f8aa 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -308,3 +308,48 @@ SYSCALL_IMPL(openat)
 {
     return do_openat(cpu_env, arg1, arg2, arg3, arg4);
 }
+
+static abi_long do_readlinkat(int dirfd, abi_ulong target_path,
+                              abi_ulong target_buf, abi_ulong bufsiz)
+{
+    char *p = lock_user_string(target_path);
+    void *buf = lock_user(VERIFY_WRITE, target_buf, bufsiz, 0);
+    abi_long ret;
+
+    if (!p || !buf) {
+        ret = -TARGET_EFAULT;
+    } else if (!bufsiz) {
+        /* Short circuit this for the magic exe check. */
+        ret = -TARGET_EINVAL;
+    } else if (is_proc_myself((const char *)p, "exe")) {
+        char real[PATH_MAX];
+        char *temp = realpath(exec_path, real);
+
+        if (temp == NULL) {
+            ret = -host_to_target_errno(errno);
+        } else {
+            ret = MIN(strlen(real), bufsiz);
+            /* We cannot NUL terminate the string. */
+            memcpy(buf, real, ret);
+        }
+    } else {
+        ret = get_errno(readlinkat(dirfd, path(p), buf, bufsiz));
+    }
+    unlock_user(buf, target_buf, ret);
+    unlock_user(p, target_path, 0);
+    return ret;
+}
+
+#ifdef TARGET_NR_readlink
+SYSCALL_IMPL(readlink)
+{
+    return do_readlinkat(AT_FDCWD, arg1, arg2, arg3);
+}
+#endif
+
+#ifdef TARGET_NR_readlinkat
+SYSCALL_IMPL(readlinkat)
+{
+    return do_readlinkat(arg1, arg2, arg3, arg4);
+}
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 32d1a285eb..035f17c0d9 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6577,8 +6577,6 @@ int host_to_target_waitstatus(int status)
     return status;
 }
 
-static int is_proc_myself(const char *filename, const char *entry);
-
 #define TIMER_MAGIC 0x0caf0000
 #define TIMER_MAGIC_MASK 0xffff0000
 
@@ -8052,59 +8050,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         }
         return ret;
 #endif
-#ifdef TARGET_NR_readlink
-    case TARGET_NR_readlink:
-        {
-            void *p2;
-            p = lock_user_string(arg1);
-            p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
-            if (!p || !p2) {
-                ret = -TARGET_EFAULT;
-            } else if (!arg3) {
-                /* Short circuit this for the magic exe check. */
-                ret = -TARGET_EINVAL;
-            } else if (is_proc_myself((const char *)p, "exe")) {
-                char real[PATH_MAX], *temp;
-                temp = realpath(exec_path, real);
-                /* Return value is # of bytes that we wrote to the buffer. */
-                if (temp == NULL) {
-                    ret = get_errno(-1);
-                } else {
-                    /* Don't worry about sign mismatch as earlier mapping
-                     * logic would have thrown a bad address error. */
-                    ret = MIN(strlen(real), arg3);
-                    /* We cannot NUL terminate the string. */
-                    memcpy(p2, real, ret);
-                }
-            } else {
-                ret = get_errno(readlink(path(p), p2, arg3));
-            }
-            unlock_user(p2, arg2, ret);
-            unlock_user(p, arg1, 0);
-        }
-        return ret;
-#endif
-#if defined(TARGET_NR_readlinkat)
-    case TARGET_NR_readlinkat:
-        {
-            void *p2;
-            p  = lock_user_string(arg2);
-            p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
-            if (!p || !p2) {
-                ret = -TARGET_EFAULT;
-            } else if (is_proc_myself((const char *)p, "exe")) {
-                char real[PATH_MAX], *temp;
-                temp = realpath(exec_path, real);
-                ret = temp == NULL ? get_errno(-1) : strlen(real) ;
-                snprintf((char *)p2, arg4, "%s", real);
-            } else {
-                ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
-            }
-            unlock_user(p2, arg3, ret);
-            unlock_user(p, arg2, 0);
-        }
-        return ret;
-#endif
 #ifdef TARGET_NR_swapon
     case TARGET_NR_swapon:
         if (!(p = lock_user_string(arg1)))
diff --git a/linux-user/strace.list b/linux-user/strace.list
index b2d3e99df7..2f466e5699 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1079,12 +1079,6 @@
 #ifdef TARGET_NR_readdir
 { TARGET_NR_readdir, "readdir" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_readlink
-{ TARGET_NR_readlink, "readlink" , NULL, print_readlink, NULL },
-#endif
-#ifdef TARGET_NR_readlinkat
-{ TARGET_NR_readlinkat, "readlinkat" , NULL, print_readlinkat, NULL },
-#endif
 #ifdef TARGET_NR_readv
 { TARGET_NR_readv, "readv" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 07/49] linux-user: Split out close
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (4 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 06/49] linux-user: Split out readlink, readlinkat Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 08/49] linux-user: Split out read, write Richard Henderson
                   ` (41 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     | 1 +
 linux-user/syscall-file.inc.c | 8 ++++++++
 linux-user/syscall.c          | 4 ----
 linux-user/strace.list        | 3 ---
 4 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index d1a6c6fa3c..797426ae6f 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -16,6 +16,7 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+SYSCALL_DEF(close, ARG_DEC);
 #ifdef TARGET_NR_open
 SYSCALL_DEF(open, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
 #endif
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 841795f8aa..feb83c4e87 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -16,6 +16,14 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+SYSCALL_IMPL(close)
+{
+    int fd = arg1;
+
+    fd_trans_unregister(fd);
+    return get_errno(close(fd));
+}
+
 /*
  * Helpers for do_openat, manipulating /proc/self/foo.
  */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 035f17c0d9..f230fe161e 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6771,10 +6771,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         fd_trans_unregister(ret);
         return ret;
 #endif
-    case TARGET_NR_close:
-        fd_trans_unregister(arg1);
-        return get_errno(close(arg1));
-
     case TARGET_NR_brk:
         return do_brk(arg1);
 #ifdef TARGET_NR_fork
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 2f466e5699..71a18123bf 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -97,9 +97,6 @@
 #ifdef TARGET_NR_clone
 { TARGET_NR_clone, "clone" , NULL, print_clone, NULL },
 #endif
-#ifdef TARGET_NR_close
-{ TARGET_NR_close, "close" , "%s(%d)", NULL, NULL },
-#endif
 #ifdef TARGET_NR_connect
 { TARGET_NR_connect, "connect" , "%s(%d,%#x,%d)", NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 08/49] linux-user: Split out read, write
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (5 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 07/49] linux-user: Split out close Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 09/49] linux-user: Reduce regpairs_aligned & target_offset64 ifdefs Richard Henderson
                   ` (40 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  2 ++
 linux-user/syscall-file.inc.c | 58 +++++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 34 --------------------
 linux-user/strace.list        |  6 ----
 4 files changed, 60 insertions(+), 40 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 797426ae6f..b031de1375 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -21,9 +21,11 @@ SYSCALL_DEF(close, ARG_DEC);
 SYSCALL_DEF(open, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
 #endif
 SYSCALL_DEF(openat, ARG_ATDIRFD, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
+SYSCALL_DEF(read, ARG_DEC, ARG_PTR, ARG_DEC);
 #ifdef TARGET_NR_readlink
 SYSCALL_DEF(readlink, ARG_STR, ARG_PTR, ARG_DEC);
 #endif
 #ifdef TARGET_NR_readlinkat
 SYSCALL_DEF(readlinkat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_DEC);
 #endif
+SYSCALL_DEF(write, ARG_DEC, ARG_PTR, ARG_DEC);
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index feb83c4e87..9c8025b252 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -317,6 +317,32 @@ SYSCALL_IMPL(openat)
     return do_openat(cpu_env, arg1, arg2, arg3, arg4);
 }
 
+SYSCALL_IMPL(read)
+{
+    int fd = arg1;
+    abi_ulong target_p = arg2;
+    abi_ulong size = arg3;
+    void *p;
+    abi_long ret;
+
+    if (size == 0) {
+        return 0;
+    }
+    p = lock_user(VERIFY_WRITE, target_p, size, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(safe_read(fd, p, size));
+    if (!is_error(ret)) {
+        TargetFdDataFunc trans = fd_trans_host_to_target_data(fd);
+        if (trans) {
+            ret = trans(p, ret);
+        }
+    }
+    unlock_user(p, target_p, ret);
+    return ret;
+}
+
 static abi_long do_readlinkat(int dirfd, abi_ulong target_path,
                               abi_ulong target_buf, abi_ulong bufsiz)
 {
@@ -361,3 +387,35 @@ SYSCALL_IMPL(readlinkat)
     return do_readlinkat(arg1, arg2, arg3, arg4);
 }
 #endif
+
+SYSCALL_IMPL(write)
+{
+    int fd = arg1;
+    abi_ulong target_p = arg2;
+    abi_ulong size = arg3;
+    TargetFdDataFunc trans;
+    abi_long ret;
+    void *p;
+
+    if (target_p == 0 && size == 0) {
+        return get_errno(safe_write(fd, 0, 0));
+    }
+    p = lock_user(VERIFY_READ, target_p, size, 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    trans = fd_trans_target_to_host_data(fd);
+    if (trans) {
+        void *copy = g_malloc(size);
+        memcpy(copy, p, size);
+        ret = trans(copy, size);
+        if (ret >= 0) {
+            ret = get_errno(safe_write(fd, copy, ret));
+        }
+        g_free(copy);
+    } else {
+        ret = get_errno(safe_write(fd, p, size));
+    }
+    unlock_user(p, target_p, 0);
+    return ret;
+}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f230fe161e..d4d5c25803 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6726,40 +6726,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         preexit_cleanup(cpu_env, arg1);
         _exit(arg1);
         return 0; /* avoid warning */
-    case TARGET_NR_read:
-        if (arg3 == 0) {
-            return 0;
-        } else {
-            if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-                return -TARGET_EFAULT;
-            ret = get_errno(safe_read(arg1, p, arg3));
-            if (ret >= 0 &&
-                fd_trans_host_to_target_data(arg1)) {
-                ret = fd_trans_host_to_target_data(arg1)(p, ret);
-            }
-            unlock_user(p, arg2, ret);
-        }
-        return ret;
-    case TARGET_NR_write:
-        if (arg2 == 0 && arg3 == 0) {
-            return get_errno(safe_write(arg1, 0, 0));
-        }
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            return -TARGET_EFAULT;
-        if (fd_trans_target_to_host_data(arg1)) {
-            void *copy = g_malloc(arg3);
-            memcpy(copy, p, arg3);
-            ret = fd_trans_target_to_host_data(arg1)(copy, arg3);
-            if (ret >= 0) {
-                ret = get_errno(safe_write(arg1, copy, ret));
-            }
-            g_free(copy);
-        } else {
-            ret = get_errno(safe_write(arg1, p, arg3));
-        }
-        unlock_user(p, arg2, 0);
-        return ret;
-
 #if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
     case TARGET_NR_name_to_handle_at:
         ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 71a18123bf..f3a1b0fe31 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1067,9 +1067,6 @@
 #ifdef TARGET_NR_quotactl
 { TARGET_NR_quotactl, "quotactl" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_read
-{ TARGET_NR_read, "read" , "%s(%d,%#x,%d)", NULL, NULL },
-#endif
 #ifdef TARGET_NR_readahead
 { TARGET_NR_readahead, "readahead" , NULL, NULL, NULL },
 #endif
@@ -1611,9 +1608,6 @@
 #ifdef TARGET_NR_waitpid
 { TARGET_NR_waitpid, "waitpid" , "%s(%d,%p,%#x)", NULL, NULL },
 #endif
-#ifdef TARGET_NR_write
-{ TARGET_NR_write, "write" , "%s(%d,%#x,%d)", NULL, NULL },
-#endif
 #ifdef TARGET_NR_writev
 { TARGET_NR_writev, "writev" , "%s(%d,%p,%#x)", NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 09/49] linux-user: Reduce regpairs_aligned & target_offset64 ifdefs
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (6 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 08/49] linux-user: Split out read, write Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 10/49] linux-user: Split out readv, writev Richard Henderson
                   ` (39 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall.c | 54 ++++++++++++++++++++------------------------
 1 file changed, 25 insertions(+), 29 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index d4d5c25803..c236a80437 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -474,37 +474,38 @@ static inline int next_free_host_timer(void)
 }
 #endif
 
-/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
+/*
+ * Returns true if syscall NUM expects 64bit types aligned even
+ * on pairs of registers.
+ */
+static inline bool regpairs_aligned(void *cpu_env, int num)
+{
 #ifdef TARGET_ARM
-static inline int regpairs_aligned(void *cpu_env, int num)
-{
-    return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
-}
-#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32)
-static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
+    return ((CPUARMState *)cpu_env)->eabi;
+#elif defined(TARGET_MIPS) && TARGET_ABI_BITS == 32
+    return true;
 #elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
-/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
- * of registers which translates to the same as ARM/MIPS, because we start with
- * r3 as arg1 */
-static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
+    /*
+     * SysV AVI for PPC32 expects 64bit parameters to be passed on
+     * odd/even pairs of registers which translates to the same as
+     * we start with r3 as arg1.
+     */
+    return true;
 #elif defined(TARGET_SH4)
-/* SH4 doesn't align register pairs, except for p{read,write}64 */
-static inline int regpairs_aligned(void *cpu_env, int num)
-{
+    /* SH4 doesn't align register pairs, except for p{read,write}64.  */
     switch (num) {
     case TARGET_NR_pread64:
     case TARGET_NR_pwrite64:
-        return 1;
-
+        return true;
     default:
-        return 0;
+        return false;
     }
-}
 #elif defined(TARGET_XTENSA)
-static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
+    return true;
 #else
-static inline int regpairs_aligned(void *cpu_env, int num) { return 0; }
+    return false;
 #endif
+}
 
 #define ERRNO_TABLE_SIZE 1200
 
@@ -6105,21 +6106,16 @@ void syscall_init(void)
     }
 }
 
-#if TARGET_ABI_BITS == 32
-static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
+static inline uint64_t target_offset64(abi_ulong word0, abi_ulong word1)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
+#if TARGET_ABI_BITS == 64
+    return word0;
+#elif defined(TARGET_WORDS_BIGENDIAN)
     return ((uint64_t)word0 << 32) | word1;
 #else
     return ((uint64_t)word1 << 32) | word0;
 #endif
 }
-#else /* TARGET_ABI_BITS == 32 */
-static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
-{
-    return word0;
-}
-#endif /* TARGET_ABI_BITS != 32 */
 
 #ifdef TARGET_NR_truncate64
 static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 10/49] linux-user: Split out readv, writev
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (7 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 09/49] linux-user: Reduce regpairs_aligned & target_offset64 ifdefs Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 11/49] linux-user: Split out pread64, pwrite64 Richard Henderson
                   ` (38 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  2 ++
 linux-user/syscall-file.inc.c | 34 ++++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 22 ----------------------
 linux-user/strace.list        |  6 ------
 4 files changed, 36 insertions(+), 28 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index b031de1375..130ba7e344 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -28,4 +28,6 @@ SYSCALL_DEF(readlink, ARG_STR, ARG_PTR, ARG_DEC);
 #ifdef TARGET_NR_readlinkat
 SYSCALL_DEF(readlinkat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_DEC);
 #endif
+SYSCALL_DEF(readv, ARG_DEC, ARG_PTR, ARG_DEC);
 SYSCALL_DEF(write, ARG_DEC, ARG_PTR, ARG_DEC);
+SYSCALL_DEF(writev, ARG_DEC, ARG_PTR, ARG_DEC);
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 9c8025b252..9bd21ac5cd 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -343,6 +343,23 @@ SYSCALL_IMPL(read)
     return ret;
 }
 
+SYSCALL_IMPL(readv)
+{
+    int fd = arg1;
+    abi_ulong target_vec = arg2;
+    int count = arg3;
+    struct iovec *vec = lock_iovec(VERIFY_WRITE, target_vec, count, 0);
+    abi_long ret;
+
+    if (vec != NULL) {
+        ret = get_errno(safe_readv(fd, vec, count));
+        unlock_iovec(vec, target_vec, count, 1);
+    } else {
+        ret = -host_to_target_errno(errno);
+    }
+    return ret;
+}
+
 static abi_long do_readlinkat(int dirfd, abi_ulong target_path,
                               abi_ulong target_buf, abi_ulong bufsiz)
 {
@@ -419,3 +436,20 @@ SYSCALL_IMPL(write)
     unlock_user(p, target_p, 0);
     return ret;
 }
+
+SYSCALL_IMPL(writev)
+{
+    int fd = arg1;
+    abi_ulong target_vec = arg2;
+    int count = arg3;
+    struct iovec *vec = lock_iovec(VERIFY_READ, target_vec, count, 1);
+    abi_long ret;
+
+    if (vec != NULL) {
+        ret = get_errno(safe_writev(fd, vec, count));
+        unlock_iovec(vec, target_vec, count, 0);
+    } else {
+        ret = -host_to_target_errno(errno);
+    }
+    return ret;
+}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c236a80437..df47ee106e 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8949,28 +8949,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         /* NOTE: the flock constant seems to be the same for every
            Linux platform */
         return get_errno(safe_flock(arg1, arg2));
-    case TARGET_NR_readv:
-        {
-            struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
-            if (vec != NULL) {
-                ret = get_errno(safe_readv(arg1, vec, arg3));
-                unlock_iovec(vec, arg2, arg3, 1);
-            } else {
-                ret = -host_to_target_errno(errno);
-            }
-        }
-        return ret;
-    case TARGET_NR_writev:
-        {
-            struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
-            if (vec != NULL) {
-                ret = get_errno(safe_writev(arg1, vec, arg3));
-                unlock_iovec(vec, arg2, arg3, 0);
-            } else {
-                ret = -host_to_target_errno(errno);
-            }
-        }
-        return ret;
 #if defined(TARGET_NR_preadv)
     case TARGET_NR_preadv:
         {
diff --git a/linux-user/strace.list b/linux-user/strace.list
index f3a1b0fe31..e02a854cea 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1073,9 +1073,6 @@
 #ifdef TARGET_NR_readdir
 { TARGET_NR_readdir, "readdir" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_readv
-{ TARGET_NR_readv, "readv" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_reboot
 { TARGET_NR_reboot, "reboot" , NULL, NULL, NULL },
 #endif
@@ -1608,9 +1605,6 @@
 #ifdef TARGET_NR_waitpid
 { TARGET_NR_waitpid, "waitpid" , "%s(%d,%p,%#x)", NULL, NULL },
 #endif
-#ifdef TARGET_NR_writev
-{ TARGET_NR_writev, "writev" , "%s(%d,%p,%#x)", NULL, NULL },
-#endif
 #ifdef TARGET_NR_utimensat
 { TARGET_NR_utimensat, "utimensat", NULL, print_utimensat, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 11/49] linux-user: Split out pread64, pwrite64
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (8 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 10/49] linux-user: Split out readv, writev Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 12/49] linux-user: Split out preadv, pwritev Richard Henderson
                   ` (37 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  6 ++++
 linux-user/syscall-file.inc.c | 62 +++++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 36 --------------------
 linux-user/strace.list        |  6 ----
 4 files changed, 68 insertions(+), 42 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 130ba7e344..027793d5d0 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -21,6 +21,12 @@ SYSCALL_DEF(close, ARG_DEC);
 SYSCALL_DEF(open, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
 #endif
 SYSCALL_DEF(openat, ARG_ATDIRFD, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
+SYSCALL_DEF_FULL(pread64, .impl = impl_pread64,
+                 .args = args_pread64_pwrite64,
+                 .arg_type = { ARG_DEC, ARG_PTR, ARG_DEC, ARG_DEC64 });
+SYSCALL_DEF_FULL(pwrite64, .impl = impl_pwrite64,
+                 .args = args_pread64_pwrite64,
+                 .arg_type = { ARG_DEC, ARG_PTR, ARG_DEC, ARG_DEC64 });
 SYSCALL_DEF(read, ARG_DEC, ARG_PTR, ARG_DEC);
 #ifdef TARGET_NR_readlink
 SYSCALL_DEF(readlink, ARG_STR, ARG_PTR, ARG_DEC);
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 9bd21ac5cd..e79cfabf56 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -317,6 +317,68 @@ SYSCALL_IMPL(openat)
     return do_openat(cpu_env, arg1, arg2, arg3, arg4);
 }
 
+/*
+ * Both pread64 and pwrite64 merge args into a 64-bit offset,
+ * but the input registers and ordering are target specific.
+ */
+#if TARGET_ABI_BITS == 32
+SYSCALL_ARGS(pread64_pwrite64)
+{
+    /* We have already assigned out[0-2].  */
+    int off = regpairs_aligned(cpu_env, TARGET_NR_pread64);
+    out[3] = target_offset64(in[3 + off], in[4 + off]);
+    return def;
+}
+#else
+#define args_pread64_pwrite64 NULL
+#endif
+
+SYSCALL_IMPL(pread64)
+{
+    int fd = arg1;
+    abi_ulong target_buf = arg2;
+    abi_ulong len = arg3;
+    uint64_t off = arg4;
+    void *p;
+    abi_long ret;
+
+    if (target_buf == 0 && len == 0) {
+        /* Special-case NULL buffer and zero length, which should succeed */
+        p = NULL;
+    } else {
+        p = lock_user(VERIFY_WRITE, target_buf, len, 0);
+        if (!p) {
+            return -TARGET_EFAULT;
+        }
+    }
+    ret = get_errno(pread64(fd, p, len, off));
+    unlock_user(p, target_buf, ret);
+    return ret;
+}
+
+SYSCALL_IMPL(pwrite64)
+{
+    int fd = arg1;
+    abi_ulong target_buf = arg2;
+    abi_ulong len = arg3;
+    uint64_t off = arg4;
+    void *p;
+    abi_long ret;
+
+    if (target_buf == 0 && len == 0) {
+        /* Special-case NULL buffer and zero length, which should succeed */
+        p = 0;
+    } else {
+        p = lock_user(VERIFY_READ, target_buf, len, 1);
+        if (!p) {
+            return -TARGET_EFAULT;
+        }
+    }
+    ret = get_errno(pwrite64(fd, p, len, off));
+    unlock_user(p, target_buf, 0);
+    return ret;
+}
+
 SYSCALL_IMPL(read)
 {
     int fd = arg1;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index df47ee106e..80806c0150 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -9312,42 +9312,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
 #else
 #error unreachable
 #endif
-#endif
-#ifdef TARGET_NR_pread64
-    case TARGET_NR_pread64:
-        if (regpairs_aligned(cpu_env, num)) {
-            arg4 = arg5;
-            arg5 = arg6;
-        }
-        if (arg2 == 0 && arg3 == 0) {
-            /* Special-case NULL buffer and zero length, which should succeed */
-            p = 0;
-        } else {
-            p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
-            if (!p) {
-                return -TARGET_EFAULT;
-            }
-        }
-        ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
-        unlock_user(p, arg2, ret);
-        return ret;
-    case TARGET_NR_pwrite64:
-        if (regpairs_aligned(cpu_env, num)) {
-            arg4 = arg5;
-            arg5 = arg6;
-        }
-        if (arg2 == 0 && arg3 == 0) {
-            /* Special-case NULL buffer and zero length, which should succeed */
-            p = 0;
-        } else {
-            p = lock_user(VERIFY_READ, arg2, arg3, 1);
-            if (!p) {
-                return -TARGET_EFAULT;
-            }
-        }
-        ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
-        unlock_user(p, arg2, 0);
-        return ret;
 #endif
     case TARGET_NR_getcwd:
         if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
diff --git a/linux-user/strace.list b/linux-user/strace.list
index e02a854cea..c7e573669d 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1025,9 +1025,6 @@
 #ifdef TARGET_NR_prctl
 { TARGET_NR_prctl, "prctl" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_pread64
-{ TARGET_NR_pread64, "pread64" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_preadv
 { TARGET_NR_preadv, "preadv" , NULL, NULL, NULL },
 #endif
@@ -1055,9 +1052,6 @@
 #ifdef TARGET_NR_putpmsg
 { TARGET_NR_putpmsg, "putpmsg" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_pwrite64
-{ TARGET_NR_pwrite64, "pwrite64" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_pwritev
 { TARGET_NR_pwritev, "pwritev" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 12/49] linux-user: Split out preadv, pwritev
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (9 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 11/49] linux-user: Split out pread64, pwrite64 Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 13/49] linux-user: Split out name_to_handle_at, open_by_handle_at Richard Henderson
                   ` (36 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  6 ++++
 linux-user/syscall-file.inc.c | 64 +++++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 49 ---------------------------
 linux-user/strace.list        |  6 ----
 4 files changed, 70 insertions(+), 55 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 027793d5d0..ae89be0e87 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -27,6 +27,12 @@ SYSCALL_DEF_FULL(pread64, .impl = impl_pread64,
 SYSCALL_DEF_FULL(pwrite64, .impl = impl_pwrite64,
                  .args = args_pread64_pwrite64,
                  .arg_type = { ARG_DEC, ARG_PTR, ARG_DEC, ARG_DEC64 });
+SYSCALL_DEF_FULL(preadv, .impl = impl_preadv,
+                 .args = args_preadv_pwritev,
+                 .arg_type = { ARG_DEC, ARG_PTR, ARG_DEC, ARG_DEC64 });
+SYSCALL_DEF_FULL(pwritev, .impl = impl_pwritev,
+                 .args = args_preadv_pwritev,
+                 .arg_type = { ARG_DEC, ARG_PTR, ARG_DEC, ARG_DEC64 });
 SYSCALL_DEF(read, ARG_DEC, ARG_PTR, ARG_DEC);
 #ifdef TARGET_NR_readlink
 SYSCALL_DEF(readlink, ARG_STR, ARG_PTR, ARG_DEC);
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index e79cfabf56..63401684c3 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -379,6 +379,70 @@ SYSCALL_IMPL(pwrite64)
     return ret;
 }
 
+/*
+ * Both preadv and pwritev merge args 4/5 into a 64-bit offset.
+ * Moreover, the parts are *always* in little-endian order.
+ */
+#if TARGET_ABI_BITS == 32
+SYSCALL_ARGS(preadv_pwritev)
+{
+    /* We have already assigned out[0-2].  */
+    abi_ulong lo = in[3], hi = in[4];
+    out[3] = (((uint64_t)hi << (TARGET_ABI_BITS - 1)) << 1) | lo;
+    return def;
+}
+#else
+#define args_preadv_pwritev NULL
+#endif
+
+/* Perform the inverse operation for the host.  */
+static inline void host_offset64_low_high(unsigned long *l, unsigned long *h,
+                                          uint64_t off)
+{
+    *l = off;
+    *h = (off >> (HOST_LONG_BITS - 1)) >> 1;
+}
+
+SYSCALL_IMPL(preadv)
+{
+    int fd = arg1;
+    abi_ulong target_vec = arg2;
+    int count = arg3;
+    uint64_t off = arg4;
+    struct iovec *vec = lock_iovec(VERIFY_WRITE, target_vec, count, 0);
+    unsigned long lo, hi;
+    abi_long ret;
+
+    if (vec == NULL) {
+        return -TARGET_EFAULT;
+    }
+
+    host_offset64_low_high(&lo, &hi, off);
+    ret = get_errno(safe_preadv(fd, vec, count, lo, hi));
+    unlock_iovec(vec, target_vec, count, 1);
+    return ret;
+}
+
+SYSCALL_IMPL(pwritev)
+{
+    int fd = arg1;
+    abi_ulong target_vec = arg2;
+    int count = arg3;
+    uint64_t off = arg4;
+    struct iovec *vec = lock_iovec(VERIFY_READ, target_vec, count, 1);
+    unsigned long lo, hi;
+    abi_long ret;
+
+    if (vec == NULL) {
+        return -TARGET_EFAULT;
+    }
+
+    host_offset64_low_high(&lo, &hi, off);
+    ret = get_errno(safe_pwritev(fd, vec, count, lo, hi));
+    unlock_iovec(vec, target_vec, count, 0);
+    return ret;
+}
+
 SYSCALL_IMPL(read)
 {
     int fd = arg1;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 80806c0150..9606f15a09 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2403,23 +2403,6 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
     return ret;
 }
 
-/* Convert target low/high pair representing file offset into the host
- * low/high pair. This function doesn't handle offsets bigger than 64 bits
- * as the kernel doesn't handle them either.
- */
-static void target_to_host_low_high(abi_ulong tlow,
-                                    abi_ulong thigh,
-                                    unsigned long *hlow,
-                                    unsigned long *hhigh)
-{
-    uint64_t off = tlow |
-        ((unsigned long long)thigh << TARGET_LONG_BITS / 2) <<
-        TARGET_LONG_BITS / 2;
-
-    *hlow = off;
-    *hhigh = (off >> HOST_LONG_BITS / 2) >> HOST_LONG_BITS / 2;
-}
-
 static struct iovec *lock_iovec(int type, abi_ulong target_addr,
                                 abi_ulong count, int copy)
 {
@@ -8949,38 +8932,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         /* NOTE: the flock constant seems to be the same for every
            Linux platform */
         return get_errno(safe_flock(arg1, arg2));
-#if defined(TARGET_NR_preadv)
-    case TARGET_NR_preadv:
-        {
-            struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
-            if (vec != NULL) {
-                unsigned long low, high;
-
-                target_to_host_low_high(arg4, arg5, &low, &high);
-                ret = get_errno(safe_preadv(arg1, vec, arg3, low, high));
-                unlock_iovec(vec, arg2, arg3, 1);
-            } else {
-                ret = -host_to_target_errno(errno);
-           }
-        }
-        return ret;
-#endif
-#if defined(TARGET_NR_pwritev)
-    case TARGET_NR_pwritev:
-        {
-            struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
-            if (vec != NULL) {
-                unsigned long low, high;
-
-                target_to_host_low_high(arg4, arg5, &low, &high);
-                ret = get_errno(safe_pwritev(arg1, vec, arg3, low, high));
-                unlock_iovec(vec, arg2, arg3, 0);
-            } else {
-                ret = -host_to_target_errno(errno);
-           }
-        }
-        return ret;
-#endif
     case TARGET_NR_getsid:
         return get_errno(getsid(arg1));
 #if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
diff --git a/linux-user/strace.list b/linux-user/strace.list
index c7e573669d..586eb55482 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1025,9 +1025,6 @@
 #ifdef TARGET_NR_prctl
 { TARGET_NR_prctl, "prctl" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_preadv
-{ TARGET_NR_preadv, "preadv" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_prlimit64
 { TARGET_NR_prlimit64, "prlimit64" , NULL, NULL, NULL },
 #endif
@@ -1052,9 +1049,6 @@
 #ifdef TARGET_NR_putpmsg
 { TARGET_NR_putpmsg, "putpmsg" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_pwritev
-{ TARGET_NR_pwritev, "pwritev" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_query_module
 { TARGET_NR_query_module, "query_module" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 13/49] linux-user: Split out name_to_handle_at, open_by_handle_at
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (10 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 12/49] linux-user: Split out preadv, pwritev Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 14/49] linux-user: Split out ipc syscalls Richard Henderson
                   ` (35 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

All targets have these syscalls, so they need not be ifdefed.
If we provide safe syscalls for the host, we can remove the
configure test for this too.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |   3 +
 linux-user/syscall.h          |   1 +
 linux-user/strace.c           |   5 +-
 linux-user/syscall-file.inc.c |  81 +++++++++++++++++++++++++++
 linux-user/syscall.c          | 102 ++--------------------------------
 configure                     |  20 -------
 linux-user/strace.list        |   3 -
 7 files changed, 93 insertions(+), 122 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index ae89be0e87..1fc89c1b08 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -17,10 +17,13 @@
  */
 
 SYSCALL_DEF(close, ARG_DEC);
+SYSCALL_DEF(name_to_handle_at,
+            ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_PTR, ARG_ATFLAG);
 #ifdef TARGET_NR_open
 SYSCALL_DEF(open, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
 #endif
 SYSCALL_DEF(openat, ARG_ATDIRFD, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
+SYSCALL_DEF(open_by_handle_at, ARG_DEC, ARG_PTR, ARG_OPENFLAG);
 SYSCALL_DEF_FULL(pread64, .impl = impl_pread64,
                  .args = args_pread64_pwrite64,
                  .arg_type = { ARG_DEC, ARG_PTR, ARG_DEC, ARG_DEC64 });
diff --git a/linux-user/syscall.h b/linux-user/syscall.h
index 43b5dc0684..83f602f8e7 100644
--- a/linux-user/syscall.h
+++ b/linux-user/syscall.h
@@ -57,6 +57,7 @@ typedef enum {
 
     /* These print as sets of flags.  */
     ARG_ATDIRFD,
+    ARG_ATFLAG,
     ARG_MODEFLAG,
     ARG_OPENFLAG,
 
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 4faeb8c031..ed311b081b 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -780,7 +780,7 @@ UNUSED static struct flags access_flags[] = {
     FLAG_END,
 };
 
-UNUSED static struct flags at_file_flags[] = {
+static struct flags const at_file_flags[] = {
 #ifdef AT_EACCESS
     FLAG_GENERIC(AT_EACCESS),
 #endif
@@ -2681,6 +2681,9 @@ static void print_syscall_def1(const SyscallDef *def, int64_t args[6])
         case ARG_ATDIRFD:
             len = add_atdirfd(b, rest, arg);
             break;
+        case ARG_ATFLAG:
+            len = add_flags(b, rest, at_file_flags, arg, false);
+            break;
         case ARG_MODEFLAG:
             len = add_flags(b, rest, mode_flags, arg, true);
             break;
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 63401684c3..81423cfd64 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -317,6 +317,87 @@ SYSCALL_IMPL(openat)
     return do_openat(cpu_env, arg1, arg2, arg3, arg4);
 }
 
+SYSCALL_IMPL(name_to_handle_at)
+{
+    struct file_handle *target_fh;
+    struct file_handle *fh;
+    int mid = 0;
+    abi_long ret;
+    char *name;
+    uint32_t size, total_size;
+
+    if (get_user_s32(size, arg3)) {
+        return -TARGET_EFAULT;
+    }
+    total_size = sizeof(struct file_handle) + size;
+    target_fh = lock_user(VERIFY_WRITE, arg3, total_size, 0);
+    if (!target_fh) {
+        return -TARGET_EFAULT;
+    }
+
+    name = lock_user_string(arg2);
+    if (!name) {
+        unlock_user(target_fh, arg3, 0);
+        return -TARGET_EFAULT;
+    }
+
+    fh = g_malloc0(total_size);
+    fh->handle_bytes = size;
+
+    ret = get_errno(safe_name_to_handle_at(arg1, path(name), fh, &mid, arg5));
+    unlock_user(name, arg2, 0);
+
+    /*
+     * man name_to_handle_at(2):
+     * Other than the use of the handle_bytes field, the caller should treat
+     * the file_handle structure as an opaque data type
+     */
+    if (!is_error(ret)) {
+        memcpy(target_fh, fh, total_size);
+        target_fh->handle_bytes = tswap32(fh->handle_bytes);
+        target_fh->handle_type = tswap32(fh->handle_type);
+        g_free(fh);
+        unlock_user(target_fh, arg3, total_size);
+
+        if (put_user_s32(mid, arg4)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+SYSCALL_IMPL(open_by_handle_at)
+{
+    abi_long mount_fd = arg1;
+    abi_long handle = arg2;
+    int host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
+    struct file_handle *target_fh;
+    struct file_handle *fh;
+    unsigned int size, total_size;
+    abi_long ret;
+
+    if (get_user_s32(size, handle)) {
+        return -TARGET_EFAULT;
+    }
+    total_size = sizeof(struct file_handle) + size;
+    target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
+    if (!target_fh) {
+        return -TARGET_EFAULT;
+    }
+
+    fh = g_memdup(target_fh, total_size);
+    fh->handle_bytes = size;
+    fh->handle_type = tswap32(target_fh->handle_type);
+
+    ret = get_errno(safe_open_by_handle_at(mount_fd, fh, host_flags));
+
+    g_free(fh);
+    unlock_user(target_fh, handle, total_size);
+
+    fd_trans_unregister(ret);
+    return ret;
+}
+
 /*
  * Both pread64 and pwrite64 merge args into a 64-bit offset,
  * but the input registers and ordering are target specific.
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9606f15a09..18dea32b60 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -816,6 +816,10 @@ safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
 safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
               size_t, len, unsigned *, prio, const struct timespec *, timeout)
 #endif
+safe_syscall5(int, name_to_handle_at, int, dirfd, const char *, pathname,
+              struct file_handle *, handle, int *, mount_id, int, flags)
+safe_syscall3(int, open_by_handle_at, int, mount_fd,
+              struct file_handle *, handle, int, flags)
 /* We do ioctl like this rather than via safe_syscall3 to preserve the
  * "third argument might be integer or pointer or not present" behaviour of
  * the libc function.
@@ -6423,93 +6427,6 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
         return -TARGET_ENOSYS;
     }
 }
-#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
-static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
-                                     abi_long handle, abi_long mount_id,
-                                     abi_long flags)
-{
-    struct file_handle *target_fh;
-    struct file_handle *fh;
-    int mid = 0;
-    abi_long ret;
-    char *name;
-    unsigned int size, total_size;
-
-    if (get_user_s32(size, handle)) {
-        return -TARGET_EFAULT;
-    }
-
-    name = lock_user_string(pathname);
-    if (!name) {
-        return -TARGET_EFAULT;
-    }
-
-    total_size = sizeof(struct file_handle) + size;
-    target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
-    if (!target_fh) {
-        unlock_user(name, pathname, 0);
-        return -TARGET_EFAULT;
-    }
-
-    fh = g_malloc0(total_size);
-    fh->handle_bytes = size;
-
-    ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
-    unlock_user(name, pathname, 0);
-
-    /* man name_to_handle_at(2):
-     * Other than the use of the handle_bytes field, the caller should treat
-     * the file_handle structure as an opaque data type
-     */
-
-    memcpy(target_fh, fh, total_size);
-    target_fh->handle_bytes = tswap32(fh->handle_bytes);
-    target_fh->handle_type = tswap32(fh->handle_type);
-    g_free(fh);
-    unlock_user(target_fh, handle, total_size);
-
-    if (put_user_s32(mid, mount_id)) {
-        return -TARGET_EFAULT;
-    }
-
-    return ret;
-
-}
-#endif
-
-#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
-static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
-                                     abi_long flags)
-{
-    struct file_handle *target_fh;
-    struct file_handle *fh;
-    unsigned int size, total_size;
-    abi_long ret;
-
-    if (get_user_s32(size, handle)) {
-        return -TARGET_EFAULT;
-    }
-
-    total_size = sizeof(struct file_handle) + size;
-    target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
-    if (!target_fh) {
-        return -TARGET_EFAULT;
-    }
-
-    fh = g_memdup(target_fh, total_size);
-    fh->handle_bytes = size;
-    fh->handle_type = tswap32(target_fh->handle_type);
-
-    ret = get_errno(open_by_handle_at(mount_fd, fh,
-                    target_to_host_bitmask(flags, fcntl_flags_tbl)));
-
-    g_free(fh);
-
-    unlock_user(target_fh, handle, total_size);
-
-    return ret;
-}
-#endif
 
 #if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
 
@@ -6705,17 +6622,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         preexit_cleanup(cpu_env, arg1);
         _exit(arg1);
         return 0; /* avoid warning */
-#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
-    case TARGET_NR_name_to_handle_at:
-        ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
-        return ret;
-#endif
-#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
-    case TARGET_NR_open_by_handle_at:
-        ret = do_open_by_handle_at(arg1, arg2, arg3);
-        fd_trans_unregister(ret);
-        return ret;
-#endif
     case TARGET_NR_brk:
         return do_brk(arg1);
 #ifdef TARGET_NR_fork
diff --git a/configure b/configure
index 3eee3fcf70..1d45056f62 100755
--- a/configure
+++ b/configure
@@ -5028,22 +5028,6 @@ if test "$debug_stack_usage" = "yes"; then
 fi
 
 
-##########################################
-# check if we have open_by_handle_at
-
-open_by_handle_at=no
-cat > $TMPC << EOF
-#include <fcntl.h>
-#if !defined(AT_EMPTY_PATH)
-# error missing definition
-#else
-int main(void) { struct file_handle fh; return open_by_handle_at(0, &fh, 0); }
-#endif
-EOF
-if compile_prog "" "" ; then
-    open_by_handle_at=yes
-fi
-
 ########################################
 # check if we have linux/magic.h
 
@@ -6701,10 +6685,6 @@ if test "$crypto_afalg" = "yes" ; then
   echo "CONFIG_AF_ALG=y" >> $config_host_mak
 fi
 
-if test "$open_by_handle_at" = "yes" ; then
-  echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak
-fi
-
 if test "$linux_magic_h" = "yes" ; then
   echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak
 fi
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 586eb55482..26ad95dc7e 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -635,9 +635,6 @@
 #ifdef TARGET_NR_munmap
 { TARGET_NR_munmap, "munmap" , NULL, print_munmap, NULL },
 #endif
-#ifdef TARGET_NR_name_to_handle_at
-{ TARGET_NR_name_to_handle_at, "name_to_handle_at" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_nanosleep
 { TARGET_NR_nanosleep, "nanosleep" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 14/49] linux-user: Split out ipc syscalls
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (11 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 13/49] linux-user: Split out name_to_handle_at, open_by_handle_at Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 15/49] linux-user: Split out memory syscalls Richard Henderson
                   ` (34 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Because of the ipc multiplex syscall, these must be done all at once.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h    |   38 ++
 linux-user/strace.c          |   83 ---
 linux-user/syscall-ipc.inc.c | 1086 ++++++++++++++++++++++++++++++++++
 linux-user/syscall.c         |  972 +-----------------------------
 linux-user/strace.list       |   42 --
 5 files changed, 1127 insertions(+), 1094 deletions(-)
 create mode 100644 linux-user/syscall-ipc.inc.c

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 1fc89c1b08..6d6349da01 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -17,6 +17,21 @@
  */
 
 SYSCALL_DEF(close, ARG_DEC);
+#ifdef TARGET_NR_ipc
+SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
+#endif
+#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_msgctl)
+SYSCALL_DEF(msgctl, ARG_DEC, ARG_DEC, ARG_PTR);
+#endif
+#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_msgget)
+SYSCALL_DEF(msgget, ARG_DEC, ARG_DEC);
+#endif
+#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_msgrcv)
+SYSCALL_DEF(msgrcv, ARG_DEC, ARG_PTR, ARG_DEC, ARG_DEC, ARG_HEX);
+#endif
+#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_msgsnd)
+SYSCALL_DEF(msgsnd, ARG_DEC, ARG_PTR, ARG_DEC, ARG_HEX);
+#endif
 SYSCALL_DEF(name_to_handle_at,
             ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_PTR, ARG_ATFLAG);
 #ifdef TARGET_NR_open
@@ -44,5 +59,28 @@ SYSCALL_DEF(readlink, ARG_STR, ARG_PTR, ARG_DEC);
 SYSCALL_DEF(readlinkat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_DEC);
 #endif
 SYSCALL_DEF(readv, ARG_DEC, ARG_PTR, ARG_DEC);
+#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_semctl)
+SYSCALL_DEF(semctl, ARG_DEC, ARG_DEC, ARG_DEC, ARG_HEX);
+#endif
+#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_semget)
+SYSCALL_DEF(semget, ARG_DEC, ARG_DEC, ARG_HEX);
+#endif
+#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_semop)
+SYSCALL_DEF(semop, ARG_DEC, ARG_PTR, ARG_DEC);
+#endif
+#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_shmat)
+SYSCALL_DEF_FULL(shmat, .impl = impl_shmat,
+                 .print_ret = print_syscall_ptr_ret,
+                 .arg_type = { ARG_DEC, ARG_PTR, ARG_HEX });
+#endif
+#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_shmctl)
+SYSCALL_DEF(shmctl, ARG_DEC, ARG_DEC, ARG_PTR);
+#endif
+#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_shmdt)
+SYSCALL_DEF(shmdt, ARG_PTR);
+#endif
+#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_shmget)
+SYSCALL_DEF(shmget, ARG_DEC, ARG_DEC, ARG_HEX);
+#endif
 SYSCALL_DEF(write, ARG_DEC, ARG_PTR, ARG_DEC);
 SYSCALL_DEF(writev, ARG_DEC, ARG_PTR, ARG_DEC);
diff --git a/linux-user/strace.c b/linux-user/strace.c
index ed311b081b..3233230527 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1,8 +1,4 @@
 #include "qemu/osdep.h"
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <sys/sem.h>
-#include <sys/shm.h>
 #include <sys/select.h>
 #include <sys/mount.h>
 #include <arpa/inet.h>
@@ -74,54 +70,6 @@ UNUSED static void print_socket_protocol(int domain, int type, int protocol);
 /*
  * Utility functions
  */
-static void
-print_ipc_cmd(int cmd)
-{
-#define output_cmd(val) \
-if( cmd == val ) { \
-    gemu_log(#val); \
-    return; \
-}
-
-    cmd &= 0xff;
-
-    /* General IPC commands */
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_SET );
-    output_cmd( IPC_STAT );
-    output_cmd( IPC_INFO );
-    /* msgctl() commands */
-    output_cmd( MSG_STAT );
-    output_cmd( MSG_INFO );
-    /* shmctl() commands */
-    output_cmd( SHM_LOCK );
-    output_cmd( SHM_UNLOCK );
-    output_cmd( SHM_STAT );
-    output_cmd( SHM_INFO );
-    /* semctl() commands */
-    output_cmd( GETPID );
-    output_cmd( GETVAL );
-    output_cmd( GETALL );
-    output_cmd( GETNCNT );
-    output_cmd( GETZCNT );
-    output_cmd( SETVAL );
-    output_cmd( SETALL );
-    output_cmd( SEM_STAT );
-    output_cmd( SEM_INFO );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-    output_cmd( IPC_RMID );
-
-    /* Some value we don't recognize */
-    gemu_log("%d",cmd);
-}
-
 static void
 print_signal(abi_ulong arg, int last)
 {
@@ -620,18 +568,6 @@ print_newselect(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_semctl
-static void
-print_semctl(const struct syscallname *name,
-             abi_long arg1, abi_long arg2, abi_long arg3,
-             abi_long arg4, abi_long arg5, abi_long arg6)
-{
-    gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ",", name->name, arg1, arg2);
-    print_ipc_cmd(arg3);
-    gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4);
-}
-#endif
-
 static void
 print_execve(const struct syscallname *name,
              abi_long arg1, abi_long arg2, abi_long arg3,
@@ -664,25 +600,6 @@ print_execve(const struct syscallname *name,
     gemu_log("NULL})");
 }
 
-#ifdef TARGET_NR_ipc
-static void
-print_ipc(const struct syscallname *name,
-          abi_long arg1, abi_long arg2, abi_long arg3,
-          abi_long arg4, abi_long arg5, abi_long arg6)
-{
-    switch(arg1) {
-    case IPCOP_semctl:
-        gemu_log("semctl(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ",", arg1, arg2);
-        print_ipc_cmd(arg3);
-        gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4);
-        break;
-    default:
-        gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")",
-                 name->name, arg1, arg2, arg3, arg4);
-    }
-}
-#endif
-
 /*
  * Variants for the return value output function
  */
diff --git a/linux-user/syscall-ipc.inc.c b/linux-user/syscall-ipc.inc.c
new file mode 100644
index 0000000000..18076017b8
--- /dev/null
+++ b/linux-user/syscall-ipc.inc.c
@@ -0,0 +1,1086 @@
+/*
+ *  Linux ipc-related syscalls
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifdef __NR_msgsnd
+safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
+              int, flags)
+safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
+              long, msgtype, int, flags)
+safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
+              unsigned, nsops, const struct timespec *, timeout)
+#else
+/*
+ * This host kernel architecture uses a single ipc syscall; fake up
+ * wrappers for the sub-operations to hide this implementation detail.
+ * Annoyingly we can't include linux/ipc.h to get the constant definitions
+ * for the call parameter because some structs in there conflict with the
+ * sys/ipc.h ones. So we just define them here, and rely on them being
+ * the same for all host architectures.
+ */
+#define Q_SEMTIMEDOP 4
+#define Q_MSGSND 11
+#define Q_MSGRCV 12
+#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
+
+safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
+              void *, ptr, long, fifth)
+
+static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
+{
+    return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
+}
+
+static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
+{
+    return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
+}
+
+static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
+                           const struct timespec *timeout)
+{
+    return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
+                    (long)timeout);
+}
+#endif
+
+/* See <linux/ipc.h> comment above.  */
+#define SEMOPM  500
+
+#define N_SHM_REGIONS  32
+
+static struct shm_region {
+    abi_ulong start;
+    abi_ulong size;
+    bool in_use;
+} shm_regions[N_SHM_REGIONS];
+
+#ifndef TARGET_SEMID64_DS
+/* asm-generic version of this struct */
+struct target_semid64_ds {
+    struct target_ipc_perm sem_perm;
+    abi_ulong sem_otime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused1;
+#endif
+    abi_ulong sem_ctime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused2;
+#endif
+    abi_ulong sem_nsems;
+    abi_ulong __unused3;
+    abi_ulong __unused4;
+};
+#endif
+
+static abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
+                                        abi_ulong target_addr)
+{
+    struct target_ipc_perm *target_ip;
+    struct target_semid64_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    target_ip = &target_sd->sem_perm;
+    host_ip->__key = tswap32(target_ip->__key);
+    host_ip->uid = tswap32(target_ip->uid);
+    host_ip->gid = tswap32(target_ip->gid);
+    host_ip->cuid = tswap32(target_ip->cuid);
+    host_ip->cgid = tswap32(target_ip->cgid);
+#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
+    host_ip->mode = tswap32(target_ip->mode);
+#else
+    host_ip->mode = tswap16(target_ip->mode);
+#endif
+#if defined(TARGET_PPC)
+    host_ip->__seq = tswap32(target_ip->__seq);
+#else
+    host_ip->__seq = tswap16(target_ip->__seq);
+#endif
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static abi_long host_to_target_ipc_perm(abi_ulong target_addr,
+                                        struct ipc_perm *host_ip)
+{
+    struct target_ipc_perm *target_ip;
+    struct target_semid64_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    target_ip = &target_sd->sem_perm;
+    target_ip->__key = tswap32(host_ip->__key);
+    target_ip->uid = tswap32(host_ip->uid);
+    target_ip->gid = tswap32(host_ip->gid);
+    target_ip->cuid = tswap32(host_ip->cuid);
+    target_ip->cgid = tswap32(host_ip->cgid);
+#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
+    target_ip->mode = tswap32(host_ip->mode);
+#else
+    target_ip->mode = tswap16(host_ip->mode);
+#endif
+#if defined(TARGET_PPC)
+    target_ip->__seq = tswap32(host_ip->__seq);
+#else
+    target_ip->__seq = tswap16(host_ip->__seq);
+#endif
+    unlock_user_struct(target_sd, target_addr, 1);
+    return 0;
+}
+
+static abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
+                                        abi_ulong target_addr)
+{
+    struct target_semid64_ds *target_sd;
+
+    if (target_to_host_ipc_perm(&host_sd->sem_perm, target_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
+    host_sd->sem_otime = tswapal(target_sd->sem_otime);
+    host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static abi_long host_to_target_semid_ds(abi_ulong target_addr,
+                                        struct semid_ds *host_sd)
+{
+    struct target_semid64_ds *target_sd;
+
+    if (host_to_target_ipc_perm(target_addr, &host_sd->sem_perm)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
+    target_sd->sem_otime = tswapal(host_sd->sem_otime);
+    target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 1);
+    return 0;
+}
+
+struct target_seminfo {
+    int semmap;
+    int semmni;
+    int semmns;
+    int semmnu;
+    int semmsl;
+    int semopm;
+    int semume;
+    int semusz;
+    int semvmx;
+    int semaem;
+};
+
+static abi_long host_to_target_seminfo(abi_ulong target_addr,
+                                       struct seminfo *host_seminfo)
+{
+    struct target_seminfo *target_seminfo;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_seminfo->semmap, &target_seminfo->semmap);
+    __put_user(host_seminfo->semmni, &target_seminfo->semmni);
+    __put_user(host_seminfo->semmns, &target_seminfo->semmns);
+    __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
+    __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
+    __put_user(host_seminfo->semopm, &target_seminfo->semopm);
+    __put_user(host_seminfo->semume, &target_seminfo->semume);
+    __put_user(host_seminfo->semusz, &target_seminfo->semusz);
+    __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
+    __put_user(host_seminfo->semaem, &target_seminfo->semaem);
+    unlock_user_struct(target_seminfo, target_addr, 1);
+    return 0;
+}
+
+union semun {
+    int val;
+    struct semid_ds *buf;
+    unsigned short *array;
+    struct seminfo *__buf;
+};
+
+union target_semun {
+    int val;
+    abi_ulong buf;
+    abi_ulong array;
+    abi_ulong __buf;
+};
+
+static abi_long target_to_host_semarray(int semid,
+                                        unsigned short **host_array,
+                                        abi_ulong target_addr)
+{
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
+
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1) {
+        return get_errno(ret);
+    }
+
+    nsems = semid_ds.sem_nsems;
+
+    *host_array = g_try_new(unsigned short, nsems);
+    if (!*host_array) {
+        return -TARGET_ENOMEM;
+    }
+    array = lock_user(VERIFY_READ, target_addr,
+                      nsems * sizeof(unsigned short), 1);
+    if (!array) {
+        g_free(*host_array);
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsems; i++) {
+        __get_user((*host_array)[i], &array[i]);
+    }
+    unlock_user(array, target_addr, 0);
+
+    return 0;
+}
+
+static abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+                                        unsigned short **host_array)
+{
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
+
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1) {
+        return get_errno(ret);
+    }
+
+    nsems = semid_ds.sem_nsems;
+
+    array = lock_user(VERIFY_WRITE, target_addr,
+                      nsems * sizeof(unsigned short), 0);
+    if (!array) {
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsems; i++) {
+        __put_user((*host_array)[i], &array[i]);
+    }
+    g_free(*host_array);
+    unlock_user(array, target_addr, 1);
+
+    return 0;
+}
+
+struct target_sembuf {
+    unsigned short sem_num;
+    short sem_op;
+    short sem_flg;
+};
+
+static abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
+                                      abi_ulong target_addr,
+                                      unsigned nsops)
+{
+    struct target_sembuf *target_sembuf;
+    int i;
+
+    target_sembuf = lock_user(VERIFY_READ, target_addr,
+                              nsops * sizeof(struct target_sembuf), 1);
+    if (!target_sembuf) {
+        return -TARGET_EFAULT;
+    }
+    for (i = 0; i < nsops; i++) {
+        __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
+        __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
+        __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
+    }
+    unlock_user(target_sembuf, target_addr, 0);
+    return 0;
+}
+
+struct target_msqid_ds {
+    struct target_ipc_perm msg_perm;
+    abi_ulong msg_stime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused1;
+#endif
+    abi_ulong msg_rtime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused2;
+#endif
+    abi_ulong msg_ctime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused3;
+#endif
+    abi_ulong __msg_cbytes;
+    abi_ulong msg_qnum;
+    abi_ulong msg_qbytes;
+    abi_ulong msg_lspid;
+    abi_ulong msg_lrpid;
+    abi_ulong __unused4;
+    abi_ulong __unused5;
+};
+
+static abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
+                                        abi_ulong target_addr)
+{
+    struct target_msqid_ds *target_md;
+
+    if (target_to_host_ipc_perm(&host_md->msg_perm, target_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    host_md->msg_stime = tswapal(target_md->msg_stime);
+    host_md->msg_rtime = tswapal(target_md->msg_rtime);
+    host_md->msg_ctime = tswapal(target_md->msg_ctime);
+    host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
+    host_md->msg_qnum = tswapal(target_md->msg_qnum);
+    host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
+    host_md->msg_lspid = tswapal(target_md->msg_lspid);
+    host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
+    unlock_user_struct(target_md, target_addr, 0);
+    return 0;
+}
+
+static abi_long host_to_target_msqid_ds(abi_ulong target_addr,
+                                        struct msqid_ds *host_md)
+{
+    struct target_msqid_ds *target_md;
+
+    if (host_to_target_ipc_perm(target_addr, &host_md->msg_perm)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    target_md->msg_stime = tswapal(host_md->msg_stime);
+    target_md->msg_rtime = tswapal(host_md->msg_rtime);
+    target_md->msg_ctime = tswapal(host_md->msg_ctime);
+    target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
+    target_md->msg_qnum = tswapal(host_md->msg_qnum);
+    target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
+    target_md->msg_lspid = tswapal(host_md->msg_lspid);
+    target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
+    unlock_user_struct(target_md, target_addr, 1);
+    return 0;
+}
+
+struct target_msginfo {
+    int msgpool;
+    int msgmap;
+    int msgmax;
+    int msgmnb;
+    int msgmni;
+    int msgssz;
+    int msgtql;
+    unsigned short int msgseg;
+};
+
+static abi_long host_to_target_msginfo(abi_ulong target_addr,
+                                       struct msginfo *host_msginfo)
+{
+    struct target_msginfo *target_msginfo;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
+    __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
+    __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
+    __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
+    __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
+    __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
+    __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
+    __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
+    unlock_user_struct(target_msginfo, target_addr, 1);
+    return 0;
+}
+
+struct target_msgbuf {
+    abi_long mtype;
+    char mtext[1];
+};
+
+static abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
+                                        abi_ulong target_addr)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (target_to_host_ipc_perm(&host_sd->shm_perm, target_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
+    __get_user(host_sd->shm_atime, &target_sd->shm_atime);
+    __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
+    __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
+    __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
+    __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static abi_long host_to_target_shmid_ds(abi_ulong target_addr,
+                                        struct shmid_ds *host_sd)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (host_to_target_ipc_perm(target_addr, &host_sd->shm_perm)) {
+        return -TARGET_EFAULT;
+    }
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
+    __put_user(host_sd->shm_atime, &target_sd->shm_atime);
+    __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
+    __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
+    __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
+    __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    unlock_user_struct(target_sd, target_addr, 1);
+    return 0;
+}
+
+struct target_shminfo {
+    abi_ulong shmmax;
+    abi_ulong shmmin;
+    abi_ulong shmmni;
+    abi_ulong shmseg;
+    abi_ulong shmall;
+};
+
+static abi_long host_to_target_shminfo(abi_ulong target_addr,
+                                       struct shminfo *host_shminfo)
+{
+    struct target_shminfo *target_shminfo;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
+    __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
+    __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
+    __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
+    __put_user(host_shminfo->shmall, &target_shminfo->shmall);
+    unlock_user_struct(target_shminfo, target_addr, 1);
+    return 0;
+}
+
+struct target_shm_info {
+    int used_ids;
+    abi_ulong shm_tot;
+    abi_ulong shm_rss;
+    abi_ulong shm_swp;
+    abi_ulong swap_attempts;
+    abi_ulong swap_successes;
+};
+
+static abi_long host_to_target_shm_info(abi_ulong target_addr,
+                                        struct shm_info *host_shm_info)
+{
+    struct target_shm_info *target_shm_info;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
+    __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
+    __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
+    __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
+    __put_user(host_shm_info->swap_attempts,
+               &target_shm_info->swap_attempts);
+    __put_user(host_shm_info->swap_successes,
+               &target_shm_info->swap_successes);
+    unlock_user_struct(target_shm_info, target_addr, 1);
+    return 0;
+}
+
+#ifndef TARGET_FORCE_SHMLBA
+/*
+ * For most architectures, SHMLBA is the same as the page size;
+ * some architectures have larger values, in which case they should
+ * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
+ * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
+ * and defining its own value for SHMLBA.
+ *
+ * The kernel also permits SHMLBA to be set by the architecture to a
+ * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
+ * this means that addresses are rounded to the large size if
+ * SHM_RND is set but addresses not aligned to that size are not rejected
+ * as long as they are at least page-aligned. Since the only architecture
+ * which uses this is ia64 this code doesn't provide for that oddity.
+ */
+static abi_ulong target_shmlba(CPUArchState *cpu_env)
+{
+    return TARGET_PAGE_SIZE;
+}
+#endif
+
+
+SYSCALL_IMPL(msgctl)
+{
+    abi_long msgid = arg1;
+    int cmd = arg2 & 0xff;
+    abi_ulong ptr = arg3;
+    struct msqid_ds dsarg;
+    struct msginfo msginfo;
+    abi_long ret;
+
+    switch (cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+    case MSG_STAT:
+        if (target_to_host_msqid_ds(&dsarg, ptr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(msgctl(msgid, cmd, &dsarg));
+        if (!is_error(ret) && host_to_target_msqid_ds(ptr, &dsarg)) {
+            return -TARGET_EFAULT;
+        }
+        return ret;
+
+    case IPC_RMID:
+        return get_errno(msgctl(msgid, cmd, NULL));
+
+    case IPC_INFO:
+    case MSG_INFO:
+        ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
+        if (host_to_target_msginfo(ptr, &msginfo)) {
+            return -TARGET_EFAULT;
+        }
+        return ret;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+}
+
+SYSCALL_IMPL(msgget)
+{
+    return get_errno(msgget(arg1, arg2));
+}
+
+SYSCALL_IMPL(msgrcv)
+{
+    int msqid = arg1;
+    abi_ulong msgp = arg2;
+    abi_long msgsz = arg3;
+    abi_long msgtyp = arg4;
+    int msgflg = arg5;
+    struct target_msgbuf *target_mb;
+    char *target_mtext;
+    struct msgbuf *host_mb;
+    abi_long ret = 0;
+
+    if (msgsz < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    host_mb = g_try_malloc(msgsz + sizeof(long));
+    if (!host_mb) {
+        ret = -TARGET_ENOMEM;
+        goto end;
+    }
+    ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
+
+    if (ret > 0) {
+        abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
+        target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
+        if (!target_mtext) {
+            ret = -TARGET_EFAULT;
+            goto end;
+        }
+        memcpy(target_mb->mtext, host_mb->mtext, ret);
+        unlock_user(target_mtext, target_mtext_addr, ret);
+    }
+    target_mb->mtype = tswapal(host_mb->mtype);
+
+ end:
+    unlock_user_struct(target_mb, msgp, 1);
+    g_free(host_mb);
+    return ret;
+}
+
+SYSCALL_IMPL(msgsnd)
+{
+    int msqid = arg1;
+    abi_ulong msgp = arg2;
+    abi_long msgsz = arg3;
+    int msgflg = arg4;
+    struct target_msgbuf *target_mb;
+    struct msgbuf *host_mb;
+    abi_long ret = 0;
+
+    if (msgsz < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) {
+        return -TARGET_EFAULT;
+    }
+    host_mb = g_try_malloc(msgsz + sizeof(long));
+    if (!host_mb) {
+        unlock_user_struct(target_mb, msgp, 0);
+        return -TARGET_ENOMEM;
+    }
+
+    host_mb->mtype = (abi_long)tswapal(target_mb->mtype);
+    memcpy(host_mb->mtext, target_mb->mtext, msgsz);
+    ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
+
+    g_free(host_mb);
+    unlock_user_struct(target_mb, msgp, 0);
+    return ret;
+}
+
+SYSCALL_IMPL(semctl)
+{
+    abi_long semid = arg1;
+    abi_long semnum = arg2;
+    int cmd = arg3 & 0xff;
+    abi_ulong target_arg = arg4;
+    union target_semun target_su = { .buf = target_arg };
+    union semun arg;
+    struct semid_ds dsarg;
+    unsigned short *array = NULL;
+    struct seminfo seminfo;
+    abi_long ret, err;
+
+    switch (cmd) {
+    case GETVAL:
+    case SETVAL:
+        /*
+         * In 64 bit cross-endian situations, we will erroneously pick up
+         * the wrong half of the union for the "val" element.  To rectify
+         * this, the entire 8-byte structure is byteswapped, followed by
+         * a swap of the 4 byte val field. In other cases, the data is
+         * already in proper host byte order.
+         */
+        if (sizeof(target_su.val) != sizeof(target_su.buf)) {
+            target_su.buf = tswapal(target_su.buf);
+            arg.val = tswap32(target_su.val);
+        } else {
+            arg.val = target_su.val;
+        }
+        return get_errno(semctl(semid, semnum, cmd, arg));
+
+    case GETALL:
+    case SETALL:
+        err = target_to_host_semarray(semid, &array, target_su.array);
+        if (err) {
+            return err;
+        }
+        arg.array = array;
+        ret = get_errno(semctl(semid, semnum, cmd, arg));
+        if (!is_error(ret)) {
+            err = host_to_target_semarray(semid, target_su.array, &array);
+            if (err) {
+                return err;
+            }
+        }
+        return ret;
+
+    case IPC_STAT:
+    case IPC_SET:
+    case SEM_STAT:
+        err = target_to_host_semid_ds(&dsarg, target_su.buf);
+        if (err) {
+            return err;
+        }
+        arg.buf = &dsarg;
+        ret = get_errno(semctl(semid, semnum, cmd, arg));
+        if (!is_error(ret)) {
+            err = host_to_target_semid_ds(target_su.buf, &dsarg);
+            if (err) {
+                return err;
+            }
+        }
+        return ret;
+
+    case IPC_INFO:
+    case SEM_INFO:
+        arg.__buf = &seminfo;
+        ret = get_errno(semctl(semid, semnum, cmd, arg));
+        if (!is_error(ret)) {
+            err = host_to_target_seminfo(target_su.__buf, &seminfo);
+            if (err) {
+                return err;
+            }
+        }
+        return ret;
+
+    case IPC_RMID:
+    case GETPID:
+    case GETNCNT:
+    case GETZCNT:
+        return get_errno(semctl(semid, semnum, cmd, NULL));
+
+    default:
+        return -TARGET_EINVAL;
+    }
+}
+
+SYSCALL_IMPL(semget)
+{
+    return get_errno(semget(arg1, arg2, arg3));
+}
+
+SYSCALL_IMPL(semop)
+{
+    abi_long semid = arg1;
+    abi_ulong ptr = arg2;
+    abi_ulong nsops = arg3;
+    struct sembuf sops[SEMOPM];
+
+    if (nsops > SEMOPM) {
+        return -TARGET_E2BIG;
+    }
+    if (target_to_host_sembuf(sops, ptr, nsops)) {
+        return -TARGET_EFAULT;
+    }
+    return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
+}
+
+SYSCALL_IMPL(shmat)
+{
+    int shmid = arg1;
+    abi_ulong shmaddr = arg2;
+    int shmflg = arg3;
+    abi_ulong raddr;
+    void *host_raddr;
+    struct shmid_ds shm_info;
+    int i, ret;
+    abi_ulong shmlba;
+
+    /* Find out the length of the shared memory segment.  */
+    ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
+    if (is_error(ret)) {
+        /* can't get length, bail out */
+        return ret;
+    }
+
+    /* Validate memory placement and alignment for the guest.  */
+    shmlba = target_shmlba(cpu_env);
+    if (shmaddr & (shmlba - 1)) {
+        if (shmflg & SHM_RND) {
+            shmaddr &= ~(shmlba - 1);
+        } else {
+            return -TARGET_EINVAL;
+        }
+    }
+    if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
+        return -TARGET_EINVAL;
+    }
+
+    mmap_lock();
+
+    if (shmaddr) {
+        host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
+    } else {
+        abi_ulong mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
+        if (mmap_start == -1) {
+            errno = ENOMEM;
+            host_raddr = (void *)-1;
+        } else {
+            host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
+        }
+    }
+    if (host_raddr == (void *)-1) {
+        mmap_unlock();
+        return get_errno((intptr_t)host_raddr);
+    }
+
+    raddr = h2g((uintptr_t)host_raddr);
+    page_set_flags(raddr, raddr + shm_info.shm_segsz,
+                   PAGE_VALID | PAGE_READ |
+                   (shmflg & SHM_RDONLY ? 0 : PAGE_WRITE));
+
+    for (i = 0; i < N_SHM_REGIONS; i++) {
+        if (!shm_regions[i].in_use) {
+            shm_regions[i].in_use = true;
+            shm_regions[i].start = raddr;
+            shm_regions[i].size = shm_info.shm_segsz;
+            break;
+        }
+    }
+    mmap_unlock();
+    return raddr;
+}
+
+SYSCALL_IMPL(shmctl)
+{
+    int shmid = arg1;
+    int cmd = arg2 & 0xff;
+    abi_ulong buf = arg3;
+    struct shmid_ds dsarg;
+    struct shminfo shminfo;
+    struct shm_info shm_info;
+    abi_long ret;
+
+    switch (cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+    case SHM_STAT:
+        if (target_to_host_shmid_ds(&dsarg, buf)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(shmctl(shmid, cmd, &dsarg));
+        if (!is_error(ret) && host_to_target_shmid_ds(buf, &dsarg)) {
+            return -TARGET_EFAULT;
+        }
+        return ret;
+
+    case IPC_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
+        if (!is_error(ret) && host_to_target_shminfo(buf, &shminfo)) {
+            return -TARGET_EFAULT;
+        }
+        return ret;
+
+    case SHM_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
+        if (!is_error(ret) && host_to_target_shm_info(buf, &shm_info)) {
+            return -TARGET_EFAULT;
+        }
+        return ret;
+
+    case IPC_RMID:
+    case SHM_LOCK:
+    case SHM_UNLOCK:
+        return get_errno(shmctl(shmid, cmd, NULL));
+
+    default:
+        return -TARGET_EINVAL;
+    }
+}
+
+SYSCALL_IMPL(shmdt)
+{
+    abi_ulong shmaddr = arg1;
+    abi_long ret;
+    int i;
+
+    mmap_lock();
+
+    for (i = 0; i < N_SHM_REGIONS; ++i) {
+        if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
+            shm_regions[i].in_use = false;
+            page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
+            break;
+        }
+    }
+    ret = get_errno(shmdt(g2h(shmaddr)));
+
+    mmap_unlock();
+
+    return ret;
+}
+
+SYSCALL_IMPL(shmget)
+{
+    return get_errno(shmget(arg1, arg2, arg3));
+}
+
+#ifdef TARGET_NR_ipc
+/*
+ * This differs from normal shmat in returning the result via a pointer.
+ * Here we have shifted that pointer to arg4.
+ */
+SYSCALL_IMPL(ipc_shmat)
+{
+    abi_long ret = impl_shmat(cpu_env, arg1, arg2, arg3, 0, 0, 0);
+
+    if (is_error(ret)) {
+        return ret;
+    }
+    if (put_user_ual(ret, arg4)) {
+        return -TARGET_EFAULT;
+    }
+    return 0;
+}
+
+static const SyscallDef def_ipc_shmat = {
+    .name = "shmat",
+    .impl = impl_ipc_shmat,
+    .arg_type = { ARG_DEC, ARG_PTR, ARG_HEX, ARG_PTR },
+};
+
+/* These get defined later via syscall-defs.h.  */
+static const SyscallDef def_semop;
+static const SyscallDef def_semget;
+static const SyscallDef def_semctl;
+static const SyscallDef def_msgget;
+static const SyscallDef def_msgsnd;
+static const SyscallDef def_msgctl;
+static const SyscallDef def_msgrcv;
+static const SyscallDef def_shmdt;
+static const SyscallDef def_shmget;
+static const SyscallDef def_shmctl;
+
+/*
+ * Demultiplex the IPC syscall and shuffle the arguments around
+ * into the "normal" ordering.
+ */
+SYSCALL_ARGS(ipc)
+{
+    int call = extract32(in[0], 0, 16);
+    int version = extract32(in[0], 16, 16);
+    abi_long first = in[1];
+    abi_long second = in[2];
+    abi_long third = in[3];
+    abi_ulong ptr = in[4];
+    abi_long fifth = in[5];
+    abi_ulong atptr;
+
+    /* IPC_* and SHM_* command values are the same on all linux platforms */
+    switch (call) {
+    case IPCOP_semop:
+        out[0] = first;
+        out[1] = ptr;
+        out[2] = second;
+        return &def_semop;
+
+    case IPCOP_semget:
+        out[0] = first;
+        out[1] = second;
+        out[2] = third;
+        return &def_semget;
+
+    case IPCOP_semctl:
+        /*
+         * The semun argument to semctl is passed by value,
+         * so dereference the ptr argument.
+         */
+        if (get_user_ual(atptr, ptr)) {
+            errno = EFAULT;
+            return NULL;
+        }
+        out[0] = first;
+        out[1] = second;
+        out[2] = third;
+        out[3] = atptr;
+        return &def_semctl;
+
+    case IPCOP_msgget:
+        out[0] = first;
+        out[1] = second;
+        return &def_msgget;
+
+    case IPCOP_msgsnd:
+        out[0] = first;
+        out[1] = ptr;
+        out[2] = second;
+        out[3] = third;
+        return &def_msgsnd;
+
+    case IPCOP_msgctl:
+        out[0] = first;
+        out[1] = second;
+        out[2] = ptr;
+        return &def_msgctl;
+
+    case IPCOP_msgrcv:
+        if (version == 0) {
+            struct target_ipc_kludge {
+                abi_long msgp;
+                abi_long msgtyp;
+            } *tmp;
+
+            if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
+                errno = EFAULT;
+                return NULL;
+            }
+            out[0] = first;
+            out[1] = tswapal(tmp->msgp);
+            out[2] = second;
+            out[3] = tswapal(tmp->msgtyp);
+            out[4] = third;
+            unlock_user_struct(tmp, ptr, 0);
+        } else {
+            out[0] = first;
+            out[1] = ptr;
+            out[2] = second;
+            out[3] = fifth;
+            out[4] = third;
+        }
+        return &def_msgrcv;
+
+    case IPCOP_shmat:
+        if (version == 1) {
+            errno = EINVAL;
+            return NULL;
+        }
+        out[0] = first;
+        out[1] = ptr;
+        out[2] = second;
+        out[3] = third;
+        return &def_ipc_shmat;
+
+    case IPCOP_shmdt:
+        out[0] = ptr;
+        return &def_shmdt;
+
+    case IPCOP_shmget:
+        out[0] = first;
+        out[1] = second;
+        out[2] = third;
+        return &def_shmget;
+
+    case IPCOP_shmctl:
+        out[0] = first;
+        out[1] = second;
+        out[2] = ptr;
+        return &def_shmctl;
+
+    default:
+        /* Invalid syscall.  Continue to impl_ipc for logging.  */
+        return def;
+    }
+}
+
+SYSCALL_IMPL(ipc)
+{
+    int call = extract32(arg1, 0, 16);
+    int version = extract32(arg1, 16, 16);
+
+    gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
+    return -TARGET_ENOSYS;
+}
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 18dea32b60..ad5ccbefdb 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -773,43 +773,6 @@ safe_syscall2(int, nanosleep, const struct timespec *, req,
 safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
               const struct timespec *, req, struct timespec *, rem)
 #endif
-#ifdef __NR_msgsnd
-safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
-              int, flags)
-safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
-              long, msgtype, int, flags)
-safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
-              unsigned, nsops, const struct timespec *, timeout)
-#else
-/* This host kernel architecture uses a single ipc syscall; fake up
- * wrappers for the sub-operations to hide this implementation detail.
- * Annoyingly we can't include linux/ipc.h to get the constant definitions
- * for the call parameter because some structs in there conflict with the
- * sys/ipc.h ones. So we just define them here, and rely on them being
- * the same for all host architectures.
- */
-#define Q_SEMTIMEDOP 4
-#define Q_MSGSND 11
-#define Q_MSGRCV 12
-#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
-
-safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
-              void *, ptr, long, fifth)
-static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
-{
-    return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
-}
-static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
-{
-    return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
-}
-static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
-                           const struct timespec *timeout)
-{
-    return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
-                    (long)timeout);
-}
-#endif
 #if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
 safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
               size_t, len, unsigned, prio, const struct timespec *, timeout)
@@ -3134,890 +3097,6 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
 }
 #endif
 
-#define N_SHM_REGIONS	32
-
-static struct shm_region {
-    abi_ulong start;
-    abi_ulong size;
-    bool in_use;
-} shm_regions[N_SHM_REGIONS];
-
-#ifndef TARGET_SEMID64_DS
-/* asm-generic version of this struct */
-struct target_semid64_ds
-{
-  struct target_ipc_perm sem_perm;
-  abi_ulong sem_otime;
-#if TARGET_ABI_BITS == 32
-  abi_ulong __unused1;
-#endif
-  abi_ulong sem_ctime;
-#if TARGET_ABI_BITS == 32
-  abi_ulong __unused2;
-#endif
-  abi_ulong sem_nsems;
-  abi_ulong __unused3;
-  abi_ulong __unused4;
-};
-#endif
-
-static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
-                                               abi_ulong target_addr)
-{
-    struct target_ipc_perm *target_ip;
-    struct target_semid64_ds *target_sd;
-
-    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
-        return -TARGET_EFAULT;
-    target_ip = &(target_sd->sem_perm);
-    host_ip->__key = tswap32(target_ip->__key);
-    host_ip->uid = tswap32(target_ip->uid);
-    host_ip->gid = tswap32(target_ip->gid);
-    host_ip->cuid = tswap32(target_ip->cuid);
-    host_ip->cgid = tswap32(target_ip->cgid);
-#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
-    host_ip->mode = tswap32(target_ip->mode);
-#else
-    host_ip->mode = tswap16(target_ip->mode);
-#endif
-#if defined(TARGET_PPC)
-    host_ip->__seq = tswap32(target_ip->__seq);
-#else
-    host_ip->__seq = tswap16(target_ip->__seq);
-#endif
-    unlock_user_struct(target_sd, target_addr, 0);
-    return 0;
-}
-
-static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
-                                               struct ipc_perm *host_ip)
-{
-    struct target_ipc_perm *target_ip;
-    struct target_semid64_ds *target_sd;
-
-    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
-        return -TARGET_EFAULT;
-    target_ip = &(target_sd->sem_perm);
-    target_ip->__key = tswap32(host_ip->__key);
-    target_ip->uid = tswap32(host_ip->uid);
-    target_ip->gid = tswap32(host_ip->gid);
-    target_ip->cuid = tswap32(host_ip->cuid);
-    target_ip->cgid = tswap32(host_ip->cgid);
-#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_PPC)
-    target_ip->mode = tswap32(host_ip->mode);
-#else
-    target_ip->mode = tswap16(host_ip->mode);
-#endif
-#if defined(TARGET_PPC)
-    target_ip->__seq = tswap32(host_ip->__seq);
-#else
-    target_ip->__seq = tswap16(host_ip->__seq);
-#endif
-    unlock_user_struct(target_sd, target_addr, 1);
-    return 0;
-}
-
-static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
-                                               abi_ulong target_addr)
-{
-    struct target_semid64_ds *target_sd;
-
-    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
-        return -TARGET_EFAULT;
-    if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
-        return -TARGET_EFAULT;
-    host_sd->sem_nsems = tswapal(target_sd->sem_nsems);
-    host_sd->sem_otime = tswapal(target_sd->sem_otime);
-    host_sd->sem_ctime = tswapal(target_sd->sem_ctime);
-    unlock_user_struct(target_sd, target_addr, 0);
-    return 0;
-}
-
-static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
-                                               struct semid_ds *host_sd)
-{
-    struct target_semid64_ds *target_sd;
-
-    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
-        return -TARGET_EFAULT;
-    if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
-        return -TARGET_EFAULT;
-    target_sd->sem_nsems = tswapal(host_sd->sem_nsems);
-    target_sd->sem_otime = tswapal(host_sd->sem_otime);
-    target_sd->sem_ctime = tswapal(host_sd->sem_ctime);
-    unlock_user_struct(target_sd, target_addr, 1);
-    return 0;
-}
-
-struct target_seminfo {
-    int semmap;
-    int semmni;
-    int semmns;
-    int semmnu;
-    int semmsl;
-    int semopm;
-    int semume;
-    int semusz;
-    int semvmx;
-    int semaem;
-};
-
-static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
-                                              struct seminfo *host_seminfo)
-{
-    struct target_seminfo *target_seminfo;
-    if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
-        return -TARGET_EFAULT;
-    __put_user(host_seminfo->semmap, &target_seminfo->semmap);
-    __put_user(host_seminfo->semmni, &target_seminfo->semmni);
-    __put_user(host_seminfo->semmns, &target_seminfo->semmns);
-    __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
-    __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
-    __put_user(host_seminfo->semopm, &target_seminfo->semopm);
-    __put_user(host_seminfo->semume, &target_seminfo->semume);
-    __put_user(host_seminfo->semusz, &target_seminfo->semusz);
-    __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
-    __put_user(host_seminfo->semaem, &target_seminfo->semaem);
-    unlock_user_struct(target_seminfo, target_addr, 1);
-    return 0;
-}
-
-union semun {
-	int val;
-	struct semid_ds *buf;
-	unsigned short *array;
-	struct seminfo *__buf;
-};
-
-union target_semun {
-	int val;
-	abi_ulong buf;
-	abi_ulong array;
-	abi_ulong __buf;
-};
-
-static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
-                                               abi_ulong target_addr)
-{
-    int nsems;
-    unsigned short *array;
-    union semun semun;
-    struct semid_ds semid_ds;
-    int i, ret;
-
-    semun.buf = &semid_ds;
-
-    ret = semctl(semid, 0, IPC_STAT, semun);
-    if (ret == -1)
-        return get_errno(ret);
-
-    nsems = semid_ds.sem_nsems;
-
-    *host_array = g_try_new(unsigned short, nsems);
-    if (!*host_array) {
-        return -TARGET_ENOMEM;
-    }
-    array = lock_user(VERIFY_READ, target_addr,
-                      nsems*sizeof(unsigned short), 1);
-    if (!array) {
-        g_free(*host_array);
-        return -TARGET_EFAULT;
-    }
-
-    for(i=0; i<nsems; i++) {
-        __get_user((*host_array)[i], &array[i]);
-    }
-    unlock_user(array, target_addr, 0);
-
-    return 0;
-}
-
-static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
-                                               unsigned short **host_array)
-{
-    int nsems;
-    unsigned short *array;
-    union semun semun;
-    struct semid_ds semid_ds;
-    int i, ret;
-
-    semun.buf = &semid_ds;
-
-    ret = semctl(semid, 0, IPC_STAT, semun);
-    if (ret == -1)
-        return get_errno(ret);
-
-    nsems = semid_ds.sem_nsems;
-
-    array = lock_user(VERIFY_WRITE, target_addr,
-                      nsems*sizeof(unsigned short), 0);
-    if (!array)
-        return -TARGET_EFAULT;
-
-    for(i=0; i<nsems; i++) {
-        __put_user((*host_array)[i], &array[i]);
-    }
-    g_free(*host_array);
-    unlock_user(array, target_addr, 1);
-
-    return 0;
-}
-
-static inline abi_long do_semctl(int semid, int semnum, int cmd,
-                                 abi_ulong target_arg)
-{
-    union target_semun target_su = { .buf = target_arg };
-    union semun arg;
-    struct semid_ds dsarg;
-    unsigned short *array = NULL;
-    struct seminfo seminfo;
-    abi_long ret = -TARGET_EINVAL;
-    abi_long err;
-    cmd &= 0xff;
-
-    switch( cmd ) {
-	case GETVAL:
-	case SETVAL:
-            /* In 64 bit cross-endian situations, we will erroneously pick up
-             * the wrong half of the union for the "val" element.  To rectify
-             * this, the entire 8-byte structure is byteswapped, followed by
-	     * a swap of the 4 byte val field. In other cases, the data is
-	     * already in proper host byte order. */
-	    if (sizeof(target_su.val) != (sizeof(target_su.buf))) {
-		target_su.buf = tswapal(target_su.buf);
-		arg.val = tswap32(target_su.val);
-	    } else {
-		arg.val = target_su.val;
-	    }
-            ret = get_errno(semctl(semid, semnum, cmd, arg));
-            break;
-	case GETALL:
-	case SETALL:
-            err = target_to_host_semarray(semid, &array, target_su.array);
-            if (err)
-                return err;
-            arg.array = array;
-            ret = get_errno(semctl(semid, semnum, cmd, arg));
-            err = host_to_target_semarray(semid, target_su.array, &array);
-            if (err)
-                return err;
-            break;
-	case IPC_STAT:
-	case IPC_SET:
-	case SEM_STAT:
-            err = target_to_host_semid_ds(&dsarg, target_su.buf);
-            if (err)
-                return err;
-            arg.buf = &dsarg;
-            ret = get_errno(semctl(semid, semnum, cmd, arg));
-            err = host_to_target_semid_ds(target_su.buf, &dsarg);
-            if (err)
-                return err;
-            break;
-	case IPC_INFO:
-	case SEM_INFO:
-            arg.__buf = &seminfo;
-            ret = get_errno(semctl(semid, semnum, cmd, arg));
-            err = host_to_target_seminfo(target_su.__buf, &seminfo);
-            if (err)
-                return err;
-            break;
-	case IPC_RMID:
-	case GETPID:
-	case GETNCNT:
-	case GETZCNT:
-            ret = get_errno(semctl(semid, semnum, cmd, NULL));
-            break;
-    }
-
-    return ret;
-}
-
-struct target_sembuf {
-    unsigned short sem_num;
-    short sem_op;
-    short sem_flg;
-};
-
-static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
-                                             abi_ulong target_addr,
-                                             unsigned nsops)
-{
-    struct target_sembuf *target_sembuf;
-    int i;
-
-    target_sembuf = lock_user(VERIFY_READ, target_addr,
-                              nsops*sizeof(struct target_sembuf), 1);
-    if (!target_sembuf)
-        return -TARGET_EFAULT;
-
-    for(i=0; i<nsops; i++) {
-        __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
-        __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
-        __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
-    }
-
-    unlock_user(target_sembuf, target_addr, 0);
-
-    return 0;
-}
-
-static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
-{
-    struct sembuf sops[nsops];
-
-    if (target_to_host_sembuf(sops, ptr, nsops))
-        return -TARGET_EFAULT;
-
-    return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
-}
-
-struct target_msqid_ds
-{
-    struct target_ipc_perm msg_perm;
-    abi_ulong msg_stime;
-#if TARGET_ABI_BITS == 32
-    abi_ulong __unused1;
-#endif
-    abi_ulong msg_rtime;
-#if TARGET_ABI_BITS == 32
-    abi_ulong __unused2;
-#endif
-    abi_ulong msg_ctime;
-#if TARGET_ABI_BITS == 32
-    abi_ulong __unused3;
-#endif
-    abi_ulong __msg_cbytes;
-    abi_ulong msg_qnum;
-    abi_ulong msg_qbytes;
-    abi_ulong msg_lspid;
-    abi_ulong msg_lrpid;
-    abi_ulong __unused4;
-    abi_ulong __unused5;
-};
-
-static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
-                                               abi_ulong target_addr)
-{
-    struct target_msqid_ds *target_md;
-
-    if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
-        return -TARGET_EFAULT;
-    if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
-        return -TARGET_EFAULT;
-    host_md->msg_stime = tswapal(target_md->msg_stime);
-    host_md->msg_rtime = tswapal(target_md->msg_rtime);
-    host_md->msg_ctime = tswapal(target_md->msg_ctime);
-    host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
-    host_md->msg_qnum = tswapal(target_md->msg_qnum);
-    host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
-    host_md->msg_lspid = tswapal(target_md->msg_lspid);
-    host_md->msg_lrpid = tswapal(target_md->msg_lrpid);
-    unlock_user_struct(target_md, target_addr, 0);
-    return 0;
-}
-
-static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
-                                               struct msqid_ds *host_md)
-{
-    struct target_msqid_ds *target_md;
-
-    if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
-        return -TARGET_EFAULT;
-    if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
-        return -TARGET_EFAULT;
-    target_md->msg_stime = tswapal(host_md->msg_stime);
-    target_md->msg_rtime = tswapal(host_md->msg_rtime);
-    target_md->msg_ctime = tswapal(host_md->msg_ctime);
-    target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
-    target_md->msg_qnum = tswapal(host_md->msg_qnum);
-    target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
-    target_md->msg_lspid = tswapal(host_md->msg_lspid);
-    target_md->msg_lrpid = tswapal(host_md->msg_lrpid);
-    unlock_user_struct(target_md, target_addr, 1);
-    return 0;
-}
-
-struct target_msginfo {
-    int msgpool;
-    int msgmap;
-    int msgmax;
-    int msgmnb;
-    int msgmni;
-    int msgssz;
-    int msgtql;
-    unsigned short int msgseg;
-};
-
-static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
-                                              struct msginfo *host_msginfo)
-{
-    struct target_msginfo *target_msginfo;
-    if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
-        return -TARGET_EFAULT;
-    __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
-    __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
-    __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
-    __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
-    __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
-    __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
-    __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
-    __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
-    unlock_user_struct(target_msginfo, target_addr, 1);
-    return 0;
-}
-
-static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
-{
-    struct msqid_ds dsarg;
-    struct msginfo msginfo;
-    abi_long ret = -TARGET_EINVAL;
-
-    cmd &= 0xff;
-
-    switch (cmd) {
-    case IPC_STAT:
-    case IPC_SET:
-    case MSG_STAT:
-        if (target_to_host_msqid_ds(&dsarg,ptr))
-            return -TARGET_EFAULT;
-        ret = get_errno(msgctl(msgid, cmd, &dsarg));
-        if (host_to_target_msqid_ds(ptr,&dsarg))
-            return -TARGET_EFAULT;
-        break;
-    case IPC_RMID:
-        ret = get_errno(msgctl(msgid, cmd, NULL));
-        break;
-    case IPC_INFO:
-    case MSG_INFO:
-        ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
-        if (host_to_target_msginfo(ptr, &msginfo))
-            return -TARGET_EFAULT;
-        break;
-    }
-
-    return ret;
-}
-
-struct target_msgbuf {
-    abi_long mtype;
-    char	mtext[1];
-};
-
-static inline abi_long do_msgsnd(int msqid, abi_long msgp,
-                                 ssize_t msgsz, int msgflg)
-{
-    struct target_msgbuf *target_mb;
-    struct msgbuf *host_mb;
-    abi_long ret = 0;
-
-    if (msgsz < 0) {
-        return -TARGET_EINVAL;
-    }
-
-    if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
-        return -TARGET_EFAULT;
-    host_mb = g_try_malloc(msgsz + sizeof(long));
-    if (!host_mb) {
-        unlock_user_struct(target_mb, msgp, 0);
-        return -TARGET_ENOMEM;
-    }
-    host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
-    memcpy(host_mb->mtext, target_mb->mtext, msgsz);
-    ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
-    g_free(host_mb);
-    unlock_user_struct(target_mb, msgp, 0);
-
-    return ret;
-}
-
-static inline abi_long do_msgrcv(int msqid, abi_long msgp,
-                                 ssize_t msgsz, abi_long msgtyp,
-                                 int msgflg)
-{
-    struct target_msgbuf *target_mb;
-    char *target_mtext;
-    struct msgbuf *host_mb;
-    abi_long ret = 0;
-
-    if (msgsz < 0) {
-        return -TARGET_EINVAL;
-    }
-
-    if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
-        return -TARGET_EFAULT;
-
-    host_mb = g_try_malloc(msgsz + sizeof(long));
-    if (!host_mb) {
-        ret = -TARGET_ENOMEM;
-        goto end;
-    }
-    ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
-
-    if (ret > 0) {
-        abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
-        target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
-        if (!target_mtext) {
-            ret = -TARGET_EFAULT;
-            goto end;
-        }
-        memcpy(target_mb->mtext, host_mb->mtext, ret);
-        unlock_user(target_mtext, target_mtext_addr, ret);
-    }
-
-    target_mb->mtype = tswapal(host_mb->mtype);
-
-end:
-    if (target_mb)
-        unlock_user_struct(target_mb, msgp, 1);
-    g_free(host_mb);
-    return ret;
-}
-
-static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
-                                               abi_ulong target_addr)
-{
-    struct target_shmid_ds *target_sd;
-
-    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
-        return -TARGET_EFAULT;
-    if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
-        return -TARGET_EFAULT;
-    __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
-    __get_user(host_sd->shm_atime, &target_sd->shm_atime);
-    __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
-    __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
-    __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
-    __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
-    __get_user(host_sd->shm_nattch, &target_sd->shm_nattch);
-    unlock_user_struct(target_sd, target_addr, 0);
-    return 0;
-}
-
-static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
-                                               struct shmid_ds *host_sd)
-{
-    struct target_shmid_ds *target_sd;
-
-    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
-        return -TARGET_EFAULT;
-    if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
-        return -TARGET_EFAULT;
-    __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
-    __put_user(host_sd->shm_atime, &target_sd->shm_atime);
-    __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
-    __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
-    __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
-    __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
-    __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
-    unlock_user_struct(target_sd, target_addr, 1);
-    return 0;
-}
-
-struct  target_shminfo {
-    abi_ulong shmmax;
-    abi_ulong shmmin;
-    abi_ulong shmmni;
-    abi_ulong shmseg;
-    abi_ulong shmall;
-};
-
-static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
-                                              struct shminfo *host_shminfo)
-{
-    struct target_shminfo *target_shminfo;
-    if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
-        return -TARGET_EFAULT;
-    __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
-    __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
-    __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
-    __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
-    __put_user(host_shminfo->shmall, &target_shminfo->shmall);
-    unlock_user_struct(target_shminfo, target_addr, 1);
-    return 0;
-}
-
-struct target_shm_info {
-    int used_ids;
-    abi_ulong shm_tot;
-    abi_ulong shm_rss;
-    abi_ulong shm_swp;
-    abi_ulong swap_attempts;
-    abi_ulong swap_successes;
-};
-
-static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
-                                               struct shm_info *host_shm_info)
-{
-    struct target_shm_info *target_shm_info;
-    if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
-        return -TARGET_EFAULT;
-    __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
-    __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
-    __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
-    __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
-    __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
-    __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
-    unlock_user_struct(target_shm_info, target_addr, 1);
-    return 0;
-}
-
-static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
-{
-    struct shmid_ds dsarg;
-    struct shminfo shminfo;
-    struct shm_info shm_info;
-    abi_long ret = -TARGET_EINVAL;
-
-    cmd &= 0xff;
-
-    switch(cmd) {
-    case IPC_STAT:
-    case IPC_SET:
-    case SHM_STAT:
-        if (target_to_host_shmid_ds(&dsarg, buf))
-            return -TARGET_EFAULT;
-        ret = get_errno(shmctl(shmid, cmd, &dsarg));
-        if (host_to_target_shmid_ds(buf, &dsarg))
-            return -TARGET_EFAULT;
-        break;
-    case IPC_INFO:
-        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
-        if (host_to_target_shminfo(buf, &shminfo))
-            return -TARGET_EFAULT;
-        break;
-    case SHM_INFO:
-        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
-        if (host_to_target_shm_info(buf, &shm_info))
-            return -TARGET_EFAULT;
-        break;
-    case IPC_RMID:
-    case SHM_LOCK:
-    case SHM_UNLOCK:
-        ret = get_errno(shmctl(shmid, cmd, NULL));
-        break;
-    }
-
-    return ret;
-}
-
-#ifndef TARGET_FORCE_SHMLBA
-/* For most architectures, SHMLBA is the same as the page size;
- * some architectures have larger values, in which case they should
- * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function.
- * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA
- * and defining its own value for SHMLBA.
- *
- * The kernel also permits SHMLBA to be set by the architecture to a
- * value larger than the page size without setting __ARCH_FORCE_SHMLBA;
- * this means that addresses are rounded to the large size if
- * SHM_RND is set but addresses not aligned to that size are not rejected
- * as long as they are at least page-aligned. Since the only architecture
- * which uses this is ia64 this code doesn't provide for that oddity.
- */
-static inline abi_ulong target_shmlba(CPUArchState *cpu_env)
-{
-    return TARGET_PAGE_SIZE;
-}
-#endif
-
-static inline abi_ulong do_shmat(CPUArchState *cpu_env,
-                                 int shmid, abi_ulong shmaddr, int shmflg)
-{
-    abi_long raddr;
-    void *host_raddr;
-    struct shmid_ds shm_info;
-    int i,ret;
-    abi_ulong shmlba;
-
-    /* find out the length of the shared memory segment */
-    ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
-    if (is_error(ret)) {
-        /* can't get length, bail out */
-        return ret;
-    }
-
-    shmlba = target_shmlba(cpu_env);
-
-    if (shmaddr & (shmlba - 1)) {
-        if (shmflg & SHM_RND) {
-            shmaddr &= ~(shmlba - 1);
-        } else {
-            return -TARGET_EINVAL;
-        }
-    }
-    if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
-        return -TARGET_EINVAL;
-    }
-
-    mmap_lock();
-
-    if (shmaddr)
-        host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
-    else {
-        abi_ulong mmap_start;
-
-        mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
-
-        if (mmap_start == -1) {
-            errno = ENOMEM;
-            host_raddr = (void *)-1;
-        } else
-            host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
-    }
-
-    if (host_raddr == (void *)-1) {
-        mmap_unlock();
-        return get_errno((long)host_raddr);
-    }
-    raddr=h2g((unsigned long)host_raddr);
-
-    page_set_flags(raddr, raddr + shm_info.shm_segsz,
-                   PAGE_VALID | PAGE_READ |
-                   ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
-
-    for (i = 0; i < N_SHM_REGIONS; i++) {
-        if (!shm_regions[i].in_use) {
-            shm_regions[i].in_use = true;
-            shm_regions[i].start = raddr;
-            shm_regions[i].size = shm_info.shm_segsz;
-            break;
-        }
-    }
-
-    mmap_unlock();
-    return raddr;
-
-}
-
-static inline abi_long do_shmdt(abi_ulong shmaddr)
-{
-    int i;
-    abi_long rv;
-
-    mmap_lock();
-
-    for (i = 0; i < N_SHM_REGIONS; ++i) {
-        if (shm_regions[i].in_use && shm_regions[i].start == shmaddr) {
-            shm_regions[i].in_use = false;
-            page_set_flags(shmaddr, shmaddr + shm_regions[i].size, 0);
-            break;
-        }
-    }
-    rv = get_errno(shmdt(g2h(shmaddr)));
-
-    mmap_unlock();
-
-    return rv;
-}
-
-#ifdef TARGET_NR_ipc
-/* ??? This only works with linear mappings.  */
-/* do_ipc() must return target values and target errnos. */
-static abi_long do_ipc(CPUArchState *cpu_env,
-                       unsigned int call, abi_long first,
-                       abi_long second, abi_long third,
-                       abi_long ptr, abi_long fifth)
-{
-    int version;
-    abi_long ret = 0;
-
-    version = call >> 16;
-    call &= 0xffff;
-
-    switch (call) {
-    case IPCOP_semop:
-        ret = do_semop(first, ptr, second);
-        break;
-
-    case IPCOP_semget:
-        ret = get_errno(semget(first, second, third));
-        break;
-
-    case IPCOP_semctl: {
-        /* The semun argument to semctl is passed by value, so dereference the
-         * ptr argument. */
-        abi_ulong atptr;
-        get_user_ual(atptr, ptr);
-        ret = do_semctl(first, second, third, atptr);
-        break;
-    }
-
-    case IPCOP_msgget:
-        ret = get_errno(msgget(first, second));
-        break;
-
-    case IPCOP_msgsnd:
-        ret = do_msgsnd(first, ptr, second, third);
-        break;
-
-    case IPCOP_msgctl:
-        ret = do_msgctl(first, second, ptr);
-        break;
-
-    case IPCOP_msgrcv:
-        switch (version) {
-        case 0:
-            {
-                struct target_ipc_kludge {
-                    abi_long msgp;
-                    abi_long msgtyp;
-                } *tmp;
-
-                if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
-                    ret = -TARGET_EFAULT;
-                    break;
-                }
-
-                ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third);
-
-                unlock_user_struct(tmp, ptr, 0);
-                break;
-            }
-        default:
-            ret = do_msgrcv(first, ptr, second, fifth, third);
-        }
-        break;
-
-    case IPCOP_shmat:
-        switch (version) {
-        default:
-        {
-            abi_ulong raddr;
-            raddr = do_shmat(cpu_env, first, ptr, second);
-            if (is_error(raddr))
-                return get_errno(raddr);
-            if (put_user_ual(raddr, third))
-                return -TARGET_EFAULT;
-            break;
-        }
-        case 1:
-            ret = -TARGET_EINVAL;
-            break;
-        }
-	break;
-    case IPCOP_shmdt:
-        ret = do_shmdt(ptr);
-	break;
-
-    case IPCOP_shmget:
-	/* IPC_* flag values are the same on all linux platforms */
-	ret = get_errno(shmget(first, second, third));
-	break;
-
-	/* IPC_* and SHM_* command values are the same on all linux platforms */
-    case IPCOP_shmctl:
-        ret = do_shmctl(first, second, ptr);
-        break;
-    default:
-	gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
-	ret = -TARGET_ENOSYS;
-	break;
-    }
-    return ret;
-}
-#endif
-
 /* kernel structure types definitions */
 
 #define STRUCT(name, ...) STRUCT_ ## name,
@@ -8395,54 +7474,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
             }
         }
         return ret;
-#ifdef TARGET_NR_ipc
-    case TARGET_NR_ipc:
-        return do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
-#endif
-#ifdef TARGET_NR_semget
-    case TARGET_NR_semget:
-        return get_errno(semget(arg1, arg2, arg3));
-#endif
-#ifdef TARGET_NR_semop
-    case TARGET_NR_semop:
-        return do_semop(arg1, arg2, arg3);
-#endif
-#ifdef TARGET_NR_semctl
-    case TARGET_NR_semctl:
-        return do_semctl(arg1, arg2, arg3, arg4);
-#endif
-#ifdef TARGET_NR_msgctl
-    case TARGET_NR_msgctl:
-        return do_msgctl(arg1, arg2, arg3);
-#endif
-#ifdef TARGET_NR_msgget
-    case TARGET_NR_msgget:
-        return get_errno(msgget(arg1, arg2));
-#endif
-#ifdef TARGET_NR_msgrcv
-    case TARGET_NR_msgrcv:
-        return do_msgrcv(arg1, arg2, arg3, arg4, arg5);
-#endif
-#ifdef TARGET_NR_msgsnd
-    case TARGET_NR_msgsnd:
-        return do_msgsnd(arg1, arg2, arg3, arg4);
-#endif
-#ifdef TARGET_NR_shmget
-    case TARGET_NR_shmget:
-        return get_errno(shmget(arg1, arg2, arg3));
-#endif
-#ifdef TARGET_NR_shmctl
-    case TARGET_NR_shmctl:
-        return do_shmctl(arg1, arg2, arg3);
-#endif
-#ifdef TARGET_NR_shmat
-    case TARGET_NR_shmat:
-        return do_shmat(cpu_env, arg1, arg2, arg3);
-#endif
-#ifdef TARGET_NR_shmdt
-    case TARGET_NR_shmdt:
-        return do_shmdt(arg1);
-#endif
     case TARGET_NR_fsync:
         return get_errno(fsync(arg1));
     case TARGET_NR_clone:
@@ -10969,6 +10000,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
                                 int64_t arg5, int64_t arg6)
 
 #include "syscall-file.inc.c"
+#include "syscall-ipc.inc.c"
 
 #undef SYSCALL_IMPL
 #undef SYSCALL_ARGS
@@ -11002,6 +10034,7 @@ static const SyscallDef * __attribute__((noinline)) syscall_table(int num)
 #define SYSCALL_DEF(NAME, ...)  case TARGET_NR_##NAME: return &def_##NAME
 #define SYSCALL_DEF_ARGS(NAME, ...)  SYSCALL_DEF(NAME)
 #define SYSCALL_DEF_FULL(NAME, ...)  SYSCALL_DEF(NAME)
+#define SYSCALL_TABLE
 
     switch (num) {
 #include "syscall-defs.h"
@@ -11011,6 +10044,7 @@ static const SyscallDef * __attribute__((noinline)) syscall_table(int num)
 #undef SYSCALL_DEF
 #undef SYSCALL_DEF_ARGS
 #undef SYSCALL_DEF_FULL
+#undef SYSCALL_TABLE
 }
 
 abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 26ad95dc7e..15dc0e9087 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -452,9 +452,6 @@
 #ifdef TARGET_NR_io_submit
 { TARGET_NR_io_submit, "io_submit" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_ipc
-{ TARGET_NR_ipc, "ipc" , NULL, print_ipc, NULL },
-#endif
 #ifdef TARGET_NR_kcmp
 { TARGET_NR_kcmp, "kcmp" , NULL, NULL, NULL },
 #endif
@@ -608,18 +605,6 @@
 #ifdef TARGET_NR_mremap
 { TARGET_NR_mremap, "mremap" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_msgctl
-{ TARGET_NR_msgctl, "msgctl" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_msgget
-{ TARGET_NR_msgget, "msgget" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_msgrcv
-{ TARGET_NR_msgrcv, "msgrcv" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_msgsnd
-{ TARGET_NR_msgsnd, "msgsnd" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_msync
 { TARGET_NR_msync, "msync" , NULL, NULL, NULL },
 #endif
@@ -917,9 +902,6 @@
 #ifdef TARGET_NR_osf_settimeofday
 { TARGET_NR_osf_settimeofday, "osf_settimeofday" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_osf_shmat
-{ TARGET_NR_osf_shmat, "osf_shmat" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_osf_signal
 { TARGET_NR_osf_signal, "osf_signal" , NULL, NULL, NULL },
 #endif
@@ -1184,18 +1166,6 @@
 #ifdef TARGET_NR_select
 { TARGET_NR_select, "select" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_semctl
-{ TARGET_NR_semctl, "semctl" , NULL, print_semctl, NULL },
-#endif
-#ifdef TARGET_NR_semget
-{ TARGET_NR_semget, "semget" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_semop
-{ TARGET_NR_semop, "semop" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_semtimedop
-{ TARGET_NR_semtimedop, "semtimedop" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_send
 { TARGET_NR_send, "send" , NULL, NULL, NULL },
 #endif
@@ -1323,18 +1293,6 @@
 #ifdef TARGET_NR_sgetmask
 { TARGET_NR_sgetmask, "sgetmask" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_shmat
-{ TARGET_NR_shmat, "shmat" , NULL, NULL, print_syscall_ret_addr },
-#endif
-#ifdef TARGET_NR_shmctl
-{ TARGET_NR_shmctl, "shmctl" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_shmdt
-{ TARGET_NR_shmdt, "shmdt" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_shmget
-{ TARGET_NR_shmget, "shmget" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_shutdown
 { TARGET_NR_shutdown, "shutdown" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 15/49] linux-user: Split out memory syscalls
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (12 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 14/49] linux-user: Split out ipc syscalls Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 16/49] linux-user: Split out exit Richard Henderson
                   ` (33 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

This includes mmap, mmap2, munmap, mlock, mlockall, munlock,
munlockall, mprotect, mremap, msync.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h    |  24 ++++++
 linux-user/syscall.h         |   2 +
 linux-user/strace.c          |  55 ++-----------
 linux-user/syscall-mem.inc.c | 154 +++++++++++++++++++++++++++++++++++
 linux-user/syscall.c         | 119 +--------------------------
 linux-user/strace.list       |  33 --------
 6 files changed, 189 insertions(+), 198 deletions(-)
 create mode 100644 linux-user/syscall-mem.inc.c

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 6d6349da01..88f433e998 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -20,6 +20,26 @@ SYSCALL_DEF(close, ARG_DEC);
 #ifdef TARGET_NR_ipc
 SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
 #endif
+SYSCALL_DEF(mlock, ARG_PTR, ARG_DEC);
+SYSCALL_DEF(mlockall, ARG_HEX);
+#ifdef TARGET_NR_mmap
+SYSCALL_DEF_FULL(mmap, .impl = impl_mmap,
+                 .args = args_mmap,
+                 .print_ret = print_syscall_ptr_ret,
+                 .arg_type = { ARG_PTR, ARG_DEC, ARG_MMAPPROT,
+                               ARG_MMAPFLAG, ARG_DEC, ARG_DEC });
+#endif
+#ifdef TARGET_NR_mmap2
+SYSCALL_DEF_FULL(mmap2, .impl = impl_mmap,
+                 .args = args_mmap2,
+                 .print_ret = print_syscall_ptr_ret,
+                 .arg_type = { ARG_PTR, ARG_DEC, ARG_MMAPPROT,
+                               ARG_MMAPFLAG, ARG_DEC, ARG_DEC64 });
+#endif
+SYSCALL_DEF(mprotect, ARG_PTR, ARG_DEC, ARG_MMAPPROT);
+SYSCALL_DEF_FULL(mremap, .impl = impl_mremap,
+                 .print_ret = print_syscall_ptr_ret,
+                 .arg_type = { ARG_PTR, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR });
 #if !defined(SYSCALL_TABLE) || defined(TARGET_NR_msgctl)
 SYSCALL_DEF(msgctl, ARG_DEC, ARG_DEC, ARG_PTR);
 #endif
@@ -32,6 +52,10 @@ SYSCALL_DEF(msgrcv, ARG_DEC, ARG_PTR, ARG_DEC, ARG_DEC, ARG_HEX);
 #if !defined(SYSCALL_TABLE) || defined(TARGET_NR_msgsnd)
 SYSCALL_DEF(msgsnd, ARG_DEC, ARG_PTR, ARG_DEC, ARG_HEX);
 #endif
+SYSCALL_DEF(msync, ARG_PTR, ARG_DEC, ARG_HEX);
+SYSCALL_DEF(munlock, ARG_PTR, ARG_DEC);
+SYSCALL_DEF(munlockall);
+SYSCALL_DEF(munmap, ARG_PTR, ARG_DEC);
 SYSCALL_DEF(name_to_handle_at,
             ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_PTR, ARG_ATFLAG);
 #ifdef TARGET_NR_open
diff --git a/linux-user/syscall.h b/linux-user/syscall.h
index 83f602f8e7..8175de4c31 100644
--- a/linux-user/syscall.h
+++ b/linux-user/syscall.h
@@ -58,6 +58,8 @@ typedef enum {
     /* These print as sets of flags.  */
     ARG_ATDIRFD,
     ARG_ATFLAG,
+    ARG_MMAPFLAG,
+    ARG_MMAPPROT,
     ARG_MODEFLAG,
     ARG_OPENFLAG,
 
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 3233230527..5619defec8 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -801,7 +801,7 @@ UNUSED static struct flags umount2_flags[] = {
     FLAG_END,
 };
 
-UNUSED static struct flags mmap_prot_flags[] = {
+static struct flags const mmap_prot_flags[] = {
     FLAG_GENERIC(PROT_NONE),
     FLAG_GENERIC(PROT_EXEC),
     FLAG_GENERIC(PROT_READ),
@@ -812,7 +812,7 @@ UNUSED static struct flags mmap_prot_flags[] = {
     FLAG_END,
 };
 
-UNUSED static struct flags mmap_flags[] = {
+static struct flags const mmap_flags[] = {
     FLAG_TARGET(MAP_SHARED),
     FLAG_TARGET(MAP_PRIVATE),
     FLAG_TARGET(MAP_ANONYMOUS),
@@ -2350,51 +2350,6 @@ print_utimensat(const struct syscallname *name,
 }
 #endif
 
-#if defined(TARGET_NR_mmap) || defined(TARGET_NR_mmap2)
-static void
-print_mmap(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_pointer(arg0, 0);
-    print_raw_param("%d", arg1, 0);
-    print_flags(mmap_prot_flags, arg2, 0);
-    print_flags(mmap_flags, arg3, 0);
-    print_raw_param("%d", arg4, 0);
-    print_raw_param("%#x", arg5, 1);
-    print_syscall_epilogue(name);
-}
-#define print_mmap2     print_mmap
-#endif
-
-#ifdef TARGET_NR_mprotect
-static void
-print_mprotect(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_pointer(arg0, 0);
-    print_raw_param("%d", arg1, 0);
-    print_flags(mmap_prot_flags, arg2, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
-#ifdef TARGET_NR_munmap
-static void
-print_munmap(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_pointer(arg0, 0);
-    print_raw_param("%d", arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_futex
 static void print_futex_op(abi_long tflag, int last)
 {
@@ -2601,6 +2556,12 @@ static void print_syscall_def1(const SyscallDef *def, int64_t args[6])
         case ARG_ATFLAG:
             len = add_flags(b, rest, at_file_flags, arg, false);
             break;
+        case ARG_MMAPFLAG:
+            len = add_flags(b, rest, mmap_flags, arg, false);
+            break;
+        case ARG_MMAPPROT:
+            len = add_flags(b, rest, mmap_prot_flags, arg, false);
+            break;
         case ARG_MODEFLAG:
             len = add_flags(b, rest, mode_flags, arg, true);
             break;
diff --git a/linux-user/syscall-mem.inc.c b/linux-user/syscall-mem.inc.c
new file mode 100644
index 0000000000..d2ce0cb8cc
--- /dev/null
+++ b/linux-user/syscall-mem.inc.c
@@ -0,0 +1,154 @@
+/*
+ *  Linux memory-related syscalls
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+static bitmask_transtbl const mmap_flags_tbl[] = {
+    { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
+    { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
+    { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
+    { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
+      MAP_ANONYMOUS, MAP_ANONYMOUS },
+    { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN,
+      MAP_GROWSDOWN, MAP_GROWSDOWN },
+    { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE,
+      MAP_DENYWRITE, MAP_DENYWRITE },
+    { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE,
+      MAP_EXECUTABLE, MAP_EXECUTABLE },
+    { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
+    { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE,
+      MAP_NORESERVE, MAP_NORESERVE },
+    { TARGET_MAP_HUGETLB, TARGET_MAP_HUGETLB, MAP_HUGETLB, MAP_HUGETLB },
+    /*
+     * MAP_STACK had been ignored by the kernel for quite some time.
+     * Recognize it for the target insofar as we do not want to pass
+     * it through to the host.
+     */
+    { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
+    { 0, 0, 0, 0 }
+};
+
+
+SYSCALL_IMPL(mlock)
+{
+    return get_errno(mlock(g2h(arg1), arg2));
+}
+
+SYSCALL_IMPL(mlockall)
+{
+    int host_flag = 0;
+    if (arg1 & TARGET_MLOCKALL_MCL_CURRENT) {
+        host_flag |= MCL_CURRENT;
+    }
+    if (arg1 & TARGET_MLOCKALL_MCL_FUTURE) {
+        host_flag |= MCL_FUTURE;
+    }
+    return get_errno(mlockall(host_flag));
+}
+
+#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
+    (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
+    defined(TARGET_M68K) || defined(TARGET_CRIS) || \
+    defined(TARGET_MICROBLAZE) || defined(TARGET_S390X)
+SYSCALL_ARGS(mmap)
+{
+    abi_ulong ptr = in[0];
+    abi_long *v = lock_user(VERIFY_READ, ptr, 6 * sizeof(abi_long), 1);
+    if (v == NULL) {
+        errno = EFAULT;
+        return NULL;
+    }
+    out[0] = tswapal(v[0]);
+    out[1] = tswapal(v[1]);
+    out[2] = tswapal(v[2]);
+    out[3] = tswapal(v[3]);
+    out[4] = tswapal(v[4]);
+    out[5] = tswapal(v[5]);
+    unlock_user(v, ptr, 0);
+    return def;
+}
+#else
+# define args_mmap NULL
+#endif
+
+SYSCALL_IMPL(mmap)
+{
+    int host_flags = target_to_host_bitmask(arg4, mmap_flags_tbl);
+    return get_errno(target_mmap(arg1, arg2, arg3, host_flags, arg5, arg6));
+}
+
+#ifdef TARGET_NR_mmap2
+/*
+ * Define mmap2 in terms of mmap.
+ * !!! Note that there is a fundamental problem here in that
+ * target_mmap has an offset parameter that is abi_ulong
+ * and not off_t.  This means that we cannot actually pass
+ * through a 64-bit file offset as intended.
+ */
+
+#ifndef MMAP_SHIFT
+# define MMAP_SHIFT 12
+#endif
+
+SYSCALL_ARGS(mmap2)
+{
+    /* We have already assigned out[0-4].  */
+    out[5] = (uint64_t)(abi_ulong)in[5] << MMAP_SHIFT;
+    return def;
+}
+#endif
+
+SYSCALL_IMPL(mprotect)
+{
+    CPUState *cpu = ENV_GET_CPU(cpu_env);
+    TaskState *ts = cpu->opaque;
+
+    /* Special hack to detect libc making the stack executable.  */
+    if ((arg3 & PROT_GROWSDOWN)
+        && arg1 >= ts->info->stack_limit
+        && arg1 <= ts->info->start_stack) {
+        arg3 &= ~PROT_GROWSDOWN;
+        arg2 = arg2 + arg1 - ts->info->stack_limit;
+        arg1 = ts->info->stack_limit;
+    }
+    return get_errno(target_mprotect(arg1, arg2, arg3));
+}
+
+SYSCALL_IMPL(mremap)
+{
+    return get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
+}
+
+SYSCALL_IMPL(msync)
+{
+    return get_errno(msync(g2h(arg1), arg2, arg3));
+}
+
+SYSCALL_IMPL(munlock)
+{
+    return get_errno(munlock(g2h(arg1), arg2));
+}
+
+SYSCALL_IMPL(munlockall)
+{
+    return get_errno(munlockall());
+}
+
+SYSCALL_IMPL(munmap)
+{
+    return get_errno(target_munmap(arg1, arg2));
+}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ad5ccbefdb..142654a0a0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4130,29 +4130,6 @@ static const StructEntry struct_termios_def = {
     .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
 };
 
-static bitmask_transtbl mmap_flags_tbl[] = {
-    { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
-    { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
-    { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
-    { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
-      MAP_ANONYMOUS, MAP_ANONYMOUS },
-    { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN,
-      MAP_GROWSDOWN, MAP_GROWSDOWN },
-    { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE,
-      MAP_DENYWRITE, MAP_DENYWRITE },
-    { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE,
-      MAP_EXECUTABLE, MAP_EXECUTABLE },
-    { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
-    { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE,
-      MAP_NORESERVE, MAP_NORESERVE },
-    { TARGET_MAP_HUGETLB, TARGET_MAP_HUGETLB, MAP_HUGETLB, MAP_HUGETLB },
-    /* MAP_STACK had been ignored by the kernel for quite some time.
-       Recognize it for the target insofar as we do not want to pass
-       it through to the host.  */
-    { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
-    { 0, 0, 0, 0 }
-};
-
 #if defined(TARGET_I386)
 
 /* NOTE: there is really one LDT for all the threads */
@@ -5373,21 +5350,6 @@ static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
     return 0;
 }
 
-#if defined(TARGET_NR_mlockall)
-static inline int target_to_host_mlockall_arg(int arg)
-{
-    int result = 0;
-
-    if (arg & TARGET_MLOCKALL_MCL_CURRENT) {
-        result |= MCL_CURRENT;
-    }
-    if (arg & TARGET_MLOCKALL_MCL_FUTURE) {
-        result |= MCL_FUTURE;
-    }
-    return result;
-}
-#endif
-
 #if (defined(TARGET_NR_stat64) || defined(TARGET_NR_lstat64) ||     \
      defined(TARGET_NR_fstat64) || defined(TARGET_NR_fstatat64) ||  \
      defined(TARGET_NR_newfstatat))
@@ -6997,86 +6959,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
            ret = get_errno(reboot(arg1, arg2, arg3, NULL));
         }
         return ret;
-#ifdef TARGET_NR_mmap
-    case TARGET_NR_mmap:
-#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
-    (defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
-    defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
-    || defined(TARGET_S390X)
-        {
-            abi_ulong *v;
-            abi_ulong v1, v2, v3, v4, v5, v6;
-            if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
-                return -TARGET_EFAULT;
-            v1 = tswapal(v[0]);
-            v2 = tswapal(v[1]);
-            v3 = tswapal(v[2]);
-            v4 = tswapal(v[3]);
-            v5 = tswapal(v[4]);
-            v6 = tswapal(v[5]);
-            unlock_user(v, arg1, 0);
-            ret = get_errno(target_mmap(v1, v2, v3,
-                                        target_to_host_bitmask(v4, mmap_flags_tbl),
-                                        v5, v6));
-        }
-#else
-        ret = get_errno(target_mmap(arg1, arg2, arg3,
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
-                                    arg5,
-                                    arg6));
-#endif
-        return ret;
-#endif
-#ifdef TARGET_NR_mmap2
-    case TARGET_NR_mmap2:
-#ifndef MMAP_SHIFT
-#define MMAP_SHIFT 12
-#endif
-        ret = target_mmap(arg1, arg2, arg3,
-                          target_to_host_bitmask(arg4, mmap_flags_tbl),
-                          arg5, arg6 << MMAP_SHIFT);
-        return get_errno(ret);
-#endif
-    case TARGET_NR_munmap:
-        return get_errno(target_munmap(arg1, arg2));
-    case TARGET_NR_mprotect:
-        {
-            TaskState *ts = cpu->opaque;
-            /* Special hack to detect libc making the stack executable.  */
-            if ((arg3 & PROT_GROWSDOWN)
-                && arg1 >= ts->info->stack_limit
-                && arg1 <= ts->info->start_stack) {
-                arg3 &= ~PROT_GROWSDOWN;
-                arg2 = arg2 + arg1 - ts->info->stack_limit;
-                arg1 = ts->info->stack_limit;
-            }
-        }
-        return get_errno(target_mprotect(arg1, arg2, arg3));
-#ifdef TARGET_NR_mremap
-    case TARGET_NR_mremap:
-        return get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
-#endif
-        /* ??? msync/mlock/munlock are broken for softmmu.  */
-#ifdef TARGET_NR_msync
-    case TARGET_NR_msync:
-        return get_errno(msync(g2h(arg1), arg2, arg3));
-#endif
-#ifdef TARGET_NR_mlock
-    case TARGET_NR_mlock:
-        return get_errno(mlock(g2h(arg1), arg2));
-#endif
-#ifdef TARGET_NR_munlock
-    case TARGET_NR_munlock:
-        return get_errno(munlock(g2h(arg1), arg2));
-#endif
-#ifdef TARGET_NR_mlockall
-    case TARGET_NR_mlockall:
-        return get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
-#endif
-#ifdef TARGET_NR_munlockall
-    case TARGET_NR_munlockall:
-        return get_errno(munlockall());
-#endif
 #ifdef TARGET_NR_truncate
     case TARGET_NR_truncate:
         if (!(p = lock_user_string(arg1)))
@@ -10001,6 +9883,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
 
 #include "syscall-file.inc.c"
 #include "syscall-ipc.inc.c"
+#include "syscall-mem.inc.c"
 
 #undef SYSCALL_IMPL
 #undef SYSCALL_ARGS
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 15dc0e9087..d0160f841f 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -554,21 +554,6 @@
 #ifdef TARGET_NR_mknodat
 { TARGET_NR_mknodat, "mknodat" , NULL, print_mknodat, NULL },
 #endif
-#ifdef TARGET_NR_mlock
-{ TARGET_NR_mlock, "mlock" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_mlock2
-{ TARGET_NR_mlock2, "mlock2" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_mlockall
-{ TARGET_NR_mlockall, "mlockall" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_mmap
-{ TARGET_NR_mmap, "mmap" , NULL, print_mmap, print_syscall_ret_addr },
-#endif
-#ifdef TARGET_NR_mmap2
-{ TARGET_NR_mmap2, "mmap2" , NULL, print_mmap2, print_syscall_ret_addr },
-#endif
 #ifdef TARGET_NR_modify_ldt
 { TARGET_NR_modify_ldt, "modify_ldt" , NULL, NULL, NULL },
 #endif
@@ -578,9 +563,6 @@
 #ifdef TARGET_NR_move_pages
 { TARGET_NR_move_pages, "move_pages" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_mprotect
-{ TARGET_NR_mprotect, "mprotect" , NULL, print_mprotect, NULL },
-#endif
 #ifdef TARGET_NR_mpx
 { TARGET_NR_mpx, "mpx" , NULL, NULL, NULL },
 #endif
@@ -602,24 +584,9 @@
 #ifdef TARGET_NR_mq_unlink
 { TARGET_NR_mq_unlink, "mq_unlink" , NULL, print_mq_unlink, NULL },
 #endif
-#ifdef TARGET_NR_mremap
-{ TARGET_NR_mremap, "mremap" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_msync
-{ TARGET_NR_msync, "msync" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_multiplexer
 { TARGET_NR_multiplexer, "multiplexer" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_munlock
-{ TARGET_NR_munlock, "munlock" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_munlockall
-{ TARGET_NR_munlockall, "munlockall" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_munmap
-{ TARGET_NR_munmap, "munmap" , NULL, print_munmap, NULL },
-#endif
 #ifdef TARGET_NR_nanosleep
 { TARGET_NR_nanosleep, "nanosleep" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 16/49] linux-user: Split out exit
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (13 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 15/49] linux-user: Split out memory syscalls Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 17/49] linux-user: Split out brk Richard Henderson
                   ` (32 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  1 +
 linux-user/syscall-proc.inc.c | 61 +++++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 38 +---------------------
 3 files changed, 63 insertions(+), 37 deletions(-)
 create mode 100644 linux-user/syscall-proc.inc.c

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 88f433e998..88aa1a6bfd 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -17,6 +17,7 @@
  */
 
 SYSCALL_DEF(close, ARG_DEC);
+SYSCALL_DEF(exit, ARG_DEC);
 #ifdef TARGET_NR_ipc
 SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
 #endif
diff --git a/linux-user/syscall-proc.inc.c b/linux-user/syscall-proc.inc.c
new file mode 100644
index 0000000000..96ad363c1a
--- /dev/null
+++ b/linux-user/syscall-proc.inc.c
@@ -0,0 +1,61 @@
+/*
+ *  Linux process related syscalls
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+SYSCALL_IMPL(exit)
+{
+    CPUState *cpu = ENV_GET_CPU(cpu_env);
+    int status = arg1;
+
+    /*
+     * In old applications this may be used to implement _exit(2).
+     * However in threaded applictions it is used for thread termination,
+     * and _exit_group is used for application termination.
+     * Do thread termination if we have more then one thread.
+     */
+    if (block_signals()) {
+        return -TARGET_ERESTARTSYS;
+    }
+
+    cpu_list_lock();
+
+    if (CPU_NEXT(first_cpu)) {
+        TaskState *ts;
+
+        /* Remove the CPU from the list.  */
+        QTAILQ_REMOVE_RCU(&cpus, cpu, node);
+
+        cpu_list_unlock();
+
+        ts = cpu->opaque;
+        if (ts->child_tidptr) {
+            put_user_u32(0, ts->child_tidptr);
+            sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
+                      NULL, NULL, 0);
+        }
+        thread_cpu = NULL;
+        object_unref(OBJECT(cpu));
+        g_free(ts);
+        rcu_unregister_thread();
+        pthread_exit(NULL);
+    }
+
+    cpu_list_unlock();
+    preexit_cleanup(cpu_env, status);
+    _exit(status);
+}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 142654a0a0..02010f9ae0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5626,43 +5626,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-    case TARGET_NR_exit:
-        /* In old applications this may be used to implement _exit(2).
-           However in threaded applictions it is used for thread termination,
-           and _exit_group is used for application termination.
-           Do thread termination if we have more then one thread.  */
-
-        if (block_signals()) {
-            return -TARGET_ERESTARTSYS;
-        }
-
-        cpu_list_lock();
-
-        if (CPU_NEXT(first_cpu)) {
-            TaskState *ts;
-
-            /* Remove the CPU from the list.  */
-            QTAILQ_REMOVE_RCU(&cpus, cpu, node);
-
-            cpu_list_unlock();
-
-            ts = cpu->opaque;
-            if (ts->child_tidptr) {
-                put_user_u32(0, ts->child_tidptr);
-                sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
-                          NULL, NULL, 0);
-            }
-            thread_cpu = NULL;
-            object_unref(OBJECT(cpu));
-            g_free(ts);
-            rcu_unregister_thread();
-            pthread_exit(NULL);
-        }
-
-        cpu_list_unlock();
-        preexit_cleanup(cpu_env, arg1);
-        _exit(arg1);
-        return 0; /* avoid warning */
     case TARGET_NR_brk:
         return do_brk(arg1);
 #ifdef TARGET_NR_fork
@@ -9884,6 +9847,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
 #include "syscall-file.inc.c"
 #include "syscall-ipc.inc.c"
 #include "syscall-mem.inc.c"
+#include "syscall-proc.inc.c"
 
 #undef SYSCALL_IMPL
 #undef SYSCALL_ARGS
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 17/49] linux-user: Split out brk
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (14 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 16/49] linux-user: Split out exit Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 18/49] linux-user: Split out clone, fork, vfork Richard Henderson
                   ` (31 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h    |  3 ++
 linux-user/strace.c          | 35 --------------
 linux-user/syscall-mem.inc.c | 90 ++++++++++++++++++++++++++++++++++
 linux-user/syscall.c         | 93 ------------------------------------
 linux-user/strace.list       |  3 --
 5 files changed, 93 insertions(+), 131 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 88aa1a6bfd..c3ed22ff16 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -16,6 +16,9 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+SYSCALL_DEF_FULL(brk, .impl = impl_brk,
+                 .print_ret = print_syscall_ptr_ret,
+                 .arg_type = { ARG_PTR });
 SYSCALL_DEF(close, ARG_DEC);
 SYSCALL_DEF(exit, ARG_DEC);
 #ifdef TARGET_NR_ipc
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 5619defec8..ba541432eb 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -604,29 +604,6 @@ print_execve(const struct syscallname *name,
  * Variants for the return value output function
  */
 
-static void
-print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
-{
-    const char *errstr = NULL;
-
-    if (ret < 0) {
-        errstr = target_strerror(-ret);
-    }
-    if (errstr) {
-        gemu_log(" = -1 errno=%d (%s)\n", (int)-ret, errstr);
-    } else {
-        gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
-    }
-}
-
-#if 0 /* currently unused */
-static void
-print_syscall_ret_raw(struct syscallname *name, abi_long ret)
-{
-        gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
-}
-#endif
-
 #ifdef TARGET_NR__newselect
 static void
 print_syscall_ret_newselect(const struct syscallname *name, abi_long ret)
@@ -1168,18 +1145,6 @@ print_access(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_brk
-static void
-print_brk(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_pointer(arg0, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_chdir
 static void
 print_chdir(const struct syscallname *name,
diff --git a/linux-user/syscall-mem.inc.c b/linux-user/syscall-mem.inc.c
index d2ce0cb8cc..17ba8e3d97 100644
--- a/linux-user/syscall-mem.inc.c
+++ b/linux-user/syscall-mem.inc.c
@@ -42,6 +42,96 @@ static bitmask_transtbl const mmap_flags_tbl[] = {
     { 0, 0, 0, 0 }
 };
 
+static abi_ulong target_brk;
+static abi_ulong target_original_brk;
+static abi_ulong brk_page;
+
+void target_set_brk(abi_ulong new_brk)
+{
+    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
+    brk_page = HOST_PAGE_ALIGN(target_brk);
+}
+
+/* do_brk() must return target values and target errnos. */
+abi_long do_brk(abi_ulong new_brk)
+{
+    abi_long mapped_addr;
+    abi_ulong new_alloc_size;
+
+    if (!new_brk) {
+        return target_brk;
+    }
+    if (new_brk < target_original_brk) {
+        return target_brk;
+    }
+
+    /*
+     * If the new brk is less than the highest page reserved to the
+     * target heap allocation, set it and we're almost done...
+     */
+    if (new_brk <= brk_page) {
+        /*
+         * Heap contents are initialized to zero,
+         * as for anonymous mapped pages.
+         */
+        if (new_brk > target_brk) {
+            memset(g2h(target_brk), 0, new_brk - target_brk);
+        }
+        target_brk = new_brk;
+        return target_brk;
+    }
+
+    /*
+     * We need to allocate more memory after the brk... Note that
+     * we don't use MAP_FIXED because that will map over the top of
+     * any existing mapping (like the one with the host libc or qemu
+     * itself); instead we treat "mapped but at wrong address" as
+     * a failure and unmap again.
+     */
+    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
+    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
+                                        PROT_READ | PROT_WRITE,
+                                        MAP_ANON | MAP_PRIVATE, 0, 0));
+
+    if (mapped_addr == brk_page) {
+        /*
+         * Heap contents are initialized to zero, as for anonymous
+         * mapped pages.  Technically the new pages are already
+         * initialized to zero since they *are* anonymous mapped
+         * pages, however we have to take care with the contents that
+         * come from the remaining part of the previous page: it may
+         * contains garbage data due to a previous heap usage (grown
+         * then shrunken).
+         */
+        memset(g2h(target_brk), 0, brk_page - target_brk);
+
+        target_brk = new_brk;
+        brk_page = HOST_PAGE_ALIGN(target_brk);
+        return target_brk;
+    } else if (mapped_addr != -1) {
+        /*
+         * Mapped but at wrong address, meaning there wasn't actually
+         * enough space for this brk.
+         */
+        target_munmap(mapped_addr, new_alloc_size);
+        mapped_addr = -1;
+    }
+
+#if defined(TARGET_ALPHA)
+    /*
+     * We (partially) emulate OSF/1 on Alpha, which requires we
+     * return a proper errno, not an unchanged brk value.
+     */
+    return -TARGET_ENOMEM;
+#endif
+    /* For everything else, return the previous break. */
+    return target_brk;
+}
+
+SYSCALL_IMPL(brk)
+{
+    return do_brk(arg1);
+}
 
 SYSCALL_IMPL(mlock)
 {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 02010f9ae0..fbca989021 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -830,97 +830,6 @@ static inline int host_to_target_sock_type(int host_type)
     return target_type;
 }
 
-static abi_ulong target_brk;
-static abi_ulong target_original_brk;
-static abi_ulong brk_page;
-
-void target_set_brk(abi_ulong new_brk)
-{
-    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
-    brk_page = HOST_PAGE_ALIGN(target_brk);
-}
-
-//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
-#define DEBUGF_BRK(message, args...)
-
-/* do_brk() must return target values and target errnos. */
-abi_long do_brk(abi_ulong new_brk)
-{
-    abi_long mapped_addr;
-    abi_ulong new_alloc_size;
-
-    DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
-
-    if (!new_brk) {
-        DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
-        return target_brk;
-    }
-    if (new_brk < target_original_brk) {
-        DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
-                   target_brk);
-        return target_brk;
-    }
-
-    /* If the new brk is less than the highest page reserved to the
-     * target heap allocation, set it and we're almost done...  */
-    if (new_brk <= brk_page) {
-        /* Heap contents are initialized to zero, as for anonymous
-         * mapped pages.  */
-        if (new_brk > target_brk) {
-            memset(g2h(target_brk), 0, new_brk - target_brk);
-        }
-	target_brk = new_brk;
-        DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
-	return target_brk;
-    }
-
-    /* We need to allocate more memory after the brk... Note that
-     * we don't use MAP_FIXED because that will map over the top of
-     * any existing mapping (like the one with the host libc or qemu
-     * itself); instead we treat "mapped but at wrong address" as
-     * a failure and unmap again.
-     */
-    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
-    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
-                                        PROT_READ|PROT_WRITE,
-                                        MAP_ANON|MAP_PRIVATE, 0, 0));
-
-    if (mapped_addr == brk_page) {
-        /* Heap contents are initialized to zero, as for anonymous
-         * mapped pages.  Technically the new pages are already
-         * initialized to zero since they *are* anonymous mapped
-         * pages, however we have to take care with the contents that
-         * come from the remaining part of the previous page: it may
-         * contains garbage data due to a previous heap usage (grown
-         * then shrunken).  */
-        memset(g2h(target_brk), 0, brk_page - target_brk);
-
-        target_brk = new_brk;
-        brk_page = HOST_PAGE_ALIGN(target_brk);
-        DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
-            target_brk);
-        return target_brk;
-    } else if (mapped_addr != -1) {
-        /* Mapped but at wrong address, meaning there wasn't actually
-         * enough space for this brk.
-         */
-        target_munmap(mapped_addr, new_alloc_size);
-        mapped_addr = -1;
-        DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
-    }
-    else {
-        DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
-    }
-
-#if defined(TARGET_ALPHA)
-    /* We (partially) emulate OSF/1 on Alpha, which requires we
-       return a proper errno, not an unchanged brk value.  */
-    return -TARGET_ENOMEM;
-#endif
-    /* For everything else, return the previous break. */
-    return target_brk;
-}
-
 static inline abi_long copy_from_user_fdset(fd_set *fds,
                                             abi_ulong target_fds_addr,
                                             int n)
@@ -5626,8 +5535,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-    case TARGET_NR_brk:
-        return do_brk(arg1);
 #ifdef TARGET_NR_fork
     case TARGET_NR_fork:
         return get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
diff --git a/linux-user/strace.list b/linux-user/strace.list
index d0160f841f..bdc1401b01 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -49,9 +49,6 @@
 #ifdef TARGET_NR_break
 { TARGET_NR_break, "break" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_brk
-{ TARGET_NR_brk, "brk" , NULL, print_brk, print_syscall_ret_addr },
-#endif
 #ifdef TARGET_NR_cachectl
 { TARGET_NR_cachectl, "cachectl" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 18/49] linux-user: Split out clone, fork, vfork
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (15 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 17/49] linux-user: Split out brk Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 19/49] linux-user: Split out wait4, waitid, waitpid Richard Henderson
                   ` (30 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Rename do_fork to do_clone, since that is what it does.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |   8 ++
 linux-user/syscall.h          |   1 +
 linux-user/strace.c           |  36 +----
 linux-user/syscall-proc.inc.c | 259 ++++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 218 ----------------------------
 linux-user/strace.list        |   9 --
 6 files changed, 272 insertions(+), 259 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index c3ed22ff16..6f6f77927b 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -19,8 +19,12 @@
 SYSCALL_DEF_FULL(brk, .impl = impl_brk,
                  .print_ret = print_syscall_ptr_ret,
                  .arg_type = { ARG_PTR });
+SYSCALL_DEF_ARGS(clone, ARG_CLONEFLAG, ARG_PTR, ARG_PTR, ARG_PTR, ARG_PTR);
 SYSCALL_DEF(close, ARG_DEC);
 SYSCALL_DEF(exit, ARG_DEC);
+#ifdef TARGET_NR_fork
+SYSCALL_DEF(fork);
+#endif
 #ifdef TARGET_NR_ipc
 SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
 #endif
@@ -110,5 +114,9 @@ SYSCALL_DEF(shmdt, ARG_PTR);
 #if !defined(SYSCALL_TABLE) || defined(TARGET_NR_shmget)
 SYSCALL_DEF(shmget, ARG_DEC, ARG_DEC, ARG_HEX);
 #endif
+#ifdef TARGET_NR_vfork
+/* Emulate vfork() with fork().  */
+SYSCALL_DEF_FULL(vfork, .impl = impl_fork);
+#endif
 SYSCALL_DEF(write, ARG_DEC, ARG_PTR, ARG_DEC);
 SYSCALL_DEF(writev, ARG_DEC, ARG_PTR, ARG_DEC);
diff --git a/linux-user/syscall.h b/linux-user/syscall.h
index 8175de4c31..f75cd3ddd0 100644
--- a/linux-user/syscall.h
+++ b/linux-user/syscall.h
@@ -58,6 +58,7 @@ typedef enum {
     /* These print as sets of flags.  */
     ARG_ATDIRFD,
     ARG_ATFLAG,
+    ARG_CLONEFLAG,
     ARG_MMAPFLAG,
     ARG_MMAPPROT,
     ARG_MODEFLAG,
diff --git a/linux-user/strace.c b/linux-user/strace.c
index ba541432eb..d7847e7cd6 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -813,7 +813,7 @@ static struct flags const mmap_flags[] = {
     FLAG_END,
 };
 
-UNUSED static struct flags clone_flags[] = {
+static struct flags const clone_flags[] = {
     FLAG_GENERIC(CLONE_VM),
     FLAG_GENERIC(CLONE_FS),
     FLAG_GENERIC(CLONE_FILES),
@@ -1183,37 +1183,6 @@ print_clock_adjtime(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_clone
-static void do_print_clone(unsigned int flags, abi_ulong newsp,
-                           abi_ulong parent_tidptr, target_ulong newtls,
-                           abi_ulong child_tidptr)
-{
-    print_flags(clone_flags, flags, 0);
-    print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, newsp, 0);
-    print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, parent_tidptr, 0);
-    print_raw_param("tls=0x" TARGET_ABI_FMT_lx, newtls, 0);
-    print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, child_tidptr, 1);
-}
-
-static void
-print_clone(const struct syscallname *name,
-    abi_long arg1, abi_long arg2, abi_long arg3,
-    abi_long arg4, abi_long arg5, abi_long arg6)
-{
-    print_syscall_prologue(name);
-#if defined(TARGET_MICROBLAZE)
-    do_print_clone(arg1, arg2, arg4, arg6, arg5);
-#elif defined(TARGET_CLONE_BACKWARDS)
-    do_print_clone(arg1, arg2, arg3, arg4, arg5);
-#elif defined(TARGET_CLONE_BACKWARDS2)
-    do_print_clone(arg2, arg1, arg3, arg5, arg4);
-#else
-    do_print_clone(arg1, arg2, arg3, arg5, arg4);
-#endif
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_creat
 static void
 print_creat(const struct syscallname *name,
@@ -2521,6 +2490,9 @@ static void print_syscall_def1(const SyscallDef *def, int64_t args[6])
         case ARG_ATFLAG:
             len = add_flags(b, rest, at_file_flags, arg, false);
             break;
+        case ARG_CLONEFLAG:
+            len = add_flags(b, rest, clone_flags, arg, false);
+            break;
         case ARG_MMAPFLAG:
             len = add_flags(b, rest, mmap_flags, arg, false);
             break;
diff --git a/linux-user/syscall-proc.inc.c b/linux-user/syscall-proc.inc.c
index 96ad363c1a..b89ac56552 100644
--- a/linux-user/syscall-proc.inc.c
+++ b/linux-user/syscall-proc.inc.c
@@ -16,6 +16,258 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#ifndef CLONE_IO
+#define CLONE_IO                0x80000000      /* Clone io context */
+#endif
+
+/*
+ * We can't directly call the host clone syscall, because this will
+ * badly confuse libc (breaking mutexes, for example). So we must
+ * divide clone flags into:
+ *  * flag combinations that look like pthread_create()
+ *  * flag combinations that look like fork()
+ *  * flags we can implement within QEMU itself
+ *  * flags we can't support and will return an error for
+ *
+ * For thread creation, all these flags must be present; for
+ * fork, none must be present.
+ */
+#define CLONE_THREAD_FLAGS                              \
+    (CLONE_VM | CLONE_FS | CLONE_FILES |                \
+     CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM)
+
+/*
+ * These flags are ignored:
+ * CLONE_DETACHED is now ignored by the kernel;
+ * CLONE_IO is just an optimisation hint to the I/O scheduler
+ */
+#define CLONE_IGNORED_FLAGS                     \
+    (CLONE_DETACHED | CLONE_IO)
+
+/* Flags for fork which we can implement within QEMU itself */
+#define CLONE_OPTIONAL_FORK_FLAGS               \
+    (CLONE_SETTLS | CLONE_PARENT_SETTID |       \
+     CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)
+
+/* Flags for thread creation which we can implement within QEMU itself */
+#define CLONE_OPTIONAL_THREAD_FLAGS                             \
+    (CLONE_SETTLS | CLONE_PARENT_SETTID |                       \
+     CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT)
+
+#define CLONE_INVALID_FORK_FLAGS                                        \
+    (~(CSIGNAL | CLONE_OPTIONAL_FORK_FLAGS | CLONE_IGNORED_FLAGS))
+
+#define CLONE_INVALID_THREAD_FLAGS                                      \
+    (~(CSIGNAL | CLONE_THREAD_FLAGS | CLONE_OPTIONAL_THREAD_FLAGS |     \
+       CLONE_IGNORED_FLAGS))
+
+/*
+ * CLONE_VFORK is special cased early in do_fork(). The other flag bits
+ * have almost all been allocated. We cannot support any of
+ * CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC,
+ * CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_PTRACE, CLONE_UNTRACED.
+ * The checks against the invalid thread masks above will catch these.
+ * (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.)
+ */
+
+/**
+ * do_clone:
+ * Arguments as for clone(2), returns target errnos.
+ */
+static abi_long do_clone(CPUArchState *env, unsigned int flags,
+                         abi_ulong newsp, abi_ulong parent_tidptr,
+                         abi_ulong child_tidptr, target_ulong newtls)
+{
+    CPUState *cpu = ENV_GET_CPU(env);
+    abi_long ret;
+    TaskState *ts;
+    CPUState *new_cpu;
+    CPUArchState *new_env;
+    sigset_t sigmask;
+
+    flags &= ~CLONE_IGNORED_FLAGS;
+
+    /* Emulate vfork() with fork() */
+    if (flags & CLONE_VFORK) {
+        flags &= ~(CLONE_VFORK | CLONE_VM);
+    }
+
+    if (flags & CLONE_VM) {
+        /* If CLONE_VM, we consider it a new thread.  */
+        TaskState *parent_ts = (TaskState *)cpu->opaque;
+        new_thread_info info;
+        pthread_attr_t attr;
+
+        if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
+            (flags & CLONE_INVALID_THREAD_FLAGS)) {
+            return -TARGET_EINVAL;
+        }
+
+        ts = g_new0(TaskState, 1);
+        init_task_state(ts);
+
+        /* Grab a mutex so that thread setup appears atomic.  */
+        pthread_mutex_lock(&clone_lock);
+
+        /* Create a new CPU instance.  */
+        new_env = cpu_copy(env);
+
+        /* Init regs that differ from the parent.  */
+        cpu_clone_regs(new_env, newsp);
+        new_cpu = ENV_GET_CPU(new_env);
+        new_cpu->opaque = ts;
+        ts->bprm = parent_ts->bprm;
+        ts->info = parent_ts->info;
+        ts->signal_mask = parent_ts->signal_mask;
+
+        if (flags & CLONE_CHILD_CLEARTID) {
+            ts->child_tidptr = child_tidptr;
+        }
+
+        if (flags & CLONE_SETTLS) {
+            cpu_set_tls(new_env, newtls);
+        }
+
+        memset(&info, 0, sizeof(info));
+        pthread_mutex_init(&info.mutex, NULL);
+        pthread_mutex_lock(&info.mutex);
+        pthread_cond_init(&info.cond, NULL);
+        info.env = new_env;
+        if (flags & CLONE_CHILD_SETTID) {
+            info.child_tidptr = child_tidptr;
+        }
+        if (flags & CLONE_PARENT_SETTID) {
+            info.parent_tidptr = parent_tidptr;
+        }
+
+        ret = pthread_attr_init(&attr);
+        ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
+        ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+        /*
+         * It is not safe to deliver signals until the child has finished
+         * initializing, so temporarily block all signals.
+         */
+        sigfillset(&sigmask);
+        sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
+
+        /*
+         * If this is our first additional thread, we need to ensure we
+         * generate code for parallel execution and flush old translations.
+         */
+        if (!parallel_cpus) {
+            parallel_cpus = true;
+            tb_flush(cpu);
+        }
+
+        ret = pthread_create(&info.thread, &attr, clone_func, &info);
+        /* TODO: Free new CPU state if thread creation failed.  */
+
+        sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
+        pthread_attr_destroy(&attr);
+        if (ret == 0) {
+            /* Wait for the child to initialize.  */
+            pthread_cond_wait(&info.cond, &info.mutex);
+            ret = info.tid;
+        } else {
+            ret = host_to_target_errno(ret);
+        }
+        pthread_mutex_unlock(&info.mutex);
+        pthread_cond_destroy(&info.cond);
+        pthread_mutex_destroy(&info.mutex);
+        pthread_mutex_unlock(&clone_lock);
+    } else {
+        /* If no CLONE_VM, we consider it a fork.  */
+        if (flags & CLONE_INVALID_FORK_FLAGS) {
+            return -TARGET_EINVAL;
+        }
+
+        /* We can't support custom termination signals.  */
+        if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
+            return -TARGET_EINVAL;
+        }
+
+        if (block_signals()) {
+            return -TARGET_ERESTARTSYS;
+        }
+
+        fork_start();
+        ret = fork();
+        if (ret == 0) {
+            /* Child Process.  */
+            cpu_clone_regs(env, newsp);
+            fork_end(1);
+            /*
+             * There is a race condition here.  The parent process could
+             * theoretically read the TID in the child process before the
+             * child tid is set.  This would require using either ptrace
+             * (not implemented) or having *_tidptr to point at a shared
+             * memory mapping.  We can't repeat the spinlock hack used
+             * above because the child process gets its own copy of the lock.
+             */
+            if (flags & CLONE_CHILD_SETTID) {
+                put_user_u32(gettid(), child_tidptr);
+            }
+            if (flags & CLONE_PARENT_SETTID) {
+                put_user_u32(gettid(), parent_tidptr);
+            }
+            ts = (TaskState *)cpu->opaque;
+            if (flags & CLONE_SETTLS) {
+                cpu_set_tls(env, newtls);
+            }
+            if (flags & CLONE_CHILD_CLEARTID) {
+                ts->child_tidptr = child_tidptr;
+            }
+        } else {
+            fork_end(0);
+            ret = get_errno(ret);
+        }
+    }
+    return ret;
+}
+
+#if defined(TARGET_MICROBLAZE) || \
+    defined(TARGET_CLONE_BACKWARDS) || \
+    defined(TARGET_CLONE_BACKWARDS2)
+SYSCALL_ARGS(clone)
+{
+    /*
+     * Linux manages to have three "standard" orderings for its
+     * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
+     * match the kernel's CONFIG_CLONE_* settings.
+     * Microblaze is further special in that it uses a sixth
+     * implicit argument to clone for the TLS pointer.
+     *
+     * Standardize on the non-BACKWARDS ordering.
+     */
+# if defined(TARGET_MICROBLAZE)
+    /* We have already assigned out[0-1].  */
+    out[2] = in[3];
+    out[3] = in[4];
+    out[4] = in[5];
+# elif defined(TARGET_CLONE_BACKWARDS)
+    /* We have already assigned out[0-2].  */
+    out[3] = in[4];
+    out[4] = in[3];
+# elif defined(TARGET_CLONE_BACKWARDS2)
+    out[0] = in[1];
+    out[1] = in[0];
+    out[2] = in[2];
+    out[3] = in[4];
+    out[4] = in[3];
+# else
+#  error Missing case
+# endif
+    return def;
+}
+#else
+#define args_clone NULL
+#endif
+
+SYSCALL_IMPL(clone)
+{
+    return do_clone(cpu_env, arg1, arg2, arg3, arg4, arg5);
+}
 
 SYSCALL_IMPL(exit)
 {
@@ -59,3 +311,10 @@ SYSCALL_IMPL(exit)
     preexit_cleanup(cpu_env, status);
     _exit(status);
 }
+
+#if defined(TARGET_NR_fork) || defined(TARGET_NR_vfork)
+SYSCALL_IMPL(fork)
+{
+    return do_clone(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0);
+}
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index fbca989021..1d18d28fbe 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -113,57 +113,6 @@
 #include "fd-trans.h"
 #include "syscall.h"
 
-#ifndef CLONE_IO
-#define CLONE_IO                0x80000000      /* Clone io context */
-#endif
-
-/* We can't directly call the host clone syscall, because this will
- * badly confuse libc (breaking mutexes, for example). So we must
- * divide clone flags into:
- *  * flag combinations that look like pthread_create()
- *  * flag combinations that look like fork()
- *  * flags we can implement within QEMU itself
- *  * flags we can't support and will return an error for
- */
-/* For thread creation, all these flags must be present; for
- * fork, none must be present.
- */
-#define CLONE_THREAD_FLAGS                              \
-    (CLONE_VM | CLONE_FS | CLONE_FILES |                \
-     CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM)
-
-/* These flags are ignored:
- * CLONE_DETACHED is now ignored by the kernel;
- * CLONE_IO is just an optimisation hint to the I/O scheduler
- */
-#define CLONE_IGNORED_FLAGS                     \
-    (CLONE_DETACHED | CLONE_IO)
-
-/* Flags for fork which we can implement within QEMU itself */
-#define CLONE_OPTIONAL_FORK_FLAGS               \
-    (CLONE_SETTLS | CLONE_PARENT_SETTID |       \
-     CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)
-
-/* Flags for thread creation which we can implement within QEMU itself */
-#define CLONE_OPTIONAL_THREAD_FLAGS                             \
-    (CLONE_SETTLS | CLONE_PARENT_SETTID |                       \
-     CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT)
-
-#define CLONE_INVALID_FORK_FLAGS                                        \
-    (~(CSIGNAL | CLONE_OPTIONAL_FORK_FLAGS | CLONE_IGNORED_FLAGS))
-
-#define CLONE_INVALID_THREAD_FLAGS                                      \
-    (~(CSIGNAL | CLONE_THREAD_FLAGS | CLONE_OPTIONAL_THREAD_FLAGS |     \
-       CLONE_IGNORED_FLAGS))
-
-/* CLONE_VFORK is special cased early in do_fork(). The other flag bits
- * have almost all been allocated. We cannot support any of
- * CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC,
- * CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_PTRACE, CLONE_UNTRACED.
- * The checks against the invalid thread masks above will catch these.
- * (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.)
- */
-
 /* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
  * once. This exercises the codepaths for restart.
  */
@@ -4397,146 +4346,6 @@ static void *clone_func(void *arg)
     return NULL;
 }
 
-/* do_fork() Must return host values and target errnos (unlike most
-   do_*() functions). */
-static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
-                   abi_ulong parent_tidptr, target_ulong newtls,
-                   abi_ulong child_tidptr)
-{
-    CPUState *cpu = ENV_GET_CPU(env);
-    int ret;
-    TaskState *ts;
-    CPUState *new_cpu;
-    CPUArchState *new_env;
-    sigset_t sigmask;
-
-    flags &= ~CLONE_IGNORED_FLAGS;
-
-    /* Emulate vfork() with fork() */
-    if (flags & CLONE_VFORK)
-        flags &= ~(CLONE_VFORK | CLONE_VM);
-
-    if (flags & CLONE_VM) {
-        TaskState *parent_ts = (TaskState *)cpu->opaque;
-        new_thread_info info;
-        pthread_attr_t attr;
-
-        if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) ||
-            (flags & CLONE_INVALID_THREAD_FLAGS)) {
-            return -TARGET_EINVAL;
-        }
-
-        ts = g_new0(TaskState, 1);
-        init_task_state(ts);
-
-        /* Grab a mutex so that thread setup appears atomic.  */
-        pthread_mutex_lock(&clone_lock);
-
-        /* we create a new CPU instance. */
-        new_env = cpu_copy(env);
-        /* Init regs that differ from the parent.  */
-        cpu_clone_regs(new_env, newsp);
-        new_cpu = ENV_GET_CPU(new_env);
-        new_cpu->opaque = ts;
-        ts->bprm = parent_ts->bprm;
-        ts->info = parent_ts->info;
-        ts->signal_mask = parent_ts->signal_mask;
-
-        if (flags & CLONE_CHILD_CLEARTID) {
-            ts->child_tidptr = child_tidptr;
-        }
-
-        if (flags & CLONE_SETTLS) {
-            cpu_set_tls (new_env, newtls);
-        }
-
-        memset(&info, 0, sizeof(info));
-        pthread_mutex_init(&info.mutex, NULL);
-        pthread_mutex_lock(&info.mutex);
-        pthread_cond_init(&info.cond, NULL);
-        info.env = new_env;
-        if (flags & CLONE_CHILD_SETTID) {
-            info.child_tidptr = child_tidptr;
-        }
-        if (flags & CLONE_PARENT_SETTID) {
-            info.parent_tidptr = parent_tidptr;
-        }
-
-        ret = pthread_attr_init(&attr);
-        ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
-        ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-        /* It is not safe to deliver signals until the child has finished
-           initializing, so temporarily block all signals.  */
-        sigfillset(&sigmask);
-        sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
-
-        /* If this is our first additional thread, we need to ensure we
-         * generate code for parallel execution and flush old translations.
-         */
-        if (!parallel_cpus) {
-            parallel_cpus = true;
-            tb_flush(cpu);
-        }
-
-        ret = pthread_create(&info.thread, &attr, clone_func, &info);
-        /* TODO: Free new CPU state if thread creation failed.  */
-
-        sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
-        pthread_attr_destroy(&attr);
-        if (ret == 0) {
-            /* Wait for the child to initialize.  */
-            pthread_cond_wait(&info.cond, &info.mutex);
-            ret = info.tid;
-        } else {
-            ret = -1;
-        }
-        pthread_mutex_unlock(&info.mutex);
-        pthread_cond_destroy(&info.cond);
-        pthread_mutex_destroy(&info.mutex);
-        pthread_mutex_unlock(&clone_lock);
-    } else {
-        /* if no CLONE_VM, we consider it is a fork */
-        if (flags & CLONE_INVALID_FORK_FLAGS) {
-            return -TARGET_EINVAL;
-        }
-
-        /* We can't support custom termination signals */
-        if ((flags & CSIGNAL) != TARGET_SIGCHLD) {
-            return -TARGET_EINVAL;
-        }
-
-        if (block_signals()) {
-            return -TARGET_ERESTARTSYS;
-        }
-
-        fork_start();
-        ret = fork();
-        if (ret == 0) {
-            /* Child Process.  */
-            cpu_clone_regs(env, newsp);
-            fork_end(1);
-            /* There is a race condition here.  The parent process could
-               theoretically read the TID in the child process before the child
-               tid is set.  This would require using either ptrace
-               (not implemented) or having *_tidptr to point at a shared memory
-               mapping.  We can't repeat the spinlock hack used above because
-               the child process gets its own copy of the lock.  */
-            if (flags & CLONE_CHILD_SETTID)
-                put_user_u32(gettid(), child_tidptr);
-            if (flags & CLONE_PARENT_SETTID)
-                put_user_u32(gettid(), parent_tidptr);
-            ts = (TaskState *)cpu->opaque;
-            if (flags & CLONE_SETTLS)
-                cpu_set_tls (env, newtls);
-            if (flags & CLONE_CHILD_CLEARTID)
-                ts->child_tidptr = child_tidptr;
-        } else {
-            fork_end(0);
-        }
-    }
-    return ret;
-}
-
 /* warning : doesn't handle linux specific flags... */
 static int target_to_host_fcntl_cmd(int cmd)
 {
@@ -5535,10 +5344,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_fork
-    case TARGET_NR_fork:
-        return get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
-#endif
 #ifdef TARGET_NR_waitpid
     case TARGET_NR_waitpid:
         {
@@ -7228,23 +7033,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         return ret;
     case TARGET_NR_fsync:
         return get_errno(fsync(arg1));
-    case TARGET_NR_clone:
-        /* Linux manages to have three different orderings for its
-         * arguments to clone(); the BACKWARDS and BACKWARDS2 defines
-         * match the kernel's CONFIG_CLONE_* settings.
-         * Microblaze is further special in that it uses a sixth
-         * implicit argument to clone for the TLS pointer.
-         */
-#if defined(TARGET_MICROBLAZE)
-        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5));
-#elif defined(TARGET_CLONE_BACKWARDS)
-        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
-#elif defined(TARGET_CLONE_BACKWARDS2)
-        ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4));
-#else
-        ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
-#endif
-        return ret;
 #ifdef __NR_exit_group
         /* new thread calls */
     case TARGET_NR_exit_group:
@@ -8079,12 +7867,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     }
 #endif
 #endif
-#ifdef TARGET_NR_vfork
-    case TARGET_NR_vfork:
-        return get_errno(do_fork(cpu_env,
-                         CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
-                         0, 0, 0, 0));
-#endif
 #ifdef TARGET_NR_ugetrlimit
     case TARGET_NR_ugetrlimit:
     {
diff --git a/linux-user/strace.list b/linux-user/strace.list
index bdc1401b01..0d978ea580 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -91,9 +91,6 @@
 #ifdef TARGET_NR_clock_settime
 { TARGET_NR_clock_settime, "clock_settime" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_clone
-{ TARGET_NR_clone, "clone" , NULL, print_clone, NULL },
-#endif
 #ifdef TARGET_NR_connect
 { TARGET_NR_connect, "connect" , "%s(%d,%#x,%d)", NULL, NULL },
 #endif
@@ -220,9 +217,6 @@
 #ifdef TARGET_NR_flock
 { TARGET_NR_flock, "flock" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_fork
-{ TARGET_NR_fork, "fork" , "%s()", NULL, NULL },
-#endif
 #ifdef TARGET_NR_fremovexattr
 { TARGET_NR_fremovexattr, "fremovexattr" , NULL, NULL, NULL },
 #endif
@@ -1485,9 +1479,6 @@
 #ifdef TARGET_NR_utrap_install
 { TARGET_NR_utrap_install, "utrap_install" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_vfork
-{ TARGET_NR_vfork, "vfork" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_vhangup
 { TARGET_NR_vhangup, "vhangup" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 19/49] linux-user: Split out wait4, waitid, waitpid
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (16 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 18/49] linux-user: Split out clone, fork, vfork Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 20/49] linux-user: Implement rusage argument to waitid Richard Henderson
                   ` (29 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that waitid is universally provided and need not be conditional.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  5 ++
 linux-user/syscall-proc.inc.c | 88 +++++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 67 --------------------------
 linux-user/strace.list        |  9 ----
 4 files changed, 93 insertions(+), 76 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 6f6f77927b..a84050a318 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -118,5 +118,10 @@ SYSCALL_DEF(shmget, ARG_DEC, ARG_DEC, ARG_HEX);
 /* Emulate vfork() with fork().  */
 SYSCALL_DEF_FULL(vfork, .impl = impl_fork);
 #endif
+SYSCALL_DEF(wait4, ARG_DEC, ARG_PTR, ARG_HEX, ARG_PTR);
+SYSCALL_DEF(waitid, ARG_HEX, ARG_DEC, ARG_PTR, ARG_HEX);
+#ifdef TARGET_NR_waitpid
+SYSCALL_DEF(waitpid, ARG_DEC, ARG_PTR, ARG_HEX);
+#endif
 SYSCALL_DEF(write, ARG_DEC, ARG_PTR, ARG_DEC);
 SYSCALL_DEF(writev, ARG_DEC, ARG_PTR, ARG_DEC);
diff --git a/linux-user/syscall-proc.inc.c b/linux-user/syscall-proc.inc.c
index b89ac56552..37f5bbe197 100644
--- a/linux-user/syscall-proc.inc.c
+++ b/linux-user/syscall-proc.inc.c
@@ -318,3 +318,91 @@ SYSCALL_IMPL(fork)
     return do_clone(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0);
 }
 #endif
+
+/*
+ * Map host to target signal numbers for the wait family of syscalls.
+ * Assume all other status bits are the same.
+ */
+int host_to_target_waitstatus(int status)
+{
+    if (WIFSIGNALED(status)) {
+        return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
+    }
+    if (WIFSTOPPED(status)) {
+        return (host_to_target_signal(WSTOPSIG(status)) << 8)
+               | (status & 0xff);
+    }
+    return status;
+}
+
+SYSCALL_IMPL(wait4)
+{
+    int status;
+    pid_t pid = arg1;
+    abi_ulong status_ptr = arg2;
+    int options = arg3;
+    abi_ulong target_rusage = arg4;
+    struct rusage rusage;
+    struct rusage *rusage_ptr = target_rusage ? &rusage : NULL;
+    abi_long ret;
+
+    ret = get_errno(safe_wait4(pid, &status, options, rusage_ptr));
+    if (!is_error(ret)) {
+        if (status_ptr && ret) {
+            status = host_to_target_waitstatus(status);
+            if (put_user_s32(status, status_ptr)) {
+                return -TARGET_EFAULT;
+            }
+        }
+        if (target_rusage) {
+            abi_long err = host_to_target_rusage(target_rusage, &rusage);
+            if (err) {
+                ret = err;
+            }
+        }
+    }
+    return ret;
+}
+
+SYSCALL_IMPL(waitid)
+{
+    idtype_t idtype = arg1;
+    id_t id = arg2;
+    abi_ulong target_info = arg3;
+    int options = arg4;
+    siginfo_t info, *info_ptr = target_info ? &info : NULL;
+    abi_long ret;
+
+    info.si_pid = 0;
+    ret = get_errno(safe_waitid(idtype, id, info_ptr, options, NULL));
+    if (!is_error(ret) && target_info && info.si_pid != 0) {
+        target_siginfo_t *p = lock_user(VERIFY_WRITE, target_info,
+                                        sizeof(target_siginfo_t), 0);
+        if (!p) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_siginfo(p, &info);
+        unlock_user(p, target_info, sizeof(target_siginfo_t));
+    }
+    return ret;
+}
+
+#ifdef TARGET_NR_waitpid
+SYSCALL_IMPL(waitpid)
+{
+    pid_t pid = arg1;
+    abi_ulong target_status = arg2;
+    int options = arg3;
+    int status;
+    abi_long ret;
+
+    ret = get_errno(safe_wait4(pid, &status, options, NULL));
+    if (!is_error(ret)
+        && target_status
+        && ret
+        && put_user_s32(host_to_target_waitstatus(status), target_status)) {
+        return -TARGET_EFAULT;
+    }
+    return ret;
+}
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 1d18d28fbe..8da92dd188 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5218,20 +5218,6 @@ static abi_long do_signalfd4(int fd, abi_long mask, int flags)
 }
 #endif
 
-/* Map host to target signal numbers for the wait family of syscalls.
-   Assume all other status bits are the same.  */
-int host_to_target_waitstatus(int status)
-{
-    if (WIFSIGNALED(status)) {
-        return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
-    }
-    if (WIFSTOPPED(status)) {
-        return (host_to_target_signal(WSTOPSIG(status)) << 8)
-               | (status & 0xff);
-    }
-    return status;
-}
-
 #define TIMER_MAGIC 0x0caf0000
 #define TIMER_MAGIC_MASK 0xffff0000
 
@@ -5344,32 +5330,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_waitpid
-    case TARGET_NR_waitpid:
-        {
-            int status;
-            ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
-            if (!is_error(ret) && arg2 && ret
-                && put_user_s32(host_to_target_waitstatus(status), arg2))
-                return -TARGET_EFAULT;
-        }
-        return ret;
-#endif
-#ifdef TARGET_NR_waitid
-    case TARGET_NR_waitid:
-        {
-            siginfo_t info;
-            info.si_pid = 0;
-            ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
-            if (!is_error(ret) && arg3 && info.si_pid != 0) {
-                if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
-                    return -TARGET_EFAULT;
-                host_to_target_siginfo(p, &info);
-                unlock_user(p, arg3, sizeof(target_siginfo_t));
-            }
-        }
-        return ret;
-#endif
 #ifdef TARGET_NR_creat /* not on alpha */
     case TARGET_NR_creat:
         if (!(p = lock_user_string(arg1)))
@@ -6969,33 +6929,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         return do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
                           arg6, arg7, arg8, 0);
 #endif
-    case TARGET_NR_wait4:
-        {
-            int status;
-            abi_long status_ptr = arg2;
-            struct rusage rusage, *rusage_ptr;
-            abi_ulong target_rusage = arg4;
-            abi_long rusage_err;
-            if (target_rusage)
-                rusage_ptr = &rusage;
-            else
-                rusage_ptr = NULL;
-            ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
-            if (!is_error(ret)) {
-                if (status_ptr && ret) {
-                    status = host_to_target_waitstatus(status);
-                    if (put_user_s32(status, status_ptr))
-                        return -TARGET_EFAULT;
-                }
-                if (target_rusage) {
-                    rusage_err = host_to_target_rusage(target_rusage, &rusage);
-                    if (rusage_err) {
-                        ret = rusage_err;
-                    }
-                }
-            }
-        }
-        return ret;
 #ifdef TARGET_NR_swapoff
     case TARGET_NR_swapoff:
         if (!(p = lock_user_string(arg1)))
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 0d978ea580..afa1521e2d 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1494,15 +1494,6 @@
 #ifdef TARGET_NR_vserver
 { TARGET_NR_vserver, "vserver" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_wait4
-{ TARGET_NR_wait4, "wait4" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_waitid
-{ TARGET_NR_waitid, "waitid" , "%s(%#x,%d,%p,%#x)", NULL, NULL },
-#endif
-#ifdef TARGET_NR_waitpid
-{ TARGET_NR_waitpid, "waitpid" , "%s(%d,%p,%#x)", NULL, NULL },
-#endif
 #ifdef TARGET_NR_utimensat
 { TARGET_NR_utimensat, "utimensat", NULL, print_utimensat, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 20/49] linux-user: Implement rusage argument to waitid
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (17 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 19/49] linux-user: Split out wait4, waitid, waitpid Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 21/49] linux-user: Split out creat Richard Henderson
                   ` (28 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

The kernel interface, which we are supposed to be implementing,
takes a fifth argument: an rusage pointer akin to wait4.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  2 +-
 linux-user/syscall-proc.inc.c | 27 +++++++++++++++++++--------
 2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index a84050a318..f099d98fa3 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -119,7 +119,7 @@ SYSCALL_DEF(shmget, ARG_DEC, ARG_DEC, ARG_HEX);
 SYSCALL_DEF_FULL(vfork, .impl = impl_fork);
 #endif
 SYSCALL_DEF(wait4, ARG_DEC, ARG_PTR, ARG_HEX, ARG_PTR);
-SYSCALL_DEF(waitid, ARG_HEX, ARG_DEC, ARG_PTR, ARG_HEX);
+SYSCALL_DEF(waitid, ARG_HEX, ARG_DEC, ARG_PTR, ARG_HEX, ARG_PTR);
 #ifdef TARGET_NR_waitpid
 SYSCALL_DEF(waitpid, ARG_DEC, ARG_PTR, ARG_HEX);
 #endif
diff --git a/linux-user/syscall-proc.inc.c b/linux-user/syscall-proc.inc.c
index 37f5bbe197..de4efed9f4 100644
--- a/linux-user/syscall-proc.inc.c
+++ b/linux-user/syscall-proc.inc.c
@@ -370,19 +370,30 @@ SYSCALL_IMPL(waitid)
     id_t id = arg2;
     abi_ulong target_info = arg3;
     int options = arg4;
+    abi_ulong target_rusage = arg5;
     siginfo_t info, *info_ptr = target_info ? &info : NULL;
+    struct rusage rusage;
+    struct rusage *rusage_ptr = target_rusage ? &rusage : NULL;
     abi_long ret;
 
     info.si_pid = 0;
-    ret = get_errno(safe_waitid(idtype, id, info_ptr, options, NULL));
-    if (!is_error(ret) && target_info && info.si_pid != 0) {
-        target_siginfo_t *p = lock_user(VERIFY_WRITE, target_info,
-                                        sizeof(target_siginfo_t), 0);
-        if (!p) {
-            return -TARGET_EFAULT;
+    ret = get_errno(safe_waitid(idtype, id, info_ptr, options, rusage_ptr));
+    if (!is_error(ret)) {
+        if (target_info && info.si_pid != 0) {
+            target_siginfo_t *p = lock_user(VERIFY_WRITE, target_info,
+                                            sizeof(target_siginfo_t), 0);
+            if (!p) {
+                return -TARGET_EFAULT;
+            }
+            host_to_target_siginfo(p, &info);
+            unlock_user(p, target_info, sizeof(target_siginfo_t));
+        }
+        if (target_rusage) {
+            abi_long err = host_to_target_rusage(target_rusage, &rusage);
+            if (err) {
+                ret = err;
+            }
         }
-        host_to_target_siginfo(p, &info);
-        unlock_user(p, target_info, sizeof(target_siginfo_t));
     }
     return ret;
 }
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 21/49] linux-user: Split out creat
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (18 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 20/49] linux-user: Implement rusage argument to waitid Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 22/49] linux-user: Split out link, linkat Richard Henderson
                   ` (27 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  3 +++
 linux-user/strace.c           | 13 -------------
 linux-user/syscall-file.inc.c | 16 ++++++++++++++++
 linux-user/syscall.c          |  9 ---------
 linux-user/strace.list        |  3 ---
 5 files changed, 19 insertions(+), 25 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index f099d98fa3..de7a99f0c6 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -21,6 +21,9 @@ SYSCALL_DEF_FULL(brk, .impl = impl_brk,
                  .arg_type = { ARG_PTR });
 SYSCALL_DEF_ARGS(clone, ARG_CLONEFLAG, ARG_PTR, ARG_PTR, ARG_PTR, ARG_PTR);
 SYSCALL_DEF(close, ARG_DEC);
+#ifdef TARGET_NR_creat
+SYSCALL_DEF(creat, ARG_STR, ARG_MODEFLAG);
+#endif
 SYSCALL_DEF(exit, ARG_DEC);
 #ifdef TARGET_NR_fork
 SYSCALL_DEF(fork);
diff --git a/linux-user/strace.c b/linux-user/strace.c
index d7847e7cd6..5cb77223fd 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1183,19 +1183,6 @@ print_clock_adjtime(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_creat
-static void
-print_creat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_file_mode(arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_execv
 static void
 print_execv(const struct syscallname *name,
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 81423cfd64..62e1790e3b 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -24,6 +24,22 @@ SYSCALL_IMPL(close)
     return get_errno(close(fd));
 }
 
+#ifdef TARGET_NR_creat
+SYSCALL_IMPL(creat)
+{
+    char *p = lock_user_string(arg1);
+    abi_long ret;
+
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(creat(p, arg2));
+    fd_trans_unregister(ret);
+    unlock_user(p, arg1, 0);
+    return ret;
+}
+#endif
+
 /*
  * Helpers for do_openat, manipulating /proc/self/foo.
  */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8da92dd188..1e9478611c 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5330,15 +5330,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_creat /* not on alpha */
-    case TARGET_NR_creat:
-        if (!(p = lock_user_string(arg1)))
-            return -TARGET_EFAULT;
-        ret = get_errno(creat(p, arg2));
-        fd_trans_unregister(ret);
-        unlock_user(p, arg1, 0);
-        return ret;
-#endif
 #ifdef TARGET_NR_link
     case TARGET_NR_link:
         {
diff --git a/linux-user/strace.list b/linux-user/strace.list
index afa1521e2d..be0392810c 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -94,9 +94,6 @@
 #ifdef TARGET_NR_connect
 { TARGET_NR_connect, "connect" , "%s(%d,%#x,%d)", NULL, NULL },
 #endif
-#ifdef TARGET_NR_creat
-{ TARGET_NR_creat, "creat" , NULL, print_creat, NULL },
-#endif
 #ifdef TARGET_NR_create_module
 { TARGET_NR_create_module, "create_module" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 22/49] linux-user: Split out link, linkat
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (19 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 21/49] linux-user: Split out creat Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 23/49] linux-user: Split out unlink, unlinkat, rmdir Richard Henderson
                   ` (26 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that linkat is universally provided.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  4 ++++
 linux-user/strace.c           | 29 -----------------------------
 linux-user/syscall-file.inc.c | 28 ++++++++++++++++++++++++++++
 linux-user/syscall.c          | 32 --------------------------------
 linux-user/strace.list        |  6 ------
 5 files changed, 32 insertions(+), 67 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index de7a99f0c6..41dd887dbc 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -31,6 +31,10 @@ SYSCALL_DEF(fork);
 #ifdef TARGET_NR_ipc
 SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
 #endif
+#ifdef TARGET_NR_link
+SYSCALL_DEF(link, ARG_STR, ARG_STR);
+#endif
+SYSCALL_DEF(linkat, ARG_ATDIRFD, ARG_STR, ARG_ATDIRFD, ARG_STR, ARG_ATFLAG);
 SYSCALL_DEF(mlock, ARG_PTR, ARG_DEC);
 SYSCALL_DEF(mlockall, ARG_HEX);
 #ifdef TARGET_NR_mmap
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 5cb77223fd..5b78eb137b 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1357,35 +1357,6 @@ print_futimesat(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_link
-static void
-print_link(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_string(arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
-#ifdef TARGET_NR_linkat
-static void
-print_linkat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_at_dirfd(arg0, 0);
-    print_string(arg1, 0);
-    print_at_dirfd(arg2, 0);
-    print_string(arg3, 0);
-    print_flags(at_file_flags, arg4, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR__llseek
 static void
 print__llseek(const struct syscallname *name,
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 62e1790e3b..c6ca80955b 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -40,6 +40,34 @@ SYSCALL_IMPL(creat)
 }
 #endif
 
+static abi_long do_linkat(int olddirfd, abi_ulong target_oldpath,
+                          int newdirfd, abi_ulong target_newpath,
+                          int flags)
+{
+    char *oldpath = lock_user_string(target_oldpath);
+    char *newpath = lock_user_string(target_newpath);
+    abi_long ret = -TARGET_EFAULT;
+
+    if (oldpath && newpath) {
+        ret = get_errno(linkat(olddirfd, oldpath, newdirfd, newpath, flags));
+    }
+    unlock_user(oldpath, target_oldpath, 0);
+    unlock_user(newpath, target_newpath, 0);
+    return ret;
+}
+
+#ifdef TARGET_NR_link
+SYSCALL_IMPL(link)
+{
+    return do_linkat(AT_FDCWD, arg1, AT_FDCWD, arg2, 0);
+}
+#endif
+
+SYSCALL_IMPL(linkat)
+{
+    return do_linkat(arg1, arg2, arg3, arg4, arg5);
+}
+
 /*
  * Helpers for do_openat, manipulating /proc/self/foo.
  */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 1e9478611c..f1e8d06996 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5330,38 +5330,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_link
-    case TARGET_NR_link:
-        {
-            void * p2;
-            p = lock_user_string(arg1);
-            p2 = lock_user_string(arg2);
-            if (!p || !p2)
-                ret = -TARGET_EFAULT;
-            else
-                ret = get_errno(link(p, p2));
-            unlock_user(p2, arg2, 0);
-            unlock_user(p, arg1, 0);
-        }
-        return ret;
-#endif
-#if defined(TARGET_NR_linkat)
-    case TARGET_NR_linkat:
-        {
-            void * p2 = NULL;
-            if (!arg2 || !arg4)
-                return -TARGET_EFAULT;
-            p  = lock_user_string(arg2);
-            p2 = lock_user_string(arg4);
-            if (!p || !p2)
-                ret = -TARGET_EFAULT;
-            else
-                ret = get_errno(linkat(arg1, p, arg3, p2, arg5));
-            unlock_user(p, arg2, 0);
-            unlock_user(p2, arg4, 0);
-        }
-        return ret;
-#endif
 #ifdef TARGET_NR_unlink
     case TARGET_NR_unlink:
         if (!(p = lock_user_string(arg1)))
diff --git a/linux-user/strace.list b/linux-user/strace.list
index be0392810c..c369915759 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -461,12 +461,6 @@
 #ifdef TARGET_NR_lgetxattr
 { TARGET_NR_lgetxattr, "lgetxattr" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_link
-{ TARGET_NR_link, "link" , NULL, print_link, NULL },
-#endif
-#ifdef TARGET_NR_linkat
-{ TARGET_NR_linkat, "linkat" , NULL, print_linkat, NULL },
-#endif
 #ifdef TARGET_NR_Linux
 { TARGET_NR_Linux, "Linux" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 23/49] linux-user: Split out unlink, unlinkat, rmdir
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (20 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 22/49] linux-user: Split out link, linkat Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 24/49] linux-user: Split out execve Richard Henderson
                   ` (25 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that unlinkat is universally provided.
Implement rmdir in terms of unlinkat.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  7 ++++++
 linux-user/syscall.h          |  1 +
 linux-user/strace.c           | 43 ++++-------------------------------
 linux-user/syscall-file.inc.c | 32 ++++++++++++++++++++++++++
 linux-user/syscall.c          | 24 -------------------
 linux-user/strace.list        |  9 --------
 6 files changed, 44 insertions(+), 72 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 41dd887dbc..78d3f600eb 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -98,6 +98,9 @@ SYSCALL_DEF(readlink, ARG_STR, ARG_PTR, ARG_DEC);
 SYSCALL_DEF(readlinkat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_DEC);
 #endif
 SYSCALL_DEF(readv, ARG_DEC, ARG_PTR, ARG_DEC);
+#ifdef TARGET_NR_rmdir
+SYSCALL_DEF(rmdir, ARG_STR);
+#endif
 #if !defined(SYSCALL_TABLE) || defined(TARGET_NR_semctl)
 SYSCALL_DEF(semctl, ARG_DEC, ARG_DEC, ARG_DEC, ARG_HEX);
 #endif
@@ -121,6 +124,10 @@ SYSCALL_DEF(shmdt, ARG_PTR);
 #if !defined(SYSCALL_TABLE) || defined(TARGET_NR_shmget)
 SYSCALL_DEF(shmget, ARG_DEC, ARG_DEC, ARG_HEX);
 #endif
+#ifdef TARGET_NR_unlink
+SYSCALL_DEF(unlink, ARG_STR);
+#endif
+SYSCALL_DEF(unlinkat, ARG_ATDIRFD, ARG_STR, ARG_UNLINKATFLAG);
 #ifdef TARGET_NR_vfork
 /* Emulate vfork() with fork().  */
 SYSCALL_DEF_FULL(vfork, .impl = impl_fork);
diff --git a/linux-user/syscall.h b/linux-user/syscall.h
index f75cd3ddd0..bdc4d653c4 100644
--- a/linux-user/syscall.h
+++ b/linux-user/syscall.h
@@ -63,6 +63,7 @@ typedef enum {
     ARG_MMAPPROT,
     ARG_MODEFLAG,
     ARG_OPENFLAG,
+    ARG_UNLINKATFLAG,
 
     /* These are interpreted as pointers.  */
     ARG_PTR,
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 5b78eb137b..a41b6dcfe7 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -684,7 +684,7 @@ static struct flags const at_file_flags[] = {
     FLAG_END,
 };
 
-UNUSED static struct flags unlinkat_flags[] = {
+static struct flags const unlinkat_flags[] = {
 #ifdef AT_REMOVEDIR
     FLAG_GENERIC(AT_REMOVEDIR),
 #endif
@@ -1798,18 +1798,6 @@ print_mkdirat(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_rmdir
-static void
-print_rmdir(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_rt_sigaction
 static void
 print_rt_sigaction(const struct syscallname *name,
@@ -2175,32 +2163,6 @@ print_umount2(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_unlink
-static void
-print_unlink(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
-#ifdef TARGET_NR_unlinkat
-static void
-print_unlinkat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_at_dirfd(arg0, 0);
-    print_string(arg1, 0);
-    print_flags(unlinkat_flags, arg2, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_utime
 static void
 print_utime(const struct syscallname *name,
@@ -2463,6 +2425,9 @@ static void print_syscall_def1(const SyscallDef *def, int64_t args[6])
         case ARG_OPENFLAG:
             len = add_open_flags(b, rest, arg);
             break;
+        case ARG_UNLINKATFLAG:
+            len = add_flags(b, rest, unlinkat_flags, arg, true);
+            break;
         case ARG_PTR:
             len = add_pointer(b, rest, arg);
             break;
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index c6ca80955b..2dd57176b3 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -656,6 +656,38 @@ SYSCALL_IMPL(readlinkat)
 }
 #endif
 
+static abi_long do_unlinkat(int dirfd, abi_ulong target_path, int flags)
+{
+    char *p = lock_user_string(target_path);
+    abi_long ret;
+
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(unlinkat(dirfd, p, flags));
+    unlock_user(p, target_path, 0);
+    return ret;
+}
+
+#ifdef TARGET_NR_unlink
+SYSCALL_IMPL(unlink)
+{
+    return do_unlinkat(AT_FDCWD, arg1, 0);
+}
+#endif
+
+#ifdef TARGET_NR_rmdir
+SYSCALL_IMPL(rmdir)
+{
+    return do_unlinkat(AT_FDCWD, arg1, AT_REMOVEDIR);
+}
+#endif
+
+SYSCALL_IMPL(unlinkat)
+{
+    return do_unlinkat(arg1, arg2, arg3);
+}
+
 SYSCALL_IMPL(write)
 {
     int fd = arg1;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f1e8d06996..eda199d46f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5330,22 +5330,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_unlink
-    case TARGET_NR_unlink:
-        if (!(p = lock_user_string(arg1)))
-            return -TARGET_EFAULT;
-        ret = get_errno(unlink(p));
-        unlock_user(p, arg1, 0);
-        return ret;
-#endif
-#if defined(TARGET_NR_unlinkat)
-    case TARGET_NR_unlinkat:
-        if (!(p = lock_user_string(arg2)))
-            return -TARGET_EFAULT;
-        ret = get_errno(unlinkat(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
-        return ret;
-#endif
     case TARGET_NR_execve:
         {
             char **argp, **envp;
@@ -5737,14 +5721,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         ret = get_errno(mkdirat(arg1, p, arg3));
         unlock_user(p, arg2, 0);
         return ret;
-#endif
-#ifdef TARGET_NR_rmdir
-    case TARGET_NR_rmdir:
-        if (!(p = lock_user_string(arg1)))
-            return -TARGET_EFAULT;
-        ret = get_errno(rmdir(p));
-        unlock_user(p, arg1, 0);
-        return ret;
 #endif
     case TARGET_NR_dup:
         ret = get_errno(dup(arg1));
diff --git a/linux-user/strace.list b/linux-user/strace.list
index c369915759..faa0a9012d 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -527,9 +527,6 @@
 #ifdef TARGET_NR_mkdirat
 { TARGET_NR_mkdirat, "mkdirat" , NULL, print_mkdirat, NULL },
 #endif
-#ifdef TARGET_NR_rmdir
-{ TARGET_NR_rmdir, "rmdir" , NULL, print_rmdir, NULL },
-#endif
 #ifdef TARGET_NR_mknod
 { TARGET_NR_mknod, "mknod" , NULL, print_mknod, NULL },
 #endif
@@ -1425,12 +1422,6 @@
 #ifdef TARGET_NR_uname
 { TARGET_NR_uname, "uname" , "%s(%p)", NULL, NULL },
 #endif
-#ifdef TARGET_NR_unlink
-{ TARGET_NR_unlink, "unlink" , NULL, print_unlink, NULL },
-#endif
-#ifdef TARGET_NR_unlinkat
-{ TARGET_NR_unlinkat, "unlinkat" , NULL, print_unlinkat, NULL },
-#endif
 #ifdef TARGET_NR_unshare
 { TARGET_NR_unshare, "unshare" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 24/49] linux-user: Split out execve
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (21 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 23/49] linux-user: Split out unlink, unlinkat, rmdir Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 25/49] linux-user: Implement execveat Richard Henderson
                   ` (24 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |   1 +
 linux-user/strace.c           |  32 ----------
 linux-user/syscall-proc.inc.c | 110 ++++++++++++++++++++++++++++++++++
 linux-user/syscall.c          |  97 ------------------------------
 linux-user/strace.list        |   3 -
 5 files changed, 111 insertions(+), 132 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 78d3f600eb..58fef48666 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -25,6 +25,7 @@ SYSCALL_DEF(close, ARG_DEC);
 SYSCALL_DEF(creat, ARG_STR, ARG_MODEFLAG);
 #endif
 SYSCALL_DEF(exit, ARG_DEC);
+SYSCALL_DEF(execve, ARG_STR, ARG_PTR, ARG_PTR);
 #ifdef TARGET_NR_fork
 SYSCALL_DEF(fork);
 #endif
diff --git a/linux-user/strace.c b/linux-user/strace.c
index a41b6dcfe7..43865e9df9 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -568,38 +568,6 @@ print_newselect(const struct syscallname *name,
 }
 #endif
 
-static void
-print_execve(const struct syscallname *name,
-             abi_long arg1, abi_long arg2, abi_long arg3,
-             abi_long arg4, abi_long arg5, abi_long arg6)
-{
-    abi_ulong arg_ptr_addr;
-    char *s;
-
-    if (!(s = lock_user_string(arg1)))
-        return;
-    gemu_log("%s(\"%s\",{", name->name, s);
-    unlock_user(s, arg1, 0);
-
-    for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) {
-        abi_ulong *arg_ptr, arg_addr;
-
-        arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
-        if (!arg_ptr)
-            return;
-    arg_addr = tswapal(*arg_ptr);
-        unlock_user(arg_ptr, arg_ptr_addr, 0);
-        if (!arg_addr)
-            break;
-        if ((s = lock_user_string(arg_addr))) {
-            gemu_log("\"%s\",", s);
-            unlock_user(s, arg_addr, 0);
-        }
-    }
-
-    gemu_log("NULL})");
-}
-
 /*
  * Variants for the return value output function
  */
diff --git a/linux-user/syscall-proc.inc.c b/linux-user/syscall-proc.inc.c
index de4efed9f4..552aea60ae 100644
--- a/linux-user/syscall-proc.inc.c
+++ b/linux-user/syscall-proc.inc.c
@@ -269,6 +269,116 @@ SYSCALL_IMPL(clone)
     return do_clone(cpu_env, arg1, arg2, arg3, arg4, arg5);
 }
 
+SYSCALL_IMPL(execve)
+{
+    char **argp, **envp;
+    int argc, envc;
+    abi_ulong gp;
+    abi_ulong guest_path = arg1;
+    abi_ulong guest_argp = arg2;
+    abi_ulong guest_envp = arg3;
+    abi_ulong addr;
+    char **q, *p;
+    int total_size = 0;
+    abi_long ret = -TARGET_EFAULT;
+
+    argc = 0;
+    for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
+        if (get_user_ual(addr, gp)) {
+            goto execve_nofree;
+        }
+        if (!addr) {
+            break;
+        }
+        argc++;
+    }
+    envc = 0;
+    for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
+        if (get_user_ual(addr, gp)) {
+            goto execve_nofree;
+        }
+        if (!addr) {
+            break;
+        }
+        envc++;
+    }
+
+    argp = g_new0(char *, argc + 1);
+    envp = g_new0(char *, envc + 1);
+
+    for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) {
+        char *this_q;
+
+        if (get_user_ual(addr, gp)) {
+            goto execve_free;
+        }
+        if (!addr) {
+            break;
+        }
+        this_q = lock_user_string(addr);
+        if (!this_q) {
+            goto execve_free;
+        }
+        *q = this_q;
+        total_size += strlen(this_q) + 1;
+    }
+
+    for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) {
+        char *this_q;
+
+        if (get_user_ual(addr, gp)) {
+            goto execve_free;
+        }
+        if (!addr) {
+            break;
+        }
+        this_q = lock_user_string(addr);
+        if (!this_q) {
+            goto execve_free;
+        }
+        *q = this_q;
+        total_size += strlen(this_q) + 1;
+    }
+
+    p = lock_user_string(guest_path);
+    if (!p) {
+        goto execve_free;
+    }
+
+    /*
+     * Although execve() is not an interruptible syscall it is
+     * a special case where we must use the safe_syscall wrapper:
+     * if we allow a signal to happen before we make the host
+     * syscall then we will 'lose' it, because at the point of
+     * execve the process leaves QEMU's control. So we use the
+     * safe syscall wrapper to ensure that we either take the
+     * signal as a guest signal, or else it does not happen
+     * before the execve completes and makes it the other
+     * program's problem.
+     */
+    ret = get_errno(safe_execve(p, argp, envp));
+    unlock_user(p, guest_path, 0);
+
+ execve_free:
+    for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp) || !addr) {
+            break;
+        }
+        unlock_user(*q, addr, 0);
+    }
+    for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) {
+        if (get_user_ual(addr, gp) || !addr) {
+            break;
+        }
+        unlock_user(*q, addr, 0);
+    }
+    g_free(argp);
+    g_free(envp);
+
+ execve_nofree:
+    return ret;
+}
+
 SYSCALL_IMPL(exit)
 {
     CPUState *cpu = ENV_GET_CPU(cpu_env);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index eda199d46f..9b5b2eb7f1 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5330,103 +5330,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-    case TARGET_NR_execve:
-        {
-            char **argp, **envp;
-            int argc, envc;
-            abi_ulong gp;
-            abi_ulong guest_argp;
-            abi_ulong guest_envp;
-            abi_ulong addr;
-            char **q;
-            int total_size = 0;
-
-            argc = 0;
-            guest_argp = arg2;
-            for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
-                if (get_user_ual(addr, gp))
-                    return -TARGET_EFAULT;
-                if (!addr)
-                    break;
-                argc++;
-            }
-            envc = 0;
-            guest_envp = arg3;
-            for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
-                if (get_user_ual(addr, gp))
-                    return -TARGET_EFAULT;
-                if (!addr)
-                    break;
-                envc++;
-            }
-
-            argp = g_new0(char *, argc + 1);
-            envp = g_new0(char *, envc + 1);
-
-            for (gp = guest_argp, q = argp; gp;
-                  gp += sizeof(abi_ulong), q++) {
-                if (get_user_ual(addr, gp))
-                    goto execve_efault;
-                if (!addr)
-                    break;
-                if (!(*q = lock_user_string(addr)))
-                    goto execve_efault;
-                total_size += strlen(*q) + 1;
-            }
-            *q = NULL;
-
-            for (gp = guest_envp, q = envp; gp;
-                  gp += sizeof(abi_ulong), q++) {
-                if (get_user_ual(addr, gp))
-                    goto execve_efault;
-                if (!addr)
-                    break;
-                if (!(*q = lock_user_string(addr)))
-                    goto execve_efault;
-                total_size += strlen(*q) + 1;
-            }
-            *q = NULL;
-
-            if (!(p = lock_user_string(arg1)))
-                goto execve_efault;
-            /* Although execve() is not an interruptible syscall it is
-             * a special case where we must use the safe_syscall wrapper:
-             * if we allow a signal to happen before we make the host
-             * syscall then we will 'lose' it, because at the point of
-             * execve the process leaves QEMU's control. So we use the
-             * safe syscall wrapper to ensure that we either take the
-             * signal as a guest signal, or else it does not happen
-             * before the execve completes and makes it the other
-             * program's problem.
-             */
-            ret = get_errno(safe_execve(p, argp, envp));
-            unlock_user(p, arg1, 0);
-
-            goto execve_end;
-
-        execve_efault:
-            ret = -TARGET_EFAULT;
-
-        execve_end:
-            for (gp = guest_argp, q = argp; *q;
-                  gp += sizeof(abi_ulong), q++) {
-                if (get_user_ual(addr, gp)
-                    || !addr)
-                    break;
-                unlock_user(*q, addr, 0);
-            }
-            for (gp = guest_envp, q = envp; *q;
-                  gp += sizeof(abi_ulong), q++) {
-                if (get_user_ual(addr, gp)
-                    || !addr)
-                    break;
-                unlock_user(*q, addr, 0);
-            }
-
-            g_free(argp);
-            g_free(envp);
-        }
-        return ret;
     case TARGET_NR_chdir:
         if (!(p = lock_user_string(arg1)))
             return -TARGET_EFAULT;
diff --git a/linux-user/strace.list b/linux-user/strace.list
index faa0a9012d..8bc3fe6088 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -139,9 +139,6 @@
 #ifdef TARGET_NR_execv
 { TARGET_NR_execv, "execv" , NULL, print_execv, NULL },
 #endif
-#ifdef TARGET_NR_execve
-{ TARGET_NR_execve, "execve" , NULL, print_execve, NULL },
-#endif
 #ifdef TARGET_NR_execveat
 { TARGET_NR_execveat, "execveat" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 25/49] linux-user: Implement execveat
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (22 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 24/49] linux-user: Split out execve Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 26/49] linux-user: Split out chdir Richard Henderson
                   ` (23 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

A trivial extension to our current execve implementation
to support the new(ish) syscall.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  1 +
 linux-user/syscall-proc.inc.c | 19 ++++++++++++++-----
 linux-user/syscall.c          |  3 ++-
 linux-user/strace.list        |  3 ---
 4 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 58fef48666..392bd1579c 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -26,6 +26,7 @@ SYSCALL_DEF(creat, ARG_STR, ARG_MODEFLAG);
 #endif
 SYSCALL_DEF(exit, ARG_DEC);
 SYSCALL_DEF(execve, ARG_STR, ARG_PTR, ARG_PTR);
+SYSCALL_DEF(execveat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_PTR, ARG_ATFLAG);
 #ifdef TARGET_NR_fork
 SYSCALL_DEF(fork);
 #endif
diff --git a/linux-user/syscall-proc.inc.c b/linux-user/syscall-proc.inc.c
index 552aea60ae..699370c290 100644
--- a/linux-user/syscall-proc.inc.c
+++ b/linux-user/syscall-proc.inc.c
@@ -269,14 +269,13 @@ SYSCALL_IMPL(clone)
     return do_clone(cpu_env, arg1, arg2, arg3, arg4, arg5);
 }
 
-SYSCALL_IMPL(execve)
+static abi_long do_execveat(int dirfd, abi_ulong guest_path,
+                            abi_ulong guest_argp, abi_ulong guest_envp,
+                            int flags)
 {
     char **argp, **envp;
     int argc, envc;
     abi_ulong gp;
-    abi_ulong guest_path = arg1;
-    abi_ulong guest_argp = arg2;
-    abi_ulong guest_envp = arg3;
     abi_ulong addr;
     char **q, *p;
     int total_size = 0;
@@ -356,7 +355,7 @@ SYSCALL_IMPL(execve)
      * before the execve completes and makes it the other
      * program's problem.
      */
-    ret = get_errno(safe_execve(p, argp, envp));
+    ret = get_errno(safe_execveat(dirfd, p, argp, envp, flags));
     unlock_user(p, guest_path, 0);
 
  execve_free:
@@ -379,6 +378,16 @@ SYSCALL_IMPL(execve)
     return ret;
 }
 
+SYSCALL_IMPL(execve)
+{
+    return do_execveat(AT_FDCWD, arg1, arg2, arg3, 0);
+}
+
+SYSCALL_IMPL(execveat)
+{
+    return do_execveat(arg1, arg2, arg3, arg4, arg5);
+}
+
 SYSCALL_IMPL(exit)
 {
     CPUState *cpu = ENV_GET_CPU(cpu_env);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9b5b2eb7f1..3a027651e3 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -682,7 +682,8 @@ safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
               struct rusage *, rusage)
 safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
               int, options, struct rusage *, rusage)
-safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
+safe_syscall5(int, execveat, int, dirfd, const char *, filename,
+              char **, argv, char **, envp, int, flags)
 safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
               fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
 safe_syscall5(int, ppoll, struct pollfd *, ufds, unsigned int, nfds,
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 8bc3fe6088..202bfa8f9e 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -139,9 +139,6 @@
 #ifdef TARGET_NR_execv
 { TARGET_NR_execv, "execv" , NULL, print_execv, NULL },
 #endif
-#ifdef TARGET_NR_execveat
-{ TARGET_NR_execveat, "execveat" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_exec_with_loader
 { TARGET_NR_exec_with_loader, "exec_with_loader" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 26/49] linux-user: Split out chdir
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (23 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 25/49] linux-user: Implement execveat Richard Henderson
@ 2019-01-18 21:30 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 27/49] linux-user: Split out time Richard Henderson
                   ` (22 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that chdir is universally provided.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  1 +
 linux-user/strace.c           | 12 ------------
 linux-user/syscall-file.inc.c | 14 ++++++++++++++
 linux-user/syscall.c          |  6 ------
 linux-user/strace.list        |  3 ---
 5 files changed, 15 insertions(+), 21 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 392bd1579c..3fad9d51f0 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -19,6 +19,7 @@
 SYSCALL_DEF_FULL(brk, .impl = impl_brk,
                  .print_ret = print_syscall_ptr_ret,
                  .arg_type = { ARG_PTR });
+SYSCALL_DEF(chdir, ARG_STR);
 SYSCALL_DEF_ARGS(clone, ARG_CLONEFLAG, ARG_PTR, ARG_PTR, ARG_PTR, ARG_PTR);
 SYSCALL_DEF(close, ARG_DEC);
 #ifdef TARGET_NR_creat
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 43865e9df9..5133998c4f 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1113,18 +1113,6 @@ print_access(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_chdir
-static void
-print_chdir(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_chmod
 static void
 print_chmod(const struct syscallname *name,
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 2dd57176b3..7a4751d460 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -16,6 +16,20 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+SYSCALL_IMPL(chdir)
+{
+    abi_ulong target_path = arg1;
+    char *p = lock_user_string(target_path);
+    abi_long ret;
+
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(chdir(p));
+    unlock_user(p, target_path, 0);
+    return ret;
+}
+
 SYSCALL_IMPL(close)
 {
     int fd = arg1;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 3a027651e3..1cdc9727a9 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5331,12 +5331,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-    case TARGET_NR_chdir:
-        if (!(p = lock_user_string(arg1)))
-            return -TARGET_EFAULT;
-        ret = get_errno(chdir(p));
-        unlock_user(p, arg1, 0);
-        return ret;
 #ifdef TARGET_NR_time
     case TARGET_NR_time:
         {
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 202bfa8f9e..357984dd6f 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -61,9 +61,6 @@
 #ifdef TARGET_NR_capset
 { TARGET_NR_capset, "capset" , "%s(%p,%p)", NULL, NULL },
 #endif
-#ifdef TARGET_NR_chdir
-{ TARGET_NR_chdir, "chdir" , NULL, print_chdir, NULL },
-#endif
 #ifdef TARGET_NR_chmod
 { TARGET_NR_chmod, "chmod" , NULL, print_chmod, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 27/49] linux-user: Split out time
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (24 preceding siblings ...)
  2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 26/49] linux-user: Split out chdir Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 28/49] linux-user: Split out mknod, mknodat Richard Henderson
                   ` (21 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  3 +++
 linux-user/syscall-time.inc.c | 32 ++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 13 +------------
 linux-user/strace.list        |  3 ---
 4 files changed, 36 insertions(+), 15 deletions(-)
 create mode 100644 linux-user/syscall-time.inc.c

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 3fad9d51f0..9950b73e76 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -127,6 +127,9 @@ SYSCALL_DEF(shmdt, ARG_PTR);
 #if !defined(SYSCALL_TABLE) || defined(TARGET_NR_shmget)
 SYSCALL_DEF(shmget, ARG_DEC, ARG_DEC, ARG_HEX);
 #endif
+#ifdef TARGET_NR_time
+SYSCALL_DEF(time, ARG_PTR);
+#endif
 #ifdef TARGET_NR_unlink
 SYSCALL_DEF(unlink, ARG_STR);
 #endif
diff --git a/linux-user/syscall-time.inc.c b/linux-user/syscall-time.inc.c
new file mode 100644
index 0000000000..14fec88e47
--- /dev/null
+++ b/linux-user/syscall-time.inc.c
@@ -0,0 +1,32 @@
+/*
+ *  Linux time related syscalls
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef TARGET_NR_time
+SYSCALL_IMPL(time)
+{
+    time_t host_time;
+    abi_long ret = get_errno(time(&host_time));
+
+    if (!is_error(ret)
+        && arg1
+        && put_user_sal(host_time, arg1)) {
+        return -TARGET_EFAULT;
+    }
+    return ret;
+}
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 1cdc9727a9..cc5360ae43 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5331,18 +5331,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_time
-    case TARGET_NR_time:
-        {
-            time_t host_time;
-            ret = get_errno(time(&host_time));
-            if (!is_error(ret)
-                && arg1
-                && put_user_sal(host_time, arg1))
-                return -TARGET_EFAULT;
-        }
-        return ret;
-#endif
 #ifdef TARGET_NR_mknod
     case TARGET_NR_mknod:
         if (!(p = lock_user_string(arg1)))
@@ -9303,6 +9291,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
 #include "syscall-ipc.inc.c"
 #include "syscall-mem.inc.c"
 #include "syscall-proc.inc.c"
+#include "syscall-time.inc.c"
 
 #undef SYSCALL_IMPL
 #undef SYSCALL_ARGS
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 357984dd6f..3505014501 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1350,9 +1350,6 @@
 #ifdef TARGET_NR_tgkill
 { TARGET_NR_tgkill, "tgkill" , NULL, print_tgkill, NULL },
 #endif
-#ifdef TARGET_NR_time
-{ TARGET_NR_time, "time" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_timer_create
 { TARGET_NR_timer_create, "timer_create" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 28/49] linux-user: Split out mknod, mknodat
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (25 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 27/49] linux-user: Split out time Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 29/49] linux-user: Split out chmod, fchmod, fchmodat Richard Henderson
                   ` (20 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that mknodat is universally provided.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  4 ++++
 linux-user/strace.c           | 39 -----------------------------------
 linux-user/syscall-file.inc.c | 26 +++++++++++++++++++++++
 linux-user/syscall.c          | 16 --------------
 linux-user/strace.list        |  6 ------
 5 files changed, 30 insertions(+), 61 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 9950b73e76..b5951e6911 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -38,6 +38,10 @@ SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
 SYSCALL_DEF(link, ARG_STR, ARG_STR);
 #endif
 SYSCALL_DEF(linkat, ARG_ATDIRFD, ARG_STR, ARG_ATDIRFD, ARG_STR, ARG_ATFLAG);
+#ifdef TARGET_NR_mknod
+SYSCALL_DEF(mknod, ARG_STR, ARG_MODEFLAG, ARG_HEX);
+#endif
+SYSCALL_DEF(mknodat, ARG_ATDIRFD, ARG_STR, ARG_MODEFLAG, ARG_HEX);
 SYSCALL_DEF(mlock, ARG_PTR, ARG_DEC);
 SYSCALL_DEF(mlockall, ARG_HEX);
 #ifdef TARGET_NR_mmap
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 5133998c4f..668e6a4759 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1911,45 +1911,6 @@ print_syslog(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_mknod
-static void
-print_mknod(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    int hasdev = (arg1 & (S_IFCHR|S_IFBLK));
-
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_file_mode(arg1, (hasdev == 0));
-    if (hasdev) {
-        print_raw_param("makedev(%d", major(arg2), 0);
-        print_raw_param("%d)", minor(arg2), 1);
-    }
-    print_syscall_epilogue(name);
-}
-#endif
-
-#ifdef TARGET_NR_mknodat
-static void
-print_mknodat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    int hasdev = (arg2 & (S_IFCHR|S_IFBLK));
-
-    print_syscall_prologue(name);
-    print_at_dirfd(arg0, 0);
-    print_string(arg1, 0);
-    print_file_mode(arg2, (hasdev == 0));
-    if (hasdev) {
-        print_raw_param("makedev(%d", major(arg3), 0);
-        print_raw_param("%d)", minor(arg3), 1);
-    }
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_mq_open
 static void
 print_mq_open(const struct syscallname *name,
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 7a4751d460..3b5a79fe74 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -82,6 +82,32 @@ SYSCALL_IMPL(linkat)
     return do_linkat(arg1, arg2, arg3, arg4, arg5);
 }
 
+static abi_long do_mknodat(int dirfd, abi_ulong target_path,
+                           mode_t mode, dev_t dev)
+{
+    char *p = lock_user_string(target_path);
+    abi_long ret;
+
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(mknodat(dirfd, p, mode, dev));
+    unlock_user(p, target_path, 0);
+    return ret;
+}
+
+#ifdef TARGET_NR_mknod
+SYSCALL_IMPL(mknod)
+{
+    return do_mknodat(AT_FDCWD, arg1, arg2, arg3);
+}
+#endif
+
+SYSCALL_IMPL(mknodat)
+{
+    return do_mknodat(arg1, arg2, arg3, arg4);
+}
+
 /*
  * Helpers for do_openat, manipulating /proc/self/foo.
  */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index cc5360ae43..d46b4df677 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5331,22 +5331,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_mknod
-    case TARGET_NR_mknod:
-        if (!(p = lock_user_string(arg1)))
-            return -TARGET_EFAULT;
-        ret = get_errno(mknod(p, arg2, arg3));
-        unlock_user(p, arg1, 0);
-        return ret;
-#endif
-#if defined(TARGET_NR_mknodat)
-    case TARGET_NR_mknodat:
-        if (!(p = lock_user_string(arg2)))
-            return -TARGET_EFAULT;
-        ret = get_errno(mknodat(arg1, p, arg3, arg4));
-        unlock_user(p, arg2, 0);
-        return ret;
-#endif
 #ifdef TARGET_NR_chmod
     case TARGET_NR_chmod:
         if (!(p = lock_user_string(arg1)))
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 3505014501..adf8955278 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -518,12 +518,6 @@
 #ifdef TARGET_NR_mkdirat
 { TARGET_NR_mkdirat, "mkdirat" , NULL, print_mkdirat, NULL },
 #endif
-#ifdef TARGET_NR_mknod
-{ TARGET_NR_mknod, "mknod" , NULL, print_mknod, NULL },
-#endif
-#ifdef TARGET_NR_mknodat
-{ TARGET_NR_mknodat, "mknodat" , NULL, print_mknodat, NULL },
-#endif
 #ifdef TARGET_NR_modify_ldt
 { TARGET_NR_modify_ldt, "modify_ldt" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 29/49] linux-user: Split out chmod, fchmod, fchmodat
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (26 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 28/49] linux-user: Split out mknod, mknodat Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 30/49] linux-user: Split out lseek, llseek Richard Henderson
                   ` (19 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that fchmodat is universally provided.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  5 +++++
 linux-user/strace.c           | 28 ----------------------------
 linux-user/syscall-file.inc.c | 30 ++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 18 ------------------
 linux-user/strace.list        |  9 ---------
 5 files changed, 35 insertions(+), 55 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index b5951e6911..3ddf8aa0e3 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -20,6 +20,9 @@ SYSCALL_DEF_FULL(brk, .impl = impl_brk,
                  .print_ret = print_syscall_ptr_ret,
                  .arg_type = { ARG_PTR });
 SYSCALL_DEF(chdir, ARG_STR);
+#ifdef TARGET_NR_chmod
+SYSCALL_DEF(chmod, ARG_STR, ARG_MODEFLAG);
+#endif
 SYSCALL_DEF_ARGS(clone, ARG_CLONEFLAG, ARG_PTR, ARG_PTR, ARG_PTR, ARG_PTR);
 SYSCALL_DEF(close, ARG_DEC);
 #ifdef TARGET_NR_creat
@@ -28,6 +31,8 @@ SYSCALL_DEF(creat, ARG_STR, ARG_MODEFLAG);
 SYSCALL_DEF(exit, ARG_DEC);
 SYSCALL_DEF(execve, ARG_STR, ARG_PTR, ARG_PTR);
 SYSCALL_DEF(execveat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_PTR, ARG_ATFLAG);
+SYSCALL_DEF(fchmod, ARG_DEC, ARG_MODEFLAG);
+SYSCALL_DEF(fchmodat, ARG_ATDIRFD, ARG_STR, ARG_MODEFLAG);
 #ifdef TARGET_NR_fork
 SYSCALL_DEF(fork);
 #endif
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 668e6a4759..66d981b9e6 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1113,19 +1113,6 @@ print_access(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_chmod
-static void
-print_chmod(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_file_mode(arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_clock_adjtime
 static void
 print_clock_adjtime(const struct syscallname *name,
@@ -1167,21 +1154,6 @@ print_faccessat(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_fchmodat
-static void
-print_fchmodat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_at_dirfd(arg0, 0);
-    print_string(arg1, 0);
-    print_file_mode(arg2, 0);
-    print_flags(at_file_flags, arg3, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_fchownat
 static void
 print_fchownat(const struct syscallname *name,
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 3b5a79fe74..9844382166 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -30,6 +30,26 @@ SYSCALL_IMPL(chdir)
     return ret;
 }
 
+static abi_long do_fchmodat(int dirfd, abi_ulong target_path, mode_t mode)
+{
+    char *p = lock_user_string(target_path);
+    abi_long ret;
+
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(fchmodat(dirfd, p, mode, 0));
+    unlock_user(p, target_path, 0);
+    return ret;
+}
+
+#ifdef TARGET_NR_chmod
+SYSCALL_IMPL(chmod)
+{
+    return do_fchmodat(AT_FDCWD, arg1, arg2);
+}
+#endif
+
 SYSCALL_IMPL(close)
 {
     int fd = arg1;
@@ -54,6 +74,16 @@ SYSCALL_IMPL(creat)
 }
 #endif
 
+SYSCALL_IMPL(fchmod)
+{
+    return get_errno(fchmod(arg1, arg2));
+}
+
+SYSCALL_IMPL(fchmodat)
+{
+    return do_fchmodat(arg1, arg2, arg3);
+}
+
 static abi_long do_linkat(int olddirfd, abi_ulong target_oldpath,
                           int newdirfd, abi_ulong target_newpath,
                           int flags)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index d46b4df677..f9101d0b08 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5331,14 +5331,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_chmod
-    case TARGET_NR_chmod:
-        if (!(p = lock_user_string(arg1)))
-            return -TARGET_EFAULT;
-        ret = get_errno(chmod(p, arg2));
-        unlock_user(p, arg1, 0);
-        return ret;
-#endif
 #ifdef TARGET_NR_lseek
     case TARGET_NR_lseek:
         return get_errno(lseek(arg1, arg2, arg3));
@@ -6410,16 +6402,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
 #ifdef TARGET_NR_ftruncate
     case TARGET_NR_ftruncate:
         return get_errno(ftruncate(arg1, arg2));
-#endif
-    case TARGET_NR_fchmod:
-        return get_errno(fchmod(arg1, arg2));
-#if defined(TARGET_NR_fchmodat)
-    case TARGET_NR_fchmodat:
-        if (!(p = lock_user_string(arg2)))
-            return -TARGET_EFAULT;
-        ret = get_errno(fchmodat(arg1, p, arg3, 0));
-        unlock_user(p, arg2, 0);
-        return ret;
 #endif
     case TARGET_NR_getpriority:
         /* Note that negative values are valid for getpriority, so we must
diff --git a/linux-user/strace.list b/linux-user/strace.list
index adf8955278..92a86c682c 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -61,9 +61,6 @@
 #ifdef TARGET_NR_capset
 { TARGET_NR_capset, "capset" , "%s(%p,%p)", NULL, NULL },
 #endif
-#ifdef TARGET_NR_chmod
-{ TARGET_NR_chmod, "chmod" , NULL, print_chmod, NULL },
-#endif
 #ifdef TARGET_NR_chown
 { TARGET_NR_chown, "chown" , NULL, NULL, NULL },
 #endif
@@ -169,12 +166,6 @@
 #ifdef TARGET_NR_fchdir
 { TARGET_NR_fchdir, "fchdir" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_fchmod
-{ TARGET_NR_fchmod, "fchmod" , "%s(%d,%#o)", NULL, NULL },
-#endif
-#ifdef TARGET_NR_fchmodat
-{ TARGET_NR_fchmodat, "fchmodat" , NULL, print_fchmodat, NULL },
-#endif
 #ifdef TARGET_NR_fchown
 { TARGET_NR_fchown, "fchown" , "%s(%d,%d,%d)", NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 30/49] linux-user: Split out lseek, llseek
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (27 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 29/49] linux-user: Split out chmod, fchmod, fchmodat Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 31/49] linux-user: Split out getpid, getppid, getxpid Richard Henderson
                   ` (18 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Canonicalise the target syscall name on llseek (new kernels)
instead of _llseek (old kernels).  Always use host lseek(3)
rather than attempting to use the host llseek(2).

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  6 ++++++
 linux-user/syscall.h          |  1 +
 linux-user/strace.c           | 39 +++++++++++++++--------------------
 linux-user/syscall-file.inc.c | 36 ++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 32 ++--------------------------
 linux-user/strace.list        |  6 ------
 6 files changed, 62 insertions(+), 58 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 3ddf8aa0e3..3453e7afdf 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -43,6 +43,12 @@ SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
 SYSCALL_DEF(link, ARG_STR, ARG_STR);
 #endif
 SYSCALL_DEF(linkat, ARG_ATDIRFD, ARG_STR, ARG_ATDIRFD, ARG_STR, ARG_ATFLAG);
+#ifdef TARGET_NR_lseek
+SYSCALL_DEF(lseek, ARG_DEC, ARG_DEC, ARG_LSEEKWHENCE);
+#endif
+#ifdef TARGET_NR_llseek
+SYSCALL_DEF_ARGS(llseek, ARG_DEC, ARG_DEC, ARG_PTR, ARG_LSEEKWHENCE);
+#endif
 #ifdef TARGET_NR_mknod
 SYSCALL_DEF(mknod, ARG_STR, ARG_MODEFLAG, ARG_HEX);
 #endif
diff --git a/linux-user/syscall.h b/linux-user/syscall.h
index bdc4d653c4..c16c0a3f1e 100644
--- a/linux-user/syscall.h
+++ b/linux-user/syscall.h
@@ -64,6 +64,7 @@ typedef enum {
     ARG_MODEFLAG,
     ARG_OPENFLAG,
     ARG_UNLINKATFLAG,
+    ARG_LSEEKWHENCE,
 
     /* These are interpreted as pointers.  */
     ARG_PTR,
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 66d981b9e6..c08dbdff0c 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -934,6 +934,20 @@ print_open_flags(abi_long flags, int last)
     gemu_log("%s%s", buf, get_comma(last));
 }
 
+static int add_lseek_whence(char *buf, int size, int whence)
+{
+    switch (whence) {
+    case SEEK_SET:
+        return snprintf(buf, size, "SEEK_SET");
+    case SEEK_CUR:
+        return snprintf(buf, size, "SEEK_CUR");
+    case SEEK_END:
+        return snprintf(buf, size, "SEEK_END");
+    default:
+        return snprintf(buf, size, "%#x", whence);
+    }
+}
+
 static void
 print_syscall_prologue(const struct syscallname *sc)
 {
@@ -1285,28 +1299,6 @@ print_futimesat(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR__llseek
-static void
-print__llseek(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    const char *whence = "UNKNOWN";
-    print_syscall_prologue(name);
-    print_raw_param("%d", arg0, 0);
-    print_raw_param("%ld", arg1, 0);
-    print_raw_param("%ld", arg2, 0);
-    print_pointer(arg3, 0);
-    switch(arg4) {
-    case SEEK_SET: whence = "SEEK_SET"; break;
-    case SEEK_CUR: whence = "SEEK_CUR"; break;
-    case SEEK_END: whence = "SEEK_END"; break;
-    }
-    gemu_log("%s",whence);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #if defined(TARGET_NR_socket)
 static void
 print_socket(const struct syscallname *name,
@@ -2317,6 +2309,9 @@ static void print_syscall_def1(const SyscallDef *def, int64_t args[6])
         case ARG_UNLINKATFLAG:
             len = add_flags(b, rest, unlinkat_flags, arg, true);
             break;
+        case ARG_LSEEKWHENCE:
+            len = add_lseek_whence(b, rest, arg);
+            break;
         case ARG_PTR:
             len = add_pointer(b, rest, arg);
             break;
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 9844382166..e23d21bdfc 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -112,6 +112,42 @@ SYSCALL_IMPL(linkat)
     return do_linkat(arg1, arg2, arg3, arg4, arg5);
 }
 
+#ifdef TARGET_NR_lseek
+SYSCALL_IMPL(lseek)
+{
+    return get_errno(lseek(arg1, arg2, arg3));
+}
+#endif
+
+#ifdef TARGET_NR_llseek
+SYSCALL_ARGS(llseek)
+{
+    /* The parts for offset are *always* in big-endian order.  */
+    abi_ulong lo = in[2], hi = in[1];
+    out[1] = (((uint64_t)hi << (TARGET_ABI_BITS - 1)) << 1) | lo;
+    out[2] = in[3];
+    out[3] = in[4];
+    return def;
+}
+
+SYSCALL_IMPL(llseek)
+{
+    int fd = arg1;
+    int64_t offset = arg2;
+    abi_ulong target_res = arg3;
+    int whence = arg4;
+
+    off_t res = lseek(fd, offset, whence);
+
+    if (res == -1) {
+        return get_errno(-1);
+    } else if (put_user_s64(res, target_res)) {
+        return -TARGET_EFAULT;
+    }
+    return 0;
+}
+#endif
+
 static abi_long do_mknodat(int dirfd, abi_ulong target_path,
                            mode_t mode, dev_t dev)
 {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f9101d0b08..09fcec7812 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -195,8 +195,8 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,	\
 #endif
 
 /* Newer kernel ports have llseek() instead of _llseek() */
-#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
-#define TARGET_NR__llseek TARGET_NR_llseek
+#if !defined(TARGET_NR_llseek) && defined(TARGET_NR__llseek)
+#define TARGET_NR_llseek TARGET_NR__llseek
 #endif
 
 #ifdef __NR_gettid
@@ -227,10 +227,6 @@ _syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count)
     (defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
 _syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
 #endif
-#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
-_syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
-          loff_t *, res, uint, wh);
-#endif
 _syscall3(int, sys_rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t *, uinfo)
 _syscall4(int, sys_rt_tgsigqueueinfo, pid_t, pid, pid_t, tid, int, sig,
           siginfo_t *, uinfo)
@@ -5331,10 +5327,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_lseek
-    case TARGET_NR_lseek:
-        return get_errno(lseek(arg1, arg2, arg3));
-#endif
 #if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
     /* Alpha specific */
     case TARGET_NR_getxpid:
@@ -6833,26 +6825,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         return get_errno(fchdir(arg1));
     case TARGET_NR_personality:
         return get_errno(personality(arg1));
-#ifdef TARGET_NR__llseek /* Not on alpha */
-    case TARGET_NR__llseek:
-        {
-            int64_t res;
-#if !defined(__NR_llseek)
-            res = lseek(arg1, ((uint64_t)arg2 << 32) | (abi_ulong)arg3, arg5);
-            if (res == -1) {
-                ret = get_errno(res);
-            } else {
-                ret = 0;
-            }
-#else
-            ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
-#endif
-            if ((ret == 0) && put_user_s64(res, arg4)) {
-                return -TARGET_EFAULT;
-            }
-        }
-        return ret;
-#endif
 #ifdef TARGET_NR_getdents
     case TARGET_NR_getdents:
 #ifdef EMULATE_GETDENTS_WITH_GETDENTS
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 92a86c682c..18c93ccc2d 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -455,9 +455,6 @@
 #ifdef TARGET_NR_llistxattr
 { TARGET_NR_llistxattr, "llistxattr" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR__llseek
-{ TARGET_NR__llseek, "_llseek" , NULL, print__llseek, NULL },
-#endif
 #ifdef TARGET_NR_lock
 { TARGET_NR_lock, "lock" , NULL, NULL, NULL },
 #endif
@@ -467,9 +464,6 @@
 #ifdef TARGET_NR_lremovexattr
 { TARGET_NR_lremovexattr, "lremovexattr" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_lseek
-{ TARGET_NR_lseek, "lseek" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_lsetxattr
 { TARGET_NR_lsetxattr, "lsetxattr" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 31/49] linux-user: Split out getpid, getppid, getxpid
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (28 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 30/49] linux-user: Split out lseek, llseek Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 32/49] linux-user: Split out mount Richard Henderson
                   ` (17 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  9 +++++++++
 linux-user/syscall-proc.inc.c | 23 +++++++++++++++++++++++
 linux-user/syscall.c          | 14 --------------
 linux-user/strace.list        |  9 ---------
 4 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 3453e7afdf..d163bbf409 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -36,6 +36,15 @@ SYSCALL_DEF(fchmodat, ARG_ATDIRFD, ARG_STR, ARG_MODEFLAG);
 #ifdef TARGET_NR_fork
 SYSCALL_DEF(fork);
 #endif
+#ifdef TARGET_NR_getpid
+SYSCALL_DEF(getpid);
+#endif
+#ifdef TARGET_NR_getppid
+SYSCALL_DEF(getppid);
+#endif
+#ifdef TARGET_NR_getxpid
+SYSCALL_DEF(getxpid);
+#endif
 #ifdef TARGET_NR_ipc
 SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
 #endif
diff --git a/linux-user/syscall-proc.inc.c b/linux-user/syscall-proc.inc.c
index 699370c290..c09c83775c 100644
--- a/linux-user/syscall-proc.inc.c
+++ b/linux-user/syscall-proc.inc.c
@@ -438,6 +438,29 @@ SYSCALL_IMPL(fork)
 }
 #endif
 
+#ifdef TARGET_NR_getpid
+SYSCALL_IMPL(getpid)
+{
+    return getpid();
+}
+#endif
+
+#ifdef TARGET_NR_getppid
+SYSCALL_IMPL(getppid)
+{
+    return getppid();
+}
+#endif
+
+#ifdef TARGET_NR_getxpid
+SYSCALL_IMPL(getxpid)
+{
+    /* Alpha specific */
+    cpu_env->ir[IR_A4] = getppid();
+    return getpid();
+}
+#endif
+
 /*
  * Map host to target signal numbers for the wait family of syscalls.
  * Assume all other status bits are the same.
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 09fcec7812..6ea1a67345 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5327,16 +5327,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
-    /* Alpha specific */
-    case TARGET_NR_getxpid:
-        ((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
-        return get_errno(getpid());
-#endif
-#ifdef TARGET_NR_getpid
-    case TARGET_NR_getpid:
-        return get_errno(getpid());
-#endif
     case TARGET_NR_mount:
         {
             /* need to look at the data field */
@@ -5668,10 +5658,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         return ret;
     }
 #endif
-#ifdef TARGET_NR_getppid /* not on alpha */
-    case TARGET_NR_getppid:
-        return get_errno(getppid());
-#endif
 #ifdef TARGET_NR_getpgrp
     case TARGET_NR_getpgrp:
         return get_errno(getpgrp());
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 18c93ccc2d..344a2232d6 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -298,15 +298,9 @@
 #ifdef TARGET_NR_getpgrp
 { TARGET_NR_getpgrp, "getpgrp" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_getpid
-{ TARGET_NR_getpid, "getpid" , "%s()", NULL, NULL },
-#endif
 #ifdef TARGET_NR_getpmsg
 { TARGET_NR_getpmsg, "getpmsg" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_getppid
-{ TARGET_NR_getppid, "getppid" , "%s()", NULL, NULL },
-#endif
 #ifdef TARGET_NR_getpriority
 { TARGET_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL },
 #endif
@@ -365,9 +359,6 @@
 #ifdef TARGET_NR_getxgid
 { TARGET_NR_getxgid, "getxgid" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_getxpid
-{ TARGET_NR_getxpid, "getxpid" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_getxuid
 { TARGET_NR_getxuid, "getxuid" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 32/49] linux-user: Split out mount
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (29 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 31/49] linux-user: Split out getpid, getppid, getxpid Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 33/49] linux-user: Split out umount, umount2 Richard Henderson
                   ` (16 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  1 +
 linux-user/syscall.h          |  1 +
 linux-user/strace.c           | 21 +++----------
 linux-user/syscall-file.inc.c | 48 ++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 55 -----------------------------------
 linux-user/strace.list        |  3 --
 6 files changed, 54 insertions(+), 75 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index d163bbf409..2b331c6a6d 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -78,6 +78,7 @@ SYSCALL_DEF_FULL(mmap2, .impl = impl_mmap,
                  .arg_type = { ARG_PTR, ARG_DEC, ARG_MMAPPROT,
                                ARG_MMAPFLAG, ARG_DEC, ARG_DEC64 });
 #endif
+SYSCALL_DEF(mount, ARG_STR, ARG_STR, ARG_STR, ARG_MOUNTFLAG, ARG_PTR);
 SYSCALL_DEF(mprotect, ARG_PTR, ARG_DEC, ARG_MMAPPROT);
 SYSCALL_DEF_FULL(mremap, .impl = impl_mremap,
                  .print_ret = print_syscall_ptr_ret,
diff --git a/linux-user/syscall.h b/linux-user/syscall.h
index c16c0a3f1e..35dd3e5fa3 100644
--- a/linux-user/syscall.h
+++ b/linux-user/syscall.h
@@ -62,6 +62,7 @@ typedef enum {
     ARG_MMAPFLAG,
     ARG_MMAPPROT,
     ARG_MODEFLAG,
+    ARG_MOUNTFLAG,
     ARG_OPENFLAG,
     ARG_UNLINKATFLAG,
     ARG_LSEEKWHENCE,
diff --git a/linux-user/strace.c b/linux-user/strace.c
index c08dbdff0c..eb02430eba 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -708,7 +708,7 @@ static struct flags const open_flags[] = {
     FLAG_END,
 };
 
-UNUSED static struct flags mount_flags[] = {
+static struct flags const mount_flags[] = {
 #ifdef MS_BIND
     FLAG_GENERIC(MS_BIND),
 #endif
@@ -2003,22 +2003,6 @@ print_symlinkat(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_mount
-static void
-print_mount(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_string(arg1, 0);
-    print_string(arg2, 0);
-    print_flags(mount_flags, arg3, 0);
-    print_pointer(arg4, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_umount
 static void
 print_umount(const struct syscallname *name,
@@ -2303,6 +2287,9 @@ static void print_syscall_def1(const SyscallDef *def, int64_t args[6])
         case ARG_MODEFLAG:
             len = add_flags(b, rest, mode_flags, arg, true);
             break;
+        case ARG_MOUNTFLAG:
+            len = add_flags(b, rest, mount_flags, arg, true);
+            break;
         case ARG_OPENFLAG:
             len = add_open_flags(b, rest, arg);
             break;
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index e23d21bdfc..d7eb72cc31 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -174,6 +174,54 @@ SYSCALL_IMPL(mknodat)
     return do_mknodat(arg1, arg2, arg3, arg4);
 }
 
+SYSCALL_IMPL(mount)
+{
+    abi_ulong target_src = arg1;
+    abi_ulong target_tgt = arg2;
+    abi_ulong target_fst = arg3;
+    abi_ulong mountflags = arg4;
+    abi_ulong target_data = arg5;
+    char *p_src = NULL, *p_tgt = NULL, *p_fst = NULL, *p_data = NULL;
+    abi_long ret = -TARGET_EFAULT;
+
+    if (target_src) {
+        p_src = lock_user_string(target_src);
+        if (!p_src) {
+            goto exit0;
+        }
+    }
+
+    p_tgt = lock_user_string(target_tgt);
+    if (!p_tgt) {
+        goto exit1;
+    }
+
+    if (target_fst) {
+        p_fst = lock_user_string(target_fst);
+        if (!p_fst) {
+            goto exit2;
+        }
+    }
+
+    /*
+     * FIXME - arg5 should be locked, but it isn't clear how to
+     * do that since it's not guaranteed to be a NULL-terminated
+     * string.
+     */
+    if (target_data) {
+        p_data = g2h(target_data);
+    }
+    ret = get_errno(mount(p_src, p_tgt, p_fst, mountflags, p_data));
+
+    unlock_user(p_fst, target_fst, 0);
+ exit2:
+    unlock_user(p_tgt, target_tgt, 0);
+ exit1:
+    unlock_user(p_src, target_src, 0);
+ exit0:
+    return ret;
+}
+
 /*
  * Helpers for do_openat, manipulating /proc/self/foo.
  */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 6ea1a67345..39e749a985 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5327,61 +5327,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-    case TARGET_NR_mount:
-        {
-            /* need to look at the data field */
-            void *p2, *p3;
-
-            if (arg1) {
-                p = lock_user_string(arg1);
-                if (!p) {
-                    return -TARGET_EFAULT;
-                }
-            } else {
-                p = NULL;
-            }
-
-            p2 = lock_user_string(arg2);
-            if (!p2) {
-                if (arg1) {
-                    unlock_user(p, arg1, 0);
-                }
-                return -TARGET_EFAULT;
-            }
-
-            if (arg3) {
-                p3 = lock_user_string(arg3);
-                if (!p3) {
-                    if (arg1) {
-                        unlock_user(p, arg1, 0);
-                    }
-                    unlock_user(p2, arg2, 0);
-                    return -TARGET_EFAULT;
-                }
-            } else {
-                p3 = NULL;
-            }
-
-            /* FIXME - arg5 should be locked, but it isn't clear how to
-             * do that since it's not guaranteed to be a NULL-terminated
-             * string.
-             */
-            if (!arg5) {
-                ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
-            } else {
-                ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
-            }
-            ret = get_errno(ret);
-
-            if (arg1) {
-                unlock_user(p, arg1, 0);
-            }
-            unlock_user(p2, arg2, 0);
-            if (arg3) {
-                unlock_user(p3, arg3, 0);
-            }
-        }
-        return ret;
 #ifdef TARGET_NR_umount
     case TARGET_NR_umount:
         if (!(p = lock_user_string(arg1)))
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 344a2232d6..5f07e0e23d 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -497,9 +497,6 @@
 #ifdef TARGET_NR_modify_ldt
 { TARGET_NR_modify_ldt, "modify_ldt" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_mount
-{ TARGET_NR_mount, "mount" , NULL, print_mount, NULL },
-#endif
 #ifdef TARGET_NR_move_pages
 { TARGET_NR_move_pages, "move_pages" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 33/49] linux-user: Split out umount, umount2
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (30 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 32/49] linux-user: Split out mount Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 34/49] linux-user: Split out stime Richard Henderson
                   ` (15 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that umount2 is unconditionally available.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  4 ++++
 linux-user/syscall.h          |  1 +
 linux-user/strace.c           | 30 ++++--------------------------
 linux-user/syscall-file.inc.c | 25 +++++++++++++++++++++++++
 linux-user/syscall.c          | 16 ----------------
 linux-user/strace.list        |  6 ------
 6 files changed, 34 insertions(+), 48 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 2b331c6a6d..0d8da0c6d6 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -155,6 +155,10 @@ SYSCALL_DEF(shmget, ARG_DEC, ARG_DEC, ARG_HEX);
 #ifdef TARGET_NR_time
 SYSCALL_DEF(time, ARG_PTR);
 #endif
+#ifdef TARGET_NR_umount
+SYSCALL_DEF(umount, ARG_STR);
+#endif
+SYSCALL_DEF(umount2, ARG_STR, ARG_UMOUNTFLAG);
 #ifdef TARGET_NR_unlink
 SYSCALL_DEF(unlink, ARG_STR);
 #endif
diff --git a/linux-user/syscall.h b/linux-user/syscall.h
index 35dd3e5fa3..3c936b648a 100644
--- a/linux-user/syscall.h
+++ b/linux-user/syscall.h
@@ -64,6 +64,7 @@ typedef enum {
     ARG_MODEFLAG,
     ARG_MOUNTFLAG,
     ARG_OPENFLAG,
+    ARG_UMOUNTFLAG,
     ARG_UNLINKATFLAG,
     ARG_LSEEKWHENCE,
 
diff --git a/linux-user/strace.c b/linux-user/strace.c
index eb02430eba..78781b8817 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -733,7 +733,7 @@ static struct flags const mount_flags[] = {
     FLAG_END,
 };
 
-UNUSED static struct flags umount2_flags[] = {
+static struct flags const umount2_flags[] = {
 #ifdef MNT_FORCE
     FLAG_GENERIC(MNT_FORCE),
 #endif
@@ -2003,31 +2003,6 @@ print_symlinkat(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_umount
-static void
-print_umount(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
-#ifdef TARGET_NR_umount2
-static void
-print_umount2(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_flags(umount2_flags, arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_utime
 static void
 print_utime(const struct syscallname *name,
@@ -2293,6 +2268,9 @@ static void print_syscall_def1(const SyscallDef *def, int64_t args[6])
         case ARG_OPENFLAG:
             len = add_open_flags(b, rest, arg);
             break;
+        case ARG_UMOUNTFLAG:
+            len = add_flags(b, rest, umount2_flags, arg, false);
+            break;
         case ARG_UNLINKATFLAG:
             len = add_flags(b, rest, unlinkat_flags, arg, true);
             break;
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index d7eb72cc31..7ec1c26347 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -810,6 +810,31 @@ SYSCALL_IMPL(readlinkat)
 }
 #endif
 
+static abi_long do_umount2(abi_ulong target_path, int flags)
+{
+    char *p = lock_user_string(target_path);
+    abi_long ret;
+
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(umount2(p, flags));
+    unlock_user(p, target_path, 0);
+    return ret;
+}
+
+#ifdef TARGET_NR_umount
+SYSCALL_IMPL(umount)
+{
+    return do_umount2(arg1, 0);
+}
+#endif
+
+SYSCALL_IMPL(umount2)
+{
+    return do_umount2(arg1, arg2);
+}
+
 static abi_long do_unlinkat(int dirfd, abi_ulong target_path, int flags)
 {
     char *p = lock_user_string(target_path);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 39e749a985..b35d84794f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5327,14 +5327,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_umount
-    case TARGET_NR_umount:
-        if (!(p = lock_user_string(arg1)))
-            return -TARGET_EFAULT;
-        ret = get_errno(umount(p));
-        unlock_user(p, arg1, 0);
-        return ret;
-#endif
 #ifdef TARGET_NR_stime /* not on alpha */
     case TARGET_NR_stime:
         {
@@ -5555,14 +5547,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
             unlock_user(p, arg1, 0);
         }
         return ret;
-#ifdef TARGET_NR_umount2
-    case TARGET_NR_umount2:
-        if (!(p = lock_user_string(arg1)))
-            return -TARGET_EFAULT;
-        ret = get_errno(umount2(p, arg2));
-        unlock_user(p, arg1, 0);
-        return ret;
-#endif
     case TARGET_NR_ioctl:
         return do_ioctl(arg1, arg2, arg3);
 #ifdef TARGET_NR_fcntl
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 5f07e0e23d..0f32c456cd 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1368,12 +1368,6 @@
 #ifdef TARGET_NR_umask
 { TARGET_NR_umask, "umask" , "%s(%#o)", NULL, NULL },
 #endif
-#ifdef TARGET_NR_umount
-{ TARGET_NR_umount, "umount" , NULL, print_umount, NULL },
-#endif
-#ifdef TARGET_NR_umount2
-{ TARGET_NR_umount2, "umount2" , NULL, print_umount2, NULL },
-#endif
 #ifdef TARGET_NR_uname
 { TARGET_NR_uname, "uname" , "%s(%p)", NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 34/49] linux-user: Split out stime
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (31 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 33/49] linux-user: Split out umount, umount2 Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 35/49] linux-user: Split out alarm, pause Richard Henderson
                   ` (14 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  3 +++
 linux-user/syscall-time.inc.c | 12 ++++++++++++
 linux-user/syscall.c          |  9 ---------
 linux-user/strace.list        |  3 ---
 4 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 0d8da0c6d6..6ca82af397 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -152,6 +152,9 @@ SYSCALL_DEF(shmdt, ARG_PTR);
 #if !defined(SYSCALL_TABLE) || defined(TARGET_NR_shmget)
 SYSCALL_DEF(shmget, ARG_DEC, ARG_DEC, ARG_HEX);
 #endif
+#ifdef TARGET_NR_stime
+SYSCALL_DEF(stime, ARG_PTR);
+#endif
 #ifdef TARGET_NR_time
 SYSCALL_DEF(time, ARG_PTR);
 #endif
diff --git a/linux-user/syscall-time.inc.c b/linux-user/syscall-time.inc.c
index 14fec88e47..d1fb72bde0 100644
--- a/linux-user/syscall-time.inc.c
+++ b/linux-user/syscall-time.inc.c
@@ -16,6 +16,18 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#ifdef TARGET_NR_stime
+SYSCALL_IMPL(stime)
+{
+    time_t host_time;
+
+    if (get_user_sal(host_time, arg1)) {
+        return -TARGET_EFAULT;
+    }
+    return get_errno(stime(&host_time));
+}
+#endif
+
 #ifdef TARGET_NR_time
 SYSCALL_IMPL(time)
 {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index b35d84794f..c0ce4068b6 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5327,15 +5327,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_stime /* not on alpha */
-    case TARGET_NR_stime:
-        {
-            time_t host_time;
-            if (get_user_sal(host_time, arg1))
-                return -TARGET_EFAULT;
-            return get_errno(stime(&host_time));
-        }
-#endif
 #ifdef TARGET_NR_alarm /* not on alpha */
     case TARGET_NR_alarm:
         return alarm(arg1);
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 0f32c456cd..a5f308c497 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1254,9 +1254,6 @@
 #ifdef TARGET_NR_statfs64
 { TARGET_NR_statfs64, "statfs64" , NULL, print_statfs64, NULL },
 #endif
-#ifdef TARGET_NR_stime
-{ TARGET_NR_stime, "stime" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_streams1
 { TARGET_NR_streams1, "streams1" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 35/49] linux-user: Split out alarm, pause
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (32 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 34/49] linux-user: Split out stime Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 36/49] linux-user: Split out utime, utimes, futimesat Richard Henderson
                   ` (13 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h    |  6 ++++++
 linux-user/syscall-sig.inc.c | 36 ++++++++++++++++++++++++++++++++++++
 linux-user/syscall.c         | 12 +-----------
 linux-user/strace.list       |  6 ------
 4 files changed, 43 insertions(+), 17 deletions(-)
 create mode 100644 linux-user/syscall-sig.inc.c

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 6ca82af397..9d0dd7457b 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -16,6 +16,9 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#ifdef TARGET_NR_alarm
+SYSCALL_DEF(alarm, ARG_DEC);
+#endif
 SYSCALL_DEF_FULL(brk, .impl = impl_brk,
                  .print_ret = print_syscall_ptr_ret,
                  .arg_type = { ARG_PTR });
@@ -106,6 +109,9 @@ SYSCALL_DEF(open, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
 #endif
 SYSCALL_DEF(openat, ARG_ATDIRFD, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
 SYSCALL_DEF(open_by_handle_at, ARG_DEC, ARG_PTR, ARG_OPENFLAG);
+#ifdef TARGET_NR_pause
+SYSCALL_DEF(pause);
+#endif
 SYSCALL_DEF_FULL(pread64, .impl = impl_pread64,
                  .args = args_pread64_pwrite64,
                  .arg_type = { ARG_DEC, ARG_PTR, ARG_DEC, ARG_DEC64 });
diff --git a/linux-user/syscall-sig.inc.c b/linux-user/syscall-sig.inc.c
new file mode 100644
index 0000000000..f4e43eb00e
--- /dev/null
+++ b/linux-user/syscall-sig.inc.c
@@ -0,0 +1,36 @@
+/*
+ *  Linux signal related syscalls
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef TARGET_NR_alarm
+SYSCALL_IMPL(alarm)
+{
+    return alarm(arg1);
+}
+#endif
+
+#ifdef TARGET_NR_pause
+SYSCALL_IMPL(pause)
+{
+    if (!block_signals()) {
+        CPUState *cpu = ENV_GET_CPU(cpu_env);
+        TaskState *ts = cpu->opaque;
+        sigsuspend(&ts->signal_mask);
+    }
+    return -TARGET_EINTR;
+}
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c0ce4068b6..f3ea9600c8 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5327,17 +5327,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_alarm /* not on alpha */
-    case TARGET_NR_alarm:
-        return alarm(arg1);
-#endif
-#ifdef TARGET_NR_pause /* not on alpha */
-    case TARGET_NR_pause:
-        if (!block_signals()) {
-            sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
-        }
-        return -TARGET_EINTR;
-#endif
 #ifdef TARGET_NR_utime
     case TARGET_NR_utime:
         {
@@ -9135,6 +9124,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
 #include "syscall-ipc.inc.c"
 #include "syscall-mem.inc.c"
 #include "syscall-proc.inc.c"
+#include "syscall-sig.inc.c"
 #include "syscall-time.inc.c"
 
 #undef SYSCALL_IMPL
diff --git a/linux-user/strace.list b/linux-user/strace.list
index a5f308c497..b119b7a20c 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -25,9 +25,6 @@
 #ifdef TARGET_NR_afs_syscall
 { TARGET_NR_afs_syscall, "afs_syscall" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_alarm
-{ TARGET_NR_alarm, "alarm" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_aplib
 { TARGET_NR_aplib, "aplib" , NULL, NULL, NULL },
 #endif
@@ -872,9 +869,6 @@
 #ifdef TARGET_NR_osf_waitid
 { TARGET_NR_osf_waitid, "osf_waitid" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_pause
-{ TARGET_NR_pause, "pause" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_pciconfig_iobase
 { TARGET_NR_pciconfig_iobase, "pciconfig_iobase" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 36/49] linux-user: Split out utime, utimes, futimesat
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (33 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 35/49] linux-user: Split out alarm, pause Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 37/49] linux-user: Split out access, faccessat Richard Henderson
                   ` (12 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  9 ++++
 linux-user/strace.c           | 41 ---------------
 linux-user/syscall-file.inc.c | 95 +++++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 63 -----------------------
 linux-user/strace.list        |  9 ----
 5 files changed, 104 insertions(+), 113 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 9d0dd7457b..2767e335d8 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -36,6 +36,9 @@ SYSCALL_DEF(execve, ARG_STR, ARG_PTR, ARG_PTR);
 SYSCALL_DEF(execveat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_PTR, ARG_ATFLAG);
 SYSCALL_DEF(fchmod, ARG_DEC, ARG_MODEFLAG);
 SYSCALL_DEF(fchmodat, ARG_ATDIRFD, ARG_STR, ARG_MODEFLAG);
+#ifdef TARGET_NR_futimesat
+SYSCALL_DEF(futimesat, ARG_ATDIRFD, ARG_STR, ARG_PTR);
+#endif
 #ifdef TARGET_NR_fork
 SYSCALL_DEF(fork);
 #endif
@@ -172,6 +175,12 @@ SYSCALL_DEF(umount2, ARG_STR, ARG_UMOUNTFLAG);
 SYSCALL_DEF(unlink, ARG_STR);
 #endif
 SYSCALL_DEF(unlinkat, ARG_ATDIRFD, ARG_STR, ARG_UNLINKATFLAG);
+#ifdef TARGET_NR_utime
+SYSCALL_DEF(utime, ARG_STR, ARG_PTR);
+#endif
+#ifdef TARGET_NR_utimes
+SYSCALL_DEF(utimes, ARG_STR, ARG_PTR);
+#endif
 #ifdef TARGET_NR_vfork
 /* Emulate vfork() with fork().  */
 SYSCALL_DEF_FULL(vfork, .impl = impl_fork);
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 78781b8817..b54949df27 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1284,21 +1284,6 @@ print_fcntl(const struct syscallname *name,
 #endif
 
 
-#ifdef TARGET_NR_futimesat
-static void
-print_futimesat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_at_dirfd(arg0, 0);
-    print_string(arg1, 0);
-    print_timeval(arg2, 0);
-    print_timeval(arg2 + sizeof (struct target_timeval), 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #if defined(TARGET_NR_socket)
 static void
 print_socket(const struct syscallname *name,
@@ -2003,32 +1988,6 @@ print_symlinkat(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_utime
-static void
-print_utime(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_pointer(arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
-#ifdef TARGET_NR_utimes
-static void
-print_utimes(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_pointer(arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_utimensat
 static void
 print_utimensat(const struct syscallname *name,
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 7ec1c26347..6a7ef80bfc 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -84,6 +84,38 @@ SYSCALL_IMPL(fchmodat)
     return do_fchmodat(arg1, arg2, arg3);
 }
 
+#ifdef TARGET_NR_futimesat
+SYSCALL_IMPL(futimesat)
+{
+    int dirfd = arg1;
+    abi_ulong target_path = arg2;
+    abi_ulong target_tv = arg3;
+    struct timeval *tvp, tv[2];
+    char *p;
+    abi_long ret;
+
+    if (target_tv) {
+        if (copy_from_user_timeval(&tv[0], target_tv)
+            || copy_from_user_timeval(&tv[1],
+                                      target_tv +
+                                      sizeof(struct target_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    p = lock_user_string(target_path);
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(futimesat(dirfd, path(p), tvp));
+    unlock_user(p, target_path, 0);
+    return ret;
+}
+#endif
+
 static abi_long do_linkat(int olddirfd, abi_ulong target_oldpath,
                           int newdirfd, abi_ulong target_newpath,
                           int flags)
@@ -867,6 +899,69 @@ SYSCALL_IMPL(unlinkat)
     return do_unlinkat(arg1, arg2, arg3);
 }
 
+#ifdef TARGET_NR_utime
+SYSCALL_IMPL(utime)
+{
+    abi_ulong target_path = arg1;
+    abi_ulong target_times = arg2;
+    struct utimbuf tbuf, *host_tbuf;
+    struct target_utimbuf *target_tbuf;
+    char *p;
+    abi_long ret;
+
+    if (target_times) {
+        if (!lock_user_struct(VERIFY_READ, target_tbuf, target_times, 1)) {
+            return -TARGET_EFAULT;
+        }
+        tbuf.actime = tswapal(target_tbuf->actime);
+        tbuf.modtime = tswapal(target_tbuf->modtime);
+        unlock_user_struct(target_tbuf, arg2, 0);
+        host_tbuf = &tbuf;
+    } else {
+        host_tbuf = NULL;
+    }
+
+    p = lock_user_string(target_path);
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(utime(p, host_tbuf));
+    unlock_user(p, target_path, 0);
+    return ret;
+}
+#endif
+
+#ifdef TARGET_NR_utimes
+SYSCALL_IMPL(utimes)
+{
+    abi_ulong target_path = arg1;
+    abi_ulong target_tv = arg2;
+    struct timeval *tvp, tv[2];
+    char *p;
+    abi_long ret;
+
+    if (target_tv) {
+        if (copy_from_user_timeval(&tv[0], target_tv)
+            || copy_from_user_timeval(&tv[1],
+                                      target_tv +
+                                      sizeof(struct target_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    p = lock_user_string(target_path);
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(utimes(p, tvp));
+    unlock_user(p, target_path, 0);
+    return ret;
+}
+#endif
+
 SYSCALL_IMPL(write)
 {
     int fd = arg1;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f3ea9600c8..ca462fde61 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5327,69 +5327,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_utime
-    case TARGET_NR_utime:
-        {
-            struct utimbuf tbuf, *host_tbuf;
-            struct target_utimbuf *target_tbuf;
-            if (arg2) {
-                if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
-                    return -TARGET_EFAULT;
-                tbuf.actime = tswapal(target_tbuf->actime);
-                tbuf.modtime = tswapal(target_tbuf->modtime);
-                unlock_user_struct(target_tbuf, arg2, 0);
-                host_tbuf = &tbuf;
-            } else {
-                host_tbuf = NULL;
-            }
-            if (!(p = lock_user_string(arg1)))
-                return -TARGET_EFAULT;
-            ret = get_errno(utime(p, host_tbuf));
-            unlock_user(p, arg1, 0);
-        }
-        return ret;
-#endif
-#ifdef TARGET_NR_utimes
-    case TARGET_NR_utimes:
-        {
-            struct timeval *tvp, tv[2];
-            if (arg2) {
-                if (copy_from_user_timeval(&tv[0], arg2)
-                    || copy_from_user_timeval(&tv[1],
-                                              arg2 + sizeof(struct target_timeval)))
-                    return -TARGET_EFAULT;
-                tvp = tv;
-            } else {
-                tvp = NULL;
-            }
-            if (!(p = lock_user_string(arg1)))
-                return -TARGET_EFAULT;
-            ret = get_errno(utimes(p, tvp));
-            unlock_user(p, arg1, 0);
-        }
-        return ret;
-#endif
-#if defined(TARGET_NR_futimesat)
-    case TARGET_NR_futimesat:
-        {
-            struct timeval *tvp, tv[2];
-            if (arg3) {
-                if (copy_from_user_timeval(&tv[0], arg3)
-                    || copy_from_user_timeval(&tv[1],
-                                              arg3 + sizeof(struct target_timeval)))
-                    return -TARGET_EFAULT;
-                tvp = tv;
-            } else {
-                tvp = NULL;
-            }
-            if (!(p = lock_user_string(arg2))) {
-                return -TARGET_EFAULT;
-            }
-            ret = get_errno(futimesat(arg1, path(p), tvp));
-            unlock_user(p, arg2, 0);
-        }
-        return ret;
-#endif
 #ifdef TARGET_NR_access
     case TARGET_NR_access:
         if (!(p = lock_user_string(arg1))) {
diff --git a/linux-user/strace.list b/linux-user/strace.list
index b119b7a20c..c0c1b896f7 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -226,9 +226,6 @@
 #ifdef TARGET_NR_futex
 { TARGET_NR_futex, "futex" , NULL, print_futex, NULL },
 #endif
-#ifdef TARGET_NR_futimesat
-{ TARGET_NR_futimesat, "futimesat" , NULL, print_futimesat, NULL },
-#endif
 #ifdef TARGET_NR_getcpu
 { TARGET_NR_getcpu, "getcpu" , "%s(%p,%d)", NULL, NULL },
 #endif
@@ -1392,12 +1389,6 @@
 #ifdef TARGET_NR_ustat
 { TARGET_NR_ustat, "ustat" , "%s(%#x,%p)", NULL, NULL },
 #endif
-#ifdef TARGET_NR_utime
-{ TARGET_NR_utime, "utime" , NULL, print_utime, NULL },
-#endif
-#ifdef TARGET_NR_utimes
-{ TARGET_NR_utimes, "utimes" , NULL, print_utimes, NULL },
-#endif
 #ifdef TARGET_NR_utrap_install
 { TARGET_NR_utrap_install, "utrap_install" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 37/49] linux-user: Split out access, faccessat
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (34 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 36/49] linux-user: Split out utime, utimes, futimesat Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 38/49] linux-user: Split out nice Richard Henderson
                   ` (11 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that faccessat is unconditionally available.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  4 ++++
 linux-user/syscall.h          |  1 +
 linux-user/strace.c           | 33 ++++-----------------------------
 linux-user/syscall-file.inc.c | 25 +++++++++++++++++++++++++
 linux-user/syscall.c          | 18 ------------------
 linux-user/strace.list        |  6 ------
 6 files changed, 34 insertions(+), 53 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 2767e335d8..39e3ae3c21 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -16,6 +16,9 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#ifdef TARGET_NR_access
+SYSCALL_DEF(access, ARG_STR, ARG_ACCESSFLAG);
+#endif
 #ifdef TARGET_NR_alarm
 SYSCALL_DEF(alarm, ARG_DEC);
 #endif
@@ -34,6 +37,7 @@ SYSCALL_DEF(creat, ARG_STR, ARG_MODEFLAG);
 SYSCALL_DEF(exit, ARG_DEC);
 SYSCALL_DEF(execve, ARG_STR, ARG_PTR, ARG_PTR);
 SYSCALL_DEF(execveat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_PTR, ARG_ATFLAG);
+SYSCALL_DEF(faccessat, ARG_ATDIRFD, ARG_STR, ARG_ACCESSFLAG);
 SYSCALL_DEF(fchmod, ARG_DEC, ARG_MODEFLAG);
 SYSCALL_DEF(fchmodat, ARG_ATDIRFD, ARG_STR, ARG_MODEFLAG);
 #ifdef TARGET_NR_futimesat
diff --git a/linux-user/syscall.h b/linux-user/syscall.h
index 3c936b648a..84a52b2d9a 100644
--- a/linux-user/syscall.h
+++ b/linux-user/syscall.h
@@ -57,6 +57,7 @@ typedef enum {
 
     /* These print as sets of flags.  */
     ARG_ATDIRFD,
+    ARG_ACCESSFLAG,
     ARG_ATFLAG,
     ARG_CLONEFLAG,
     ARG_MMAPFLAG,
diff --git a/linux-user/strace.c b/linux-user/strace.c
index b54949df27..da2cc30f82 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -634,7 +634,7 @@ print_syscall_ret_adjtimex(const struct syscallname *name, abi_long ret)
     gemu_log("\n");
 }
 
-UNUSED static struct flags access_flags[] = {
+static struct flags const access_flags[] = {
     FLAG_GENERIC(F_OK),
     FLAG_GENERIC(R_OK),
     FLAG_GENERIC(W_OK),
@@ -1114,19 +1114,6 @@ print_accept(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_access
-static void
-print_access(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_flags(access_flags, arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_clock_adjtime
 static void
 print_clock_adjtime(const struct syscallname *name,
@@ -1153,21 +1140,6 @@ print_execv(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_faccessat
-static void
-print_faccessat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_at_dirfd(arg0, 0);
-    print_string(arg1, 0);
-    print_flags(access_flags, arg2, 0);
-    print_flags(at_file_flags, arg3, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_fchownat
 static void
 print_fchownat(const struct syscallname *name,
@@ -2206,6 +2178,9 @@ static void print_syscall_def1(const SyscallDef *def, int64_t args[6])
         case ARG_ATDIRFD:
             len = add_atdirfd(b, rest, arg);
             break;
+        case ARG_ACCESSFLAG:
+            len = add_flags(b, rest, access_flags, arg, false);
+            break;
         case ARG_ATFLAG:
             len = add_flags(b, rest, at_file_flags, arg, false);
             break;
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 6a7ef80bfc..3111abd861 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -16,6 +16,26 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+static abi_long do_faccessat(int dirfd, abi_ulong target_path, int mode)
+{
+    char *p = lock_user_string(target_path);
+    abi_long ret;
+
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(faccessat(dirfd, p, mode, 0));
+    unlock_user(p, target_path, 0);
+    return ret;
+}
+
+#ifdef TARGET_NR_access
+SYSCALL_IMPL(access)
+{
+    return do_faccessat(AT_FDCWD, arg1, arg2);
+}
+#endif
+
 SYSCALL_IMPL(chdir)
 {
     abi_ulong target_path = arg1;
@@ -74,6 +94,11 @@ SYSCALL_IMPL(creat)
 }
 #endif
 
+SYSCALL_IMPL(faccessat)
+{
+    return do_faccessat(arg1, arg2, arg3);
+}
+
 SYSCALL_IMPL(fchmod)
 {
     return get_errno(fchmod(arg1, arg2));
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ca462fde61..9074cf8b8d 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5327,24 +5327,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_access
-    case TARGET_NR_access:
-        if (!(p = lock_user_string(arg1))) {
-            return -TARGET_EFAULT;
-        }
-        ret = get_errno(access(path(p), arg2));
-        unlock_user(p, arg1, 0);
-        return ret;
-#endif
-#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
-    case TARGET_NR_faccessat:
-        if (!(p = lock_user_string(arg2))) {
-            return -TARGET_EFAULT;
-        }
-        ret = get_errno(faccessat(arg1, p, arg3, 0));
-        unlock_user(p, arg2, 0);
-        return ret;
-#endif
 #ifdef TARGET_NR_nice /* not on alpha */
     case TARGET_NR_nice:
         return get_errno(nice(arg1));
diff --git a/linux-user/strace.list b/linux-user/strace.list
index c0c1b896f7..fc0eb91e29 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -9,9 +9,6 @@
 #ifdef TARGET_NR_accept4
 { TARGET_NR_accept4, "accept4" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_access
-{ TARGET_NR_access, "access" , NULL, print_access, NULL },
-#endif
 #ifdef TARGET_NR_acct
 { TARGET_NR_acct, "acct" , NULL, NULL, NULL },
 #endif
@@ -142,9 +139,6 @@
 #ifdef TARGET_NR_exit_group
 { TARGET_NR_exit_group, "exit_group" , "%s(%d)\n", NULL, NULL },
 #endif
-#ifdef TARGET_NR_faccessat
-{ TARGET_NR_faccessat, "faccessat" , NULL, print_faccessat, NULL },
-#endif
 #ifdef TARGET_NR_fadvise64
 { TARGET_NR_fadvise64, "fadvise64" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 38/49] linux-user: Split out nice
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (35 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 37/49] linux-user: Split out access, faccessat Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 39/49] linux-user: Split out sync, syncfs Richard Henderson
                   ` (10 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     | 3 +++
 linux-user/syscall-proc.inc.c | 7 +++++++
 linux-user/syscall.c          | 4 ----
 linux-user/strace.list        | 3 ---
 4 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 39e3ae3c21..860754aaca 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -111,6 +111,9 @@ SYSCALL_DEF(munlockall);
 SYSCALL_DEF(munmap, ARG_PTR, ARG_DEC);
 SYSCALL_DEF(name_to_handle_at,
             ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_PTR, ARG_ATFLAG);
+#ifdef TARGET_NR_nice
+SYSCALL_DEF(nice, ARG_DEC);
+#endif
 #ifdef TARGET_NR_open
 SYSCALL_DEF(open, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
 #endif
diff --git a/linux-user/syscall-proc.inc.c b/linux-user/syscall-proc.inc.c
index c09c83775c..58c0a22300 100644
--- a/linux-user/syscall-proc.inc.c
+++ b/linux-user/syscall-proc.inc.c
@@ -461,6 +461,13 @@ SYSCALL_IMPL(getxpid)
 }
 #endif
 
+#ifdef TARGET_NR_nice
+SYSCALL_IMPL(nice)
+{
+    return get_errno(nice(arg1));
+}
+#endif
+
 /*
  * Map host to target signal numbers for the wait family of syscalls.
  * Assume all other status bits are the same.
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9074cf8b8d..351b2a6288 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5327,10 +5327,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_nice /* not on alpha */
-    case TARGET_NR_nice:
-        return get_errno(nice(arg1));
-#endif
     case TARGET_NR_sync:
         sync();
         return 0;
diff --git a/linux-user/strace.list b/linux-user/strace.list
index fc0eb91e29..aaea23d433 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -527,9 +527,6 @@
 #ifdef TARGET_NR_nfsservctl
 { TARGET_NR_nfsservctl, "nfsservctl" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_nice
-{ TARGET_NR_nice, "nice" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_old_adjtimex
 { TARGET_NR_old_adjtimex, "old_adjtimex" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 39/49] linux-user: Split out sync, syncfs
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (36 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 38/49] linux-user: Split out nice Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 40/49] linux-user: Split out kill Richard Henderson
                   ` (9 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that syncfs is universally available.
If !CONFIG_SYNCFS, provide our own syscall replacement.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  2 ++
 linux-user/syscall-file.inc.c | 11 +++++++++++
 linux-user/syscall.c          | 20 ++++++++++++--------
 linux-user/strace.list        |  6 ------
 4 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 860754aaca..497fbdba66 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -171,6 +171,8 @@ SYSCALL_DEF(shmget, ARG_DEC, ARG_DEC, ARG_HEX);
 #ifdef TARGET_NR_stime
 SYSCALL_DEF(stime, ARG_PTR);
 #endif
+SYSCALL_DEF(sync);
+SYSCALL_DEF(syncfs, ARG_DEC);
 #ifdef TARGET_NR_time
 SYSCALL_DEF(time, ARG_PTR);
 #endif
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 3111abd861..80dec33971 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -867,6 +867,17 @@ SYSCALL_IMPL(readlinkat)
 }
 #endif
 
+SYSCALL_IMPL(sync)
+{
+    sync();
+    return 0;
+}
+
+SYSCALL_IMPL(syncfs)
+{
+    return get_errno(syncfs(arg1));
+}
+
 static abi_long do_umount2(abi_ulong target_path, int flags)
 {
     char *p = lock_user_string(target_path);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 351b2a6288..6668e4ada8 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -199,6 +199,15 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,	\
 #define TARGET_NR_llseek TARGET_NR__llseek
 #endif
 
+/*
+ * These definitions produce an ENOSYS from the host kernel.
+ * Performing a bogus sysacll is lazier than boilerplating
+ * the replacement functions here in C.
+ */
+#ifndef __NR_syncfs
+#define __NR_syncfs  -1
+#endif
+
 #ifdef __NR_gettid
 _syscall0(int, gettid)
 #else
@@ -264,11 +273,13 @@ _syscall3(int, ioprio_set, int, which, int, who, int, ioprio)
 #if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
 _syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags)
 #endif
-
 #if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
 _syscall5(int, kcmp, pid_t, pid1, pid_t, pid2, int, type,
           unsigned long, idx1, unsigned long, idx2)
 #endif
+#ifndef CONFIG_SYNCFS
+_syscall1(int, syncfs, int, fd)
+#endif
 
 static bitmask_transtbl fcntl_flags_tbl[] = {
   { TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
@@ -5327,13 +5338,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-    case TARGET_NR_sync:
-        sync();
-        return 0;
-#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
-    case TARGET_NR_syncfs:
-        return get_errno(syncfs(arg1));
-#endif
     case TARGET_NR_kill:
         return get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
 #ifdef TARGET_NR_rename
diff --git a/linux-user/strace.list b/linux-user/strace.list
index aaea23d433..56f25c15b7 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1260,12 +1260,6 @@
 #ifdef TARGET_NR_symlinkat
 { TARGET_NR_symlinkat, "symlinkat", NULL, print_symlinkat, NULL },
 #endif
-#ifdef TARGET_NR_sync
-{ TARGET_NR_sync, "sync" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_syncfs
-{ TARGET_NR_syncfs, "syncfs" , "%s(%d)", NULL, NULL },
-#endif
 #ifdef TARGET_NR_syscall
 { TARGET_NR_syscall, "syscall" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 40/49] linux-user: Split out kill
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (37 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 39/49] linux-user: Split out sync, syncfs Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 41/49] linux-user: Split out rename, renameat, renameat2 Richard Henderson
                   ` (8 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h    |  1 +
 linux-user/syscall.h         |  7 +++-
 linux-user/strace.c          | 76 ++++++++++++++++++------------------
 linux-user/syscall-sig.inc.c |  5 +++
 linux-user/syscall.c         |  2 -
 linux-user/strace.list       |  3 --
 6 files changed, 48 insertions(+), 46 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 497fbdba66..c672b5ad99 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -58,6 +58,7 @@ SYSCALL_DEF(getxpid);
 #ifdef TARGET_NR_ipc
 SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
 #endif
+SYSCALL_DEF(kill, ARG_DEC, ARG_SIGNAL);
 #ifdef TARGET_NR_link
 SYSCALL_DEF(link, ARG_STR, ARG_STR);
 #endif
diff --git a/linux-user/syscall.h b/linux-user/syscall.h
index 84a52b2d9a..642fb6dccb 100644
--- a/linux-user/syscall.h
+++ b/linux-user/syscall.h
@@ -55,8 +55,12 @@ typedef enum {
     ARG_HEX,
     ARG_OCT,
 
-    /* These print as sets of flags.  */
+    /* These numbers are interpreted.  */
     ARG_ATDIRFD,
+    ARG_SIGNAL,
+    ARG_LSEEKWHENCE,
+
+    /* These print as sets of flags.  */
     ARG_ACCESSFLAG,
     ARG_ATFLAG,
     ARG_CLONEFLAG,
@@ -67,7 +71,6 @@ typedef enum {
     ARG_OPENFLAG,
     ARG_UMOUNTFLAG,
     ARG_UNLINKATFLAG,
-    ARG_LSEEKWHENCE,
 
     /* These are interpreted as pointers.  */
     ARG_PTR,
diff --git a/linux-user/strace.c b/linux-user/strace.c
index da2cc30f82..ec36fcf2c2 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -70,35 +70,43 @@ UNUSED static void print_socket_protocol(int domain, int type, int protocol);
 /*
  * Utility functions
  */
+static int
+add_signal(char *buf, int size, int sig)
+{
+    static const char * const signals[] = {
+        [TARGET_SIGHUP]  = "SIGHUP",
+        [TARGET_SIGINT]  = "SIGINT",
+        [TARGET_SIGQUIT] = "SIGQUIT",
+        [TARGET_SIGILL]  = "SIGILL",
+        [TARGET_SIGABRT] = "SIGABRT",
+        [TARGET_SIGFPE]  = "SIGFPE",
+        [TARGET_SIGKILL] = "SIGKILL",
+        [TARGET_SIGSEGV] = "SIGSEGV",
+        [TARGET_SIGPIPE] = "SIGPIPE",
+        [TARGET_SIGALRM] = "SIGALRM",
+        [TARGET_SIGTERM] = "SIGTERM",
+        [TARGET_SIGUSR1] = "SIGUSR1",
+        [TARGET_SIGUSR2] = "SIGUSR2",
+        [TARGET_SIGCHLD] = "SIGCHLD",
+        [TARGET_SIGCONT] = "SIGCONT",
+        [TARGET_SIGSTOP] = "SIGSTOP",
+        [TARGET_SIGTTIN] = "SIGTTIN",
+        [TARGET_SIGTTOU] = "SIGTTOU",
+    };
+
+    if (sig >= 0 && sig < ARRAY_SIZE(signals) && signals[sig]) {
+        return snprintf(buf, size, "%s", signals[sig]);
+    } else {
+        return snprintf(buf, size, "%d", sig);
+    }
+}
+
 static void
 print_signal(abi_ulong arg, int last)
 {
-    const char *signal_name = NULL;
-    switch(arg) {
-    case TARGET_SIGHUP: signal_name = "SIGHUP"; break;
-    case TARGET_SIGINT: signal_name = "SIGINT"; break;
-    case TARGET_SIGQUIT: signal_name = "SIGQUIT"; break;
-    case TARGET_SIGILL: signal_name = "SIGILL"; break;
-    case TARGET_SIGABRT: signal_name = "SIGABRT"; break;
-    case TARGET_SIGFPE: signal_name = "SIGFPE"; break;
-    case TARGET_SIGKILL: signal_name = "SIGKILL"; break;
-    case TARGET_SIGSEGV: signal_name = "SIGSEGV"; break;
-    case TARGET_SIGPIPE: signal_name = "SIGPIPE"; break;
-    case TARGET_SIGALRM: signal_name = "SIGALRM"; break;
-    case TARGET_SIGTERM: signal_name = "SIGTERM"; break;
-    case TARGET_SIGUSR1: signal_name = "SIGUSR1"; break;
-    case TARGET_SIGUSR2: signal_name = "SIGUSR2"; break;
-    case TARGET_SIGCHLD: signal_name = "SIGCHLD"; break;
-    case TARGET_SIGCONT: signal_name = "SIGCONT"; break;
-    case TARGET_SIGSTOP: signal_name = "SIGSTOP"; break;
-    case TARGET_SIGTTIN: signal_name = "SIGTTIN"; break;
-    case TARGET_SIGTTOU: signal_name = "SIGTTOU"; break;
-    }
-    if (signal_name == NULL) {
-        print_raw_param("%ld", arg, last);
-        return;
-    }
-    gemu_log("%s%s", signal_name, get_comma(last));
+    char buf[16];
+    add_signal(buf, sizeof(buf), arg);
+    gemu_log("%s%s", buf, get_comma(last));
 }
 
 static void print_si_code(int arg)
@@ -2032,19 +2040,6 @@ print_futex(const struct syscallname *name,
 }
 #endif
 
-#ifdef TARGET_NR_kill
-static void
-print_kill(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_raw_param("%d", arg0, 0);
-    print_signal(arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_tkill
 static void
 print_tkill(const struct syscallname *name,
@@ -2178,6 +2173,9 @@ static void print_syscall_def1(const SyscallDef *def, int64_t args[6])
         case ARG_ATDIRFD:
             len = add_atdirfd(b, rest, arg);
             break;
+        case ARG_SIGNAL:
+            len = add_signal(b, rest, arg);
+            break;
         case ARG_ACCESSFLAG:
             len = add_flags(b, rest, access_flags, arg, false);
             break;
diff --git a/linux-user/syscall-sig.inc.c b/linux-user/syscall-sig.inc.c
index f4e43eb00e..a4fbcc567d 100644
--- a/linux-user/syscall-sig.inc.c
+++ b/linux-user/syscall-sig.inc.c
@@ -23,6 +23,11 @@ SYSCALL_IMPL(alarm)
 }
 #endif
 
+SYSCALL_IMPL(kill)
+{
+    return get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
+}
+
 #ifdef TARGET_NR_pause
 SYSCALL_IMPL(pause)
 {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 6668e4ada8..fef955ce66 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5338,8 +5338,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-    case TARGET_NR_kill:
-        return get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
 #ifdef TARGET_NR_rename
     case TARGET_NR_rename:
         {
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 56f25c15b7..b120f11dc2 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -410,9 +410,6 @@
 #ifdef TARGET_NR_keyctl
 { TARGET_NR_keyctl, "keyctl" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_kill
-{ TARGET_NR_kill, "kill", NULL, print_kill, NULL },
-#endif
 #ifdef TARGET_NR_lchown
 { TARGET_NR_lchown, "lchown" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 41/49] linux-user: Split out rename, renameat, renameat2
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (38 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 40/49] linux-user: Split out kill Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 42/49] linux-user: Split out mkdir, mkdirat Richard Henderson
                   ` (7 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that renameat2 is universally available for guests.
Merge sys_renameat2 into the new do_renameat2 helper.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  8 +++++
 linux-user/syscall.h          |  1 +
 linux-user/strace.c           | 39 ++++++---------------
 linux-user/syscall-file.inc.c | 45 ++++++++++++++++++++++++
 linux-user/syscall.c          | 64 -----------------------------------
 linux-user/strace.list        |  9 -----
 6 files changed, 65 insertions(+), 101 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index c672b5ad99..0ed01aa100 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -142,6 +142,14 @@ SYSCALL_DEF(readlink, ARG_STR, ARG_PTR, ARG_DEC);
 #ifdef TARGET_NR_readlinkat
 SYSCALL_DEF(readlinkat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_DEC);
 #endif
+#ifdef TARGET_NR_rename
+SYSCALL_DEF(rename, ARG_STR, ARG_STR);
+#endif
+#ifdef TARGET_NR_renameat
+SYSCALL_DEF(renameat, ARG_ATDIRFD, ARG_STR, ARG_ATDIRFD, ARG_STR);
+#endif
+SYSCALL_DEF(renameat2, ARG_ATDIRFD, ARG_STR,
+            ARG_ATDIRFD, ARG_STR, ARG_RENAMEFLAG);
 SYSCALL_DEF(readv, ARG_DEC, ARG_PTR, ARG_DEC);
 #ifdef TARGET_NR_rmdir
 SYSCALL_DEF(rmdir, ARG_STR);
diff --git a/linux-user/syscall.h b/linux-user/syscall.h
index 642fb6dccb..7b197840f5 100644
--- a/linux-user/syscall.h
+++ b/linux-user/syscall.h
@@ -69,6 +69,7 @@ typedef enum {
     ARG_MODEFLAG,
     ARG_MOUNTFLAG,
     ARG_OPENFLAG,
+    ARG_RENAMEFLAG,
     ARG_UMOUNTFLAG,
     ARG_UNLINKATFLAG,
 
diff --git a/linux-user/strace.c b/linux-user/strace.c
index ec36fcf2c2..6dce7e52c0 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -4,6 +4,7 @@
 #include <arpa/inet.h>
 #include <netinet/tcp.h>
 #include <linux/if_packet.h>
+#include <linux/fs.h>
 #include <sched.h>
 #include "qemu.h"
 #include "syscall.h"
@@ -741,6 +742,13 @@ static struct flags const mount_flags[] = {
     FLAG_END,
 };
 
+static struct flags const renameat2_flags[] = {
+    FLAG_GENERIC(RENAME_EXCHANGE),
+    FLAG_GENERIC(RENAME_NOREPLACE),
+    FLAG_GENERIC(RENAME_WHITEOUT),
+    FLAG_END,
+};
+
 static struct flags const umount2_flags[] = {
 #ifdef MNT_FORCE
     FLAG_GENERIC(MNT_FORCE),
@@ -1887,34 +1895,6 @@ print_fstatat64(const struct syscallname *name,
 #define print_newfstatat    print_fstatat64
 #endif
 
-#ifdef TARGET_NR_rename
-static void
-print_rename(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_string(arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
-#ifdef TARGET_NR_renameat
-static void
-print_renameat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_at_dirfd(arg0, 0);
-    print_string(arg1, 0);
-    print_at_dirfd(arg2, 0);
-    print_string(arg3, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_statfs
 static void
 print_statfs(const struct syscallname *name,
@@ -2200,6 +2180,9 @@ static void print_syscall_def1(const SyscallDef *def, int64_t args[6])
         case ARG_OPENFLAG:
             len = add_open_flags(b, rest, arg);
             break;
+        case ARG_RENAMEFLAG:
+            len = add_flags(b, rest, renameat2_flags, arg, false);
+            break;
         case ARG_UMOUNTFLAG:
             len = add_flags(b, rest, umount2_flags, arg, false);
             break;
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 80dec33971..9099107631 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -867,6 +867,51 @@ SYSCALL_IMPL(readlinkat)
 }
 #endif
 
+static abi_long do_renameat2(int oldfd, abi_ulong target_oldpath,
+                             int newfd, abi_ulong target_newpath,
+                             unsigned int flags)
+{
+    char *p_old = lock_user_string(target_oldpath);
+    char *p_new = lock_user_string(target_newpath);
+    abi_long ret = -TARGET_EFAULT;
+
+    if (p_old && p_new) {
+        if (flags == 0) {
+            ret = renameat(oldfd, p_old, newfd, p_new);
+        } else {
+#ifdef __NR_renameat2
+            ret = syscall(__NR_renameat2, oldfd, p_old, newfd, p_new, flags);
+#else
+            errno = ENOSYS;
+            ret = -1;
+#endif
+        }
+        ret = get_errno(ret);
+    }
+    unlock_user(p_old, target_oldpath, 0);
+    unlock_user(p_new, target_newpath, 0);
+    return ret;
+}
+
+#ifdef TARGET_NR_rename
+SYSCALL_IMPL(rename)
+{
+    return do_renameat2(AT_FDCWD, arg1, AT_FDCWD, arg2, 0);
+}
+#endif
+
+#ifdef TARGET_NR_renameat
+SYSCALL_IMPL(renameat)
+{
+    return do_renameat2(arg1, arg2, arg3, arg4, 0);
+}
+#endif
+
+SYSCALL_IMPL(renameat2)
+{
+    return do_renameat2(arg1, arg2, arg3, arg4, arg5);
+}
+
 SYSCALL_IMPL(sync)
 {
     sync();
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index fef955ce66..fe38ec59d4 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -341,24 +341,6 @@ static int sys_utimensat(int dirfd, const char *pathname,
 #endif
 #endif /* TARGET_NR_utimensat */
 
-#ifdef TARGET_NR_renameat2
-#if defined(__NR_renameat2)
-#define __NR_sys_renameat2 __NR_renameat2
-_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd,
-          const char *, new, unsigned int, flags)
-#else
-static int sys_renameat2(int oldfd, const char *old,
-                         int newfd, const char *new, int flags)
-{
-    if (flags == 0) {
-        return renameat(oldfd, old, newfd, new);
-    }
-    errno = ENOSYS;
-    return -1;
-}
-#endif
-#endif /* TARGET_NR_renameat2 */
-
 #ifdef CONFIG_INOTIFY
 #include <sys/inotify.h>
 
@@ -5338,52 +5320,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_rename
-    case TARGET_NR_rename:
-        {
-            void *p2;
-            p = lock_user_string(arg1);
-            p2 = lock_user_string(arg2);
-            if (!p || !p2)
-                ret = -TARGET_EFAULT;
-            else
-                ret = get_errno(rename(p, p2));
-            unlock_user(p2, arg2, 0);
-            unlock_user(p, arg1, 0);
-        }
-        return ret;
-#endif
-#if defined(TARGET_NR_renameat)
-    case TARGET_NR_renameat:
-        {
-            void *p2;
-            p  = lock_user_string(arg2);
-            p2 = lock_user_string(arg4);
-            if (!p || !p2)
-                ret = -TARGET_EFAULT;
-            else
-                ret = get_errno(renameat(arg1, p, arg3, p2));
-            unlock_user(p2, arg4, 0);
-            unlock_user(p, arg2, 0);
-        }
-        return ret;
-#endif
-#if defined(TARGET_NR_renameat2)
-    case TARGET_NR_renameat2:
-        {
-            void *p2;
-            p  = lock_user_string(arg2);
-            p2 = lock_user_string(arg4);
-            if (!p || !p2) {
-                ret = -TARGET_EFAULT;
-            } else {
-                ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5));
-            }
-            unlock_user(p2, arg4, 0);
-            unlock_user(p, arg2, 0);
-        }
-        return ret;
-#endif
 #ifdef TARGET_NR_mkdir
     case TARGET_NR_mkdir:
         if (!(p = lock_user_string(arg1)))
diff --git a/linux-user/strace.list b/linux-user/strace.list
index b120f11dc2..56aab25d9f 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -944,15 +944,6 @@
 #ifdef TARGET_NR_removexattr
 { TARGET_NR_removexattr, "removexattr" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_rename
-{ TARGET_NR_rename, "rename" , NULL, print_rename, NULL },
-#endif
-#ifdef TARGET_NR_renameat
-{ TARGET_NR_renameat, "renameat" , NULL, print_renameat, NULL },
-#endif
-#ifdef TARGET_NR_renameat2
-{ TARGET_NR_renameat2, "renameat2" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_request_key
 { TARGET_NR_request_key, "request_key" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 42/49] linux-user: Split out mkdir, mkdirat
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (39 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 41/49] linux-user: Split out rename, renameat, renameat2 Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 43/49] linux-user: Split out dup, dup2, dup3 Richard Henderson
                   ` (6 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that mkdirat is universally available.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  4 ++++
 linux-user/strace.c           | 27 ---------------------------
 linux-user/syscall-file.inc.c | 25 +++++++++++++++++++++++++
 linux-user/syscall.c          | 16 ----------------
 linux-user/strace.list        |  6 ------
 5 files changed, 29 insertions(+), 49 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 0ed01aa100..8b6d8f75ff 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -69,6 +69,10 @@ SYSCALL_DEF(lseek, ARG_DEC, ARG_DEC, ARG_LSEEKWHENCE);
 #ifdef TARGET_NR_llseek
 SYSCALL_DEF_ARGS(llseek, ARG_DEC, ARG_DEC, ARG_PTR, ARG_LSEEKWHENCE);
 #endif
+#ifdef TARGET_NR_mkdir
+SYSCALL_DEF(mkdir, ARG_STR, ARG_MODEFLAG);
+#endif
+SYSCALL_DEF(mkdirat, ARG_ATDIRFD, ARG_STR, ARG_MODEFLAG);
 #ifdef TARGET_NR_mknod
 SYSCALL_DEF(mknod, ARG_STR, ARG_MODEFLAG, ARG_HEX);
 #endif
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 6dce7e52c0..ca8e110675 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1664,33 +1664,6 @@ print_fstat(const struct syscallname *name,
 #define print_fstat64     print_fstat
 #endif
 
-#ifdef TARGET_NR_mkdir
-static void
-print_mkdir(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_string(arg0, 0);
-    print_file_mode(arg1, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
-#ifdef TARGET_NR_mkdirat
-static void
-print_mkdirat(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_at_dirfd(arg0, 0);
-    print_string(arg1, 0);
-    print_file_mode(arg2, 1);
-    print_syscall_epilogue(name);
-}
-#endif
-
 #ifdef TARGET_NR_rt_sigaction
 static void
 print_rt_sigaction(const struct syscallname *name,
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 9099107631..83174c5781 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -205,6 +205,31 @@ SYSCALL_IMPL(llseek)
 }
 #endif
 
+static abi_long do_mkdirat(int dirfd, abi_ulong target_path, mode_t mode)
+{
+    char *p = lock_user_string(target_path);
+    abi_long ret;
+
+    if (!p) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(mkdirat(dirfd, p, mode));
+    unlock_user(p, target_path, 0);
+    return ret;
+}
+
+#ifdef TARGET_NR_mkdir
+SYSCALL_IMPL(mkdir)
+{
+    return do_mkdirat(AT_FDCWD, arg1, arg2);
+}
+#endif
+
+SYSCALL_IMPL(mkdirat)
+{
+    return do_mkdirat(arg1, arg2, arg3);
+}
+
 static abi_long do_mknodat(int dirfd, abi_ulong target_path,
                            mode_t mode, dev_t dev)
 {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index fe38ec59d4..7874a48840 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5320,22 +5320,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_mkdir
-    case TARGET_NR_mkdir:
-        if (!(p = lock_user_string(arg1)))
-            return -TARGET_EFAULT;
-        ret = get_errno(mkdir(p, arg2));
-        unlock_user(p, arg1, 0);
-        return ret;
-#endif
-#if defined(TARGET_NR_mkdirat)
-    case TARGET_NR_mkdirat:
-        if (!(p = lock_user_string(arg2)))
-            return -TARGET_EFAULT;
-        ret = get_errno(mkdirat(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
-        return ret;
-#endif
     case TARGET_NR_dup:
         ret = get_errno(dup(arg1));
         if (ret >= 0) {
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 56aab25d9f..678feeeb7b 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -473,12 +473,6 @@
 #ifdef TARGET_NR_mincore
 { TARGET_NR_mincore, "mincore" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_mkdir
-{ TARGET_NR_mkdir, "mkdir" , NULL, print_mkdir, NULL },
-#endif
-#ifdef TARGET_NR_mkdirat
-{ TARGET_NR_mkdirat, "mkdirat" , NULL, print_mkdirat, NULL },
-#endif
 #ifdef TARGET_NR_modify_ldt
 { TARGET_NR_modify_ldt, "modify_ldt" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 43/49] linux-user: Split out dup, dup2, dup3
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (40 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 42/49] linux-user: Split out mkdir, mkdirat Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 44/49] linux-user: Split out pipe, pipe2 Richard Henderson
                   ` (5 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that dup3 is universally available for guests.
Implement host support with syscall when !CONFIG_DUP3.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  5 +++++
 linux-user/syscall-file.inc.c | 42 +++++++++++++++++++++++++++++++++++
 linux-user/syscall.c          | 33 +++------------------------
 linux-user/strace.list        |  6 -----
 4 files changed, 50 insertions(+), 36 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 8b6d8f75ff..062adddd75 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -34,6 +34,11 @@ SYSCALL_DEF(close, ARG_DEC);
 #ifdef TARGET_NR_creat
 SYSCALL_DEF(creat, ARG_STR, ARG_MODEFLAG);
 #endif
+SYSCALL_DEF(dup, ARG_DEC);
+#ifdef TARGET_NR_dup2
+SYSCALL_DEF(dup2, ARG_DEC, ARG_DEC);
+#endif
+SYSCALL_DEF(dup3, ARG_DEC, ARG_DEC, ARG_OPENFLAG);
 SYSCALL_DEF(exit, ARG_DEC);
 SYSCALL_DEF(execve, ARG_STR, ARG_PTR, ARG_PTR);
 SYSCALL_DEF(execveat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_PTR, ARG_ATFLAG);
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 83174c5781..5e8298fdb3 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -94,6 +94,48 @@ SYSCALL_IMPL(creat)
 }
 #endif
 
+SYSCALL_IMPL(dup)
+{
+    abi_long ret = get_errno(dup(arg1));
+    if (ret >= 0) {
+        fd_trans_dup(arg1, ret);
+    }
+    return ret;
+}
+
+#ifdef TARGET_NR_dup2
+SYSCALL_IMPL(dup2)
+{
+    abi_long ret = get_errno(dup2(arg1, arg2));
+    if (ret >= 0) {
+        fd_trans_dup(arg1, arg2);
+    }
+    return ret;
+}
+#endif
+
+SYSCALL_IMPL(dup3)
+{
+    int ofd = arg1;
+    int nfd = arg2;
+    int host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
+    abi_long ret;
+
+#ifdef CONFIG_DUP3
+    ret = dup3(ofd, nfd, host_flags);
+#else
+    if (host_flags == 0) {
+        if (ofd == nfd) {
+            return -TARGET_EINVAL;
+        }
+        ret = dup2(ofd, nfd);
+    } else {
+        ret = syscall(__NR_dup3, ofd, nfd, host_flags);
+    }
+#endif
+    return get_errno(ret);
+}
+
 SYSCALL_IMPL(faccessat)
 {
     return do_faccessat(arg1, arg2, arg3);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 7874a48840..29a9d5fce4 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -204,6 +204,9 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,	\
  * Performing a bogus sysacll is lazier than boilerplating
  * the replacement functions here in C.
  */
+#ifndef __NR_dup3
+#define __NR_dup3  -1
+#endif
 #ifndef __NR_syncfs
 #define __NR_syncfs  -1
 #endif
@@ -5320,12 +5323,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-    case TARGET_NR_dup:
-        ret = get_errno(dup(arg1));
-        if (ret >= 0) {
-            fd_trans_dup(arg1, ret);
-        }
-        return ret;
 #ifdef TARGET_NR_pipe
     case TARGET_NR_pipe:
         return do_pipe(cpu_env, arg1, 0, 0);
@@ -5380,30 +5377,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         ret = get_errno(chroot(p));
         unlock_user(p, arg1, 0);
         return ret;
-#ifdef TARGET_NR_dup2
-    case TARGET_NR_dup2:
-        ret = get_errno(dup2(arg1, arg2));
-        if (ret >= 0) {
-            fd_trans_dup(arg1, arg2);
-        }
-        return ret;
-#endif
-#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
-    case TARGET_NR_dup3:
-    {
-        int host_flags;
-
-        if ((arg3 & ~TARGET_O_CLOEXEC) != 0) {
-            return -EINVAL;
-        }
-        host_flags = target_to_host_bitmask(arg3, fcntl_flags_tbl);
-        ret = get_errno(dup3(arg1, arg2, host_flags));
-        if (ret >= 0) {
-            fd_trans_dup(arg1, arg2);
-        }
-        return ret;
-    }
-#endif
 #ifdef TARGET_NR_getpgrp
     case TARGET_NR_getpgrp:
         return get_errno(getpgrp());
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 678feeeb7b..151b0eb42d 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -91,12 +91,6 @@
 #ifdef TARGET_NR_dipc
 { TARGET_NR_dipc, "dipc" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_dup
-{ TARGET_NR_dup, "dup" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_dup2
-{ TARGET_NR_dup2, "dup2" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_epoll_create
 { TARGET_NR_epoll_create, "epoll_create" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 44/49] linux-user: Split out pipe, pipe2
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (41 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 43/49] linux-user: Split out dup, dup2, dup3 Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 45/49] linux-user: Split out times Richard Henderson
                   ` (4 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Note that pipe2 is universally available for guests.
Implement host support with syscall when !CONFIG_PIPE2.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     | 10 ++++++
 linux-user/syscall-file.inc.c | 51 +++++++++++++++++++++++++++
 linux-user/syscall.c          | 65 +++++++----------------------------
 linux-user/strace.list        |  6 ----
 4 files changed, 74 insertions(+), 58 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 062adddd75..bd3301a72f 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -132,6 +132,16 @@ SYSCALL_DEF(open_by_handle_at, ARG_DEC, ARG_PTR, ARG_OPENFLAG);
 #ifdef TARGET_NR_pause
 SYSCALL_DEF(pause);
 #endif
+#ifdef TARGET_NR_pipe
+# if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || \
+     defined(TARGET_SH4) || defined(TARGET_SPARC)
+/* ??? We have no way for strace to display the second returned fd.  */
+SYSCALL_DEF(pipe);
+# else
+SYSCALL_DEF(pipe, ARG_PTR);
+# endif
+#endif
+SYSCALL_DEF(pipe2, ARG_PTR, ARG_OPENFLAG);
 SYSCALL_DEF_FULL(pread64, .impl = impl_pread64,
                  .args = args_pread64_pwrite64,
                  .arg_type = { ARG_DEC, ARG_PTR, ARG_DEC, ARG_DEC64 });
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 5e8298fdb3..90aacfacaf 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -720,6 +720,57 @@ SYSCALL_IMPL(open_by_handle_at)
     return ret;
 }
 
+static abi_long do_pipe(CPUArchState *cpu_env, abi_ulong target_fds,
+                        int target_flags, bool is_pipe2)
+{
+    int host_flags = target_to_host_bitmask(target_flags, fcntl_flags_tbl);
+    int host_fds[2];
+    abi_long ret;
+
+    ret = pipe2(host_fds, host_flags);
+    if (is_error(ret)) {
+        return get_errno(ret);
+    }
+
+    /*
+     * Several targets have special calling conventions for the original
+     * pipe syscall, but didn't replicate this into the pipe2 syscall.
+     */
+    if (!is_pipe2) {
+#if defined(TARGET_ALPHA)
+        cpu_env->ir[IR_A4] = host_fds[1];
+        return host_fds[0];
+#elif defined(TARGET_MIPS)
+        cpu_env->active_tc.gpr[3] = host_fds[1];
+        return host_fds[0];
+#elif defined(TARGET_SH4)
+        cpu_env->gregs[1] = host_fds[1];
+        return host_fds[0];
+#elif defined(TARGET_SPARC)
+        cpu_env->regwptr[1] = host_fds[1];
+        return host_fds[0];
+#endif
+    }
+
+    if (put_user_s32(host_fds[0], target_fds)
+        || put_user_s32(host_fds[1], target_fds + 4)) {
+        return -TARGET_EFAULT;
+    }
+    return 0;
+}
+
+#ifdef TARGET_NR_pipe
+SYSCALL_IMPL(pipe)
+{
+    return do_pipe(cpu_env, arg1, 0, false);
+}
+#endif
+
+SYSCALL_IMPL(pipe2)
+{
+    return do_pipe(cpu_env, arg1, arg2, true);
+}
+
 /*
  * Both pread64 and pwrite64 merge args into a 64-bit offset,
  * but the input registers and ordering are target specific.
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 29a9d5fce4..3a322a61ca 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -207,6 +207,9 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,	\
 #ifndef __NR_dup3
 #define __NR_dup3  -1
 #endif
+#ifndef __NR_pipe2
+#define __NR_pipe2  -1
+#endif
 #ifndef __NR_syncfs
 #define __NR_syncfs  -1
 #endif
@@ -283,6 +286,16 @@ _syscall5(int, kcmp, pid_t, pid1, pid_t, pid2, int, type,
 #ifndef CONFIG_SYNCFS
 _syscall1(int, syncfs, int, fd)
 #endif
+#ifndef CONFIG_PIPE2
+static int pipe2(int *fds, int flags)
+{
+    if (flags) {
+        return syscall(__NR_pipe2, fds, flags);
+    } else {
+        return pipe(fds);
+    }
+}
+#endif
 
 static bitmask_transtbl fcntl_flags_tbl[] = {
   { TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
@@ -1134,49 +1147,6 @@ static abi_long do_old_select(abi_ulong arg1)
 #endif
 #endif
 
-static abi_long do_pipe2(int host_pipe[], int flags)
-{
-#ifdef CONFIG_PIPE2
-    return pipe2(host_pipe, flags);
-#else
-    return -ENOSYS;
-#endif
-}
-
-static abi_long do_pipe(void *cpu_env, abi_ulong pipedes,
-                        int flags, int is_pipe2)
-{
-    int host_pipe[2];
-    abi_long ret;
-    ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
-
-    if (is_error(ret))
-        return get_errno(ret);
-
-    /* Several targets have special calling conventions for the original
-       pipe syscall, but didn't replicate this into the pipe2 syscall.  */
-    if (!is_pipe2) {
-#if defined(TARGET_ALPHA)
-        ((CPUAlphaState *)cpu_env)->ir[IR_A4] = host_pipe[1];
-        return host_pipe[0];
-#elif defined(TARGET_MIPS)
-        ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
-        return host_pipe[0];
-#elif defined(TARGET_SH4)
-        ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
-        return host_pipe[0];
-#elif defined(TARGET_SPARC)
-        ((CPUSPARCState*)cpu_env)->regwptr[1] = host_pipe[1];
-        return host_pipe[0];
-#endif
-    }
-
-    if (put_user_s32(host_pipe[0], pipedes)
-        || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
-        return -TARGET_EFAULT;
-    return get_errno(ret);
-}
-
 static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
                                               abi_ulong target_addr,
                                               socklen_t len)
@@ -5323,15 +5293,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_pipe
-    case TARGET_NR_pipe:
-        return do_pipe(cpu_env, arg1, 0, 0);
-#endif
-#ifdef TARGET_NR_pipe2
-    case TARGET_NR_pipe2:
-        return do_pipe(cpu_env, arg1,
-                       target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
-#endif
     case TARGET_NR_times:
         {
             struct target_tms *tmsp;
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 151b0eb42d..ac25e13bfa 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -860,9 +860,6 @@
 #ifdef TARGET_NR_personality
 { TARGET_NR_personality, "personality" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_pipe
-{ TARGET_NR_pipe, "pipe" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_pivot_root
 { TARGET_NR_pivot_root, "pivot_root" , NULL, NULL, NULL },
 #endif
@@ -1377,9 +1374,6 @@
 #ifdef TARGET_NR_sync_file_range2
 { TARGET_NR_sync_file_range2, "sync_file_range2", NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_pipe2
-{ TARGET_NR_pipe2, "pipe2", NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_atomic_cmpxchg_32
 { TARGET_NR_atomic_cmpxchg_32, "atomic_cmpxchg_32", NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 45/49] linux-user: Split out times
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (42 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 44/49] linux-user: Split out pipe, pipe2 Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 46/49] linux-user: Split out acct Richard Henderson
                   ` (3 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  1 +
 linux-user/syscall-proc.inc.c | 25 +++++++++++++++++++++++++
 linux-user/syscall.c          | 18 ------------------
 linux-user/strace.list        |  3 ---
 4 files changed, 26 insertions(+), 21 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index bd3301a72f..25d5aaccd1 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -204,6 +204,7 @@ SYSCALL_DEF(syncfs, ARG_DEC);
 #ifdef TARGET_NR_time
 SYSCALL_DEF(time, ARG_PTR);
 #endif
+SYSCALL_DEF(times, ARG_PTR);
 #ifdef TARGET_NR_umount
 SYSCALL_DEF(umount, ARG_STR);
 #endif
diff --git a/linux-user/syscall-proc.inc.c b/linux-user/syscall-proc.inc.c
index 58c0a22300..09a0306406 100644
--- a/linux-user/syscall-proc.inc.c
+++ b/linux-user/syscall-proc.inc.c
@@ -468,6 +468,31 @@ SYSCALL_IMPL(nice)
 }
 #endif
 
+SYSCALL_IMPL(times)
+{
+    abi_ulong target_buf = arg1;
+    struct tms tms;
+    abi_long ret;
+
+    ret = get_errno(times(&tms));
+    if (target_buf) {
+        struct target_tms *tmsp = lock_user(VERIFY_WRITE, target_buf,
+                                            sizeof(struct target_tms), 0);
+        if (!tmsp) {
+            return -TARGET_EFAULT;
+        }
+        tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
+        tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
+        tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
+        tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
+        unlock_user(tmsp, target_buf, sizeof(struct target_tms));
+    }
+    if (!is_error(ret)) {
+        ret = host_to_target_clock_t(ret);
+    }
+    return ret;
+}
+
 /*
  * Map host to target signal numbers for the wait family of syscalls.
  * Assume all other status bits are the same.
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 3a322a61ca..d0bf339281 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5293,24 +5293,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-    case TARGET_NR_times:
-        {
-            struct target_tms *tmsp;
-            struct tms tms;
-            ret = get_errno(times(&tms));
-            if (arg1) {
-                tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
-                if (!tmsp)
-                    return -TARGET_EFAULT;
-                tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
-                tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
-                tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
-                tmsp->tms_cstime = tswapal(host_to_target_clock_t(tms.tms_cstime));
-            }
-            if (!is_error(ret))
-                ret = host_to_target_clock_t(ret);
-        }
-        return ret;
     case TARGET_NR_acct:
         if (arg1 == 0) {
             ret = get_errno(acct(NULL));
diff --git a/linux-user/strace.list b/linux-user/strace.list
index ac25e13bfa..4ea11f162e 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1290,9 +1290,6 @@
 #ifdef TARGET_NR_timerfd_settime
 { TARGET_NR_timerfd_settime, "timerfd_settime" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_times
-{ TARGET_NR_times, "times" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_tkill
 { TARGET_NR_tkill, "tkill" , NULL, print_tkill, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 46/49] linux-user: Split out acct
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (43 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 45/49] linux-user: Split out times Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 47/49] linux-user: Move syscall_init to the end Richard Henderson
                   ` (2 subsequent siblings)
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h     |  1 +
 linux-user/syscall-file.inc.c | 18 ++++++++++++++++++
 linux-user/syscall.c          | 11 -----------
 linux-user/strace.list        |  3 ---
 4 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index 25d5aaccd1..f8f280f376 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -19,6 +19,7 @@
 #ifdef TARGET_NR_access
 SYSCALL_DEF(access, ARG_STR, ARG_ACCESSFLAG);
 #endif
+SYSCALL_DEF(acct, ARG_STR);
 #ifdef TARGET_NR_alarm
 SYSCALL_DEF(alarm, ARG_DEC);
 #endif
diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
index 90aacfacaf..dd0bf877d5 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -36,6 +36,24 @@ SYSCALL_IMPL(access)
 }
 #endif
 
+SYSCALL_IMPL(acct)
+{
+    abi_ulong target_path = arg1;
+    abi_long ret;
+
+    if (target_path == 0) {
+        ret = get_errno(acct(NULL));
+    } else {
+        char *p = lock_user_string(target_path);
+        if (!p) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(acct(path(p)));
+        unlock_user(p, target_path, 0);
+    }
+    return ret;
+}
+
 SYSCALL_IMPL(chdir)
 {
     abi_ulong target_path = arg1;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index d0bf339281..33d536262f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5293,17 +5293,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-    case TARGET_NR_acct:
-        if (arg1 == 0) {
-            ret = get_errno(acct(NULL));
-        } else {
-            if (!(p = lock_user_string(arg1))) {
-                return -TARGET_EFAULT;
-            }
-            ret = get_errno(acct(path(p)));
-            unlock_user(p, arg1, 0);
-        }
-        return ret;
     case TARGET_NR_ioctl:
         return do_ioctl(arg1, arg2, arg3);
 #ifdef TARGET_NR_fcntl
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 4ea11f162e..9f2f8977b4 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -9,9 +9,6 @@
 #ifdef TARGET_NR_accept4
 { TARGET_NR_accept4, "accept4" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_acct
-{ TARGET_NR_acct, "acct" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_add_key
 { TARGET_NR_add_key, "add_key" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 47/49] linux-user: Move syscall_init to the end
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (44 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 46/49] linux-user: Split out acct Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl Richard Henderson
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 49/49] linux-user: Split out fcntl, fcntl64 Richard Henderson
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

No functional change.  This will aid moving everything
related to ioctls to a separate file.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall.c | 113 +++++++++++++++++++++++--------------------
 1 file changed, 61 insertions(+), 52 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 33d536262f..82b7267b20 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4778,58 +4778,6 @@ _syscall1(int, sys_setgid, gid_t, gid)
 _syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
 _syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
 
-void syscall_init(void)
-{
-    IOCTLEntry *ie;
-    const argtype *arg_type;
-    int size;
-    int i;
-
-    thunk_init(STRUCT_MAX);
-
-#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
-#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
-#include "syscall_types.h"
-#undef STRUCT
-#undef STRUCT_SPECIAL
-
-    /* Build target_to_host_errno_table[] table from
-     * host_to_target_errno_table[]. */
-    for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
-        target_to_host_errno_table[host_to_target_errno_table[i]] = i;
-    }
-
-    /* we patch the ioctl size if necessary. We rely on the fact that
-       no ioctl has all the bits at '1' in the size field */
-    ie = ioctl_entries;
-    while (ie->target_cmd != 0) {
-        if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
-            TARGET_IOC_SIZEMASK) {
-            arg_type = ie->arg_type;
-            if (arg_type[0] != TYPE_PTR) {
-                fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
-                        ie->target_cmd);
-                exit(1);
-            }
-            arg_type++;
-            size = thunk_type_size(arg_type, 0);
-            ie->target_cmd = (ie->target_cmd &
-                              ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
-                (size << TARGET_IOC_SIZESHIFT);
-        }
-
-        /* automatic consistency check if same arch */
-#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
-    (defined(__x86_64__) && defined(TARGET_X86_64))
-        if (unlikely(ie->target_cmd != ie->host_cmd)) {
-            fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
-                    ie->name, ie->target_cmd, ie->host_cmd);
-        }
-#endif
-        ie++;
-    }
-}
-
 static inline uint64_t target_offset64(abi_ulong word0, abi_ulong word1)
 {
 #if TARGET_ABI_BITS == 64
@@ -8983,3 +8931,64 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     trace_guest_user_syscall_ret(cpu, num, ret);
     return ret;
 }
+
+void syscall_init(void)
+{
+    IOCTLEntry *ie;
+    const argtype *arg_type;
+    int size;
+    int i;
+
+    thunk_init(STRUCT_MAX);
+
+#define STRUCT(name, ...) \
+    thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
+#define STRUCT_SPECIAL(name) \
+    thunk_register_struct_direct(STRUCT_ ## name, #name, \
+                                 &struct_ ## name ## _def);
+
+#include "syscall_types.h"
+
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+    /*
+     * Build target_to_host_errno_table[] table from
+     * host_to_target_errno_table[].
+     */
+    for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
+        target_to_host_errno_table[host_to_target_errno_table[i]] = i;
+    }
+
+    /*
+     * We patch the ioctl size if necessary.  We rely on the fact that
+     * no ioctl has all the bits at '1' in the size field.
+     */
+    ie = ioctl_entries;
+    while (ie->target_cmd != 0) {
+        if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
+            TARGET_IOC_SIZEMASK) {
+            arg_type = ie->arg_type;
+            if (arg_type[0] != TYPE_PTR) {
+                fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
+                        ie->target_cmd);
+                exit(1);
+            }
+            arg_type++;
+            size = thunk_type_size(arg_type, 0);
+            ie->target_cmd = (ie->target_cmd &
+                              ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
+                (size << TARGET_IOC_SIZESHIFT);
+        }
+
+        /* automatic consistency check if same arch */
+#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
+    (defined(__x86_64__) && defined(TARGET_X86_64))
+        if (unlikely(ie->target_cmd != ie->host_cmd)) {
+            fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
+                    ie->name, ie->target_cmd, ie->host_cmd);
+        }
+#endif
+        ie++;
+    }
+}
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (45 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 47/49] linux-user: Move syscall_init to the end Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  2019-02-13 13:09   ` Laurent Vivier
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 49/49] linux-user: Split out fcntl, fcntl64 Richard Henderson
  47 siblings, 1 reply; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h      |   1 +
 linux-user/syscall-ioctl.inc.c | 873 +++++++++++++++++++++++++++++++++
 linux-user/syscall.c           | 843 +------------------------------
 linux-user/strace.list         |   3 -
 4 files changed, 875 insertions(+), 845 deletions(-)
 create mode 100644 linux-user/syscall-ioctl.inc.c

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index f8f280f376..f58b9745a4 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -61,6 +61,7 @@ SYSCALL_DEF(getppid);
 #ifdef TARGET_NR_getxpid
 SYSCALL_DEF(getxpid);
 #endif
+SYSCALL_DEF(ioctl, ARG_DEC, ARG_HEX);
 #ifdef TARGET_NR_ipc
 SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
 #endif
diff --git a/linux-user/syscall-ioctl.inc.c b/linux-user/syscall-ioctl.inc.c
new file mode 100644
index 0000000000..820994105f
--- /dev/null
+++ b/linux-user/syscall-ioctl.inc.c
@@ -0,0 +1,873 @@
+/*
+ *  Linux ioctl syscall implementation
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+typedef struct IOCTLEntry IOCTLEntry;
+
+typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
+                             int fd, int cmd, abi_long arg);
+
+struct IOCTLEntry {
+    int target_cmd;
+    unsigned int host_cmd;
+    const char *name;
+    int access;
+    do_ioctl_fn *do_ioctl;
+    const argtype arg_type[5];
+};
+
+#define IOC_R 0x0001
+#define IOC_W 0x0002
+#define IOC_RW (IOC_R | IOC_W)
+
+#define MAX_STRUCT_SIZE 4096
+
+#ifdef CONFIG_FIEMAP
+/*
+ * So fiemap access checks don't overflow on 32 bit systems.
+ * This is very slightly smaller than the limit imposed by
+ * the underlying kernel.
+ */
+#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap))  \
+                            / sizeof(struct fiemap_extent))
+
+static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
+                                       int fd, int cmd, abi_long arg)
+{
+    /*
+     * The parameter for this ioctl is a struct fiemap followed
+     * by an array of struct fiemap_extent whose size is set
+     * in fiemap->fm_extent_count. The array is filled in by the
+     * ioctl.
+     */
+    int target_size_in, target_size_out;
+    struct fiemap *fm;
+    const argtype *arg_type = ie->arg_type;
+    const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
+    void *argptr, *p;
+    abi_long ret;
+    int i, extent_size = thunk_type_size(extent_arg_type, 0);
+    uint32_t outbufsz;
+    int free_fm = 0;
+
+    assert(arg_type[0] == TYPE_PTR);
+    assert(ie->access == IOC_RW);
+    arg_type++;
+    target_size_in = thunk_type_size(arg_type, 0);
+    argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
+    if (!argptr) {
+        return -TARGET_EFAULT;
+    }
+    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+    unlock_user(argptr, arg, 0);
+    fm = (struct fiemap *)buf_temp;
+    if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
+        return -TARGET_EINVAL;
+    }
+
+    outbufsz = sizeof(*fm) + sizeof(struct fiemap_extent) * fm->fm_extent_count;
+
+    if (outbufsz > MAX_STRUCT_SIZE) {
+        /*
+         * We can't fit all the extents into the fixed size buffer.
+         * Allocate one that is large enough and use it instead.
+         */
+        fm = g_try_malloc(outbufsz);
+        if (!fm) {
+            return -TARGET_ENOMEM;
+        }
+        memcpy(fm, buf_temp, sizeof(struct fiemap));
+        free_fm = 1;
+    }
+    ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
+    if (!is_error(ret)) {
+        target_size_out = target_size_in;
+        /*
+         * An extent_count of 0 means we were only counting the extents
+         * so there are no structs to copy
+         */
+        if (fm->fm_extent_count != 0) {
+            target_size_out += fm->fm_mapped_extents * extent_size;
+        }
+        argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
+        if (!argptr) {
+            ret = -TARGET_EFAULT;
+        } else {
+            /* Convert the struct fiemap */
+            thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
+            if (fm->fm_extent_count != 0) {
+                p = argptr + target_size_in;
+                /* ...and then all the struct fiemap_extents */
+                for (i = 0; i < fm->fm_mapped_extents; i++) {
+                    thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
+                                  THUNK_TARGET);
+                    p += extent_size;
+                }
+            }
+            unlock_user(argptr, arg, target_size_out);
+        }
+    }
+    if (free_fm) {
+        g_free(fm);
+    }
+    return ret;
+}
+#endif
+
+static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
+                                int fd, int cmd, abi_long arg)
+{
+    const argtype *arg_type = ie->arg_type;
+    int target_size;
+    void *argptr;
+    int ret;
+    struct ifconf *host_ifconf;
+    uint32_t outbufsz;
+    const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
+    int target_ifreq_size;
+    int nb_ifreq;
+    int free_buf = 0;
+    int i;
+    int target_ifc_len;
+    abi_long target_ifc_buf;
+    int host_ifc_len;
+    char *host_ifc_buf;
+
+    assert(arg_type[0] == TYPE_PTR);
+    assert(ie->access == IOC_RW);
+
+    arg_type++;
+    target_size = thunk_type_size(arg_type, 0);
+
+    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+    if (!argptr) {
+        return -TARGET_EFAULT;
+    }
+    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+    unlock_user(argptr, arg, 0);
+
+    host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
+    target_ifc_len = host_ifconf->ifc_len;
+    target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
+
+    target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
+    nb_ifreq = target_ifc_len / target_ifreq_size;
+    host_ifc_len = nb_ifreq * sizeof(struct ifreq);
+
+    outbufsz = sizeof(*host_ifconf) + host_ifc_len;
+    if (outbufsz > MAX_STRUCT_SIZE) {
+        /*
+         * We can't fit all the extents into the fixed size buffer.
+         * Allocate one that is large enough and use it instead.
+         */
+        host_ifconf = malloc(outbufsz);
+        if (!host_ifconf) {
+            return -TARGET_ENOMEM;
+        }
+        memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
+        free_buf = 1;
+    }
+    host_ifc_buf = (char *)host_ifconf + sizeof(*host_ifconf);
+
+    host_ifconf->ifc_len = host_ifc_len;
+    host_ifconf->ifc_buf = host_ifc_buf;
+
+    ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
+    if (!is_error(ret)) {
+        /* convert host ifc_len to target ifc_len */
+
+        nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
+        target_ifc_len = nb_ifreq * target_ifreq_size;
+        host_ifconf->ifc_len = target_ifc_len;
+
+        /* restore target ifc_buf */
+
+        host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
+
+        /* copy struct ifconf to target user */
+
+        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+        if (!argptr) {
+            return -TARGET_EFAULT;
+        }
+        thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
+        unlock_user(argptr, arg, target_size);
+
+        /* copy ifreq[] to target user */
+
+        argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
+        for (i = 0; i < nb_ifreq ; i++) {
+            thunk_convert(argptr + i * target_ifreq_size,
+                          host_ifc_buf + i * sizeof(struct ifreq),
+                          ifreq_arg_type, THUNK_TARGET);
+        }
+        unlock_user(argptr, target_ifc_buf, target_ifc_len);
+    }
+
+    if (free_buf) {
+        free(host_ifconf);
+    }
+
+    return ret;
+}
+
+#if defined(CONFIG_USBFS)
+#if HOST_LONG_BITS > 64
+#error USBDEVFS thunks do not support >64 bit hosts yet.
+#endif
+struct live_urb {
+    uint64_t target_urb_adr;
+    uint64_t target_buf_adr;
+    char *target_buf_ptr;
+    struct usbdevfs_urb host_urb;
+};
+
+static GHashTable *usbdevfs_urb_hashtable(void)
+{
+    static GHashTable *urb_hashtable;
+
+    if (!urb_hashtable) {
+        urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
+    }
+    return urb_hashtable;
+}
+
+static void urb_hashtable_insert(struct live_urb *urb)
+{
+    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
+    g_hash_table_insert(urb_hashtable, urb, urb);
+}
+
+static struct live_urb *urb_hashtable_lookup(uint64_t target_urb_adr)
+{
+    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
+    return g_hash_table_lookup(urb_hashtable, &target_urb_adr);
+}
+
+static void urb_hashtable_remove(struct live_urb *urb)
+{
+    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
+    g_hash_table_remove(urb_hashtable, urb);
+}
+
+static abi_long
+do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
+                          int fd, int cmd, abi_long arg)
+{
+    const argtype usbfsurb_arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_urb) };
+    const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
+    struct live_urb *lurb;
+    void *argptr;
+    uint64_t hurb;
+    int target_size;
+    uintptr_t target_urb_adr;
+    abi_long ret;
+
+    target_size = thunk_type_size(usbfsurb_arg_type, THUNK_TARGET);
+
+    memset(buf_temp, 0, sizeof(uint64_t));
+    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    memcpy(&hurb, buf_temp, sizeof(uint64_t));
+    lurb = (void *)((uintptr_t)hurb - offsetof(struct live_urb, host_urb));
+    if (!lurb->target_urb_adr) {
+        return -TARGET_EFAULT;
+    }
+    urb_hashtable_remove(lurb);
+    unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr,
+                lurb->host_urb.buffer_length);
+    lurb->target_buf_ptr = NULL;
+
+    /* restore the guest buffer pointer */
+    lurb->host_urb.buffer = (void *)(uintptr_t)lurb->target_buf_adr;
+
+    /* update the guest urb struct */
+    argptr = lock_user(VERIFY_WRITE, lurb->target_urb_adr, target_size, 0);
+    if (!argptr) {
+        g_free(lurb);
+        return -TARGET_EFAULT;
+    }
+    thunk_convert(argptr, &lurb->host_urb, usbfsurb_arg_type, THUNK_TARGET);
+    unlock_user(argptr, lurb->target_urb_adr, target_size);
+
+    target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
+    /* write back the urb handle */
+    argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+    if (!argptr) {
+        g_free(lurb);
+        return -TARGET_EFAULT;
+    }
+
+    /* GHashTable uses 64-bit keys but thunk_convert expects uintptr_t */
+    target_urb_adr = lurb->target_urb_adr;
+    thunk_convert(argptr, &target_urb_adr, ptrvoid_arg_type, THUNK_TARGET);
+    unlock_user(argptr, arg, target_size);
+
+    g_free(lurb);
+    return ret;
+}
+
+static abi_long
+do_ioctl_usbdevfs_discardurb(const IOCTLEntry *ie,
+                             uint8_t *buf_temp __attribute__((unused)),
+                             int fd, int cmd, abi_long arg)
+{
+    struct live_urb *lurb;
+
+    /* map target address back to host URB with metadata. */
+    lurb = urb_hashtable_lookup(arg);
+    if (!lurb) {
+        return -TARGET_EFAULT;
+    }
+    return get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
+}
+
+static abi_long
+do_ioctl_usbdevfs_submiturb(const IOCTLEntry *ie, uint8_t *buf_temp,
+                            int fd, int cmd, abi_long arg)
+{
+    const argtype *arg_type = ie->arg_type;
+    int target_size;
+    abi_long ret;
+    void *argptr;
+    int rw_dir;
+    struct live_urb *lurb;
+
+    /*
+     * each submitted URB needs to map to a unique ID for the
+     * kernel, and that unique ID needs to be a pointer to
+     * host memory.  hence, we need to malloc for each URB.
+     * isochronous transfers have a variable length struct.
+     */
+    arg_type++;
+    target_size = thunk_type_size(arg_type, THUNK_TARGET);
+
+    /* construct host copy of urb and metadata */
+    lurb = g_try_malloc0(sizeof(struct live_urb));
+    if (!lurb) {
+        return -TARGET_ENOMEM;
+    }
+
+    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+    if (!argptr) {
+        g_free(lurb);
+        return -TARGET_EFAULT;
+    }
+    thunk_convert(&lurb->host_urb, argptr, arg_type, THUNK_HOST);
+    unlock_user(argptr, arg, 0);
+
+    lurb->target_urb_adr = arg;
+    lurb->target_buf_adr = (uintptr_t)lurb->host_urb.buffer;
+
+    /* buffer space used depends on endpoint type so lock the entire buffer */
+    /* control type urbs should check the buffer contents for true direction */
+    rw_dir = lurb->host_urb.endpoint & USB_DIR_IN ? VERIFY_WRITE : VERIFY_READ;
+    lurb->target_buf_ptr = lock_user(rw_dir, lurb->target_buf_adr,
+                                     lurb->host_urb.buffer_length, 1);
+    if (lurb->target_buf_ptr == NULL) {
+        g_free(lurb);
+        return -TARGET_EFAULT;
+    }
+
+    /* update buffer pointer in host copy */
+    lurb->host_urb.buffer = lurb->target_buf_ptr;
+
+    ret = get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
+    if (is_error(ret)) {
+        unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr, 0);
+        g_free(lurb);
+    } else {
+        urb_hashtable_insert(lurb);
+    }
+
+    return ret;
+}
+#endif /* CONFIG_USBFS */
+
+static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
+                            int cmd, abi_long arg)
+{
+    void *argptr;
+    struct dm_ioctl *host_dm;
+    abi_long guest_data;
+    uint32_t guest_data_size;
+    int target_size;
+    const argtype *arg_type = ie->arg_type;
+    abi_long ret;
+    void *big_buf = NULL;
+    char *host_data;
+
+    arg_type++;
+    target_size = thunk_type_size(arg_type, 0);
+    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+    if (!argptr) {
+        ret = -TARGET_EFAULT;
+        goto out;
+    }
+    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+    unlock_user(argptr, arg, 0);
+
+    /* buf_temp is too small, so fetch things into a bigger buffer */
+    big_buf = g_malloc0(((struct dm_ioctl *)buf_temp)->data_size * 2);
+    memcpy(big_buf, buf_temp, target_size);
+    buf_temp = big_buf;
+    host_dm = big_buf;
+
+    guest_data = arg + host_dm->data_start;
+    if ((guest_data - arg) < 0) {
+        ret = -TARGET_EINVAL;
+        goto out;
+    }
+    guest_data_size = host_dm->data_size - host_dm->data_start;
+    host_data = (char *)host_dm + host_dm->data_start;
+
+    argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
+    if (!argptr) {
+        ret = -TARGET_EFAULT;
+        goto out;
+    }
+
+    switch (ie->host_cmd) {
+    case DM_REMOVE_ALL:
+    case DM_LIST_DEVICES:
+    case DM_DEV_CREATE:
+    case DM_DEV_REMOVE:
+    case DM_DEV_SUSPEND:
+    case DM_DEV_STATUS:
+    case DM_DEV_WAIT:
+    case DM_TABLE_STATUS:
+    case DM_TABLE_CLEAR:
+    case DM_TABLE_DEPS:
+    case DM_LIST_VERSIONS:
+        /* no input data */
+        break;
+    case DM_DEV_RENAME:
+    case DM_DEV_SET_GEOMETRY:
+        /* data contains only strings */
+        memcpy(host_data, argptr, guest_data_size);
+        break;
+    case DM_TARGET_MSG:
+        memcpy(host_data, argptr, guest_data_size);
+        *(uint64_t *)host_data = tswap64(*(uint64_t *)argptr);
+        break;
+    case DM_TABLE_LOAD:
+    {
+        void *gspec = argptr;
+        void *cur_data = host_data;
+        const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
+        int spec_size = thunk_type_size(arg_type, 0);
+        int i;
+
+        for (i = 0; i < host_dm->target_count; i++) {
+            struct dm_target_spec *spec = cur_data;
+            uint32_t next;
+            int slen;
+
+            thunk_convert(spec, gspec, arg_type, THUNK_HOST);
+            slen = strlen((char *)gspec + spec_size) + 1;
+            next = spec->next;
+            spec->next = sizeof(*spec) + slen;
+            strcpy((char *)&spec[1], gspec + spec_size);
+            gspec += next;
+            cur_data += spec->next;
+        }
+        break;
+    }
+    default:
+        ret = -TARGET_EINVAL;
+        unlock_user(argptr, guest_data, 0);
+        goto out;
+    }
+    unlock_user(argptr, guest_data, 0);
+
+    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
+    if (!is_error(ret)) {
+        guest_data = arg + host_dm->data_start;
+        guest_data_size = host_dm->data_size - host_dm->data_start;
+        argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
+        switch (ie->host_cmd) {
+        case DM_REMOVE_ALL:
+        case DM_DEV_CREATE:
+        case DM_DEV_REMOVE:
+        case DM_DEV_RENAME:
+        case DM_DEV_SUSPEND:
+        case DM_DEV_STATUS:
+        case DM_TABLE_LOAD:
+        case DM_TABLE_CLEAR:
+        case DM_TARGET_MSG:
+        case DM_DEV_SET_GEOMETRY:
+            /* no return data */
+            break;
+        case DM_LIST_DEVICES:
+        {
+            struct dm_name_list *nl = (void *)host_dm + host_dm->data_start;
+            uint32_t remaining_data = guest_data_size;
+            void *cur_data = argptr;
+            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
+            int nl_size = 12; /* can't use thunk_size due to alignment */
+
+            while (1) {
+                uint32_t next = nl->next;
+                if (next) {
+                    nl->next = nl_size + (strlen(nl->name) + 1);
+                }
+                if (remaining_data < nl->next) {
+                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
+                    break;
+                }
+                thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
+                strcpy(cur_data + nl_size, nl->name);
+                cur_data += nl->next;
+                remaining_data -= nl->next;
+                if (!next) {
+                    break;
+                }
+                nl = (void *)nl + next;
+            }
+            break;
+        }
+        case DM_DEV_WAIT:
+        case DM_TABLE_STATUS:
+        {
+            struct dm_target_spec *spec
+                = (void *)host_dm + host_dm->data_start;
+            void *cur_data = argptr;
+            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
+            int spec_size = thunk_type_size(arg_type, 0);
+            int i;
+
+            for (i = 0; i < host_dm->target_count; i++) {
+                uint32_t next = spec->next;
+                int slen = strlen((char *)&spec[1]) + 1;
+                spec->next = (cur_data - argptr) + spec_size + slen;
+                if (guest_data_size < spec->next) {
+                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
+                    break;
+                }
+                thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
+                strcpy(cur_data + spec_size, (char *)&spec[1]);
+                cur_data = argptr + spec->next;
+                spec = (void *)host_dm + host_dm->data_start + next;
+            }
+            break;
+        }
+        case DM_TABLE_DEPS:
+        {
+            void *hdata = (void *)host_dm + host_dm->data_start;
+            int count = *(uint32_t *)hdata;
+            uint64_t *hdev = hdata + 8;
+            uint64_t *gdev = argptr + 8;
+            int i;
+
+            *(uint32_t *)argptr = tswap32(count);
+            for (i = 0; i < count; i++) {
+                *gdev = tswap64(*hdev);
+                gdev++;
+                hdev++;
+            }
+            break;
+        }
+        case DM_LIST_VERSIONS:
+        {
+            struct dm_target_versions *vers
+                = (void *)host_dm + host_dm->data_start;
+            uint32_t remaining_data = guest_data_size;
+            void *cur_data = argptr;
+            const argtype arg_type[]
+                = { MK_STRUCT(STRUCT_dm_target_versions) };
+            int vers_size = thunk_type_size(arg_type, 0);
+
+            while (1) {
+                uint32_t next = vers->next;
+                if (next) {
+                    vers->next = vers_size + strlen(vers->name) + 1;
+                }
+                if (remaining_data < vers->next) {
+                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
+                    break;
+                }
+                thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
+                strcpy(cur_data + vers_size, vers->name);
+                cur_data += vers->next;
+                remaining_data -= vers->next;
+                if (!next) {
+                    break;
+                }
+                vers = (void *)vers + next;
+            }
+            break;
+        }
+        default:
+            unlock_user(argptr, guest_data, 0);
+            ret = -TARGET_EINVAL;
+            goto out;
+        }
+        unlock_user(argptr, guest_data, guest_data_size);
+
+        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+        if (!argptr) {
+            ret = -TARGET_EFAULT;
+            goto out;
+        }
+        thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+        unlock_user(argptr, arg, target_size);
+    }
+out:
+    g_free(big_buf);
+    return ret;
+}
+
+static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
+                               int cmd, abi_long arg)
+{
+    void *argptr;
+    int target_size;
+    const argtype *arg_type = ie->arg_type;
+    const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
+    abi_long ret;
+    struct blkpg_ioctl_arg *host_blkpg = (void *)buf_temp;
+    struct blkpg_partition host_part;
+
+    /* Read and convert blkpg */
+    arg_type++;
+    target_size = thunk_type_size(arg_type, 0);
+    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+    if (!argptr) {
+        ret = -TARGET_EFAULT;
+        goto out;
+    }
+    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+    unlock_user(argptr, arg, 0);
+
+    switch (host_blkpg->op) {
+    case BLKPG_ADD_PARTITION:
+    case BLKPG_DEL_PARTITION:
+        /* payload is struct blkpg_partition */
+        break;
+    default:
+        /* Unknown opcode */
+        ret = -TARGET_EINVAL;
+        goto out;
+    }
+
+    /* Read and convert blkpg->data */
+    arg = (abi_long)(uintptr_t)host_blkpg->data;
+    target_size = thunk_type_size(part_arg_type, 0);
+    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+    if (!argptr) {
+        ret = -TARGET_EFAULT;
+        goto out;
+    }
+    thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
+    unlock_user(argptr, arg, 0);
+
+    /* Swizzle the data pointer to our local copy and call! */
+    host_blkpg->data = &host_part;
+    ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
+
+out:
+    return ret;
+}
+
+static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
+                            int fd, int cmd, abi_long arg)
+{
+    const argtype *arg_type = ie->arg_type;
+    const StructEntry *se;
+    const argtype *field_types;
+    const int *dst_offsets, *src_offsets;
+    int target_size;
+    void *argptr;
+    abi_ulong *target_rt_dev_ptr;
+    unsigned long *host_rt_dev_ptr;
+    abi_long ret;
+    int i;
+
+    assert(ie->access == IOC_W);
+    assert(*arg_type == TYPE_PTR);
+    arg_type++;
+    assert(*arg_type == TYPE_STRUCT);
+    target_size = thunk_type_size(arg_type, 0);
+    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+    if (!argptr) {
+        return -TARGET_EFAULT;
+    }
+    arg_type++;
+    assert(*arg_type == (int)STRUCT_rtentry);
+    se = struct_entries + *arg_type++;
+    assert(se->convert[0] == NULL);
+    /* convert struct here to be able to catch rt_dev string */
+    field_types = se->field_types;
+    dst_offsets = se->field_offsets[THUNK_HOST];
+    src_offsets = se->field_offsets[THUNK_TARGET];
+    for (i = 0; i < se->nb_fields; i++) {
+        if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
+            assert(*field_types == TYPE_PTRVOID);
+            target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
+            host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
+            if (*target_rt_dev_ptr != 0) {
+                *host_rt_dev_ptr = (unsigned long)lock_user_string(
+                    tswapal(*target_rt_dev_ptr));
+                if (!*host_rt_dev_ptr) {
+                    unlock_user(argptr, arg, 0);
+                    return -TARGET_EFAULT;
+                }
+            } else {
+                *host_rt_dev_ptr = 0;
+            }
+            field_types++;
+            continue;
+        }
+        field_types = thunk_convert(buf_temp + dst_offsets[i],
+                                    argptr + src_offsets[i],
+                                    field_types, THUNK_HOST);
+    }
+    unlock_user(argptr, arg, 0);
+
+    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
+    if (*host_rt_dev_ptr != 0) {
+        unlock_user((void *)*host_rt_dev_ptr,
+                    *target_rt_dev_ptr, 0);
+    }
+    return ret;
+}
+
+static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
+                                     int fd, int cmd, abi_long arg)
+{
+    int sig = target_to_host_signal(arg);
+    return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
+}
+
+#ifdef TIOCGPTPEER
+static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
+                                     int fd, int cmd, abi_long arg)
+{
+    int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
+    return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
+}
+#endif
+
+static IOCTLEntry ioctl_entries[] = {
+#define IOCTL(cmd, access, ...)                                 \
+    { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
+#define IOCTL_SPECIAL(cmd, access, dofn, ...)                           \
+    { TARGET_ ## cmd, cmd, #cmd, access, dofn, {  __VA_ARGS__ } },
+#define IOCTL_IGNORE(cmd)                       \
+    { TARGET_ ## cmd, 0, #cmd },
+#include "ioctls.h"
+    { 0, 0, },
+};
+
+/* ??? Implement proper locking for ioctls.  */
+SYSCALL_IMPL(ioctl)
+{
+    int fd = arg1;
+    abi_ulong cmd = arg2;
+    abi_ulong arg = arg3;
+    const IOCTLEntry *ie;
+    const argtype *arg_type;
+    abi_long ret;
+    uint8_t buf_temp[MAX_STRUCT_SIZE];
+    int target_size;
+    void *argptr;
+
+    for (ie = ioctl_entries; ; ie++) {
+        if (ie->target_cmd == 0) {
+            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
+            return -TARGET_ENOSYS;
+        }
+        if (ie->target_cmd == cmd) {
+            break;
+        }
+    }
+
+    arg_type = ie->arg_type;
+    if (ie->do_ioctl) {
+        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
+    } else if (!ie->host_cmd) {
+        /*
+         * Some architectures define BSD ioctls in their headers
+         * that are not implemented in Linux.
+         */
+        return -TARGET_ENOSYS;
+    }
+
+    switch (arg_type[0]) {
+    case TYPE_NULL:
+        /* no argument */
+        ret = get_errno(safe_ioctl(fd, ie->host_cmd));
+        break;
+    case TYPE_PTRVOID:
+    case TYPE_INT:
+        ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
+        break;
+    case TYPE_PTR:
+        arg_type++;
+        target_size = thunk_type_size(arg_type, 0);
+        switch (ie->access) {
+        case IOC_R:
+            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+                if (!argptr) {
+                    return -TARGET_EFAULT;
+                }
+                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+        case IOC_W:
+            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+            if (!argptr) {
+                return -TARGET_EFAULT;
+            }
+            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+            unlock_user(argptr, arg, 0);
+            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
+            break;
+        default:
+        case IOC_RW:
+            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+            if (!argptr) {
+                return -TARGET_EFAULT;
+            }
+            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+            unlock_user(argptr, arg, 0);
+            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
+            if (!is_error(ret)) {
+                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+                if (!argptr) {
+                    return -TARGET_EFAULT;
+                }
+                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+                unlock_user(argptr, arg, target_size);
+            }
+            break;
+        }
+        break;
+    default:
+        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
+                 (long)cmd, arg_type[0]);
+        ret = -TARGET_ENOSYS;
+        break;
+    }
+    return ret;
+}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 82b7267b20..03ecf0a15a 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2935,846 +2935,6 @@ STRUCT_MAX
 #undef STRUCT
 #undef STRUCT_SPECIAL
 
-typedef struct IOCTLEntry IOCTLEntry;
-
-typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
-                             int fd, int cmd, abi_long arg);
-
-struct IOCTLEntry {
-    int target_cmd;
-    unsigned int host_cmd;
-    const char *name;
-    int access;
-    do_ioctl_fn *do_ioctl;
-    const argtype arg_type[5];
-};
-
-#define IOC_R 0x0001
-#define IOC_W 0x0002
-#define IOC_RW (IOC_R | IOC_W)
-
-#define MAX_STRUCT_SIZE 4096
-
-#ifdef CONFIG_FIEMAP
-/* So fiemap access checks don't overflow on 32 bit systems.
- * This is very slightly smaller than the limit imposed by
- * the underlying kernel.
- */
-#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap))  \
-                            / sizeof(struct fiemap_extent))
-
-static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
-                                       int fd, int cmd, abi_long arg)
-{
-    /* The parameter for this ioctl is a struct fiemap followed
-     * by an array of struct fiemap_extent whose size is set
-     * in fiemap->fm_extent_count. The array is filled in by the
-     * ioctl.
-     */
-    int target_size_in, target_size_out;
-    struct fiemap *fm;
-    const argtype *arg_type = ie->arg_type;
-    const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
-    void *argptr, *p;
-    abi_long ret;
-    int i, extent_size = thunk_type_size(extent_arg_type, 0);
-    uint32_t outbufsz;
-    int free_fm = 0;
-
-    assert(arg_type[0] == TYPE_PTR);
-    assert(ie->access == IOC_RW);
-    arg_type++;
-    target_size_in = thunk_type_size(arg_type, 0);
-    argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
-    if (!argptr) {
-        return -TARGET_EFAULT;
-    }
-    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
-    unlock_user(argptr, arg, 0);
-    fm = (struct fiemap *)buf_temp;
-    if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
-        return -TARGET_EINVAL;
-    }
-
-    outbufsz = sizeof (*fm) +
-        (sizeof(struct fiemap_extent) * fm->fm_extent_count);
-
-    if (outbufsz > MAX_STRUCT_SIZE) {
-        /* We can't fit all the extents into the fixed size buffer.
-         * Allocate one that is large enough and use it instead.
-         */
-        fm = g_try_malloc(outbufsz);
-        if (!fm) {
-            return -TARGET_ENOMEM;
-        }
-        memcpy(fm, buf_temp, sizeof(struct fiemap));
-        free_fm = 1;
-    }
-    ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
-    if (!is_error(ret)) {
-        target_size_out = target_size_in;
-        /* An extent_count of 0 means we were only counting the extents
-         * so there are no structs to copy
-         */
-        if (fm->fm_extent_count != 0) {
-            target_size_out += fm->fm_mapped_extents * extent_size;
-        }
-        argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
-        if (!argptr) {
-            ret = -TARGET_EFAULT;
-        } else {
-            /* Convert the struct fiemap */
-            thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
-            if (fm->fm_extent_count != 0) {
-                p = argptr + target_size_in;
-                /* ...and then all the struct fiemap_extents */
-                for (i = 0; i < fm->fm_mapped_extents; i++) {
-                    thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
-                                  THUNK_TARGET);
-                    p += extent_size;
-                }
-            }
-            unlock_user(argptr, arg, target_size_out);
-        }
-    }
-    if (free_fm) {
-        g_free(fm);
-    }
-    return ret;
-}
-#endif
-
-static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
-                                int fd, int cmd, abi_long arg)
-{
-    const argtype *arg_type = ie->arg_type;
-    int target_size;
-    void *argptr;
-    int ret;
-    struct ifconf *host_ifconf;
-    uint32_t outbufsz;
-    const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
-    int target_ifreq_size;
-    int nb_ifreq;
-    int free_buf = 0;
-    int i;
-    int target_ifc_len;
-    abi_long target_ifc_buf;
-    int host_ifc_len;
-    char *host_ifc_buf;
-
-    assert(arg_type[0] == TYPE_PTR);
-    assert(ie->access == IOC_RW);
-
-    arg_type++;
-    target_size = thunk_type_size(arg_type, 0);
-
-    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
-    if (!argptr)
-        return -TARGET_EFAULT;
-    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
-    unlock_user(argptr, arg, 0);
-
-    host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
-    target_ifc_len = host_ifconf->ifc_len;
-    target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
-
-    target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
-    nb_ifreq = target_ifc_len / target_ifreq_size;
-    host_ifc_len = nb_ifreq * sizeof(struct ifreq);
-
-    outbufsz = sizeof(*host_ifconf) + host_ifc_len;
-    if (outbufsz > MAX_STRUCT_SIZE) {
-        /* We can't fit all the extents into the fixed size buffer.
-         * Allocate one that is large enough and use it instead.
-         */
-        host_ifconf = malloc(outbufsz);
-        if (!host_ifconf) {
-            return -TARGET_ENOMEM;
-        }
-        memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
-        free_buf = 1;
-    }
-    host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
-
-    host_ifconf->ifc_len = host_ifc_len;
-    host_ifconf->ifc_buf = host_ifc_buf;
-
-    ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
-    if (!is_error(ret)) {
-	/* convert host ifc_len to target ifc_len */
-
-        nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
-        target_ifc_len = nb_ifreq * target_ifreq_size;
-        host_ifconf->ifc_len = target_ifc_len;
-
-	/* restore target ifc_buf */
-
-        host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
-
-	/* copy struct ifconf to target user */
-
-        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
-        if (!argptr)
-            return -TARGET_EFAULT;
-        thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
-        unlock_user(argptr, arg, target_size);
-
-	/* copy ifreq[] to target user */
-
-        argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
-        for (i = 0; i < nb_ifreq ; i++) {
-            thunk_convert(argptr + i * target_ifreq_size,
-                          host_ifc_buf + i * sizeof(struct ifreq),
-                          ifreq_arg_type, THUNK_TARGET);
-        }
-        unlock_user(argptr, target_ifc_buf, target_ifc_len);
-    }
-
-    if (free_buf) {
-        free(host_ifconf);
-    }
-
-    return ret;
-}
-
-#if defined(CONFIG_USBFS)
-#if HOST_LONG_BITS > 64
-#error USBDEVFS thunks do not support >64 bit hosts yet.
-#endif
-struct live_urb {
-    uint64_t target_urb_adr;
-    uint64_t target_buf_adr;
-    char *target_buf_ptr;
-    struct usbdevfs_urb host_urb;
-};
-
-static GHashTable *usbdevfs_urb_hashtable(void)
-{
-    static GHashTable *urb_hashtable;
-
-    if (!urb_hashtable) {
-        urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
-    }
-    return urb_hashtable;
-}
-
-static void urb_hashtable_insert(struct live_urb *urb)
-{
-    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
-    g_hash_table_insert(urb_hashtable, urb, urb);
-}
-
-static struct live_urb *urb_hashtable_lookup(uint64_t target_urb_adr)
-{
-    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
-    return g_hash_table_lookup(urb_hashtable, &target_urb_adr);
-}
-
-static void urb_hashtable_remove(struct live_urb *urb)
-{
-    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
-    g_hash_table_remove(urb_hashtable, urb);
-}
-
-static abi_long
-do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
-                          int fd, int cmd, abi_long arg)
-{
-    const argtype usbfsurb_arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_urb) };
-    const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
-    struct live_urb *lurb;
-    void *argptr;
-    uint64_t hurb;
-    int target_size;
-    uintptr_t target_urb_adr;
-    abi_long ret;
-
-    target_size = thunk_type_size(usbfsurb_arg_type, THUNK_TARGET);
-
-    memset(buf_temp, 0, sizeof(uint64_t));
-    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
-    if (is_error(ret)) {
-        return ret;
-    }
-
-    memcpy(&hurb, buf_temp, sizeof(uint64_t));
-    lurb = (void *)((uintptr_t)hurb - offsetof(struct live_urb, host_urb));
-    if (!lurb->target_urb_adr) {
-        return -TARGET_EFAULT;
-    }
-    urb_hashtable_remove(lurb);
-    unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr,
-        lurb->host_urb.buffer_length);
-    lurb->target_buf_ptr = NULL;
-
-    /* restore the guest buffer pointer */
-    lurb->host_urb.buffer = (void *)(uintptr_t)lurb->target_buf_adr;
-
-    /* update the guest urb struct */
-    argptr = lock_user(VERIFY_WRITE, lurb->target_urb_adr, target_size, 0);
-    if (!argptr) {
-        g_free(lurb);
-        return -TARGET_EFAULT;
-    }
-    thunk_convert(argptr, &lurb->host_urb, usbfsurb_arg_type, THUNK_TARGET);
-    unlock_user(argptr, lurb->target_urb_adr, target_size);
-
-    target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
-    /* write back the urb handle */
-    argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
-    if (!argptr) {
-        g_free(lurb);
-        return -TARGET_EFAULT;
-    }
-
-    /* GHashTable uses 64-bit keys but thunk_convert expects uintptr_t */
-    target_urb_adr = lurb->target_urb_adr;
-    thunk_convert(argptr, &target_urb_adr, ptrvoid_arg_type, THUNK_TARGET);
-    unlock_user(argptr, arg, target_size);
-
-    g_free(lurb);
-    return ret;
-}
-
-static abi_long
-do_ioctl_usbdevfs_discardurb(const IOCTLEntry *ie,
-                             uint8_t *buf_temp __attribute__((unused)),
-                             int fd, int cmd, abi_long arg)
-{
-    struct live_urb *lurb;
-
-    /* map target address back to host URB with metadata. */
-    lurb = urb_hashtable_lookup(arg);
-    if (!lurb) {
-        return -TARGET_EFAULT;
-    }
-    return get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
-}
-
-static abi_long
-do_ioctl_usbdevfs_submiturb(const IOCTLEntry *ie, uint8_t *buf_temp,
-                            int fd, int cmd, abi_long arg)
-{
-    const argtype *arg_type = ie->arg_type;
-    int target_size;
-    abi_long ret;
-    void *argptr;
-    int rw_dir;
-    struct live_urb *lurb;
-
-    /*
-     * each submitted URB needs to map to a unique ID for the
-     * kernel, and that unique ID needs to be a pointer to
-     * host memory.  hence, we need to malloc for each URB.
-     * isochronous transfers have a variable length struct.
-     */
-    arg_type++;
-    target_size = thunk_type_size(arg_type, THUNK_TARGET);
-
-    /* construct host copy of urb and metadata */
-    lurb = g_try_malloc0(sizeof(struct live_urb));
-    if (!lurb) {
-        return -TARGET_ENOMEM;
-    }
-
-    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
-    if (!argptr) {
-        g_free(lurb);
-        return -TARGET_EFAULT;
-    }
-    thunk_convert(&lurb->host_urb, argptr, arg_type, THUNK_HOST);
-    unlock_user(argptr, arg, 0);
-
-    lurb->target_urb_adr = arg;
-    lurb->target_buf_adr = (uintptr_t)lurb->host_urb.buffer;
-
-    /* buffer space used depends on endpoint type so lock the entire buffer */
-    /* control type urbs should check the buffer contents for true direction */
-    rw_dir = lurb->host_urb.endpoint & USB_DIR_IN ? VERIFY_WRITE : VERIFY_READ;
-    lurb->target_buf_ptr = lock_user(rw_dir, lurb->target_buf_adr,
-        lurb->host_urb.buffer_length, 1);
-    if (lurb->target_buf_ptr == NULL) {
-        g_free(lurb);
-        return -TARGET_EFAULT;
-    }
-
-    /* update buffer pointer in host copy */
-    lurb->host_urb.buffer = lurb->target_buf_ptr;
-
-    ret = get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
-    if (is_error(ret)) {
-        unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr, 0);
-        g_free(lurb);
-    } else {
-        urb_hashtable_insert(lurb);
-    }
-
-    return ret;
-}
-#endif /* CONFIG_USBFS */
-
-static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
-                            int cmd, abi_long arg)
-{
-    void *argptr;
-    struct dm_ioctl *host_dm;
-    abi_long guest_data;
-    uint32_t guest_data_size;
-    int target_size;
-    const argtype *arg_type = ie->arg_type;
-    abi_long ret;
-    void *big_buf = NULL;
-    char *host_data;
-
-    arg_type++;
-    target_size = thunk_type_size(arg_type, 0);
-    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
-    if (!argptr) {
-        ret = -TARGET_EFAULT;
-        goto out;
-    }
-    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
-    unlock_user(argptr, arg, 0);
-
-    /* buf_temp is too small, so fetch things into a bigger buffer */
-    big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
-    memcpy(big_buf, buf_temp, target_size);
-    buf_temp = big_buf;
-    host_dm = big_buf;
-
-    guest_data = arg + host_dm->data_start;
-    if ((guest_data - arg) < 0) {
-        ret = -TARGET_EINVAL;
-        goto out;
-    }
-    guest_data_size = host_dm->data_size - host_dm->data_start;
-    host_data = (char*)host_dm + host_dm->data_start;
-
-    argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
-    if (!argptr) {
-        ret = -TARGET_EFAULT;
-        goto out;
-    }
-
-    switch (ie->host_cmd) {
-    case DM_REMOVE_ALL:
-    case DM_LIST_DEVICES:
-    case DM_DEV_CREATE:
-    case DM_DEV_REMOVE:
-    case DM_DEV_SUSPEND:
-    case DM_DEV_STATUS:
-    case DM_DEV_WAIT:
-    case DM_TABLE_STATUS:
-    case DM_TABLE_CLEAR:
-    case DM_TABLE_DEPS:
-    case DM_LIST_VERSIONS:
-        /* no input data */
-        break;
-    case DM_DEV_RENAME:
-    case DM_DEV_SET_GEOMETRY:
-        /* data contains only strings */
-        memcpy(host_data, argptr, guest_data_size);
-        break;
-    case DM_TARGET_MSG:
-        memcpy(host_data, argptr, guest_data_size);
-        *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
-        break;
-    case DM_TABLE_LOAD:
-    {
-        void *gspec = argptr;
-        void *cur_data = host_data;
-        const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
-        int spec_size = thunk_type_size(arg_type, 0);
-        int i;
-
-        for (i = 0; i < host_dm->target_count; i++) {
-            struct dm_target_spec *spec = cur_data;
-            uint32_t next;
-            int slen;
-
-            thunk_convert(spec, gspec, arg_type, THUNK_HOST);
-            slen = strlen((char*)gspec + spec_size) + 1;
-            next = spec->next;
-            spec->next = sizeof(*spec) + slen;
-            strcpy((char*)&spec[1], gspec + spec_size);
-            gspec += next;
-            cur_data += spec->next;
-        }
-        break;
-    }
-    default:
-        ret = -TARGET_EINVAL;
-        unlock_user(argptr, guest_data, 0);
-        goto out;
-    }
-    unlock_user(argptr, guest_data, 0);
-
-    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
-    if (!is_error(ret)) {
-        guest_data = arg + host_dm->data_start;
-        guest_data_size = host_dm->data_size - host_dm->data_start;
-        argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
-        switch (ie->host_cmd) {
-        case DM_REMOVE_ALL:
-        case DM_DEV_CREATE:
-        case DM_DEV_REMOVE:
-        case DM_DEV_RENAME:
-        case DM_DEV_SUSPEND:
-        case DM_DEV_STATUS:
-        case DM_TABLE_LOAD:
-        case DM_TABLE_CLEAR:
-        case DM_TARGET_MSG:
-        case DM_DEV_SET_GEOMETRY:
-            /* no return data */
-            break;
-        case DM_LIST_DEVICES:
-        {
-            struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
-            uint32_t remaining_data = guest_data_size;
-            void *cur_data = argptr;
-            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
-            int nl_size = 12; /* can't use thunk_size due to alignment */
-
-            while (1) {
-                uint32_t next = nl->next;
-                if (next) {
-                    nl->next = nl_size + (strlen(nl->name) + 1);
-                }
-                if (remaining_data < nl->next) {
-                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
-                    break;
-                }
-                thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
-                strcpy(cur_data + nl_size, nl->name);
-                cur_data += nl->next;
-                remaining_data -= nl->next;
-                if (!next) {
-                    break;
-                }
-                nl = (void*)nl + next;
-            }
-            break;
-        }
-        case DM_DEV_WAIT:
-        case DM_TABLE_STATUS:
-        {
-            struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
-            void *cur_data = argptr;
-            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
-            int spec_size = thunk_type_size(arg_type, 0);
-            int i;
-
-            for (i = 0; i < host_dm->target_count; i++) {
-                uint32_t next = spec->next;
-                int slen = strlen((char*)&spec[1]) + 1;
-                spec->next = (cur_data - argptr) + spec_size + slen;
-                if (guest_data_size < spec->next) {
-                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
-                    break;
-                }
-                thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
-                strcpy(cur_data + spec_size, (char*)&spec[1]);
-                cur_data = argptr + spec->next;
-                spec = (void*)host_dm + host_dm->data_start + next;
-            }
-            break;
-        }
-        case DM_TABLE_DEPS:
-        {
-            void *hdata = (void*)host_dm + host_dm->data_start;
-            int count = *(uint32_t*)hdata;
-            uint64_t *hdev = hdata + 8;
-            uint64_t *gdev = argptr + 8;
-            int i;
-
-            *(uint32_t*)argptr = tswap32(count);
-            for (i = 0; i < count; i++) {
-                *gdev = tswap64(*hdev);
-                gdev++;
-                hdev++;
-            }
-            break;
-        }
-        case DM_LIST_VERSIONS:
-        {
-            struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
-            uint32_t remaining_data = guest_data_size;
-            void *cur_data = argptr;
-            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
-            int vers_size = thunk_type_size(arg_type, 0);
-
-            while (1) {
-                uint32_t next = vers->next;
-                if (next) {
-                    vers->next = vers_size + (strlen(vers->name) + 1);
-                }
-                if (remaining_data < vers->next) {
-                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
-                    break;
-                }
-                thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
-                strcpy(cur_data + vers_size, vers->name);
-                cur_data += vers->next;
-                remaining_data -= vers->next;
-                if (!next) {
-                    break;
-                }
-                vers = (void*)vers + next;
-            }
-            break;
-        }
-        default:
-            unlock_user(argptr, guest_data, 0);
-            ret = -TARGET_EINVAL;
-            goto out;
-        }
-        unlock_user(argptr, guest_data, guest_data_size);
-
-        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
-        if (!argptr) {
-            ret = -TARGET_EFAULT;
-            goto out;
-        }
-        thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
-        unlock_user(argptr, arg, target_size);
-    }
-out:
-    g_free(big_buf);
-    return ret;
-}
-
-static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
-                               int cmd, abi_long arg)
-{
-    void *argptr;
-    int target_size;
-    const argtype *arg_type = ie->arg_type;
-    const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
-    abi_long ret;
-
-    struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
-    struct blkpg_partition host_part;
-
-    /* Read and convert blkpg */
-    arg_type++;
-    target_size = thunk_type_size(arg_type, 0);
-    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
-    if (!argptr) {
-        ret = -TARGET_EFAULT;
-        goto out;
-    }
-    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
-    unlock_user(argptr, arg, 0);
-
-    switch (host_blkpg->op) {
-    case BLKPG_ADD_PARTITION:
-    case BLKPG_DEL_PARTITION:
-        /* payload is struct blkpg_partition */
-        break;
-    default:
-        /* Unknown opcode */
-        ret = -TARGET_EINVAL;
-        goto out;
-    }
-
-    /* Read and convert blkpg->data */
-    arg = (abi_long)(uintptr_t)host_blkpg->data;
-    target_size = thunk_type_size(part_arg_type, 0);
-    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
-    if (!argptr) {
-        ret = -TARGET_EFAULT;
-        goto out;
-    }
-    thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
-    unlock_user(argptr, arg, 0);
-
-    /* Swizzle the data pointer to our local copy and call! */
-    host_blkpg->data = &host_part;
-    ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
-
-out:
-    return ret;
-}
-
-static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
-                                int fd, int cmd, abi_long arg)
-{
-    const argtype *arg_type = ie->arg_type;
-    const StructEntry *se;
-    const argtype *field_types;
-    const int *dst_offsets, *src_offsets;
-    int target_size;
-    void *argptr;
-    abi_ulong *target_rt_dev_ptr;
-    unsigned long *host_rt_dev_ptr;
-    abi_long ret;
-    int i;
-
-    assert(ie->access == IOC_W);
-    assert(*arg_type == TYPE_PTR);
-    arg_type++;
-    assert(*arg_type == TYPE_STRUCT);
-    target_size = thunk_type_size(arg_type, 0);
-    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
-    if (!argptr) {
-        return -TARGET_EFAULT;
-    }
-    arg_type++;
-    assert(*arg_type == (int)STRUCT_rtentry);
-    se = struct_entries + *arg_type++;
-    assert(se->convert[0] == NULL);
-    /* convert struct here to be able to catch rt_dev string */
-    field_types = se->field_types;
-    dst_offsets = se->field_offsets[THUNK_HOST];
-    src_offsets = se->field_offsets[THUNK_TARGET];
-    for (i = 0; i < se->nb_fields; i++) {
-        if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
-            assert(*field_types == TYPE_PTRVOID);
-            target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
-            host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
-            if (*target_rt_dev_ptr != 0) {
-                *host_rt_dev_ptr = (unsigned long)lock_user_string(
-                                                  tswapal(*target_rt_dev_ptr));
-                if (!*host_rt_dev_ptr) {
-                    unlock_user(argptr, arg, 0);
-                    return -TARGET_EFAULT;
-                }
-            } else {
-                *host_rt_dev_ptr = 0;
-            }
-            field_types++;
-            continue;
-        }
-        field_types = thunk_convert(buf_temp + dst_offsets[i],
-                                    argptr + src_offsets[i],
-                                    field_types, THUNK_HOST);
-    }
-    unlock_user(argptr, arg, 0);
-
-    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
-    if (*host_rt_dev_ptr != 0) {
-        unlock_user((void *)*host_rt_dev_ptr,
-                    *target_rt_dev_ptr, 0);
-    }
-    return ret;
-}
-
-static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
-                                     int fd, int cmd, abi_long arg)
-{
-    int sig = target_to_host_signal(arg);
-    return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
-}
-
-#ifdef TIOCGPTPEER
-static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
-                                     int fd, int cmd, abi_long arg)
-{
-    int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
-    return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
-}
-#endif
-
-static IOCTLEntry ioctl_entries[] = {
-#define IOCTL(cmd, access, ...) \
-    { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
-#define IOCTL_SPECIAL(cmd, access, dofn, ...)                      \
-    { TARGET_ ## cmd, cmd, #cmd, access, dofn, {  __VA_ARGS__ } },
-#define IOCTL_IGNORE(cmd) \
-    { TARGET_ ## cmd, 0, #cmd },
-#include "ioctls.h"
-    { 0, 0, },
-};
-
-/* ??? Implement proper locking for ioctls.  */
-/* do_ioctl() Must return target values and target errnos. */
-static abi_long do_ioctl(int fd, int cmd, abi_long arg)
-{
-    const IOCTLEntry *ie;
-    const argtype *arg_type;
-    abi_long ret;
-    uint8_t buf_temp[MAX_STRUCT_SIZE];
-    int target_size;
-    void *argptr;
-
-    ie = ioctl_entries;
-    for(;;) {
-        if (ie->target_cmd == 0) {
-            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
-            return -TARGET_ENOSYS;
-        }
-        if (ie->target_cmd == cmd)
-            break;
-        ie++;
-    }
-    arg_type = ie->arg_type;
-    if (ie->do_ioctl) {
-        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
-    } else if (!ie->host_cmd) {
-        /* Some architectures define BSD ioctls in their headers
-           that are not implemented in Linux.  */
-        return -TARGET_ENOSYS;
-    }
-
-    switch(arg_type[0]) {
-    case TYPE_NULL:
-        /* no argument */
-        ret = get_errno(safe_ioctl(fd, ie->host_cmd));
-        break;
-    case TYPE_PTRVOID:
-    case TYPE_INT:
-        ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
-        break;
-    case TYPE_PTR:
-        arg_type++;
-        target_size = thunk_type_size(arg_type, 0);
-        switch(ie->access) {
-        case IOC_R:
-            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
-            if (!is_error(ret)) {
-                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
-                if (!argptr)
-                    return -TARGET_EFAULT;
-                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
-                unlock_user(argptr, arg, target_size);
-            }
-            break;
-        case IOC_W:
-            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
-            if (!argptr)
-                return -TARGET_EFAULT;
-            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
-            unlock_user(argptr, arg, 0);
-            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
-            break;
-        default:
-        case IOC_RW:
-            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
-            if (!argptr)
-                return -TARGET_EFAULT;
-            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
-            unlock_user(argptr, arg, 0);
-            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
-            if (!is_error(ret)) {
-                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
-                if (!argptr)
-                    return -TARGET_EFAULT;
-                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
-                unlock_user(argptr, arg, target_size);
-            }
-            break;
-        }
-        break;
-    default:
-        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
-                 (long)cmd, arg_type[0]);
-        ret = -TARGET_ENOSYS;
-        break;
-    }
-    return ret;
-}
-
 static const bitmask_transtbl iflag_tbl[] = {
         { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
         { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
@@ -5241,8 +4401,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-    case TARGET_NR_ioctl:
-        return do_ioctl(arg1, arg2, arg3);
 #ifdef TARGET_NR_fcntl
     case TARGET_NR_fcntl:
         return do_fcntl(arg1, arg2, arg3);
@@ -8811,6 +7969,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
                                 int64_t arg5, int64_t arg6)
 
 #include "syscall-file.inc.c"
+#include "syscall-ioctl.inc.c"
 #include "syscall-ipc.inc.c"
 #include "syscall-mem.inc.c"
 #include "syscall-proc.inc.c"
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 9f2f8977b4..15208b5349 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -365,9 +365,6 @@
 #ifdef TARGET_NR_io_cancel
 { TARGET_NR_io_cancel, "io_cancel" , NULL, NULL, NULL },
 #endif
-#ifdef TARGET_NR_ioctl
-{ TARGET_NR_ioctl, "ioctl" , NULL, NULL, NULL },
-#endif
 #ifdef TARGET_NR_io_destroy
 { TARGET_NR_io_destroy, "io_destroy" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [Qemu-devel] [PATCH v6 49/49] linux-user: Split out fcntl, fcntl64
  2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
                   ` (46 preceding siblings ...)
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl Richard Henderson
@ 2019-01-18 21:31 ` Richard Henderson
  47 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-01-18 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: laurent

Preserving strace functionality is tricky with this one.
Rearrange to lookup structures that contain the data for
both execution and strace for each command.

Do not allow lookup of 64-bit fcntl commands from 32-bit fcntl.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall-defs.h      |   6 +
 linux-user/strace.c            | 100 ----------
 linux-user/syscall-fcntl.inc.c | 322 +++++++++++++++++++++++++++++++++
 linux-user/syscall.c           | 256 +-------------------------
 linux-user/strace.list         |   6 -
 5 files changed, 329 insertions(+), 361 deletions(-)
 create mode 100644 linux-user/syscall-fcntl.inc.c

diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index f58b9745a4..5cf39f2bb9 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -46,6 +46,12 @@ SYSCALL_DEF(execveat, ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_PTR, ARG_ATFLAG);
 SYSCALL_DEF(faccessat, ARG_ATDIRFD, ARG_STR, ARG_ACCESSFLAG);
 SYSCALL_DEF(fchmod, ARG_DEC, ARG_MODEFLAG);
 SYSCALL_DEF(fchmodat, ARG_ATDIRFD, ARG_STR, ARG_MODEFLAG);
+#ifdef TARGET_NR_fcntl
+SYSCALL_DEF_FULL(fcntl, .impl = impl_fcntl, .print = print_fcntl);
+#endif
+#if TARGET_ABI_BITS == 32
+SYSCALL_DEF_FULL(fcntl64, .impl = impl_fcntl64, .print = print_fcntl64);
+#endif
 #ifdef TARGET_NR_futimesat
 SYSCALL_DEF(futimesat, ARG_ATDIRFD, ARG_STR, ARG_PTR);
 #endif
diff --git a/linux-user/strace.c b/linux-user/strace.c
index ca8e110675..787bf41307 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1172,106 +1172,6 @@ print_fchownat(const struct syscallname *name,
 }
 #endif
 
-#if defined(TARGET_NR_fcntl) || defined(TARGET_NR_fcntl64)
-static void
-print_fcntl(const struct syscallname *name,
-    abi_long arg0, abi_long arg1, abi_long arg2,
-    abi_long arg3, abi_long arg4, abi_long arg5)
-{
-    print_syscall_prologue(name);
-    print_raw_param("%d", arg0, 0);
-    switch(arg1) {
-    case TARGET_F_DUPFD:
-        gemu_log("F_DUPFD,");
-        print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
-        break;
-    case TARGET_F_GETFD:
-        gemu_log("F_GETFD");
-        break;
-    case TARGET_F_SETFD:
-        gemu_log("F_SETFD,");
-        print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
-        break;
-    case TARGET_F_GETFL:
-        gemu_log("F_GETFL");
-        break;
-    case TARGET_F_SETFL:
-        gemu_log("F_SETFL,");
-        print_open_flags(arg2, 1);
-        break;
-    case TARGET_F_GETLK:
-        gemu_log("F_GETLK,");
-        print_pointer(arg2, 1);
-        break;
-    case TARGET_F_SETLK:
-        gemu_log("F_SETLK,");
-        print_pointer(arg2, 1);
-        break;
-    case TARGET_F_SETLKW:
-        gemu_log("F_SETLKW,");
-        print_pointer(arg2, 1);
-        break;
-    case TARGET_F_GETOWN:
-        gemu_log("F_GETOWN");
-        break;
-    case TARGET_F_SETOWN:
-        gemu_log("F_SETOWN,");
-        print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
-        break;
-    case TARGET_F_GETSIG:
-        gemu_log("F_GETSIG");
-        break;
-    case TARGET_F_SETSIG:
-        gemu_log("F_SETSIG,");
-        print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
-        break;
-#if TARGET_ABI_BITS == 32
-    case TARGET_F_GETLK64:
-        gemu_log("F_GETLK64,");
-        print_pointer(arg2, 1);
-        break;
-    case TARGET_F_SETLK64:
-        gemu_log("F_SETLK64,");
-        print_pointer(arg2, 1);
-        break;
-    case TARGET_F_SETLKW64:
-        gemu_log("F_SETLKW64,");
-        print_pointer(arg2, 1);
-        break;
-#endif
-    case TARGET_F_SETLEASE:
-        gemu_log("F_SETLEASE,");
-        print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
-        break;
-    case TARGET_F_GETLEASE:
-        gemu_log("F_GETLEASE");
-        break;
-    case TARGET_F_SETPIPE_SZ:
-        gemu_log("F_SETPIPE_SZ,");
-        print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
-        break;
-    case TARGET_F_GETPIPE_SZ:
-        gemu_log("F_GETPIPE_SZ");
-        break;
-    case TARGET_F_DUPFD_CLOEXEC:
-        gemu_log("F_DUPFD_CLOEXEC,");
-        print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
-        break;
-    case TARGET_F_NOTIFY:
-        gemu_log("F_NOTIFY,");
-        print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
-        break;
-    default:
-        print_raw_param(TARGET_ABI_FMT_ld, arg1, 0);
-        print_pointer(arg2, 1);
-        break;
-    }
-    print_syscall_epilogue(name);
-}
-#define print_fcntl64   print_fcntl
-#endif
-
-
 #if defined(TARGET_NR_socket)
 static void
 print_socket(const struct syscallname *name,
diff --git a/linux-user/syscall-fcntl.inc.c b/linux-user/syscall-fcntl.inc.c
new file mode 100644
index 0000000000..768682bd17
--- /dev/null
+++ b/linux-user/syscall-fcntl.inc.c
@@ -0,0 +1,322 @@
+/*
+ *  Linux fcntl syscall implementation
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+typedef struct FcntlEntry FcntlEntry;
+
+typedef abi_long FcntlFn(int fd, int host_cmd, abi_long arg);
+
+struct FcntlEntry {
+    const char *name;
+    FcntlFn *host_fn;
+    int host_cmd;
+    SyscallArgType arg_type;
+};
+
+static abi_long do_fcntl_int(int fd, int host_cmd, abi_long arg)
+{
+    return get_errno(safe_fcntl(fd, host_cmd, arg));
+}
+
+static abi_long do_fcntl_getfl(int fd, int host_cmd, abi_long arg)
+{
+    abi_long ret = get_errno(safe_fcntl(fd, host_cmd));
+    if (!is_error(ret)) {
+        ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
+    }
+    return ret;
+}
+
+static abi_long do_fcntl_setfl(int fd, int host_cmd, abi_long arg)
+{
+    return get_errno(safe_fcntl(fd, host_cmd,
+                                target_to_host_bitmask(arg, fcntl_flags_tbl)));
+}
+
+static abi_long do_fcntl_getlk_1(int fd, int host_cmd, abi_long arg,
+                                 from_flock64_fn *copy_from,
+                                 to_flock64_fn *copy_to)
+{
+    struct flock64 fl64;
+    abi_long ret;
+
+    ret = copy_from(&fl64, arg);
+    if (ret == 0) {
+        ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
+        if (ret == 0) {
+            ret = copy_to(arg, &fl64);
+        }
+    }
+    return ret;
+}
+
+static abi_long do_fcntl_setlk_1(int fd, int host_cmd, abi_long arg,
+                                 from_flock64_fn *copy_from)
+{
+    struct flock64 fl64;
+    abi_long ret;
+
+    ret = copy_from(&fl64, arg);
+    if (ret == 0) {
+        ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
+    }
+    return ret;
+}
+
+static abi_long do_fcntl_getlk(int fd, int cmd, abi_long arg)
+{
+    return do_fcntl_getlk_1(fd, cmd, arg,
+                            copy_from_user_flock,
+                            copy_to_user_flock);
+}
+
+static abi_long do_fcntl_setlk(int fd, int cmd, abi_long arg)
+{
+    return do_fcntl_setlk_1(fd, cmd, arg, copy_from_user_flock);
+}
+
+static abi_long do_fcntl_getlk64(int fd, int cmd, abi_long arg)
+{
+    return do_fcntl_getlk_1(fd, cmd, arg,
+                            copy_from_user_flock64,
+                            copy_to_user_flock64);
+}
+
+static abi_long do_fcntl_setlk64(int fd, int cmd, abi_long arg)
+{
+    return do_fcntl_setlk_1(fd, cmd, arg, copy_from_user_flock64);
+}
+
+#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
+static abi_long do_fcntl_oabi_getlk64(int fd, int cmd, abi_long arg)
+{
+    return do_fcntl_getlk_1(fd, cmd, arg,
+                            copy_from_user_oabi_flock64,
+                            copy_to_user_oabi_flock64);
+}
+
+static abi_long do_fcntl_oabi_setlk64(int fd, int cmd, abi_long arg)
+{
+    return do_fcntl_setlk_1(fd, cmd, arg, copy_from_user_oabi_flock64);
+}
+#endif /* TARGET_ARM */
+
+#ifdef F_GETOWN_EX
+static abi_long do_fcntl_getown_ex(int fd, int cmd, abi_long arg)
+{
+    struct f_owner_ex fox;
+    abi_long ret = get_errno(safe_fcntl(fd, cmd, &fox));
+
+    if (!is_error(ret)) {
+        struct target_f_owner_ex *target_fox;
+        if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0)) {
+            return -TARGET_EFAULT;
+        }
+        target_fox->type = tswap32(fox.type);
+        target_fox->pid = tswap32(fox.pid);
+        unlock_user_struct(target_fox, arg, 1);
+    }
+    return ret;
+}
+
+static abi_long do_fcntl_setown_ex(int fd, int cmd, abi_long arg)
+{
+    struct target_f_owner_ex *target_fox;
+    struct f_owner_ex fox;
+
+    if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1)) {
+        return -TARGET_EFAULT;
+    }
+    fox.type = tswap32(target_fox->type);
+    fox.pid = tswap32(target_fox->pid);
+    unlock_user_struct(target_fox, arg, 0);
+    return get_errno(safe_fcntl(fd, cmd, &fox));
+}
+#endif /* F_GETOWN_EX */
+
+static const FcntlEntry *target_fcntl_cmd(int cmd, int is_64)
+{
+#define CMD2(T, H, A, FN)                                            \
+    case TARGET_##T: do {                                            \
+        static const FcntlEntry ent_##T = {                          \
+            .name = #T, .host_cmd = H, .host_fn = FN, .arg_type = A  \
+        };                                                           \
+        return &ent_##T;                                             \
+    } while(0)
+
+#define CMD1(T, A, FN)                                               \
+    case TARGET_##T: do {                                            \
+        static const FcntlEntry ent_##T = {                          \
+            .name = #T, .host_cmd = T, .host_fn = FN, .arg_type = A  \
+        };                                                           \
+        return &ent_##T;                                             \
+    } while(0)
+
+#if TARGET_ABI_BITS == 64
+# ifdef __powerpc64__
+/*
+ * On PPC64, glibc headers has the F_*LK* defined to 12, 13 and 14 and
+ * is not supported by kernel. The glibc fcntl call actually adjusts
+ * them to 5, 6 and 7 before making the syscall(). Since we make the
+ * syscall directly, adjust to what is supported by the kernel.
+ */
+#  define HOST_CMD_ADJ64(C)  (C - (F_GETLK64 - 5))
+# else
+#  define HOST_CMD_ADJ64(C)  C
+# endif
+# define CMD64(T, FN)                                                \
+    case TARGET_##T: do {                                            \
+        static const FcntlEntry ent_##T = {                          \
+            .name = #T, .host_cmd = HOST_CMD_ADJ64(T),               \
+            .host_fn = do_fcntl_##FN, .arg_type = ARG_PTR            \
+        };                                                           \
+        return &ent_##T;                                             \
+    } while(0)
+#elif defined(TARGET_ARM)
+# define CMD64(T, FN)                                                \
+    case TARGET_##T: do {                                            \
+        if (!is_64) {                                                \
+            return NULL;                                             \
+        } else if (is_64 > 0) {                                      \
+            static const FcntlEntry ent_##T = {                      \
+                .name = #T, .host_cmd = T,                           \
+                .host_fn = do_fcntl_##FN, .arg_type = ARG_PTR        \
+            };                                                       \
+            return &ent_##T;                                         \
+        } else {                                                     \
+            static const FcntlEntry ent_oabi_##T = {                 \
+                .name = #T, .host_cmd = T,                           \
+                .host_fn = do_fcntl_oabi_##FN, .arg_type = ARG_PTR   \
+            };                                                       \
+            return &ent_oabi_##T;                                    \
+        }                                                            \
+    } while (0)
+#else
+# define CMD64(T, FN)                                                \
+    case TARGET_##T: do {                                            \
+        static const FcntlEntry ent_##T = {                          \
+            .name = #T, .host_cmd = T,                               \
+            .host_fn = do_fcntl_##FN, .arg_type = ARG_PTR            \
+        };                                                           \
+        return is_64 ? &ent_##T : NULL;                              \
+    } while (0)
+#endif
+
+    switch (cmd) {
+    CMD1(F_DUPFD, ARG_DEC, do_fcntl_int);
+    CMD1(F_GETFD, ARG_NONE, do_fcntl_int);
+    CMD1(F_SETFD, ARG_DEC, do_fcntl_int);
+    CMD1(F_GETFL, ARG_NONE, do_fcntl_getfl);
+    CMD1(F_SETFL, ARG_DEC, do_fcntl_setfl);
+
+    CMD2(F_GETLK, F_GETLK64, ARG_PTR, do_fcntl_getlk);
+    CMD2(F_SETLK, F_SETLK64, ARG_PTR, do_fcntl_setlk);
+    CMD2(F_SETLKW, F_SETLKW64, ARG_PTR, do_fcntl_setlk);
+
+    CMD1(F_GETOWN, ARG_NONE, do_fcntl_int);
+    CMD1(F_SETOWN, ARG_DEC, do_fcntl_int);
+    CMD1(F_GETSIG, ARG_NONE, do_fcntl_int);
+    CMD1(F_SETSIG, ARG_DEC, do_fcntl_int);
+
+    CMD64(F_GETLK64, getlk64);
+    CMD64(F_SETLK64, setlk64);
+    CMD64(F_SETLKW64, setlk64);
+
+    CMD1(F_GETLEASE, ARG_NONE, do_fcntl_int);
+    CMD1(F_SETLEASE, ARG_DEC, do_fcntl_int);
+#ifdef F_DUPFD_CLOEXEC
+    CMD1(F_DUPFD_CLOEXEC, ARG_DEC, do_fcntl_int);
+#endif
+    CMD1(F_NOTIFY, ARG_DEC, do_fcntl_int);
+#ifdef F_GETOWN_EX
+    CMD1(F_GETOWN_EX, ARG_PTR, do_fcntl_getown_ex);
+    CMD1(F_SETOWN_EX, ARG_PTR, do_fcntl_setown_ex);
+#endif
+#ifdef F_SETPIPE_SZ
+    CMD1(F_SETPIPE_SZ, ARG_DEC, do_fcntl_int);
+    CMD1(F_GETPIPE_SZ, ARG_DEC, do_fcntl_int);
+#endif
+    }
+    return NULL;
+
+#undef CMD1
+#undef CMD2
+#undef CMD64
+#undef HOST_CMD_ADJ64
+}
+
+static abi_long do_fcntl(int fd, int target_cmd, abi_ulong arg, int is_64)
+{
+    const FcntlEntry *ent = target_fcntl_cmd(target_cmd, is_64);
+
+    if (ent == NULL) {
+        return -TARGET_EINVAL;
+    }
+    return ent->host_fn(fd, ent->host_cmd, arg);
+}
+
+static void do_print_fcntl(const SyscallDef *def, int fd, int target_cmd,
+                           abi_ulong arg, int is_64)
+{
+    const FcntlEntry *ent = target_fcntl_cmd(target_cmd, is_64);
+
+    switch (ent->arg_type) {
+    case ARG_NONE:
+        gemu_log("%d %s(%d,%s)", getpid(), def->name, fd, ent->name);
+        break;
+    case ARG_DEC:
+        gemu_log("%d %s(%d,%s," TARGET_ABI_FMT_ld ")",
+                 getpid(), def->name, fd, ent->name, arg);
+        break;
+    case ARG_PTR:
+        gemu_log("%d %s(%d,%s,0x" TARGET_ABI_FMT_lx ")",
+                 getpid(), def->name, fd, ent->name, arg);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+#ifdef TARGET_NR_fcntl
+SYSCALL_IMPL(fcntl)
+{
+    return do_fcntl(arg1, arg2, arg3, 0);
+}
+
+static void print_fcntl(const SyscallDef *def, int64_t in[6])
+{
+    return do_print_fcntl(def, in[0], in[1], in[2], 0);
+}
+#endif
+
+#if TARGET_ABI_BITS == 32
+SYSCALL_IMPL(fcntl64)
+{
+    int is_64 = 1;
+#ifdef TARGET_ARM
+    if (!cpu_env->eabi) {
+        is_64 = -1;
+    }
+#endif
+    return do_fcntl(arg1, arg2, arg3, is_64);
+}
+
+static void print_fcntl64(const SyscallDef *def, int64_t in[6])
+{
+    return do_print_fcntl(def, in[0], in[1], in[2], 1);
+}
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 03ecf0a15a..bce26592d2 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -3469,102 +3469,6 @@ static void *clone_func(void *arg)
     return NULL;
 }
 
-/* warning : doesn't handle linux specific flags... */
-static int target_to_host_fcntl_cmd(int cmd)
-{
-    int ret;
-
-    switch(cmd) {
-    case TARGET_F_DUPFD:
-    case TARGET_F_GETFD:
-    case TARGET_F_SETFD:
-    case TARGET_F_GETFL:
-    case TARGET_F_SETFL:
-        ret = cmd;
-        break;
-    case TARGET_F_GETLK:
-        ret = F_GETLK64;
-        break;
-    case TARGET_F_SETLK:
-        ret = F_SETLK64;
-        break;
-    case TARGET_F_SETLKW:
-        ret = F_SETLKW64;
-        break;
-    case TARGET_F_GETOWN:
-        ret = F_GETOWN;
-        break;
-    case TARGET_F_SETOWN:
-        ret = F_SETOWN;
-        break;
-    case TARGET_F_GETSIG:
-        ret = F_GETSIG;
-        break;
-    case TARGET_F_SETSIG:
-        ret = F_SETSIG;
-        break;
-#if TARGET_ABI_BITS == 32
-    case TARGET_F_GETLK64:
-        ret = F_GETLK64;
-        break;
-    case TARGET_F_SETLK64:
-        ret = F_SETLK64;
-        break;
-    case TARGET_F_SETLKW64:
-        ret = F_SETLKW64;
-        break;
-#endif
-    case TARGET_F_SETLEASE:
-        ret = F_SETLEASE;
-        break;
-    case TARGET_F_GETLEASE:
-        ret = F_GETLEASE;
-        break;
-#ifdef F_DUPFD_CLOEXEC
-    case TARGET_F_DUPFD_CLOEXEC:
-        ret = F_DUPFD_CLOEXEC;
-        break;
-#endif
-    case TARGET_F_NOTIFY:
-        ret = F_NOTIFY;
-        break;
-#ifdef F_GETOWN_EX
-    case TARGET_F_GETOWN_EX:
-        ret = F_GETOWN_EX;
-        break;
-#endif
-#ifdef F_SETOWN_EX
-    case TARGET_F_SETOWN_EX:
-        ret = F_SETOWN_EX;
-        break;
-#endif
-#ifdef F_SETPIPE_SZ
-    case TARGET_F_SETPIPE_SZ:
-        ret = F_SETPIPE_SZ;
-        break;
-    case TARGET_F_GETPIPE_SZ:
-        ret = F_GETPIPE_SZ;
-        break;
-#endif
-    default:
-        ret = -TARGET_EINVAL;
-        break;
-    }
-
-#if defined(__powerpc64__)
-    /* On PPC64, glibc headers has the F_*LK* defined to 12, 13 and 14 and
-     * is not supported by kernel. The glibc fcntl call actually adjusts
-     * them to 5, 6 and 7 before making the syscall(). Since we make the
-     * syscall directly, adjust to what is supported by the kernel.
-     */
-    if (ret >= F_GETLK64 && ret <= F_SETLKW64) {
-        ret -= F_GETLK64 - 5;
-    }
-#endif
-
-    return ret;
-}
-
 #define FLOCK_TRANSTBL \
     switch (type) { \
     TRANSTBL_CONVERT(F_RDLCK); \
@@ -3730,114 +3634,6 @@ static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
     return 0;
 }
 
-static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
-{
-    struct flock64 fl64;
-#ifdef F_GETOWN_EX
-    struct f_owner_ex fox;
-    struct target_f_owner_ex *target_fox;
-#endif
-    abi_long ret;
-    int host_cmd = target_to_host_fcntl_cmd(cmd);
-
-    if (host_cmd == -TARGET_EINVAL)
-	    return host_cmd;
-
-    switch(cmd) {
-    case TARGET_F_GETLK:
-        ret = copy_from_user_flock(&fl64, arg);
-        if (ret) {
-            return ret;
-        }
-        ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
-        if (ret == 0) {
-            ret = copy_to_user_flock(arg, &fl64);
-        }
-        break;
-
-    case TARGET_F_SETLK:
-    case TARGET_F_SETLKW:
-        ret = copy_from_user_flock(&fl64, arg);
-        if (ret) {
-            return ret;
-        }
-        ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
-        break;
-
-    case TARGET_F_GETLK64:
-        ret = copy_from_user_flock64(&fl64, arg);
-        if (ret) {
-            return ret;
-        }
-        ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
-        if (ret == 0) {
-            ret = copy_to_user_flock64(arg, &fl64);
-        }
-        break;
-    case TARGET_F_SETLK64:
-    case TARGET_F_SETLKW64:
-        ret = copy_from_user_flock64(&fl64, arg);
-        if (ret) {
-            return ret;
-        }
-        ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
-        break;
-
-    case TARGET_F_GETFL:
-        ret = get_errno(safe_fcntl(fd, host_cmd, arg));
-        if (ret >= 0) {
-            ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
-        }
-        break;
-
-    case TARGET_F_SETFL:
-        ret = get_errno(safe_fcntl(fd, host_cmd,
-                                   target_to_host_bitmask(arg,
-                                                          fcntl_flags_tbl)));
-        break;
-
-#ifdef F_GETOWN_EX
-    case TARGET_F_GETOWN_EX:
-        ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
-        if (ret >= 0) {
-            if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
-                return -TARGET_EFAULT;
-            target_fox->type = tswap32(fox.type);
-            target_fox->pid = tswap32(fox.pid);
-            unlock_user_struct(target_fox, arg, 1);
-        }
-        break;
-#endif
-
-#ifdef F_SETOWN_EX
-    case TARGET_F_SETOWN_EX:
-        if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
-            return -TARGET_EFAULT;
-        fox.type = tswap32(target_fox->type);
-        fox.pid = tswap32(target_fox->pid);
-        unlock_user_struct(target_fox, arg, 0);
-        ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
-        break;
-#endif
-
-    case TARGET_F_SETOWN:
-    case TARGET_F_GETOWN:
-    case TARGET_F_SETSIG:
-    case TARGET_F_GETSIG:
-    case TARGET_F_SETLEASE:
-    case TARGET_F_GETLEASE:
-    case TARGET_F_SETPIPE_SZ:
-    case TARGET_F_GETPIPE_SZ:
-        ret = get_errno(safe_fcntl(fd, host_cmd, arg));
-        break;
-
-    default:
-        ret = get_errno(safe_fcntl(fd, cmd, arg));
-        break;
-    }
-    return ret;
-}
-
 #ifdef USE_UID16
 
 static inline int high2lowuid(int uid)
@@ -4401,10 +4197,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
     void *p;
 
     switch(num) {
-#ifdef TARGET_NR_fcntl
-    case TARGET_NR_fcntl:
-        return do_fcntl(arg1, arg2, arg3);
-#endif
     case TARGET_NR_setpgid:
         return get_errno(setpgid(arg1, arg2));
     case TARGET_NR_umask:
@@ -6935,53 +6727,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
            This is a hint, so ignoring and returning success is ok.  */
         return 0;
 #endif
-#if TARGET_ABI_BITS == 32
-    case TARGET_NR_fcntl64:
-    {
-	int cmd;
-	struct flock64 fl;
-        from_flock64_fn *copyfrom = copy_from_user_flock64;
-        to_flock64_fn *copyto = copy_to_user_flock64;
-
-#ifdef TARGET_ARM
-        if (!((CPUARMState *)cpu_env)->eabi) {
-            copyfrom = copy_from_user_oabi_flock64;
-            copyto = copy_to_user_oabi_flock64;
-        }
-#endif
-
-	cmd = target_to_host_fcntl_cmd(arg2);
-        if (cmd == -TARGET_EINVAL) {
-            return cmd;
-        }
-
-        switch(arg2) {
-        case TARGET_F_GETLK64:
-            ret = copyfrom(&fl, arg3);
-            if (ret) {
-                break;
-            }
-            ret = get_errno(safe_fcntl(arg1, cmd, &fl));
-            if (ret == 0) {
-                ret = copyto(arg3, &fl);
-            }
-	    break;
-
-        case TARGET_F_SETLK64:
-        case TARGET_F_SETLKW64:
-            ret = copyfrom(&fl, arg3);
-            if (ret) {
-                break;
-            }
-            ret = get_errno(safe_fcntl(arg1, cmd, &fl));
-	    break;
-        default:
-            ret = do_fcntl(arg1, arg2, arg3);
-            break;
-        }
-        return ret;
-    }
-#endif
 #ifdef TARGET_NR_cacheflush
     case TARGET_NR_cacheflush:
         /* self-modifying code is handled automatically, so nothing needed */
@@ -7968,6 +7713,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
                                 int64_t arg2, int64_t arg3, int64_t arg4, \
                                 int64_t arg5, int64_t arg6)
 
+#include "syscall-fcntl.inc.c"
 #include "syscall-file.inc.c"
 #include "syscall-ioctl.inc.c"
 #include "syscall-ipc.inc.c"
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 15208b5349..8762892db5 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -157,12 +157,6 @@
 #ifdef TARGET_NR_fchownat
 { TARGET_NR_fchownat, "fchownat" , NULL, print_fchownat, NULL },
 #endif
-#ifdef TARGET_NR_fcntl
-{ TARGET_NR_fcntl, "fcntl" , NULL, print_fcntl, NULL },
-#endif
-#ifdef TARGET_NR_fcntl64
-{ TARGET_NR_fcntl64, "fcntl64" , NULL, print_fcntl64, NULL },
-#endif
 #ifdef TARGET_NR_fdatasync
 { TARGET_NR_fdatasync, "fdatasync" , NULL, NULL, NULL },
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 59+ messages in thread

* Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
  2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl Richard Henderson
@ 2019-02-13 13:09   ` Laurent Vivier
  2019-02-13 13:46     ` Laurent Vivier
  0 siblings, 1 reply; 59+ messages in thread
From: Laurent Vivier @ 2019-02-13 13:09 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel

Hi,

this one is really a cut'n'paste but it introduces a problem with 
qemu-alpha, I don't know how/why:

  $ sudo unshare --ipc --uts --pid --fork --kill-child --mount chroot chroot/alpha/sid/
  Unsupported ioctl: cmd=0x80047476

And then it hangs.

I'll try to debug.

Thanks,
Laurent

On 18/01/2019 22:31, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  linux-user/syscall-defs.h      |   1 +
>  linux-user/syscall-ioctl.inc.c | 873 +++++++++++++++++++++++++++++++++
>  linux-user/syscall.c           | 843 +------------------------------
>  linux-user/strace.list         |   3 -
>  4 files changed, 875 insertions(+), 845 deletions(-)
>  create mode 100644 linux-user/syscall-ioctl.inc.c
> 
> diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
> index f8f280f376..f58b9745a4 100644
> --- a/linux-user/syscall-defs.h
> +++ b/linux-user/syscall-defs.h
> @@ -61,6 +61,7 @@ SYSCALL_DEF(getppid);
>  #ifdef TARGET_NR_getxpid
>  SYSCALL_DEF(getxpid);
>  #endif
> +SYSCALL_DEF(ioctl, ARG_DEC, ARG_HEX);
>  #ifdef TARGET_NR_ipc
>  SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
>  #endif
> diff --git a/linux-user/syscall-ioctl.inc.c b/linux-user/syscall-ioctl.inc.c
> new file mode 100644
> index 0000000000..820994105f
> --- /dev/null
> +++ b/linux-user/syscall-ioctl.inc.c
> @@ -0,0 +1,873 @@
> +/*
> + *  Linux ioctl syscall implementation
> + *  Copyright (c) 2003 Fabrice Bellard
> + *
> + *  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
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +typedef struct IOCTLEntry IOCTLEntry;
> +
> +typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                             int fd, int cmd, abi_long arg);
> +
> +struct IOCTLEntry {
> +    int target_cmd;
> +    unsigned int host_cmd;
> +    const char *name;
> +    int access;
> +    do_ioctl_fn *do_ioctl;
> +    const argtype arg_type[5];
> +};
> +
> +#define IOC_R 0x0001
> +#define IOC_W 0x0002
> +#define IOC_RW (IOC_R | IOC_W)
> +
> +#define MAX_STRUCT_SIZE 4096
> +
> +#ifdef CONFIG_FIEMAP
> +/*
> + * So fiemap access checks don't overflow on 32 bit systems.
> + * This is very slightly smaller than the limit imposed by
> + * the underlying kernel.
> + */
> +#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap))  \
> +                            / sizeof(struct fiemap_extent))
> +
> +static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                                       int fd, int cmd, abi_long arg)
> +{
> +    /*
> +     * The parameter for this ioctl is a struct fiemap followed
> +     * by an array of struct fiemap_extent whose size is set
> +     * in fiemap->fm_extent_count. The array is filled in by the
> +     * ioctl.
> +     */
> +    int target_size_in, target_size_out;
> +    struct fiemap *fm;
> +    const argtype *arg_type = ie->arg_type;
> +    const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
> +    void *argptr, *p;
> +    abi_long ret;
> +    int i, extent_size = thunk_type_size(extent_arg_type, 0);
> +    uint32_t outbufsz;
> +    int free_fm = 0;
> +
> +    assert(arg_type[0] == TYPE_PTR);
> +    assert(ie->access == IOC_RW);
> +    arg_type++;
> +    target_size_in = thunk_type_size(arg_type, 0);
> +    argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
> +    if (!argptr) {
> +        return -TARGET_EFAULT;
> +    }
> +    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> +    unlock_user(argptr, arg, 0);
> +    fm = (struct fiemap *)buf_temp;
> +    if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
> +        return -TARGET_EINVAL;
> +    }
> +
> +    outbufsz = sizeof(*fm) + sizeof(struct fiemap_extent) * fm->fm_extent_count;
> +
> +    if (outbufsz > MAX_STRUCT_SIZE) {
> +        /*
> +         * We can't fit all the extents into the fixed size buffer.
> +         * Allocate one that is large enough and use it instead.
> +         */
> +        fm = g_try_malloc(outbufsz);
> +        if (!fm) {
> +            return -TARGET_ENOMEM;
> +        }
> +        memcpy(fm, buf_temp, sizeof(struct fiemap));
> +        free_fm = 1;
> +    }
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
> +    if (!is_error(ret)) {
> +        target_size_out = target_size_in;
> +        /*
> +         * An extent_count of 0 means we were only counting the extents
> +         * so there are no structs to copy
> +         */
> +        if (fm->fm_extent_count != 0) {
> +            target_size_out += fm->fm_mapped_extents * extent_size;
> +        }
> +        argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
> +        if (!argptr) {
> +            ret = -TARGET_EFAULT;
> +        } else {
> +            /* Convert the struct fiemap */
> +            thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
> +            if (fm->fm_extent_count != 0) {
> +                p = argptr + target_size_in;
> +                /* ...and then all the struct fiemap_extents */
> +                for (i = 0; i < fm->fm_mapped_extents; i++) {
> +                    thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
> +                                  THUNK_TARGET);
> +                    p += extent_size;
> +                }
> +            }
> +            unlock_user(argptr, arg, target_size_out);
> +        }
> +    }
> +    if (free_fm) {
> +        g_free(fm);
> +    }
> +    return ret;
> +}
> +#endif
> +
> +static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                                int fd, int cmd, abi_long arg)
> +{
> +    const argtype *arg_type = ie->arg_type;
> +    int target_size;
> +    void *argptr;
> +    int ret;
> +    struct ifconf *host_ifconf;
> +    uint32_t outbufsz;
> +    const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
> +    int target_ifreq_size;
> +    int nb_ifreq;
> +    int free_buf = 0;
> +    int i;
> +    int target_ifc_len;
> +    abi_long target_ifc_buf;
> +    int host_ifc_len;
> +    char *host_ifc_buf;
> +
> +    assert(arg_type[0] == TYPE_PTR);
> +    assert(ie->access == IOC_RW);
> +
> +    arg_type++;
> +    target_size = thunk_type_size(arg_type, 0);
> +
> +    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +    if (!argptr) {
> +        return -TARGET_EFAULT;
> +    }
> +    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> +    unlock_user(argptr, arg, 0);
> +
> +    host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
> +    target_ifc_len = host_ifconf->ifc_len;
> +    target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
> +
> +    target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
> +    nb_ifreq = target_ifc_len / target_ifreq_size;
> +    host_ifc_len = nb_ifreq * sizeof(struct ifreq);
> +
> +    outbufsz = sizeof(*host_ifconf) + host_ifc_len;
> +    if (outbufsz > MAX_STRUCT_SIZE) {
> +        /*
> +         * We can't fit all the extents into the fixed size buffer.
> +         * Allocate one that is large enough and use it instead.
> +         */
> +        host_ifconf = malloc(outbufsz);
> +        if (!host_ifconf) {
> +            return -TARGET_ENOMEM;
> +        }
> +        memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
> +        free_buf = 1;
> +    }
> +    host_ifc_buf = (char *)host_ifconf + sizeof(*host_ifconf);
> +
> +    host_ifconf->ifc_len = host_ifc_len;
> +    host_ifconf->ifc_buf = host_ifc_buf;
> +
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
> +    if (!is_error(ret)) {
> +        /* convert host ifc_len to target ifc_len */
> +
> +        nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
> +        target_ifc_len = nb_ifreq * target_ifreq_size;
> +        host_ifconf->ifc_len = target_ifc_len;
> +
> +        /* restore target ifc_buf */
> +
> +        host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
> +
> +        /* copy struct ifconf to target user */
> +
> +        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> +        if (!argptr) {
> +            return -TARGET_EFAULT;
> +        }
> +        thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
> +        unlock_user(argptr, arg, target_size);
> +
> +        /* copy ifreq[] to target user */
> +
> +        argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
> +        for (i = 0; i < nb_ifreq ; i++) {
> +            thunk_convert(argptr + i * target_ifreq_size,
> +                          host_ifc_buf + i * sizeof(struct ifreq),
> +                          ifreq_arg_type, THUNK_TARGET);
> +        }
> +        unlock_user(argptr, target_ifc_buf, target_ifc_len);
> +    }
> +
> +    if (free_buf) {
> +        free(host_ifconf);
> +    }
> +
> +    return ret;
> +}
> +
> +#if defined(CONFIG_USBFS)
> +#if HOST_LONG_BITS > 64
> +#error USBDEVFS thunks do not support >64 bit hosts yet.
> +#endif
> +struct live_urb {
> +    uint64_t target_urb_adr;
> +    uint64_t target_buf_adr;
> +    char *target_buf_ptr;
> +    struct usbdevfs_urb host_urb;
> +};
> +
> +static GHashTable *usbdevfs_urb_hashtable(void)
> +{
> +    static GHashTable *urb_hashtable;
> +
> +    if (!urb_hashtable) {
> +        urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
> +    }
> +    return urb_hashtable;
> +}
> +
> +static void urb_hashtable_insert(struct live_urb *urb)
> +{
> +    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> +    g_hash_table_insert(urb_hashtable, urb, urb);
> +}
> +
> +static struct live_urb *urb_hashtable_lookup(uint64_t target_urb_adr)
> +{
> +    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> +    return g_hash_table_lookup(urb_hashtable, &target_urb_adr);
> +}
> +
> +static void urb_hashtable_remove(struct live_urb *urb)
> +{
> +    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> +    g_hash_table_remove(urb_hashtable, urb);
> +}
> +
> +static abi_long
> +do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                          int fd, int cmd, abi_long arg)
> +{
> +    const argtype usbfsurb_arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_urb) };
> +    const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
> +    struct live_urb *lurb;
> +    void *argptr;
> +    uint64_t hurb;
> +    int target_size;
> +    uintptr_t target_urb_adr;
> +    abi_long ret;
> +
> +    target_size = thunk_type_size(usbfsurb_arg_type, THUNK_TARGET);
> +
> +    memset(buf_temp, 0, sizeof(uint64_t));
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +    if (is_error(ret)) {
> +        return ret;
> +    }
> +
> +    memcpy(&hurb, buf_temp, sizeof(uint64_t));
> +    lurb = (void *)((uintptr_t)hurb - offsetof(struct live_urb, host_urb));
> +    if (!lurb->target_urb_adr) {
> +        return -TARGET_EFAULT;
> +    }
> +    urb_hashtable_remove(lurb);
> +    unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr,
> +                lurb->host_urb.buffer_length);
> +    lurb->target_buf_ptr = NULL;
> +
> +    /* restore the guest buffer pointer */
> +    lurb->host_urb.buffer = (void *)(uintptr_t)lurb->target_buf_adr;
> +
> +    /* update the guest urb struct */
> +    argptr = lock_user(VERIFY_WRITE, lurb->target_urb_adr, target_size, 0);
> +    if (!argptr) {
> +        g_free(lurb);
> +        return -TARGET_EFAULT;
> +    }
> +    thunk_convert(argptr, &lurb->host_urb, usbfsurb_arg_type, THUNK_TARGET);
> +    unlock_user(argptr, lurb->target_urb_adr, target_size);
> +
> +    target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
> +    /* write back the urb handle */
> +    argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> +    if (!argptr) {
> +        g_free(lurb);
> +        return -TARGET_EFAULT;
> +    }
> +
> +    /* GHashTable uses 64-bit keys but thunk_convert expects uintptr_t */
> +    target_urb_adr = lurb->target_urb_adr;
> +    thunk_convert(argptr, &target_urb_adr, ptrvoid_arg_type, THUNK_TARGET);
> +    unlock_user(argptr, arg, target_size);
> +
> +    g_free(lurb);
> +    return ret;
> +}
> +
> +static abi_long
> +do_ioctl_usbdevfs_discardurb(const IOCTLEntry *ie,
> +                             uint8_t *buf_temp __attribute__((unused)),
> +                             int fd, int cmd, abi_long arg)
> +{
> +    struct live_urb *lurb;
> +
> +    /* map target address back to host URB with metadata. */
> +    lurb = urb_hashtable_lookup(arg);
> +    if (!lurb) {
> +        return -TARGET_EFAULT;
> +    }
> +    return get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
> +}
> +
> +static abi_long
> +do_ioctl_usbdevfs_submiturb(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                            int fd, int cmd, abi_long arg)
> +{
> +    const argtype *arg_type = ie->arg_type;
> +    int target_size;
> +    abi_long ret;
> +    void *argptr;
> +    int rw_dir;
> +    struct live_urb *lurb;
> +
> +    /*
> +     * each submitted URB needs to map to a unique ID for the
> +     * kernel, and that unique ID needs to be a pointer to
> +     * host memory.  hence, we need to malloc for each URB.
> +     * isochronous transfers have a variable length struct.
> +     */
> +    arg_type++;
> +    target_size = thunk_type_size(arg_type, THUNK_TARGET);
> +
> +    /* construct host copy of urb and metadata */
> +    lurb = g_try_malloc0(sizeof(struct live_urb));
> +    if (!lurb) {
> +        return -TARGET_ENOMEM;
> +    }
> +
> +    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +    if (!argptr) {
> +        g_free(lurb);
> +        return -TARGET_EFAULT;
> +    }
> +    thunk_convert(&lurb->host_urb, argptr, arg_type, THUNK_HOST);
> +    unlock_user(argptr, arg, 0);
> +
> +    lurb->target_urb_adr = arg;
> +    lurb->target_buf_adr = (uintptr_t)lurb->host_urb.buffer;
> +
> +    /* buffer space used depends on endpoint type so lock the entire buffer */
> +    /* control type urbs should check the buffer contents for true direction */
> +    rw_dir = lurb->host_urb.endpoint & USB_DIR_IN ? VERIFY_WRITE : VERIFY_READ;
> +    lurb->target_buf_ptr = lock_user(rw_dir, lurb->target_buf_adr,
> +                                     lurb->host_urb.buffer_length, 1);
> +    if (lurb->target_buf_ptr == NULL) {
> +        g_free(lurb);
> +        return -TARGET_EFAULT;
> +    }
> +
> +    /* update buffer pointer in host copy */
> +    lurb->host_urb.buffer = lurb->target_buf_ptr;
> +
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
> +    if (is_error(ret)) {
> +        unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr, 0);
> +        g_free(lurb);
> +    } else {
> +        urb_hashtable_insert(lurb);
> +    }
> +
> +    return ret;
> +}
> +#endif /* CONFIG_USBFS */
> +
> +static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
> +                            int cmd, abi_long arg)
> +{
> +    void *argptr;
> +    struct dm_ioctl *host_dm;
> +    abi_long guest_data;
> +    uint32_t guest_data_size;
> +    int target_size;
> +    const argtype *arg_type = ie->arg_type;
> +    abi_long ret;
> +    void *big_buf = NULL;
> +    char *host_data;
> +
> +    arg_type++;
> +    target_size = thunk_type_size(arg_type, 0);
> +    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +    if (!argptr) {
> +        ret = -TARGET_EFAULT;
> +        goto out;
> +    }
> +    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> +    unlock_user(argptr, arg, 0);
> +
> +    /* buf_temp is too small, so fetch things into a bigger buffer */
> +    big_buf = g_malloc0(((struct dm_ioctl *)buf_temp)->data_size * 2);
> +    memcpy(big_buf, buf_temp, target_size);
> +    buf_temp = big_buf;
> +    host_dm = big_buf;
> +
> +    guest_data = arg + host_dm->data_start;
> +    if ((guest_data - arg) < 0) {
> +        ret = -TARGET_EINVAL;
> +        goto out;
> +    }
> +    guest_data_size = host_dm->data_size - host_dm->data_start;
> +    host_data = (char *)host_dm + host_dm->data_start;
> +
> +    argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
> +    if (!argptr) {
> +        ret = -TARGET_EFAULT;
> +        goto out;
> +    }
> +
> +    switch (ie->host_cmd) {
> +    case DM_REMOVE_ALL:
> +    case DM_LIST_DEVICES:
> +    case DM_DEV_CREATE:
> +    case DM_DEV_REMOVE:
> +    case DM_DEV_SUSPEND:
> +    case DM_DEV_STATUS:
> +    case DM_DEV_WAIT:
> +    case DM_TABLE_STATUS:
> +    case DM_TABLE_CLEAR:
> +    case DM_TABLE_DEPS:
> +    case DM_LIST_VERSIONS:
> +        /* no input data */
> +        break;
> +    case DM_DEV_RENAME:
> +    case DM_DEV_SET_GEOMETRY:
> +        /* data contains only strings */
> +        memcpy(host_data, argptr, guest_data_size);
> +        break;
> +    case DM_TARGET_MSG:
> +        memcpy(host_data, argptr, guest_data_size);
> +        *(uint64_t *)host_data = tswap64(*(uint64_t *)argptr);
> +        break;
> +    case DM_TABLE_LOAD:
> +    {
> +        void *gspec = argptr;
> +        void *cur_data = host_data;
> +        const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
> +        int spec_size = thunk_type_size(arg_type, 0);
> +        int i;
> +
> +        for (i = 0; i < host_dm->target_count; i++) {
> +            struct dm_target_spec *spec = cur_data;
> +            uint32_t next;
> +            int slen;
> +
> +            thunk_convert(spec, gspec, arg_type, THUNK_HOST);
> +            slen = strlen((char *)gspec + spec_size) + 1;
> +            next = spec->next;
> +            spec->next = sizeof(*spec) + slen;
> +            strcpy((char *)&spec[1], gspec + spec_size);
> +            gspec += next;
> +            cur_data += spec->next;
> +        }
> +        break;
> +    }
> +    default:
> +        ret = -TARGET_EINVAL;
> +        unlock_user(argptr, guest_data, 0);
> +        goto out;
> +    }
> +    unlock_user(argptr, guest_data, 0);
> +
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +    if (!is_error(ret)) {
> +        guest_data = arg + host_dm->data_start;
> +        guest_data_size = host_dm->data_size - host_dm->data_start;
> +        argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
> +        switch (ie->host_cmd) {
> +        case DM_REMOVE_ALL:
> +        case DM_DEV_CREATE:
> +        case DM_DEV_REMOVE:
> +        case DM_DEV_RENAME:
> +        case DM_DEV_SUSPEND:
> +        case DM_DEV_STATUS:
> +        case DM_TABLE_LOAD:
> +        case DM_TABLE_CLEAR:
> +        case DM_TARGET_MSG:
> +        case DM_DEV_SET_GEOMETRY:
> +            /* no return data */
> +            break;
> +        case DM_LIST_DEVICES:
> +        {
> +            struct dm_name_list *nl = (void *)host_dm + host_dm->data_start;
> +            uint32_t remaining_data = guest_data_size;
> +            void *cur_data = argptr;
> +            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
> +            int nl_size = 12; /* can't use thunk_size due to alignment */
> +
> +            while (1) {
> +                uint32_t next = nl->next;
> +                if (next) {
> +                    nl->next = nl_size + (strlen(nl->name) + 1);
> +                }
> +                if (remaining_data < nl->next) {
> +                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> +                    break;
> +                }
> +                thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
> +                strcpy(cur_data + nl_size, nl->name);
> +                cur_data += nl->next;
> +                remaining_data -= nl->next;
> +                if (!next) {
> +                    break;
> +                }
> +                nl = (void *)nl + next;
> +            }
> +            break;
> +        }
> +        case DM_DEV_WAIT:
> +        case DM_TABLE_STATUS:
> +        {
> +            struct dm_target_spec *spec
> +                = (void *)host_dm + host_dm->data_start;
> +            void *cur_data = argptr;
> +            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
> +            int spec_size = thunk_type_size(arg_type, 0);
> +            int i;
> +
> +            for (i = 0; i < host_dm->target_count; i++) {
> +                uint32_t next = spec->next;
> +                int slen = strlen((char *)&spec[1]) + 1;
> +                spec->next = (cur_data - argptr) + spec_size + slen;
> +                if (guest_data_size < spec->next) {
> +                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> +                    break;
> +                }
> +                thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
> +                strcpy(cur_data + spec_size, (char *)&spec[1]);
> +                cur_data = argptr + spec->next;
> +                spec = (void *)host_dm + host_dm->data_start + next;
> +            }
> +            break;
> +        }
> +        case DM_TABLE_DEPS:
> +        {
> +            void *hdata = (void *)host_dm + host_dm->data_start;
> +            int count = *(uint32_t *)hdata;
> +            uint64_t *hdev = hdata + 8;
> +            uint64_t *gdev = argptr + 8;
> +            int i;
> +
> +            *(uint32_t *)argptr = tswap32(count);
> +            for (i = 0; i < count; i++) {
> +                *gdev = tswap64(*hdev);
> +                gdev++;
> +                hdev++;
> +            }
> +            break;
> +        }
> +        case DM_LIST_VERSIONS:
> +        {
> +            struct dm_target_versions *vers
> +                = (void *)host_dm + host_dm->data_start;
> +            uint32_t remaining_data = guest_data_size;
> +            void *cur_data = argptr;
> +            const argtype arg_type[]
> +                = { MK_STRUCT(STRUCT_dm_target_versions) };
> +            int vers_size = thunk_type_size(arg_type, 0);
> +
> +            while (1) {
> +                uint32_t next = vers->next;
> +                if (next) {
> +                    vers->next = vers_size + strlen(vers->name) + 1;
> +                }
> +                if (remaining_data < vers->next) {
> +                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> +                    break;
> +                }
> +                thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
> +                strcpy(cur_data + vers_size, vers->name);
> +                cur_data += vers->next;
> +                remaining_data -= vers->next;
> +                if (!next) {
> +                    break;
> +                }
> +                vers = (void *)vers + next;
> +            }
> +            break;
> +        }
> +        default:
> +            unlock_user(argptr, guest_data, 0);
> +            ret = -TARGET_EINVAL;
> +            goto out;
> +        }
> +        unlock_user(argptr, guest_data, guest_data_size);
> +
> +        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> +        if (!argptr) {
> +            ret = -TARGET_EFAULT;
> +            goto out;
> +        }
> +        thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> +        unlock_user(argptr, arg, target_size);
> +    }
> +out:
> +    g_free(big_buf);
> +    return ret;
> +}
> +
> +static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
> +                               int cmd, abi_long arg)
> +{
> +    void *argptr;
> +    int target_size;
> +    const argtype *arg_type = ie->arg_type;
> +    const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
> +    abi_long ret;
> +    struct blkpg_ioctl_arg *host_blkpg = (void *)buf_temp;
> +    struct blkpg_partition host_part;
> +
> +    /* Read and convert blkpg */
> +    arg_type++;
> +    target_size = thunk_type_size(arg_type, 0);
> +    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +    if (!argptr) {
> +        ret = -TARGET_EFAULT;
> +        goto out;
> +    }
> +    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> +    unlock_user(argptr, arg, 0);
> +
> +    switch (host_blkpg->op) {
> +    case BLKPG_ADD_PARTITION:
> +    case BLKPG_DEL_PARTITION:
> +        /* payload is struct blkpg_partition */
> +        break;
> +    default:
> +        /* Unknown opcode */
> +        ret = -TARGET_EINVAL;
> +        goto out;
> +    }
> +
> +    /* Read and convert blkpg->data */
> +    arg = (abi_long)(uintptr_t)host_blkpg->data;
> +    target_size = thunk_type_size(part_arg_type, 0);
> +    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +    if (!argptr) {
> +        ret = -TARGET_EFAULT;
> +        goto out;
> +    }
> +    thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
> +    unlock_user(argptr, arg, 0);
> +
> +    /* Swizzle the data pointer to our local copy and call! */
> +    host_blkpg->data = &host_part;
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
> +
> +out:
> +    return ret;
> +}
> +
> +static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                            int fd, int cmd, abi_long arg)
> +{
> +    const argtype *arg_type = ie->arg_type;
> +    const StructEntry *se;
> +    const argtype *field_types;
> +    const int *dst_offsets, *src_offsets;
> +    int target_size;
> +    void *argptr;
> +    abi_ulong *target_rt_dev_ptr;
> +    unsigned long *host_rt_dev_ptr;
> +    abi_long ret;
> +    int i;
> +
> +    assert(ie->access == IOC_W);
> +    assert(*arg_type == TYPE_PTR);
> +    arg_type++;
> +    assert(*arg_type == TYPE_STRUCT);
> +    target_size = thunk_type_size(arg_type, 0);
> +    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +    if (!argptr) {
> +        return -TARGET_EFAULT;
> +    }
> +    arg_type++;
> +    assert(*arg_type == (int)STRUCT_rtentry);
> +    se = struct_entries + *arg_type++;
> +    assert(se->convert[0] == NULL);
> +    /* convert struct here to be able to catch rt_dev string */
> +    field_types = se->field_types;
> +    dst_offsets = se->field_offsets[THUNK_HOST];
> +    src_offsets = se->field_offsets[THUNK_TARGET];
> +    for (i = 0; i < se->nb_fields; i++) {
> +        if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
> +            assert(*field_types == TYPE_PTRVOID);
> +            target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
> +            host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
> +            if (*target_rt_dev_ptr != 0) {
> +                *host_rt_dev_ptr = (unsigned long)lock_user_string(
> +                    tswapal(*target_rt_dev_ptr));
> +                if (!*host_rt_dev_ptr) {
> +                    unlock_user(argptr, arg, 0);
> +                    return -TARGET_EFAULT;
> +                }
> +            } else {
> +                *host_rt_dev_ptr = 0;
> +            }
> +            field_types++;
> +            continue;
> +        }
> +        field_types = thunk_convert(buf_temp + dst_offsets[i],
> +                                    argptr + src_offsets[i],
> +                                    field_types, THUNK_HOST);
> +    }
> +    unlock_user(argptr, arg, 0);
> +
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +    if (*host_rt_dev_ptr != 0) {
> +        unlock_user((void *)*host_rt_dev_ptr,
> +                    *target_rt_dev_ptr, 0);
> +    }
> +    return ret;
> +}
> +
> +static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                                     int fd, int cmd, abi_long arg)
> +{
> +    int sig = target_to_host_signal(arg);
> +    return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
> +}
> +
> +#ifdef TIOCGPTPEER
> +static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                                     int fd, int cmd, abi_long arg)
> +{
> +    int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
> +    return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
> +}
> +#endif
> +
> +static IOCTLEntry ioctl_entries[] = {
> +#define IOCTL(cmd, access, ...)                                 \
> +    { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
> +#define IOCTL_SPECIAL(cmd, access, dofn, ...)                           \
> +    { TARGET_ ## cmd, cmd, #cmd, access, dofn, {  __VA_ARGS__ } },
> +#define IOCTL_IGNORE(cmd)                       \
> +    { TARGET_ ## cmd, 0, #cmd },
> +#include "ioctls.h"
> +    { 0, 0, },
> +};
> +
> +/* ??? Implement proper locking for ioctls.  */
> +SYSCALL_IMPL(ioctl)
> +{
> +    int fd = arg1;
> +    abi_ulong cmd = arg2;
> +    abi_ulong arg = arg3;
> +    const IOCTLEntry *ie;
> +    const argtype *arg_type;
> +    abi_long ret;
> +    uint8_t buf_temp[MAX_STRUCT_SIZE];
> +    int target_size;
> +    void *argptr;
> +
> +    for (ie = ioctl_entries; ; ie++) {
> +        if (ie->target_cmd == 0) {
> +            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
> +            return -TARGET_ENOSYS;
> +        }
> +        if (ie->target_cmd == cmd) {
> +            break;
> +        }
> +    }
> +
> +    arg_type = ie->arg_type;
> +    if (ie->do_ioctl) {
> +        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
> +    } else if (!ie->host_cmd) {
> +        /*
> +         * Some architectures define BSD ioctls in their headers
> +         * that are not implemented in Linux.
> +         */
> +        return -TARGET_ENOSYS;
> +    }
> +
> +    switch (arg_type[0]) {
> +    case TYPE_NULL:
> +        /* no argument */
> +        ret = get_errno(safe_ioctl(fd, ie->host_cmd));
> +        break;
> +    case TYPE_PTRVOID:
> +    case TYPE_INT:
> +        ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
> +        break;
> +    case TYPE_PTR:
> +        arg_type++;
> +        target_size = thunk_type_size(arg_type, 0);
> +        switch (ie->access) {
> +        case IOC_R:
> +            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +            if (!is_error(ret)) {
> +                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> +                if (!argptr) {
> +                    return -TARGET_EFAULT;
> +                }
> +                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> +                unlock_user(argptr, arg, target_size);
> +            }
> +            break;
> +        case IOC_W:
> +            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +            if (!argptr) {
> +                return -TARGET_EFAULT;
> +            }
> +            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> +            unlock_user(argptr, arg, 0);
> +            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +            break;
> +        default:
> +        case IOC_RW:
> +            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +            if (!argptr) {
> +                return -TARGET_EFAULT;
> +            }
> +            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> +            unlock_user(argptr, arg, 0);
> +            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +            if (!is_error(ret)) {
> +                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> +                if (!argptr) {
> +                    return -TARGET_EFAULT;
> +                }
> +                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> +                unlock_user(argptr, arg, target_size);
> +            }
> +            break;
> +        }
> +        break;
> +    default:
> +        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
> +                 (long)cmd, arg_type[0]);
> +        ret = -TARGET_ENOSYS;
> +        break;
> +    }
> +    return ret;
> +}
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 82b7267b20..03ecf0a15a 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -2935,846 +2935,6 @@ STRUCT_MAX
>  #undef STRUCT
>  #undef STRUCT_SPECIAL
>  
> -typedef struct IOCTLEntry IOCTLEntry;
> -
> -typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                             int fd, int cmd, abi_long arg);
> -
> -struct IOCTLEntry {
> -    int target_cmd;
> -    unsigned int host_cmd;
> -    const char *name;
> -    int access;
> -    do_ioctl_fn *do_ioctl;
> -    const argtype arg_type[5];
> -};
> -
> -#define IOC_R 0x0001
> -#define IOC_W 0x0002
> -#define IOC_RW (IOC_R | IOC_W)
> -
> -#define MAX_STRUCT_SIZE 4096
> -
> -#ifdef CONFIG_FIEMAP
> -/* So fiemap access checks don't overflow on 32 bit systems.
> - * This is very slightly smaller than the limit imposed by
> - * the underlying kernel.
> - */
> -#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap))  \
> -                            / sizeof(struct fiemap_extent))
> -
> -static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                                       int fd, int cmd, abi_long arg)
> -{
> -    /* The parameter for this ioctl is a struct fiemap followed
> -     * by an array of struct fiemap_extent whose size is set
> -     * in fiemap->fm_extent_count. The array is filled in by the
> -     * ioctl.
> -     */
> -    int target_size_in, target_size_out;
> -    struct fiemap *fm;
> -    const argtype *arg_type = ie->arg_type;
> -    const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
> -    void *argptr, *p;
> -    abi_long ret;
> -    int i, extent_size = thunk_type_size(extent_arg_type, 0);
> -    uint32_t outbufsz;
> -    int free_fm = 0;
> -
> -    assert(arg_type[0] == TYPE_PTR);
> -    assert(ie->access == IOC_RW);
> -    arg_type++;
> -    target_size_in = thunk_type_size(arg_type, 0);
> -    argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
> -    if (!argptr) {
> -        return -TARGET_EFAULT;
> -    }
> -    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> -    unlock_user(argptr, arg, 0);
> -    fm = (struct fiemap *)buf_temp;
> -    if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
> -        return -TARGET_EINVAL;
> -    }
> -
> -    outbufsz = sizeof (*fm) +
> -        (sizeof(struct fiemap_extent) * fm->fm_extent_count);
> -
> -    if (outbufsz > MAX_STRUCT_SIZE) {
> -        /* We can't fit all the extents into the fixed size buffer.
> -         * Allocate one that is large enough and use it instead.
> -         */
> -        fm = g_try_malloc(outbufsz);
> -        if (!fm) {
> -            return -TARGET_ENOMEM;
> -        }
> -        memcpy(fm, buf_temp, sizeof(struct fiemap));
> -        free_fm = 1;
> -    }
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
> -    if (!is_error(ret)) {
> -        target_size_out = target_size_in;
> -        /* An extent_count of 0 means we were only counting the extents
> -         * so there are no structs to copy
> -         */
> -        if (fm->fm_extent_count != 0) {
> -            target_size_out += fm->fm_mapped_extents * extent_size;
> -        }
> -        argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
> -        if (!argptr) {
> -            ret = -TARGET_EFAULT;
> -        } else {
> -            /* Convert the struct fiemap */
> -            thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
> -            if (fm->fm_extent_count != 0) {
> -                p = argptr + target_size_in;
> -                /* ...and then all the struct fiemap_extents */
> -                for (i = 0; i < fm->fm_mapped_extents; i++) {
> -                    thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
> -                                  THUNK_TARGET);
> -                    p += extent_size;
> -                }
> -            }
> -            unlock_user(argptr, arg, target_size_out);
> -        }
> -    }
> -    if (free_fm) {
> -        g_free(fm);
> -    }
> -    return ret;
> -}
> -#endif
> -
> -static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                                int fd, int cmd, abi_long arg)
> -{
> -    const argtype *arg_type = ie->arg_type;
> -    int target_size;
> -    void *argptr;
> -    int ret;
> -    struct ifconf *host_ifconf;
> -    uint32_t outbufsz;
> -    const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
> -    int target_ifreq_size;
> -    int nb_ifreq;
> -    int free_buf = 0;
> -    int i;
> -    int target_ifc_len;
> -    abi_long target_ifc_buf;
> -    int host_ifc_len;
> -    char *host_ifc_buf;
> -
> -    assert(arg_type[0] == TYPE_PTR);
> -    assert(ie->access == IOC_RW);
> -
> -    arg_type++;
> -    target_size = thunk_type_size(arg_type, 0);
> -
> -    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -    if (!argptr)
> -        return -TARGET_EFAULT;
> -    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> -    unlock_user(argptr, arg, 0);
> -
> -    host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
> -    target_ifc_len = host_ifconf->ifc_len;
> -    target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
> -
> -    target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
> -    nb_ifreq = target_ifc_len / target_ifreq_size;
> -    host_ifc_len = nb_ifreq * sizeof(struct ifreq);
> -
> -    outbufsz = sizeof(*host_ifconf) + host_ifc_len;
> -    if (outbufsz > MAX_STRUCT_SIZE) {
> -        /* We can't fit all the extents into the fixed size buffer.
> -         * Allocate one that is large enough and use it instead.
> -         */
> -        host_ifconf = malloc(outbufsz);
> -        if (!host_ifconf) {
> -            return -TARGET_ENOMEM;
> -        }
> -        memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
> -        free_buf = 1;
> -    }
> -    host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
> -
> -    host_ifconf->ifc_len = host_ifc_len;
> -    host_ifconf->ifc_buf = host_ifc_buf;
> -
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
> -    if (!is_error(ret)) {
> -	/* convert host ifc_len to target ifc_len */
> -
> -        nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
> -        target_ifc_len = nb_ifreq * target_ifreq_size;
> -        host_ifconf->ifc_len = target_ifc_len;
> -
> -	/* restore target ifc_buf */
> -
> -        host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
> -
> -	/* copy struct ifconf to target user */
> -
> -        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> -        if (!argptr)
> -            return -TARGET_EFAULT;
> -        thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
> -        unlock_user(argptr, arg, target_size);
> -
> -	/* copy ifreq[] to target user */
> -
> -        argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
> -        for (i = 0; i < nb_ifreq ; i++) {
> -            thunk_convert(argptr + i * target_ifreq_size,
> -                          host_ifc_buf + i * sizeof(struct ifreq),
> -                          ifreq_arg_type, THUNK_TARGET);
> -        }
> -        unlock_user(argptr, target_ifc_buf, target_ifc_len);
> -    }
> -
> -    if (free_buf) {
> -        free(host_ifconf);
> -    }
> -
> -    return ret;
> -}
> -
> -#if defined(CONFIG_USBFS)
> -#if HOST_LONG_BITS > 64
> -#error USBDEVFS thunks do not support >64 bit hosts yet.
> -#endif
> -struct live_urb {
> -    uint64_t target_urb_adr;
> -    uint64_t target_buf_adr;
> -    char *target_buf_ptr;
> -    struct usbdevfs_urb host_urb;
> -};
> -
> -static GHashTable *usbdevfs_urb_hashtable(void)
> -{
> -    static GHashTable *urb_hashtable;
> -
> -    if (!urb_hashtable) {
> -        urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
> -    }
> -    return urb_hashtable;
> -}
> -
> -static void urb_hashtable_insert(struct live_urb *urb)
> -{
> -    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> -    g_hash_table_insert(urb_hashtable, urb, urb);
> -}
> -
> -static struct live_urb *urb_hashtable_lookup(uint64_t target_urb_adr)
> -{
> -    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> -    return g_hash_table_lookup(urb_hashtable, &target_urb_adr);
> -}
> -
> -static void urb_hashtable_remove(struct live_urb *urb)
> -{
> -    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> -    g_hash_table_remove(urb_hashtable, urb);
> -}
> -
> -static abi_long
> -do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                          int fd, int cmd, abi_long arg)
> -{
> -    const argtype usbfsurb_arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_urb) };
> -    const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
> -    struct live_urb *lurb;
> -    void *argptr;
> -    uint64_t hurb;
> -    int target_size;
> -    uintptr_t target_urb_adr;
> -    abi_long ret;
> -
> -    target_size = thunk_type_size(usbfsurb_arg_type, THUNK_TARGET);
> -
> -    memset(buf_temp, 0, sizeof(uint64_t));
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -    if (is_error(ret)) {
> -        return ret;
> -    }
> -
> -    memcpy(&hurb, buf_temp, sizeof(uint64_t));
> -    lurb = (void *)((uintptr_t)hurb - offsetof(struct live_urb, host_urb));
> -    if (!lurb->target_urb_adr) {
> -        return -TARGET_EFAULT;
> -    }
> -    urb_hashtable_remove(lurb);
> -    unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr,
> -        lurb->host_urb.buffer_length);
> -    lurb->target_buf_ptr = NULL;
> -
> -    /* restore the guest buffer pointer */
> -    lurb->host_urb.buffer = (void *)(uintptr_t)lurb->target_buf_adr;
> -
> -    /* update the guest urb struct */
> -    argptr = lock_user(VERIFY_WRITE, lurb->target_urb_adr, target_size, 0);
> -    if (!argptr) {
> -        g_free(lurb);
> -        return -TARGET_EFAULT;
> -    }
> -    thunk_convert(argptr, &lurb->host_urb, usbfsurb_arg_type, THUNK_TARGET);
> -    unlock_user(argptr, lurb->target_urb_adr, target_size);
> -
> -    target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
> -    /* write back the urb handle */
> -    argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> -    if (!argptr) {
> -        g_free(lurb);
> -        return -TARGET_EFAULT;
> -    }
> -
> -    /* GHashTable uses 64-bit keys but thunk_convert expects uintptr_t */
> -    target_urb_adr = lurb->target_urb_adr;
> -    thunk_convert(argptr, &target_urb_adr, ptrvoid_arg_type, THUNK_TARGET);
> -    unlock_user(argptr, arg, target_size);
> -
> -    g_free(lurb);
> -    return ret;
> -}
> -
> -static abi_long
> -do_ioctl_usbdevfs_discardurb(const IOCTLEntry *ie,
> -                             uint8_t *buf_temp __attribute__((unused)),
> -                             int fd, int cmd, abi_long arg)
> -{
> -    struct live_urb *lurb;
> -
> -    /* map target address back to host URB with metadata. */
> -    lurb = urb_hashtable_lookup(arg);
> -    if (!lurb) {
> -        return -TARGET_EFAULT;
> -    }
> -    return get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
> -}
> -
> -static abi_long
> -do_ioctl_usbdevfs_submiturb(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                            int fd, int cmd, abi_long arg)
> -{
> -    const argtype *arg_type = ie->arg_type;
> -    int target_size;
> -    abi_long ret;
> -    void *argptr;
> -    int rw_dir;
> -    struct live_urb *lurb;
> -
> -    /*
> -     * each submitted URB needs to map to a unique ID for the
> -     * kernel, and that unique ID needs to be a pointer to
> -     * host memory.  hence, we need to malloc for each URB.
> -     * isochronous transfers have a variable length struct.
> -     */
> -    arg_type++;
> -    target_size = thunk_type_size(arg_type, THUNK_TARGET);
> -
> -    /* construct host copy of urb and metadata */
> -    lurb = g_try_malloc0(sizeof(struct live_urb));
> -    if (!lurb) {
> -        return -TARGET_ENOMEM;
> -    }
> -
> -    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -    if (!argptr) {
> -        g_free(lurb);
> -        return -TARGET_EFAULT;
> -    }
> -    thunk_convert(&lurb->host_urb, argptr, arg_type, THUNK_HOST);
> -    unlock_user(argptr, arg, 0);
> -
> -    lurb->target_urb_adr = arg;
> -    lurb->target_buf_adr = (uintptr_t)lurb->host_urb.buffer;
> -
> -    /* buffer space used depends on endpoint type so lock the entire buffer */
> -    /* control type urbs should check the buffer contents for true direction */
> -    rw_dir = lurb->host_urb.endpoint & USB_DIR_IN ? VERIFY_WRITE : VERIFY_READ;
> -    lurb->target_buf_ptr = lock_user(rw_dir, lurb->target_buf_adr,
> -        lurb->host_urb.buffer_length, 1);
> -    if (lurb->target_buf_ptr == NULL) {
> -        g_free(lurb);
> -        return -TARGET_EFAULT;
> -    }
> -
> -    /* update buffer pointer in host copy */
> -    lurb->host_urb.buffer = lurb->target_buf_ptr;
> -
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
> -    if (is_error(ret)) {
> -        unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr, 0);
> -        g_free(lurb);
> -    } else {
> -        urb_hashtable_insert(lurb);
> -    }
> -
> -    return ret;
> -}
> -#endif /* CONFIG_USBFS */
> -
> -static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
> -                            int cmd, abi_long arg)
> -{
> -    void *argptr;
> -    struct dm_ioctl *host_dm;
> -    abi_long guest_data;
> -    uint32_t guest_data_size;
> -    int target_size;
> -    const argtype *arg_type = ie->arg_type;
> -    abi_long ret;
> -    void *big_buf = NULL;
> -    char *host_data;
> -
> -    arg_type++;
> -    target_size = thunk_type_size(arg_type, 0);
> -    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -    if (!argptr) {
> -        ret = -TARGET_EFAULT;
> -        goto out;
> -    }
> -    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> -    unlock_user(argptr, arg, 0);
> -
> -    /* buf_temp is too small, so fetch things into a bigger buffer */
> -    big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
> -    memcpy(big_buf, buf_temp, target_size);
> -    buf_temp = big_buf;
> -    host_dm = big_buf;
> -
> -    guest_data = arg + host_dm->data_start;
> -    if ((guest_data - arg) < 0) {
> -        ret = -TARGET_EINVAL;
> -        goto out;
> -    }
> -    guest_data_size = host_dm->data_size - host_dm->data_start;
> -    host_data = (char*)host_dm + host_dm->data_start;
> -
> -    argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
> -    if (!argptr) {
> -        ret = -TARGET_EFAULT;
> -        goto out;
> -    }
> -
> -    switch (ie->host_cmd) {
> -    case DM_REMOVE_ALL:
> -    case DM_LIST_DEVICES:
> -    case DM_DEV_CREATE:
> -    case DM_DEV_REMOVE:
> -    case DM_DEV_SUSPEND:
> -    case DM_DEV_STATUS:
> -    case DM_DEV_WAIT:
> -    case DM_TABLE_STATUS:
> -    case DM_TABLE_CLEAR:
> -    case DM_TABLE_DEPS:
> -    case DM_LIST_VERSIONS:
> -        /* no input data */
> -        break;
> -    case DM_DEV_RENAME:
> -    case DM_DEV_SET_GEOMETRY:
> -        /* data contains only strings */
> -        memcpy(host_data, argptr, guest_data_size);
> -        break;
> -    case DM_TARGET_MSG:
> -        memcpy(host_data, argptr, guest_data_size);
> -        *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
> -        break;
> -    case DM_TABLE_LOAD:
> -    {
> -        void *gspec = argptr;
> -        void *cur_data = host_data;
> -        const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
> -        int spec_size = thunk_type_size(arg_type, 0);
> -        int i;
> -
> -        for (i = 0; i < host_dm->target_count; i++) {
> -            struct dm_target_spec *spec = cur_data;
> -            uint32_t next;
> -            int slen;
> -
> -            thunk_convert(spec, gspec, arg_type, THUNK_HOST);
> -            slen = strlen((char*)gspec + spec_size) + 1;
> -            next = spec->next;
> -            spec->next = sizeof(*spec) + slen;
> -            strcpy((char*)&spec[1], gspec + spec_size);
> -            gspec += next;
> -            cur_data += spec->next;
> -        }
> -        break;
> -    }
> -    default:
> -        ret = -TARGET_EINVAL;
> -        unlock_user(argptr, guest_data, 0);
> -        goto out;
> -    }
> -    unlock_user(argptr, guest_data, 0);
> -
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -    if (!is_error(ret)) {
> -        guest_data = arg + host_dm->data_start;
> -        guest_data_size = host_dm->data_size - host_dm->data_start;
> -        argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
> -        switch (ie->host_cmd) {
> -        case DM_REMOVE_ALL:
> -        case DM_DEV_CREATE:
> -        case DM_DEV_REMOVE:
> -        case DM_DEV_RENAME:
> -        case DM_DEV_SUSPEND:
> -        case DM_DEV_STATUS:
> -        case DM_TABLE_LOAD:
> -        case DM_TABLE_CLEAR:
> -        case DM_TARGET_MSG:
> -        case DM_DEV_SET_GEOMETRY:
> -            /* no return data */
> -            break;
> -        case DM_LIST_DEVICES:
> -        {
> -            struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
> -            uint32_t remaining_data = guest_data_size;
> -            void *cur_data = argptr;
> -            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
> -            int nl_size = 12; /* can't use thunk_size due to alignment */
> -
> -            while (1) {
> -                uint32_t next = nl->next;
> -                if (next) {
> -                    nl->next = nl_size + (strlen(nl->name) + 1);
> -                }
> -                if (remaining_data < nl->next) {
> -                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> -                    break;
> -                }
> -                thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
> -                strcpy(cur_data + nl_size, nl->name);
> -                cur_data += nl->next;
> -                remaining_data -= nl->next;
> -                if (!next) {
> -                    break;
> -                }
> -                nl = (void*)nl + next;
> -            }
> -            break;
> -        }
> -        case DM_DEV_WAIT:
> -        case DM_TABLE_STATUS:
> -        {
> -            struct dm_target_spec *spec = (void*)host_dm + host_dm->data_start;
> -            void *cur_data = argptr;
> -            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
> -            int spec_size = thunk_type_size(arg_type, 0);
> -            int i;
> -
> -            for (i = 0; i < host_dm->target_count; i++) {
> -                uint32_t next = spec->next;
> -                int slen = strlen((char*)&spec[1]) + 1;
> -                spec->next = (cur_data - argptr) + spec_size + slen;
> -                if (guest_data_size < spec->next) {
> -                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> -                    break;
> -                }
> -                thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
> -                strcpy(cur_data + spec_size, (char*)&spec[1]);
> -                cur_data = argptr + spec->next;
> -                spec = (void*)host_dm + host_dm->data_start + next;
> -            }
> -            break;
> -        }
> -        case DM_TABLE_DEPS:
> -        {
> -            void *hdata = (void*)host_dm + host_dm->data_start;
> -            int count = *(uint32_t*)hdata;
> -            uint64_t *hdev = hdata + 8;
> -            uint64_t *gdev = argptr + 8;
> -            int i;
> -
> -            *(uint32_t*)argptr = tswap32(count);
> -            for (i = 0; i < count; i++) {
> -                *gdev = tswap64(*hdev);
> -                gdev++;
> -                hdev++;
> -            }
> -            break;
> -        }
> -        case DM_LIST_VERSIONS:
> -        {
> -            struct dm_target_versions *vers = (void*)host_dm + host_dm->data_start;
> -            uint32_t remaining_data = guest_data_size;
> -            void *cur_data = argptr;
> -            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_versions) };
> -            int vers_size = thunk_type_size(arg_type, 0);
> -
> -            while (1) {
> -                uint32_t next = vers->next;
> -                if (next) {
> -                    vers->next = vers_size + (strlen(vers->name) + 1);
> -                }
> -                if (remaining_data < vers->next) {
> -                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> -                    break;
> -                }
> -                thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
> -                strcpy(cur_data + vers_size, vers->name);
> -                cur_data += vers->next;
> -                remaining_data -= vers->next;
> -                if (!next) {
> -                    break;
> -                }
> -                vers = (void*)vers + next;
> -            }
> -            break;
> -        }
> -        default:
> -            unlock_user(argptr, guest_data, 0);
> -            ret = -TARGET_EINVAL;
> -            goto out;
> -        }
> -        unlock_user(argptr, guest_data, guest_data_size);
> -
> -        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> -        if (!argptr) {
> -            ret = -TARGET_EFAULT;
> -            goto out;
> -        }
> -        thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> -        unlock_user(argptr, arg, target_size);
> -    }
> -out:
> -    g_free(big_buf);
> -    return ret;
> -}
> -
> -static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
> -                               int cmd, abi_long arg)
> -{
> -    void *argptr;
> -    int target_size;
> -    const argtype *arg_type = ie->arg_type;
> -    const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) };
> -    abi_long ret;
> -
> -    struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp;
> -    struct blkpg_partition host_part;
> -
> -    /* Read and convert blkpg */
> -    arg_type++;
> -    target_size = thunk_type_size(arg_type, 0);
> -    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -    if (!argptr) {
> -        ret = -TARGET_EFAULT;
> -        goto out;
> -    }
> -    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> -    unlock_user(argptr, arg, 0);
> -
> -    switch (host_blkpg->op) {
> -    case BLKPG_ADD_PARTITION:
> -    case BLKPG_DEL_PARTITION:
> -        /* payload is struct blkpg_partition */
> -        break;
> -    default:
> -        /* Unknown opcode */
> -        ret = -TARGET_EINVAL;
> -        goto out;
> -    }
> -
> -    /* Read and convert blkpg->data */
> -    arg = (abi_long)(uintptr_t)host_blkpg->data;
> -    target_size = thunk_type_size(part_arg_type, 0);
> -    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -    if (!argptr) {
> -        ret = -TARGET_EFAULT;
> -        goto out;
> -    }
> -    thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST);
> -    unlock_user(argptr, arg, 0);
> -
> -    /* Swizzle the data pointer to our local copy and call! */
> -    host_blkpg->data = &host_part;
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_blkpg));
> -
> -out:
> -    return ret;
> -}
> -
> -static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                                int fd, int cmd, abi_long arg)
> -{
> -    const argtype *arg_type = ie->arg_type;
> -    const StructEntry *se;
> -    const argtype *field_types;
> -    const int *dst_offsets, *src_offsets;
> -    int target_size;
> -    void *argptr;
> -    abi_ulong *target_rt_dev_ptr;
> -    unsigned long *host_rt_dev_ptr;
> -    abi_long ret;
> -    int i;
> -
> -    assert(ie->access == IOC_W);
> -    assert(*arg_type == TYPE_PTR);
> -    arg_type++;
> -    assert(*arg_type == TYPE_STRUCT);
> -    target_size = thunk_type_size(arg_type, 0);
> -    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -    if (!argptr) {
> -        return -TARGET_EFAULT;
> -    }
> -    arg_type++;
> -    assert(*arg_type == (int)STRUCT_rtentry);
> -    se = struct_entries + *arg_type++;
> -    assert(se->convert[0] == NULL);
> -    /* convert struct here to be able to catch rt_dev string */
> -    field_types = se->field_types;
> -    dst_offsets = se->field_offsets[THUNK_HOST];
> -    src_offsets = se->field_offsets[THUNK_TARGET];
> -    for (i = 0; i < se->nb_fields; i++) {
> -        if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
> -            assert(*field_types == TYPE_PTRVOID);
> -            target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
> -            host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
> -            if (*target_rt_dev_ptr != 0) {
> -                *host_rt_dev_ptr = (unsigned long)lock_user_string(
> -                                                  tswapal(*target_rt_dev_ptr));
> -                if (!*host_rt_dev_ptr) {
> -                    unlock_user(argptr, arg, 0);
> -                    return -TARGET_EFAULT;
> -                }
> -            } else {
> -                *host_rt_dev_ptr = 0;
> -            }
> -            field_types++;
> -            continue;
> -        }
> -        field_types = thunk_convert(buf_temp + dst_offsets[i],
> -                                    argptr + src_offsets[i],
> -                                    field_types, THUNK_HOST);
> -    }
> -    unlock_user(argptr, arg, 0);
> -
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -    if (*host_rt_dev_ptr != 0) {
> -        unlock_user((void *)*host_rt_dev_ptr,
> -                    *target_rt_dev_ptr, 0);
> -    }
> -    return ret;
> -}
> -
> -static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                                     int fd, int cmd, abi_long arg)
> -{
> -    int sig = target_to_host_signal(arg);
> -    return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
> -}
> -
> -#ifdef TIOCGPTPEER
> -static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                                     int fd, int cmd, abi_long arg)
> -{
> -    int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
> -    return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
> -}
> -#endif
> -
> -static IOCTLEntry ioctl_entries[] = {
> -#define IOCTL(cmd, access, ...) \
> -    { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
> -#define IOCTL_SPECIAL(cmd, access, dofn, ...)                      \
> -    { TARGET_ ## cmd, cmd, #cmd, access, dofn, {  __VA_ARGS__ } },
> -#define IOCTL_IGNORE(cmd) \
> -    { TARGET_ ## cmd, 0, #cmd },
> -#include "ioctls.h"
> -    { 0, 0, },
> -};
> -
> -/* ??? Implement proper locking for ioctls.  */
> -/* do_ioctl() Must return target values and target errnos. */
> -static abi_long do_ioctl(int fd, int cmd, abi_long arg)
> -{
> -    const IOCTLEntry *ie;
> -    const argtype *arg_type;
> -    abi_long ret;
> -    uint8_t buf_temp[MAX_STRUCT_SIZE];
> -    int target_size;
> -    void *argptr;
> -
> -    ie = ioctl_entries;
> -    for(;;) {
> -        if (ie->target_cmd == 0) {
> -            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
> -            return -TARGET_ENOSYS;
> -        }
> -        if (ie->target_cmd == cmd)
> -            break;
> -        ie++;
> -    }
> -    arg_type = ie->arg_type;
> -    if (ie->do_ioctl) {
> -        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
> -    } else if (!ie->host_cmd) {
> -        /* Some architectures define BSD ioctls in their headers
> -           that are not implemented in Linux.  */
> -        return -TARGET_ENOSYS;
> -    }
> -
> -    switch(arg_type[0]) {
> -    case TYPE_NULL:
> -        /* no argument */
> -        ret = get_errno(safe_ioctl(fd, ie->host_cmd));
> -        break;
> -    case TYPE_PTRVOID:
> -    case TYPE_INT:
> -        ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
> -        break;
> -    case TYPE_PTR:
> -        arg_type++;
> -        target_size = thunk_type_size(arg_type, 0);
> -        switch(ie->access) {
> -        case IOC_R:
> -            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -            if (!is_error(ret)) {
> -                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> -                if (!argptr)
> -                    return -TARGET_EFAULT;
> -                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> -                unlock_user(argptr, arg, target_size);
> -            }
> -            break;
> -        case IOC_W:
> -            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -            if (!argptr)
> -                return -TARGET_EFAULT;
> -            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> -            unlock_user(argptr, arg, 0);
> -            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -            break;
> -        default:
> -        case IOC_RW:
> -            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -            if (!argptr)
> -                return -TARGET_EFAULT;
> -            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> -            unlock_user(argptr, arg, 0);
> -            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -            if (!is_error(ret)) {
> -                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> -                if (!argptr)
> -                    return -TARGET_EFAULT;
> -                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> -                unlock_user(argptr, arg, target_size);
> -            }
> -            break;
> -        }
> -        break;
> -    default:
> -        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
> -                 (long)cmd, arg_type[0]);
> -        ret = -TARGET_ENOSYS;
> -        break;
> -    }
> -    return ret;
> -}
> -
>  static const bitmask_transtbl iflag_tbl[] = {
>          { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
>          { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
> @@ -5241,8 +4401,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
>      void *p;
>  
>      switch(num) {
> -    case TARGET_NR_ioctl:
> -        return do_ioctl(arg1, arg2, arg3);
>  #ifdef TARGET_NR_fcntl
>      case TARGET_NR_fcntl:
>          return do_fcntl(arg1, arg2, arg3);
> @@ -8811,6 +7969,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
>                                  int64_t arg5, int64_t arg6)
>  
>  #include "syscall-file.inc.c"
> +#include "syscall-ioctl.inc.c"
>  #include "syscall-ipc.inc.c"
>  #include "syscall-mem.inc.c"
>  #include "syscall-proc.inc.c"
> diff --git a/linux-user/strace.list b/linux-user/strace.list
> index 9f2f8977b4..15208b5349 100644
> --- a/linux-user/strace.list
> +++ b/linux-user/strace.list
> @@ -365,9 +365,6 @@
>  #ifdef TARGET_NR_io_cancel
>  { TARGET_NR_io_cancel, "io_cancel" , NULL, NULL, NULL },
>  #endif
> -#ifdef TARGET_NR_ioctl
> -{ TARGET_NR_ioctl, "ioctl" , NULL, NULL, NULL },
> -#endif
>  #ifdef TARGET_NR_io_destroy
>  { TARGET_NR_io_destroy, "io_destroy" , NULL, NULL, NULL },
>  #endif
> 

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
  2019-02-13 13:09   ` Laurent Vivier
@ 2019-02-13 13:46     ` Laurent Vivier
  2019-04-09 23:15       ` Richard Henderson
  0 siblings, 1 reply; 59+ messages in thread
From: Laurent Vivier @ 2019-02-13 13:46 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel

On 13/02/2019 14:09, Laurent Vivier wrote:
> Hi,
> 
> this one is really a cut'n'paste but it introduces a problem with 
> qemu-alpha, I don't know how/why:
> 
>   $ sudo unshare --ipc --uts --pid --fork --kill-child --mount chroot chroot/alpha/sid/
>   Unsupported ioctl: cmd=0x80047476
> 
> And then it hangs.
> 
> I'll try to debug.

In fact it happens with sid, with ppc64 too, but not with m68k and sh4.

And only with "unshare --pid --fork".

Without "unshare", the result is:

  Unsupported ioctl: cmd=0x80047476
  bash: cannot set terminal process group (11507): Function not implemented
  bash: no job control in this shell
  Unsupported ioctl: cmd=0x80087467
  Unsupported ioctl: cmd=0x80087467
  Unsupported ioctl: cmd=0x802c7415

Thanks,
Laurent

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
  2019-02-13 13:46     ` Laurent Vivier
@ 2019-04-09 23:15       ` Richard Henderson
  2019-04-09 23:15         ` Richard Henderson
  2019-04-09 23:30         ` Richard Henderson
  0 siblings, 2 replies; 59+ messages in thread
From: Richard Henderson @ 2019-04-09 23:15 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel

On 2/13/19 3:46 AM, Laurent Vivier wrote:
> On 13/02/2019 14:09, Laurent Vivier wrote:
>> Hi,
>>
>> this one is really a cut'n'paste but it introduces a problem with 
>> qemu-alpha, I don't know how/why:
>>
>>   $ sudo unshare --ipc --uts --pid --fork --kill-child --mount chroot chroot/alpha/sid/
>>   Unsupported ioctl: cmd=0x80047476
>>
>> And then it hangs.
>>
>> I'll try to debug.
> 
> In fact it happens with sid, with ppc64 too, but not with m68k and sh4.
> 
> And only with "unshare --pid --fork".
> 
> Without "unshare", the result is:
> 
>   Unsupported ioctl: cmd=0x80047476
>   bash: cannot set terminal process group (11507): Function not implemented
>   bash: no job control in this shell
>   Unsupported ioctl: cmd=0x80087467
>   Unsupported ioctl: cmd=0x80087467
>   Unsupported ioctl: cmd=0x802c7415

I'm just now getting back to this, and cannot replicate the issue, at least
rebased onto master.  With or without unshare, I see your "without unshare"
results.

The rebase onto master is at

  https://github.com/rth7680/qemu.git lu-split-6


r~

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
  2019-04-09 23:15       ` Richard Henderson
@ 2019-04-09 23:15         ` Richard Henderson
  2019-04-09 23:30         ` Richard Henderson
  1 sibling, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-04-09 23:15 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel

On 2/13/19 3:46 AM, Laurent Vivier wrote:
> On 13/02/2019 14:09, Laurent Vivier wrote:
>> Hi,
>>
>> this one is really a cut'n'paste but it introduces a problem with 
>> qemu-alpha, I don't know how/why:
>>
>>   $ sudo unshare --ipc --uts --pid --fork --kill-child --mount chroot chroot/alpha/sid/
>>   Unsupported ioctl: cmd=0x80047476
>>
>> And then it hangs.
>>
>> I'll try to debug.
> 
> In fact it happens with sid, with ppc64 too, but not with m68k and sh4.
> 
> And only with "unshare --pid --fork".
> 
> Without "unshare", the result is:
> 
>   Unsupported ioctl: cmd=0x80047476
>   bash: cannot set terminal process group (11507): Function not implemented
>   bash: no job control in this shell
>   Unsupported ioctl: cmd=0x80087467
>   Unsupported ioctl: cmd=0x80087467
>   Unsupported ioctl: cmd=0x802c7415

I'm just now getting back to this, and cannot replicate the issue, at least
rebased onto master.  With or without unshare, I see your "without unshare"
results.

The rebase onto master is at

  https://github.com/rth7680/qemu.git lu-split-6


r~


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
  2019-04-09 23:15       ` Richard Henderson
  2019-04-09 23:15         ` Richard Henderson
@ 2019-04-09 23:30         ` Richard Henderson
  2019-04-09 23:30           ` Richard Henderson
  2019-04-10  1:55           ` Richard Henderson
  1 sibling, 2 replies; 59+ messages in thread
From: Richard Henderson @ 2019-04-09 23:30 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel

On 4/9/19 1:15 PM, Richard Henderson wrote:
> On 2/13/19 3:46 AM, Laurent Vivier wrote:
>> In fact it happens with sid, with ppc64 too, but not with m68k and sh4.
>>
>> And only with "unshare --pid --fork".
>>
>> Without "unshare", the result is:
>>
>>   Unsupported ioctl: cmd=0x80047476
>>   bash: cannot set terminal process group (11507): Function not implemented
>>   bash: no job control in this shell
>>   Unsupported ioctl: cmd=0x80087467
>>   Unsupported ioctl: cmd=0x80087467
>>   Unsupported ioctl: cmd=0x802c7415
> 
> I'm just now getting back to this, and cannot replicate the issue

... Oh nevermind.  I should be expecting no "unsupported" at all, since that's
what we get with master.


r~

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
  2019-04-09 23:30         ` Richard Henderson
@ 2019-04-09 23:30           ` Richard Henderson
  2019-04-10  1:55           ` Richard Henderson
  1 sibling, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-04-09 23:30 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel

On 4/9/19 1:15 PM, Richard Henderson wrote:
> On 2/13/19 3:46 AM, Laurent Vivier wrote:
>> In fact it happens with sid, with ppc64 too, but not with m68k and sh4.
>>
>> And only with "unshare --pid --fork".
>>
>> Without "unshare", the result is:
>>
>>   Unsupported ioctl: cmd=0x80047476
>>   bash: cannot set terminal process group (11507): Function not implemented
>>   bash: no job control in this shell
>>   Unsupported ioctl: cmd=0x80087467
>>   Unsupported ioctl: cmd=0x80087467
>>   Unsupported ioctl: cmd=0x802c7415
> 
> I'm just now getting back to this, and cannot replicate the issue

... Oh nevermind.  I should be expecting no "unsupported" at all, since that's
what we get with master.


r~


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
  2019-04-09 23:30         ` Richard Henderson
  2019-04-09 23:30           ` Richard Henderson
@ 2019-04-10  1:55           ` Richard Henderson
  2019-04-10  1:55             ` Richard Henderson
  2019-05-09 15:44             ` Laurent Vivier
  1 sibling, 2 replies; 59+ messages in thread
From: Richard Henderson @ 2019-04-10  1:55 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel

On 4/9/19 1:30 PM, Richard Henderson wrote:
> On 4/9/19 1:15 PM, Richard Henderson wrote:
>> On 2/13/19 3:46 AM, Laurent Vivier wrote:
>>> In fact it happens with sid, with ppc64 too, but not with m68k and sh4.
>>>
>>> And only with "unshare --pid --fork".
>>>
>>> Without "unshare", the result is:
>>>
>>>   Unsupported ioctl: cmd=0x80047476
>>>   bash: cannot set terminal process group (11507): Function not implemented
>>>   bash: no job control in this shell
>>>   Unsupported ioctl: cmd=0x80087467
>>>   Unsupported ioctl: cmd=0x80087467
>>>   Unsupported ioctl: cmd=0x802c7415
>>
>> I'm just now getting back to this, and cannot replicate the issue
> 
> ... Oh nevermind.  I should be expecting no "unsupported" at all, since that's
> what we get with master.

The cause is that "cmd" accidentally changed from "int" in the do_ioctl
parameter list to "abi_ulong" as a local variable in impl_ioctl.  This caused a
table lookup failure on any ioctl with bit 31 set, for 64-bit guests.


r~

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
  2019-04-10  1:55           ` Richard Henderson
@ 2019-04-10  1:55             ` Richard Henderson
  2019-05-09 15:44             ` Laurent Vivier
  1 sibling, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-04-10  1:55 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel

On 4/9/19 1:30 PM, Richard Henderson wrote:
> On 4/9/19 1:15 PM, Richard Henderson wrote:
>> On 2/13/19 3:46 AM, Laurent Vivier wrote:
>>> In fact it happens with sid, with ppc64 too, but not with m68k and sh4.
>>>
>>> And only with "unshare --pid --fork".
>>>
>>> Without "unshare", the result is:
>>>
>>>   Unsupported ioctl: cmd=0x80047476
>>>   bash: cannot set terminal process group (11507): Function not implemented
>>>   bash: no job control in this shell
>>>   Unsupported ioctl: cmd=0x80087467
>>>   Unsupported ioctl: cmd=0x80087467
>>>   Unsupported ioctl: cmd=0x802c7415
>>
>> I'm just now getting back to this, and cannot replicate the issue
> 
> ... Oh nevermind.  I should be expecting no "unsupported" at all, since that's
> what we get with master.

The cause is that "cmd" accidentally changed from "int" in the do_ioctl
parameter list to "abi_ulong" as a local variable in impl_ioctl.  This caused a
table lookup failure on any ioctl with bit 31 set, for 64-bit guests.


r~


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
  2019-04-10  1:55           ` Richard Henderson
  2019-04-10  1:55             ` Richard Henderson
@ 2019-05-09 15:44             ` Laurent Vivier
  2019-05-09 15:54               ` Richard Henderson
  1 sibling, 1 reply; 59+ messages in thread
From: Laurent Vivier @ 2019-05-09 15:44 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel

On 10/04/2019 03:55, Richard Henderson wrote:
> On 4/9/19 1:30 PM, Richard Henderson wrote:
>> On 4/9/19 1:15 PM, Richard Henderson wrote:
>>> On 2/13/19 3:46 AM, Laurent Vivier wrote:
>>>> In fact it happens with sid, with ppc64 too, but not with m68k and sh4.
>>>>
>>>> And only with "unshare --pid --fork".
>>>>
>>>> Without "unshare", the result is:
>>>>
>>>>    Unsupported ioctl: cmd=0x80047476
>>>>    bash: cannot set terminal process group (11507): Function not implemented
>>>>    bash: no job control in this shell
>>>>    Unsupported ioctl: cmd=0x80087467
>>>>    Unsupported ioctl: cmd=0x80087467
>>>>    Unsupported ioctl: cmd=0x802c7415
>>>
>>> I'm just now getting back to this, and cannot replicate the issue
>>
>> ... Oh nevermind.  I should be expecting no "unsupported" at all, since that's
>> what we get with master.
> 
> The cause is that "cmd" accidentally changed from "int" in the do_ioctl
> parameter list to "abi_ulong" as a local variable in impl_ioctl.  This caused a
> table lookup failure on any ioctl with bit 31 set, for 64-bit guests.

Do you plan to send a new version of this series?

Thanks,
Laurent


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
  2019-05-09 15:44             ` Laurent Vivier
@ 2019-05-09 15:54               ` Richard Henderson
  0 siblings, 0 replies; 59+ messages in thread
From: Richard Henderson @ 2019-05-09 15:54 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel

On 5/9/19 8:44 AM, Laurent Vivier wrote:
> Do you plan to send a new version of this series?

Yes.  Soon(tm).


r~


^ permalink raw reply	[flat|nested] 59+ messages in thread

end of thread, other threads:[~2019-05-09 15:56 UTC | newest]

Thread overview: 59+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-01-18 21:30 [Qemu-devel] [PATCH v6 00/49] linux-user: Split do_syscall Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 01/49] linux-user: Setup split syscall infrastructure Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 03/49] linux-user: Split out open, open_at Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 04/49] linux-user: Share more code for open and openat Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 05/49] linux-user: Tidy do_openat loop over fakes Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 06/49] linux-user: Split out readlink, readlinkat Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 07/49] linux-user: Split out close Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 08/49] linux-user: Split out read, write Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 09/49] linux-user: Reduce regpairs_aligned & target_offset64 ifdefs Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 10/49] linux-user: Split out readv, writev Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 11/49] linux-user: Split out pread64, pwrite64 Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 12/49] linux-user: Split out preadv, pwritev Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 13/49] linux-user: Split out name_to_handle_at, open_by_handle_at Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 14/49] linux-user: Split out ipc syscalls Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 15/49] linux-user: Split out memory syscalls Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 16/49] linux-user: Split out exit Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 17/49] linux-user: Split out brk Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 18/49] linux-user: Split out clone, fork, vfork Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 19/49] linux-user: Split out wait4, waitid, waitpid Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 20/49] linux-user: Implement rusage argument to waitid Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 21/49] linux-user: Split out creat Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 22/49] linux-user: Split out link, linkat Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 23/49] linux-user: Split out unlink, unlinkat, rmdir Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 24/49] linux-user: Split out execve Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 25/49] linux-user: Implement execveat Richard Henderson
2019-01-18 21:30 ` [Qemu-devel] [PATCH v6 26/49] linux-user: Split out chdir Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 27/49] linux-user: Split out time Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 28/49] linux-user: Split out mknod, mknodat Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 29/49] linux-user: Split out chmod, fchmod, fchmodat Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 30/49] linux-user: Split out lseek, llseek Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 31/49] linux-user: Split out getpid, getppid, getxpid Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 32/49] linux-user: Split out mount Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 33/49] linux-user: Split out umount, umount2 Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 34/49] linux-user: Split out stime Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 35/49] linux-user: Split out alarm, pause Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 36/49] linux-user: Split out utime, utimes, futimesat Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 37/49] linux-user: Split out access, faccessat Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 38/49] linux-user: Split out nice Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 39/49] linux-user: Split out sync, syncfs Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 40/49] linux-user: Split out kill Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 41/49] linux-user: Split out rename, renameat, renameat2 Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 42/49] linux-user: Split out mkdir, mkdirat Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 43/49] linux-user: Split out dup, dup2, dup3 Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 44/49] linux-user: Split out pipe, pipe2 Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 45/49] linux-user: Split out times Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 46/49] linux-user: Split out acct Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 47/49] linux-user: Move syscall_init to the end Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl Richard Henderson
2019-02-13 13:09   ` Laurent Vivier
2019-02-13 13:46     ` Laurent Vivier
2019-04-09 23:15       ` Richard Henderson
2019-04-09 23:15         ` Richard Henderson
2019-04-09 23:30         ` Richard Henderson
2019-04-09 23:30           ` Richard Henderson
2019-04-10  1:55           ` Richard Henderson
2019-04-10  1:55             ` Richard Henderson
2019-05-09 15:44             ` Laurent Vivier
2019-05-09 15:54               ` Richard Henderson
2019-01-18 21:31 ` [Qemu-devel] [PATCH v6 49/49] linux-user: Split out fcntl, fcntl64 Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).