* [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall
@ 2018-12-19 4:21 Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 1/8] linux-user: Setup split syscall infrastructure Richard Henderson
` (9 more replies)
0 siblings, 10 replies; 15+ messages in thread
From: Richard Henderson @ 2018-12-19 4:21 UTC (permalink / raw)
To: qemu-devel; +Cc: laurent
Version 4 was back in August:
https://lists.gnu.org/archive/html/qemu-devel/2018-08/msg03745.html
Version 5 continues the file split via inclusion. This incorporates
Laurent's suggestion to have a "def" file that is included twice to
generate both SyscallDef structures and fill in syscall_table's switch.
Again, this just converts a few syscalls as proof of concept.
r~
Richard Henderson (8):
linux-user: Setup split syscall infrastructure
linux-user: Split out some simple file syscalls
linux-user: Reduce regpairs_aligned & target_offset64 ifdefs
linux-user: Split out preadv, pwritev, readv, writev, pread64,
pwrite64
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 some process syscalls
linux-user/syscall-defs.h | 231 +++
linux-user/syscall.h | 93 ++
linux-user/strace.c | 567 ++++----
linux-user/syscall-file.inc.c | 638 +++++++++
linux-user/syscall-ipc.inc.c | 1086 ++++++++++++++
linux-user/syscall-mem.inc.c | 154 ++
linux-user/syscall-proc.inc.c | 861 ++++++++++++
linux-user/syscall.c | 2500 ++-------------------------------
linux-user/strace.list | 243 ----
9 files changed, 3499 insertions(+), 2874 deletions(-)
create mode 100644 linux-user/syscall-defs.h
create mode 100644 linux-user/syscall.h
create mode 100644 linux-user/syscall-file.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
--
2.17.2
^ permalink raw reply [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH v5 1/8] linux-user: Setup split syscall infrastructure
2018-12-19 4:21 [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall Richard Henderson
@ 2018-12-19 4:21 ` Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 2/8] linux-user: Split out some simple file syscalls Richard Henderson
` (8 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2018-12-19 4:21 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.h | 89 ++++++++++
linux-user/strace.c | 388 +++++++++++++++++++++++++++++++------------
linux-user/syscall.c | 107 +++++++++++-
3 files changed, 471 insertions(+), 113 deletions(-)
create mode 100644 linux-user/syscall.h
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 d1d14945f9..0d9e1dc483 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 280137da8c..5d388ffd62 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 */
@@ -11480,12 +11481,74 @@ 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 the definition for a "simple" syscall. Such does not use
+ * SyscallArgsFn and only uses arg_type for strace.
+ */
+#define SYSCALL_DEF(NAME, ...) \
+ static const SyscallDef def_##NAME = { \
+ .name = #NAME, .impl = impl_##NAME, .arg_type = { __VA_ARGS__ } \
+ }
+
+/*
+ * Emit the definition for a syscall that also has an args hook,
+ * and uses arg_type for strace.
+ */
+#define SYSCALL_DEF_ARGS(NAME, ...) \
+ static const SyscallDef def_##NAME = { \
+ .name = #NAME, .args = args_##NAME, .impl = impl_##NAME, \
+ .arg_type = { __VA_ARGS__ } \
+ }
+
+/*
+ * Emit a complete SyscallDef structure.
+ */
+#define SYSCALL_DEF_FULL(NAME, ...) \
+ static const SyscallDef def_##NAME = { .name = #NAME, __VA_ARGS__ }
+
+#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) {
+ }
+ 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
@@ -11505,16 +11568,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] 15+ messages in thread
* [Qemu-devel] [PATCH v5 2/8] linux-user: Split out some simple file syscalls
2018-12-19 4:21 [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 1/8] linux-user: Setup split syscall infrastructure Richard Henderson
@ 2018-12-19 4:21 ` Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 3/8] linux-user: Reduce regpairs_aligned & target_offset64 ifdefs Richard Henderson
` (7 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2018-12-19 4:21 UTC (permalink / raw)
To: qemu-devel; +Cc: laurent
This includes close, open, openat, read, readlink, readlinkat, write.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/syscall-defs.h | 31 +++
linux-user/syscall-file.inc.c | 433 ++++++++++++++++++++++++++++++++++
linux-user/syscall.c | 376 +----------------------------
3 files changed, 468 insertions(+), 372 deletions(-)
create mode 100644 linux-user/syscall-defs.h
create mode 100644 linux-user/syscall-file.inc.c
diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
new file mode 100644
index 0000000000..b031de1375
--- /dev/null
+++ b/linux-user/syscall-defs.h
@@ -0,0 +1,31 @@
+/*
+ * 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/>.
+ */
+
+SYSCALL_DEF(close, ARG_DEC);
+#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(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
new file mode 100644
index 0000000000..11e75044c1
--- /dev/null
+++ b/linux-user/syscall-file.inc.c
@@ -0,0 +1,433 @@
+/*
+ * 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));
+ if (!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 abi_long do_openat(void *cpu_env, int dirfd, abi_ulong target_path,
+ int target_flags, int mode)
+{
+ struct fake_open {
+ const char *filename;
+ int (*fill)(void *cpu_env, int fd);
+ int (*cmp)(const char *s1, const char *s2);
+ };
+ 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
+ };
+
+ 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;
+ }
+
+ if (is_proc_myself(pathname, "exe")) {
+ ret = qemu_getauxval(AT_EXECFD);
+ if (ret == 0) {
+ ret = get_errno(safe_openat(dirfd, exec_path, flags, mode));
+ }
+ goto done;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(fakes); ++i) {
+ if (fakes[i].cmp(pathname, fakes[i].filename)) {
+ const char *tmpdir;
+ char filename[PATH_MAX];
+
+ /* Create temporary file. */
+ tmpdir = getenv("TMPDIR");
+ if (!tmpdir) {
+ tmpdir = "/tmp";
+ }
+ snprintf(filename, sizeof(filename),
+ "%s/qemu-open.XXXXXX", tmpdir);
+ ret = mkstemp(filename);
+ if (ret < 0) {
+ ret = -TARGET_ENOENT;
+ goto done;
+ }
+ unlink(filename);
+
+ /* Add contents to the temporary file. */
+ if (fakes[i].fill(cpu_env, ret)) {
+ close(ret);
+ ret = -TARGET_ENOENT;
+ goto done;
+ }
+
+ lseek(ret, 0, SEEK_SET);
+ goto done;
+ }
+ }
+
+ ret = get_errno(safe_openat(dirfd, path(pathname), flags, mode));
+ done:
+ fd_trans_unregister(ret);
+ unlock_user(pathname, target_path, 0);
+ return ret;
+}
+
+SYSCALL_IMPL(close)
+{
+ fd_trans_unregister(arg1);
+ return get_errno(close(arg1));
+}
+
+#ifdef TARGET_NR_open
+SYSCALL_IMPL(open)
+{
+ return do_openat(cpu_env, AT_FDCWD, arg1, arg2, arg3);
+}
+#endif
+
+SYSCALL_IMPL(openat)
+{
+ return do_openat(cpu_env, arg1, arg2, arg3, arg4);
+}
+
+SYSCALL_IMPL(read)
+{
+ abi_long ret;
+ void *p;
+
+ if (arg3 == 0) {
+ return 0;
+ }
+ p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(safe_read(arg1, p, arg3));
+
+ if (!is_error(ret)) {
+ TargetFdDataFunc trans = fd_trans_host_to_target_data(arg1);
+ if (trans) {
+ ret = trans(p, ret);
+ }
+ }
+ unlock_user(p, arg2, ret);
+ return ret;
+}
+
+static abi_long do_readlink_proc_exe(char *buf, abi_ulong bufsiz)
+{
+ char real[PATH_MAX];
+ char *temp = realpath(exec_path, real);
+ abi_long ret;
+
+ /* Return value is # of bytes that we wrote to the buffer. */
+ if (temp == NULL) {
+ return -host_to_target_errno(errno);
+ }
+ ret = MIN(strlen(real), bufsiz);
+ /* We cannot NUL terminate the string. */
+ memcpy(buf, real, ret);
+ return ret;
+}
+
+#ifdef TARGET_NR_readlink
+SYSCALL_IMPL(readlink)
+{
+ char *p = lock_user_string(arg1);
+ abi_ulong bufsiz = arg3;
+ void *buf = lock_user(VERIFY_WRITE, arg2, 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(p, "exe")) {
+ ret = do_readlink_proc_exe(buf, bufsiz);
+ } else {
+ ret = get_errno(readlink(path(p), buf, bufsiz));
+ }
+ unlock_user(buf, arg2, ret);
+ unlock_user(p, arg1, 0);
+ return ret;
+}
+#endif
+
+#ifdef TARGET_NR_readlinkat
+SYSCALL_IMPL(readlinkat)
+{
+ char *p = lock_user_string(arg2);
+ abi_ulong bufsiz = arg4;
+ void *buf = lock_user(VERIFY_WRITE, arg3, 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(p, "exe")) {
+ ret = do_readlink_proc_exe(buf, bufsiz);
+ } else {
+ ret = get_errno(readlinkat(arg1, path(p), buf, bufsiz));
+ }
+ unlock_user(buf, arg3, ret);
+ unlock_user(p, arg2, 0);
+ return ret;
+}
+#endif
+
+SYSCALL_IMPL(write)
+{
+ TargetFdDataFunc trans;
+ abi_long ret;
+ void *p;
+
+ if (arg2 == 0 && arg3 == 0) {
+ return get_errno(safe_write(arg1, 0, 0));
+ }
+ p = lock_user(VERIFY_READ, arg2, arg3, 1);
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ trans = fd_trans_target_to_host_data(arg1);
+ if (trans) {
+ void *copy = g_malloc(arg3);
+ memcpy(copy, p, arg3);
+ ret = trans(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;
+}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 5d388ffd62..7118f07441 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6538,267 +6538,6 @@ 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);
-}
-
#define TIMER_MAGIC 0x0caf0000
#define TIMER_MAGIC_MASK 0xffff0000
@@ -6948,60 +6687,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;
-
-#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);
@@ -7013,10 +6698,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
@@ -8292,59 +7973,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)))
@@ -11492,6 +11120,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
@@ -11521,6 +11150,8 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
#define SYSCALL_DEF_FULL(NAME, ...) \
static const SyscallDef def_##NAME = { .name = #NAME, __VA_ARGS__ }
+#include "syscall-defs.h"
+
#undef SYSCALL_DEF
#undef SYSCALL_DEF_ARGS
#undef SYSCALL_DEF_FULL
@@ -11532,6 +11163,7 @@ static const SyscallDef *syscall_table(int num)
#define SYSCALL_DEF_FULL(NAME, ...) SYSCALL_DEF(NAME)
switch (num) {
+#include "syscall-defs.h"
}
return NULL;
--
2.17.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH v5 3/8] linux-user: Reduce regpairs_aligned & target_offset64 ifdefs
2018-12-19 4:21 [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 1/8] linux-user: Setup split syscall infrastructure Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 2/8] linux-user: Split out some simple file syscalls Richard Henderson
@ 2018-12-19 4:21 ` Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 4/8] linux-user: Split out preadv, pwritev, readv, writev, pread64, pwrite64 Richard Henderson
` (6 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2018-12-19 4:21 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 7118f07441..d4c11c3e93 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
@@ -6066,21 +6067,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] 15+ messages in thread
* [Qemu-devel] [PATCH v5 4/8] linux-user: Split out preadv, pwritev, readv, writev, pread64, pwrite64
2018-12-19 4:21 [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall Richard Henderson
` (2 preceding siblings ...)
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 3/8] linux-user: Reduce regpairs_aligned & target_offset64 ifdefs Richard Henderson
@ 2018-12-19 4:21 ` Richard Henderson
2019-01-10 15:17 ` Laurent Vivier
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 5/8] linux-user: Split out name_to_handle_at, open_by_handle_at Richard Henderson
` (5 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Richard Henderson @ 2018-12-19 4:21 UTC (permalink / raw)
To: qemu-devel; +Cc: laurent
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/syscall-defs.h | 14 ++++
linux-user/syscall-file.inc.c | 124 ++++++++++++++++++++++++++++++++++
linux-user/syscall.c | 93 -------------------------
linux-user/strace.list | 18 -----
4 files changed, 138 insertions(+), 111 deletions(-)
diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index b031de1375..ae89be0e87 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -21,6 +21,18 @@ 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_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);
@@ -28,4 +40,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 11e75044c1..410a763eee 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -315,6 +315,104 @@ 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)
+{
+ void *p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+ abi_long ret;
+
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(pread64(arg1, p, arg3, arg4));
+ unlock_user(p, arg2, ret);
+ return ret;
+}
+
+SYSCALL_IMPL(pwrite64)
+{
+ void *p = lock_user(VERIFY_READ, arg2, arg3, 0);
+ abi_long ret;
+
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(pwrite64(arg1, p, arg3, arg4));
+ unlock_user(p, arg2, 0);
+ 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] = ((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)
+{
+ struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
+ unsigned long lo, hi;
+ abi_long ret;
+
+ if (vec == NULL) {
+ return -host_to_target_errno(errno);
+ }
+
+ host_offset64_low_high(&lo, &hi, arg4);
+ ret = get_errno(safe_preadv(arg1, vec, arg3, lo, hi));
+ unlock_iovec(vec, arg2, arg3, 1);
+ return ret;
+}
+
+SYSCALL_IMPL(pwritev)
+{
+ struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
+ unsigned long lo, hi;
+ abi_long ret;
+
+ if (vec == NULL) {
+ ret = -host_to_target_errno(errno);
+ }
+
+ host_offset64_low_high(&lo, &hi, arg4);
+ ret = get_errno(safe_pwritev(arg1, vec, arg3, lo, hi));
+ unlock_iovec(vec, arg2, arg3, 0);
+ return ret;
+}
+
SYSCALL_IMPL(read)
{
abi_long ret;
@@ -403,6 +501,19 @@ SYSCALL_IMPL(readlinkat)
}
#endif
+SYSCALL_IMPL(readv)
+{
+ struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
+ abi_long ret;
+
+ if (vec == NULL) {
+ return -host_to_target_errno(errno);
+ }
+ ret = get_errno(safe_readv(arg1, vec, arg3));
+ unlock_iovec(vec, arg2, arg3, 1);
+ return ret;
+}
+
SYSCALL_IMPL(write)
{
TargetFdDataFunc trans;
@@ -431,3 +542,16 @@ SYSCALL_IMPL(write)
unlock_user(p, arg2, 0);
return ret;
}
+
+SYSCALL_IMPL(writev)
+{
+ struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
+ abi_long ret;
+
+ if (vec == NULL) {
+ return -host_to_target_errno(errno);
+ }
+ ret = get_errno(safe_writev(arg1, vec, arg3));
+ unlock_iovec(vec, arg2, arg3, 0);
+ return ret;
+}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index d4c11c3e93..9a9b6c543c 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2364,23 +2364,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)
{
@@ -8910,60 +8893,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:
- {
- 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 ?) */
@@ -9295,28 +9224,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 (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
- 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 (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
- 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 ff8bb19f5f..8f96b7a105 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1034,12 +1034,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
#ifdef TARGET_NR_prlimit64
{ TARGET_NR_prlimit64, "prlimit64" , NULL, NULL, NULL },
#endif
@@ -1064,12 +1058,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
#ifdef TARGET_NR_query_module
{ TARGET_NR_query_module, "query_module" , NULL, NULL, NULL },
#endif
@@ -1091,9 +1079,6 @@
#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
#ifdef TARGET_NR_reboot
{ TARGET_NR_reboot, "reboot" , NULL, NULL, NULL },
#endif
@@ -1629,9 +1614,6 @@
#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
#ifdef TARGET_NR_utimensat
{ TARGET_NR_utimensat, "utimensat", NULL, print_utimensat, NULL },
#endif
--
2.17.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH v5 5/8] linux-user: Split out name_to_handle_at, open_by_handle_at
2018-12-19 4:21 [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall Richard Henderson
` (3 preceding siblings ...)
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 4/8] linux-user: Split out preadv, pwritev, readv, writev, pread64, pwrite64 Richard Henderson
@ 2018-12-19 4:21 ` Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 6/8] linux-user: Split out ipc syscalls Richard Henderson
` (4 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2018-12-19 4:21 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.h | 1 +
linux-user/strace.c | 5 +-
linux-user/syscall-file.inc.c | 81 +++++++++++++++++++++++++++
linux-user/syscall.c | 102 ++--------------------------------
linux-user/strace.list | 3 -
6 files changed, 93 insertions(+), 102 deletions(-)
diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
index ae89be0e87..3d52835216 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -21,6 +21,9 @@ 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(name_to_handle_at,
+ ARG_ATDIRFD, ARG_STR, ARG_PTR, ARG_PTR, ARG_ATFLAG);
+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 0d9e1dc483..661e5de7f7 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
@@ -2745,6 +2745,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 410a763eee..e7b8068a46 100644
--- a/linux-user/syscall-file.inc.c
+++ b/linux-user/syscall-file.inc.c
@@ -315,6 +315,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 9a9b6c543c..98eb3a9c94 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.
@@ -6384,93 +6388,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)
@@ -6666,17 +6583,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/linux-user/strace.list b/linux-user/strace.list
index 8f96b7a105..c61b3b9d09 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -638,9 +638,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] 15+ messages in thread
* [Qemu-devel] [PATCH v5 6/8] linux-user: Split out ipc syscalls
2018-12-19 4:21 [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall Richard Henderson
` (4 preceding siblings ...)
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 5/8] linux-user: Split out name_to_handle_at, open_by_handle_at Richard Henderson
@ 2018-12-19 4:21 ` Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 7/8] linux-user: Split out memory syscalls Richard Henderson
` (3 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2018-12-19 4:21 UTC (permalink / raw)
To: qemu-devel; +Cc: laurent
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 3d52835216..2712867228 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
#ifdef TARGET_NR_open
SYSCALL_DEF(open, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
#endif
@@ -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 661e5de7f7..95cf9837cf 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 98eb3a9c94..249eb85d4a 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)
@@ -3095,890 +3058,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,
@@ -8356,54 +7435,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:
@@ -10930,6 +9961,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
@@ -10970,6 +10002,7 @@ 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)
+#define SYSCALL_TABLE
switch (num) {
#include "syscall-defs.h"
@@ -10979,6 +10012,7 @@ static const SyscallDef *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 c61b3b9d09..9385ea3dd1 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -455,9 +455,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
@@ -611,18 +608,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
@@ -926,9 +911,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
@@ -1202,18 +1184,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
@@ -1341,18 +1311,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] 15+ messages in thread
* [Qemu-devel] [PATCH v5 7/8] linux-user: Split out memory syscalls
2018-12-19 4:21 [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall Richard Henderson
` (5 preceding siblings ...)
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 6/8] linux-user: Split out ipc syscalls Richard Henderson
@ 2018-12-19 4:21 ` Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 8/8] linux-user: Split out some process syscalls Richard Henderson
` (2 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Richard Henderson @ 2018-12-19 4:21 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 2712867228..a057aa9150 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);
#ifdef TARGET_NR_open
SYSCALL_DEF(open, ARG_STR, ARG_OPENFLAG, ARG_MODEFLAG);
#endif
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 95cf9837cf..8bc7338af8 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),
@@ -2414,51 +2414,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)
{
@@ -2665,6 +2620,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 249eb85d4a..fda7376e58 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4091,29 +4091,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 */
@@ -5334,21 +5311,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))
@@ -6958,86 +6920,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)))
@@ -9962,6 +9844,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 9385ea3dd1..ac7cf77021 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -557,21 +557,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
@@ -581,9 +566,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
@@ -605,24 +587,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] 15+ messages in thread
* [Qemu-devel] [PATCH v5 8/8] linux-user: Split out some process syscalls
2018-12-19 4:21 [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall Richard Henderson
` (6 preceding siblings ...)
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 7/8] linux-user: Split out memory syscalls Richard Henderson
@ 2018-12-19 4:21 ` Richard Henderson
2019-01-10 14:17 ` Laurent Vivier
2018-12-25 3:19 ` [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall no-reply
2019-01-09 9:50 ` Laurent Vivier
9 siblings, 1 reply; 15+ messages in thread
From: Richard Henderson @ 2018-12-19 4:21 UTC (permalink / raw)
To: qemu-devel; +Cc: laurent
This includes clone, getgroups, gettid, setfsgid, setfsuid,
setgroups, setsid, setuid, fork, getegid, getegid32, geteuid,
geteuid32, getgid, getgid32, getgroups32, getpgrp, getpid,
getppid, getresgid, getresgid32, getresuid, getresuid32,
getuid, getuid32, getxgid, getxpid, getxuid, setfsgid32,
setgsuid32, setgid32, setgroups32, setregid, setregid32,
setresgid, setresgid32, setresuid, setresuid32, setreuid,
setreuid32, setuid32, vfork.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/syscall-defs.h | 121 +++++
linux-user/syscall.h | 1 +
linux-user/strace.c | 36 +-
linux-user/syscall-proc.inc.c | 861 ++++++++++++++++++++++++++++++++++
linux-user/syscall.c | 677 +-------------------------
linux-user/strace.list | 147 ------
6 files changed, 988 insertions(+), 855 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 a057aa9150..a7f78793fd 100644
--- a/linux-user/syscall-defs.h
+++ b/linux-user/syscall-defs.h
@@ -16,7 +16,80 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+SYSCALL_DEF_ARGS(clone, ARG_CLONEFLAG, ARG_PTR, ARG_PTR, ARG_PTR, ARG_PTR);
SYSCALL_DEF(close, ARG_DEC);
+#ifdef TARGET_NR_fork
+SYSCALL_DEF(fork);
+#endif
+#ifdef TARGET_NR_getegid
+SYSCALL_DEF(getegid);
+#endif
+#ifdef TARGET_NR_getegid32
+SYSCALL_DEF(getegid32);
+#endif
+#ifdef TARGET_NR_geteuid
+SYSCALL_DEF(geteuid);
+#endif
+#ifdef TARGET_NR_geteuid32
+SYSCALL_DEF(geteuid32);
+#endif
+#ifdef TARGET_NR_getgid
+SYSCALL_DEF(getgid);
+#endif
+#ifdef TARGET_NR_getgid32
+SYSCALL_DEF(getgid32);
+#endif
+SYSCALL_DEF(getgroups, ARG_DEC, ARG_PTR);
+#ifdef TARGET_NR_getgroups32
+SYSCALL_DEF(getgroups32, ARG_DEC, ARG_PTR);
+#endif
+#ifdef TARGET_NR_getresgid
+SYSCALL_DEF(getresgid, ARG_PTR, ARG_PTR, ARG_PTR);
+#endif
+#ifdef TARGET_NR_getresgid32
+SYSCALL_DEF(getresgid32, ARG_PTR, ARG_PTR, ARG_PTR);
+#endif
+#ifdef TARGET_NR_getresuid
+SYSCALL_DEF(getresuid, ARG_PTR, ARG_PTR, ARG_PTR);
+#endif
+#ifdef TARGET_NR_getresuid32
+SYSCALL_DEF(getresuid32, ARG_PTR, ARG_PTR, ARG_PTR);
+#endif
+#ifdef TARGET_NR_getpgrp
+SYSCALL_DEF(getpgrp);
+#endif
+#ifdef TARGET_NR_getpid
+SYSCALL_DEF(getpid);
+#endif
+#ifdef TARGET_NR_getppid
+SYSCALL_DEF(getppid);
+#endif
+SYSCALL_DEF(gettid);
+#ifdef TARGET_NR_getuid
+SYSCALL_DEF(getuid);
+#endif
+#ifdef TARGET_NR_getuid32
+SYSCALL_DEF(getuid32);
+#endif
+#ifdef TARGET_NR_getxgid
+SYSCALL_DEF(getxgid);
+#endif
+#ifdef TARGET_NR_getxpid
+SYSCALL_DEF(getxpid);
+#endif
+#ifdef TARGET_NR_getxuid
+SYSCALL_DEF(getxuid);
+#endif
+#ifdef TARGET_NR_get_thread_area
+# if defined(TARGET_I386) && defined(TARGET_ABI32)
+SYSCALL_DEF_FULL(get_thread_area, .impl = impl_get_thread_area,
+ .print_ret = print_syscall_ptr_ret,
+ .arg_type = { ARG_PTR });
+# else
+SYSCALL_DEF_FULL(get_thread_area, .impl = impl_get_thread_area,
+ .print_ret = print_syscall_ptr_ret);
+# endif
+#endif
#ifdef TARGET_NR_ipc
SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
#endif
@@ -92,6 +165,51 @@ SYSCALL_DEF(semget, ARG_DEC, ARG_DEC, ARG_HEX);
#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_semop)
SYSCALL_DEF(semop, ARG_DEC, ARG_PTR, ARG_DEC);
#endif
+SYSCALL_DEF(setfsgid, ARG_DEC);
+#ifdef TARGET_NR_setfsgid32
+SYSCALL_DEF(setfsgid32, ARG_DEC);
+#endif
+SYSCALL_DEF(setfsuid, ARG_DEC);
+#ifdef TARGET_NR_setfsuid32
+SYSCALL_DEF(setfsuid32, ARG_DEC);
+#endif
+SYSCALL_DEF(setgid, ARG_DEC);
+#ifdef TARGET_NR_setgid32
+SYSCALL_DEF(setgid32, ARG_DEC);
+#endif
+SYSCALL_DEF(setgroups, ARG_DEC, ARG_PTR);
+#ifdef TARGET_NR_setgroups32
+SYSCALL_DEF(setgroups32, ARG_DEC, ARG_PTR);
+#endif
+SYSCALL_DEF(setregid, ARG_DEC, ARG_DEC);
+#ifdef TARGET_NR_setregid32
+SYSCALL_DEF(setregid32, ARG_DEC, ARG_DEC);
+#endif
+#ifdef TARGET_NR_setresgid
+SYSCALL_DEF(setresgid, ARG_DEC, ARG_DEC, ARG_DEC);
+#endif
+#ifdef TARGET_NR_setresgid32
+SYSCALL_DEF(setresgid32, ARG_DEC, ARG_DEC, ARG_DEC);
+#endif
+#ifdef TARGET_NR_setresuid
+SYSCALL_DEF(setresuid, ARG_DEC, ARG_DEC, ARG_DEC);
+#endif
+#ifdef TARGET_NR_setresuid32
+SYSCALL_DEF(setresuid32, ARG_DEC, ARG_DEC, ARG_DEC);
+#endif
+SYSCALL_DEF(setreuid, ARG_DEC, ARG_DEC);
+#ifdef TARGET_NR_setreuid32
+SYSCALL_DEF(setreuid32, ARG_DEC, ARG_DEC);
+#endif
+SYSCALL_DEF(setsid);
+SYSCALL_DEF(setuid, ARG_DEC);
+#ifdef TARGET_NR_setuid32
+SYSCALL_DEF(setuid32, ARG_DEC);
+#endif
+#ifdef TARGET_NR_set_thread_area
+SYSCALL_DEF(set_thread_area, ARG_PTR);
+#endif
+SYSCALL_DEF(set_tid_address, ARG_PTR);
#if !defined(SYSCALL_TABLE) || defined(TARGET_NR_shmat)
SYSCALL_DEF_FULL(shmat, .impl = impl_shmat,
.print_ret = print_syscall_ptr_ret,
@@ -108,3 +226,6 @@ 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);
+#ifdef TARGET_NR_vfork
+SYSCALL_DEF(vfork);
+#endif
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 8bc7338af8..19b0403d74 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -836,7 +836,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),
@@ -1218,37 +1218,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,
@@ -2620,6 +2589,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
new file mode 100644
index 0000000000..dee441b4ff
--- /dev/null
+++ b/linux-user/syscall-proc.inc.c
@@ -0,0 +1,861 @@
+/*
+ * 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/>.
+ */
+
+
+/*
+ * We must do direct syscalls for setting UID/GID, because we want to
+ * implement the Linux system call semantics of "change only for this thread",
+ * not the libc/POSIX semantics of "change for all threads in process".
+ * (See http://ewontfix.com/17/ for more details.)
+ * We use the 32-bit version of the syscalls if present; if it is not
+ * then either the host architecture supports 32-bit UIDs natively with
+ * the standard syscall, or the 16-bit UID is the best we can do.
+ */
+#ifdef __NR_setuid32
+#define __NR_sys_setuid __NR_setuid32
+#else
+#define __NR_sys_setuid __NR_setuid
+#endif
+#ifdef __NR_setgid32
+#define __NR_sys_setgid __NR_setgid32
+#else
+#define __NR_sys_setgid __NR_setgid
+#endif
+#ifdef __NR_setresuid32
+#define __NR_sys_setresuid __NR_setresuid32
+#else
+#define __NR_sys_setresuid __NR_setresuid
+#endif
+#ifdef __NR_setresgid32
+#define __NR_sys_setresgid __NR_setresgid32
+#else
+#define __NR_sys_setresgid __NR_setresgid
+#endif
+
+_syscall1(int, sys_setuid, uid_t, uid)
+_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)
+
+#ifndef __NR_gettid
+#define __NR_gettid -1
+#endif
+_syscall0(int, gettid)
+
+#ifndef __NR_set_tid_address
+#define __NR_set_tid_address -1
+#endif
+_syscall1(int, set_tid_address, int *, tidptr)
+
+
+/*
+ * 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.)
+ */
+
+#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))
+
+#define NEW_STACK_SIZE 0x40000
+
+static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
+typedef struct {
+ CPUArchState *env;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ pthread_t thread;
+ uint32_t tid;
+ abi_ulong child_tidptr;
+ abi_ulong parent_tidptr;
+ sigset_t sigmask;
+} new_thread_info;
+
+static void *clone_func(void *arg)
+{
+ new_thread_info *info = arg;
+ CPUArchState *env = info->env;
+ CPUState *cpu = ENV_GET_CPU(env);
+ TaskState *ts = (TaskState *)cpu->opaque;
+
+ rcu_register_thread();
+ tcg_register_thread();
+ thread_cpu = cpu;
+ info->tid = gettid();
+ task_settid(ts);
+ if (info->child_tidptr) {
+ put_user_u32(info->tid, info->child_tidptr);
+ }
+ if (info->parent_tidptr) {
+ put_user_u32(info->tid, info->parent_tidptr);
+ }
+ /* Enable signals. */
+ sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
+ /* Signal to the parent that we're ready. */
+ pthread_mutex_lock(&info->mutex);
+ pthread_cond_broadcast(&info->cond);
+ pthread_mutex_unlock(&info->mutex);
+ /* Wait until the parent has finished initializing the tls state. */
+ pthread_mutex_lock(&clone_lock);
+ pthread_mutex_unlock(&clone_lock);
+ cpu_loop(env);
+ /* never exits */
+ return NULL;
+}
+
+static int do_fork(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);
+ 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 = -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 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) {
+ return get_errno(-1);
+ }
+ 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;
+}
+
+SYSCALL_ARGS(clone)
+{
+ abi_ulong fl, sp, ptid, ctid, tls;
+
+ /*
+ * 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)
+ fl = in[0], sp = in[1], ptid = in[3], ctid = in[4], tls = in[5];
+#elif defined(TARGET_CLONE_BACKWARDS)
+ fl = in[0], sp = in[1], ptid = in[2], tls = in[3], ctid = in[4];
+#elif defined(TARGET_CLONE_BACKWARDS2)
+ sp = in[0], fl = in[1], ptid = in[2], ctid = in[3], tls = in[4];
+#else
+ fl = in[0], sp = in[1], ptid = in[2], ctid = in[3], tls = in[4];
+#endif
+ out[0] = fl, out[1] = sp, out[2] = ptid, out[3] = ctid, out[4] = tls;
+ return def;
+}
+
+SYSCALL_IMPL(clone)
+{
+ /* We've done all of the odd ABI adjustment above. */
+ return do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5);
+}
+
+#ifdef TARGET_NR_fork
+SYSCALL_IMPL(fork)
+{
+ return do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0);
+}
+#endif
+
+#ifdef TARGET_NR_vfork
+SYSCALL_IMPL(vfork)
+{
+ return do_fork(cpu_env, CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
+ 0, 0, 0, 0);
+}
+#endif
+
+#ifdef TARGET_NR_getegid
+SYSCALL_IMPL(getegid)
+{
+ return get_errno(high2lowgid(getegid()));
+}
+#endif
+
+#ifdef TARGET_NR_getegid32
+SYSCALL_IMPL(getegid32)
+{
+ return get_errno(getegid());
+}
+#endif
+
+#ifdef TARGET_NR_geteuid
+SYSCALL_IMPL(geteuid)
+{
+ return get_errno(high2lowuid(geteuid()));
+}
+#endif
+
+#ifdef TARGET_NR_geteuid32
+SYSCALL_IMPL(geteuid32)
+{
+ return get_errno(geteuid());
+}
+#endif
+
+#ifdef TARGET_NR_getgid
+SYSCALL_IMPL(getgid)
+{
+ return get_errno(high2lowgid(getgid()));
+}
+#endif
+
+#ifdef TARGET_NR_getgid32
+SYSCALL_IMPL(getgid32)
+{
+ return get_errno(getgid());
+}
+#endif
+
+SYSCALL_IMPL(getgroups)
+{
+ int gidsetsize = arg1;
+ gid_t *grouplist;
+ abi_long ret;
+
+ grouplist = g_try_new(gid_t, gidsetsize);
+ if (!grouplist) {
+ return -TARGET_ENOMEM;
+ }
+ ret = get_errno(getgroups(gidsetsize, grouplist));
+
+ if (!is_error(ret) && gidsetsize != 0) {
+ size_t target_grouplist_size = gidsetsize * sizeof(target_id);
+ target_id *target_grouplist
+ = lock_user(VERIFY_WRITE, arg2, target_grouplist_size, 0);
+ if (target_grouplist) {
+ int i;
+ for (i = 0; i < ret; i++) {
+ target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
+ }
+ unlock_user(target_grouplist, arg2, target_grouplist_size);
+ } else {
+ ret = -TARGET_EFAULT;
+ }
+ }
+ g_free(grouplist);
+ return ret;
+}
+
+#ifdef TARGET_NR_getgroups32
+SYSCALL_IMPL(getgroups32)
+{
+ int gidsetsize = arg1;
+ gid_t *grouplist;
+ abi_long ret;
+
+ grouplist = g_try_new(gid_t, gidsetsize);
+ if (!grouplist) {
+ return -TARGET_ENOMEM;
+ }
+ ret = get_errno(getgroups(gidsetsize, grouplist));
+
+ if (!is_error(ret) && gidsetsize != 0) {
+ uint32_t *target_grouplist
+ = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
+ if (target_grouplist) {
+ int i;
+ for (i = 0; i < ret; i++) {
+ target_grouplist[i] = tswap32(grouplist[i]);
+ }
+ unlock_user(target_grouplist, arg2, gidsetsize * 4);
+ } else {
+ ret = -TARGET_EFAULT;
+ }
+ }
+ return ret;
+}
+#endif
+
+#ifdef TARGET_NR_getresgid
+SYSCALL_IMPL(getresgid)
+{
+ gid_t rgid, egid, sgid;
+ abi_long ret = get_errno(getresgid(&rgid, &egid, &sgid));
+
+ if (!is_error(ret) &&
+ (put_user_id(high2lowgid(rgid), arg1) ||
+ put_user_id(high2lowgid(egid), arg2) ||
+ put_user_id(high2lowgid(sgid), arg3))) {
+ return -TARGET_EFAULT;
+ }
+ return ret;
+}
+#endif
+
+#ifdef TARGET_NR_getresgid32
+SYSCALL_IMPL(getresgid32)
+{
+ gid_t rgid, egid, sgid;
+ abi_long ret = get_errno(getresgid(&rgid, &egid, &sgid));
+
+ if (!is_error(ret) &&
+ (put_user_u32(rgid, arg1) ||
+ put_user_u32(egid, arg2) ||
+ put_user_u32(sgid, arg3))) {
+ return -TARGET_EFAULT;
+ }
+ return ret;
+}
+#endif
+
+#ifdef TARGET_NR_getresuid
+SYSCALL_IMPL(getresuid)
+{
+ uid_t ruid, euid, suid;
+ abi_long ret = get_errno(getresuid(&ruid, &euid, &suid));
+
+ if (!is_error(ret) &&
+ (put_user_id(high2lowuid(ruid), arg1) ||
+ put_user_id(high2lowuid(euid), arg2) ||
+ put_user_id(high2lowuid(suid), arg3))) {
+ return -TARGET_EFAULT;
+ }
+ return ret;
+}
+#endif
+
+#ifdef TARGET_NR_getresuid32
+SYSCALL_IMPL(getresuid32)
+{
+ uid_t ruid, euid, suid;
+ abi_long ret = get_errno(getresuid(&ruid, &euid, &suid));
+
+ if (!is_error(ret) &&
+ (put_user_u32(ruid, arg1) ||
+ put_user_u32(euid, arg2) ||
+ put_user_u32(suid, arg3))) {
+ return -TARGET_EFAULT;
+ }
+ return ret;
+}
+#endif
+
+#ifdef TARGET_NR_getpgrp
+SYSCALL_IMPL(getpgrp)
+{
+ return get_errno(getpgrp());
+}
+#endif
+
+#ifdef TARGET_NR_getpid
+SYSCALL_IMPL(getpid)
+{
+ return get_errno(getpid());
+}
+#endif
+
+#ifdef TARGET_NR_getppid
+SYSCALL_IMPL(getppid)
+{
+ return get_errno(getppid());
+}
+#endif
+
+SYSCALL_IMPL(gettid)
+{
+ return get_errno(gettid());
+}
+
+#ifdef TARGET_NR_getuid
+SYSCALL_IMPL(getuid)
+{
+ return get_errno(high2lowuid(getuid()));
+}
+#endif
+
+#ifdef TARGET_NR_getuid32
+SYSCALL_IMPL(getuid32)
+{
+ return get_errno(getuid());
+}
+#endif
+
+#ifdef TARGET_NR_getxgid
+SYSCALL_IMPL(getxgid)
+{
+ /* Alpha specific */
+ cpu_env->ir[IR_A4] = getegid();
+ return get_errno(getgid());
+}
+#endif
+
+#ifdef TARGET_NR_getxpid
+SYSCALL_IMPL(getxpid)
+{
+ /* Alpha specific */
+ cpu_env->ir[IR_A4] = getppid();
+ return get_errno(getpid());
+}
+#endif
+
+#ifdef TARGET_NR_getxuid
+SYSCALL_IMPL(getxuid)
+{
+ /* Alpha specific */
+ cpu_env->ir[IR_A4] = geteuid();
+ return get_errno(getuid());
+}
+#endif
+
+SYSCALL_IMPL(setfsgid)
+{
+ return get_errno(setfsgid(arg1));
+}
+
+#ifdef TARGET_NR_setfsgid32
+SYSCALL_IMPL(setfsgid32)
+{
+ return get_errno(setfsgid(arg1));
+}
+#endif
+
+SYSCALL_IMPL(setfsuid)
+{
+ return get_errno(setfsuid(arg1));
+}
+
+#ifdef TARGET_NR_setfsuid32
+SYSCALL_IMPL(setfsuid32)
+{
+ return get_errno(setfsuid(arg1));
+}
+#endif
+
+SYSCALL_IMPL(setgid)
+{
+ return get_errno(sys_setgid(low2highgid(arg1)));
+}
+
+#ifdef TARGET_NR_setgid32
+SYSCALL_IMPL(setgid32)
+{
+ return get_errno(sys_setgid(arg1));
+}
+#endif
+
+SYSCALL_IMPL(setgroups)
+{
+ int gidsetsize = arg1;
+ gid_t *grouplist = NULL;
+ abi_long ret;
+
+ if (gidsetsize != 0) {
+ size_t target_grouplist_size = gidsetsize * sizeof(target_id);
+ target_id *target_grouplist
+ = lock_user(VERIFY_READ, arg2, target_grouplist_size, 1);
+ int i;
+
+ if (!target_grouplist) {
+ return -TARGET_EFAULT;
+ }
+ grouplist = g_try_new(gid_t, gidsetsize);
+ if (!grouplist) {
+ unlock_user(target_grouplist, arg2, 0);
+ return -TARGET_ENOMEM;
+ }
+
+ for (i = 0; i < gidsetsize; i++) {
+ grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
+ }
+ unlock_user(target_grouplist, arg2, 0);
+ }
+ ret = get_errno(setgroups(gidsetsize, grouplist));
+ g_free(grouplist);
+ return ret;
+}
+
+#ifdef TARGET_NR_setgroups32
+SYSCALL_IMPL(setgroups32)
+{
+ int gidsetsize = arg1;
+ gid_t *grouplist = NULL;
+ abi_long ret;
+
+ if (gidsetsize != 0) {
+ uint32_t *target_grouplist
+ = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
+ int i;
+
+ if (!target_grouplist) {
+ return -TARGET_EFAULT;
+ }
+ grouplist = g_try_new(gid_t, gidsetsize);
+ if (!grouplist) {
+ unlock_user(target_grouplist, arg2, 0);
+ return -TARGET_ENOMEM;
+ }
+
+ for (i = 0; i < gidsetsize; i++) {
+ grouplist[i] = tswap32(target_grouplist[i]);
+ }
+ unlock_user(target_grouplist, arg2, 0);
+ }
+ ret = get_errno(setgroups(gidsetsize, grouplist));
+ g_free(grouplist);
+ return ret;
+}
+#endif
+
+SYSCALL_IMPL(setregid)
+{
+ return get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
+}
+
+#ifdef TARGET_NR_setregid32
+SYSCALL_IMPL(setregid32)
+{
+ return get_errno(setregid(arg1, arg2));
+}
+#endif
+
+#ifdef TARGET_NR_setresgid
+SYSCALL_IMPL(setresgid)
+{
+ return get_errno(sys_setresgid(low2highgid(arg1),
+ low2highgid(arg2),
+ low2highgid(arg3)));
+}
+#endif
+
+#ifdef TARGET_NR_setresgid32
+SYSCALL_IMPL(setresgid32)
+{
+ return get_errno(sys_setresgid(arg1, arg2, arg3));
+}
+#endif
+
+#ifdef TARGET_NR_setresuid
+SYSCALL_IMPL(setresuid)
+{
+ return get_errno(sys_setresuid(low2highuid(arg1),
+ low2highuid(arg2),
+ low2highuid(arg3)));
+}
+#endif
+
+#ifdef TARGET_NR_setresuid32
+SYSCALL_IMPL(setresuid32)
+{
+ return get_errno(sys_setresuid(arg1, arg2, arg3));
+}
+#endif
+
+SYSCALL_IMPL(setreuid)
+{
+ return get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
+}
+
+#ifdef TARGET_NR_setreuid32
+SYSCALL_IMPL(setreuid32)
+{
+ return get_errno(setreuid(arg1, arg2));
+}
+#endif
+
+SYSCALL_IMPL(setsid)
+{
+ return get_errno(setsid());
+}
+
+SYSCALL_IMPL(setuid)
+{
+ return get_errno(sys_setuid(low2highuid(arg1)));
+}
+
+#ifdef TARGET_NR_setuid32
+SYSCALL_IMPL(setuid32)
+{
+ return get_errno(sys_setuid(arg1));
+}
+#endif
+
+#ifdef TARGET_NR_get_thread_area
+#if defined(TARGET_I386) && defined(TARGET_ABI32)
+static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
+{
+ struct target_modify_ldt_ldt_s *target_ldt_info;
+ uint64_t *gdt_table = g2h(env->gdt.base);
+ uint32_t base_addr, limit, flags;
+ int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
+ int seg_not_present, useable, lm;
+ uint32_t *lp, entry_1, entry_2;
+
+ lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
+ if (!target_ldt_info) {
+ return -TARGET_EFAULT;
+ }
+ idx = tswap32(target_ldt_info->entry_number);
+ if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
+ idx > TARGET_GDT_ENTRY_TLS_MAX) {
+ unlock_user_struct(target_ldt_info, ptr, 1);
+ return -TARGET_EINVAL;
+ }
+ lp = (uint32_t *)(gdt_table + idx);
+ entry_1 = tswap32(lp[0]);
+ entry_2 = tswap32(lp[1]);
+
+ read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
+ contents = (entry_2 >> 10) & 3;
+ seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
+ seg_32bit = (entry_2 >> 22) & 1;
+ limit_in_pages = (entry_2 >> 23) & 1;
+ useable = (entry_2 >> 20) & 1;
+#ifdef TARGET_ABI32
+ lm = 0;
+#else
+ lm = (entry_2 >> 21) & 1;
+#endif
+ flags = (seg_32bit << 0) | (contents << 1) |
+ (read_exec_only << 3) | (limit_in_pages << 4) |
+ (seg_not_present << 5) | (useable << 6) | (lm << 7);
+ limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
+ base_addr = (entry_1 >> 16) |
+ (entry_2 & 0xff000000) |
+ ((entry_2 & 0xff) << 16);
+ target_ldt_info->base_addr = tswapal(base_addr);
+ target_ldt_info->limit = tswap32(limit);
+ target_ldt_info->flags = tswap32(flags);
+ unlock_user_struct(target_ldt_info, ptr, 1);
+ return 0;
+}
+#endif
+
+SYSCALL_IMPL(get_thread_area)
+{
+#if defined(TARGET_I386) && defined(TARGET_ABI32)
+ return do_get_thread_area(cpu_env, arg1);
+#elif defined(TARGET_M68K)
+ CPUState *cpu = ENV_GET_CPU(cpu_env);
+ TaskState *ts = cpu->opaque;
+ return ts->tp_value;
+#else
+ return -TARGET_ENOSYS;
+#endif
+}
+#endif
+
+#ifdef TARGET_NR_set_thread_area
+SYSCALL_IMPL(set_thread_area)
+{
+#if defined(TARGET_MIPS)
+ cpu_env->active_tc.CP0_UserLocal = arg1;
+ return 0;
+#elif defined(TARGET_CRIS)
+ if (arg1 & 0xff) {
+ return -TARGET_EINVAL;
+ }
+ cpu_env->pregs[PR_PID] = arg1;
+ return 0;
+#elif defined(TARGET_I386) && defined(TARGET_ABI32)
+ return do_set_thread_area(cpu_env, arg1);
+#elif defined(TARGET_M68K)
+ CPUState *cpu = ENV_GET_CPU(cpu_env);
+ TaskState *ts = cpu->opaque;
+ ts->tp_value = arg1;
+ return 0;
+#else
+ return -TARGET_ENOSYS;
+#endif
+}
+#endif
+
+SYSCALL_IMPL(set_tid_address)
+{
+ return get_errno(set_tid_address((int *)g2h(arg1)));
+}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index fda7376e58..73d8ec3283 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.
*/
@@ -250,16 +199,6 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
#define TARGET_NR__llseek TARGET_NR_llseek
#endif
-#ifdef __NR_gettid
-_syscall0(int, gettid)
-#else
-/* This is a replacement for the host gettid() and must return a host
- errno. */
-static int gettid(void) {
- return -ENOSYS;
-}
-#endif
-
/* For the 64-bit guest on 32-bit host case we must emulate
* getdents using getdents64, because otherwise the host
* might hand us back more dirent records than we can fit
@@ -289,9 +228,6 @@ _syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
#ifdef __NR_exit_group
_syscall1(int,exit_group,int,error_code)
#endif
-#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
-_syscall1(int,set_tid_address,int *,tidptr)
-#endif
#if defined(TARGET_NR_futex) && defined(__NR_futex)
_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
const struct timespec *,timeout,int *,uaddr2,int,val3)
@@ -4315,53 +4251,6 @@ install:
lp[1] = tswap32(entry_2);
return 0;
}
-
-static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
-{
- struct target_modify_ldt_ldt_s *target_ldt_info;
- uint64_t *gdt_table = g2h(env->gdt.base);
- uint32_t base_addr, limit, flags;
- int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
- int seg_not_present, useable, lm;
- uint32_t *lp, entry_1, entry_2;
-
- lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1);
- if (!target_ldt_info)
- return -TARGET_EFAULT;
- idx = tswap32(target_ldt_info->entry_number);
- if (idx < TARGET_GDT_ENTRY_TLS_MIN ||
- idx > TARGET_GDT_ENTRY_TLS_MAX) {
- unlock_user_struct(target_ldt_info, ptr, 1);
- return -TARGET_EINVAL;
- }
- lp = (uint32_t *)(gdt_table + idx);
- entry_1 = tswap32(lp[0]);
- entry_2 = tswap32(lp[1]);
-
- read_exec_only = ((entry_2 >> 9) & 1) ^ 1;
- contents = (entry_2 >> 10) & 3;
- seg_not_present = ((entry_2 >> 15) & 1) ^ 1;
- seg_32bit = (entry_2 >> 22) & 1;
- limit_in_pages = (entry_2 >> 23) & 1;
- useable = (entry_2 >> 20) & 1;
-#ifdef TARGET_ABI32
- lm = 0;
-#else
- lm = (entry_2 >> 21) & 1;
-#endif
- flags = (seg_32bit << 0) | (contents << 1) |
- (read_exec_only << 3) | (limit_in_pages << 4) |
- (seg_not_present << 5) | (useable << 6) | (lm << 7);
- limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000);
- base_addr = (entry_1 >> 16) |
- (entry_2 & 0xff000000) |
- ((entry_2 & 0xff) << 16);
- target_ldt_info->base_addr = tswapal(base_addr);
- target_ldt_info->limit = tswap32(limit);
- target_ldt_info->flags = tswap32(flags);
- unlock_user_struct(target_ldt_info, ptr, 1);
- return 0;
-}
#endif /* TARGET_I386 && TARGET_ABI32 */
#ifndef TARGET_ABI32
@@ -4401,194 +4290,6 @@ abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
#endif /* defined(TARGET_I386) */
-#define NEW_STACK_SIZE 0x40000
-
-
-static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
-typedef struct {
- CPUArchState *env;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- pthread_t thread;
- uint32_t tid;
- abi_ulong child_tidptr;
- abi_ulong parent_tidptr;
- sigset_t sigmask;
-} new_thread_info;
-
-static void *clone_func(void *arg)
-{
- new_thread_info *info = arg;
- CPUArchState *env;
- CPUState *cpu;
- TaskState *ts;
-
- rcu_register_thread();
- tcg_register_thread();
- env = info->env;
- cpu = ENV_GET_CPU(env);
- thread_cpu = cpu;
- ts = (TaskState *)cpu->opaque;
- info->tid = gettid();
- task_settid(ts);
- if (info->child_tidptr)
- put_user_u32(info->tid, info->child_tidptr);
- if (info->parent_tidptr)
- put_user_u32(info->tid, info->parent_tidptr);
- /* Enable signals. */
- sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
- /* Signal to the parent that we're ready. */
- pthread_mutex_lock(&info->mutex);
- pthread_cond_broadcast(&info->cond);
- pthread_mutex_unlock(&info->mutex);
- /* Wait until the parent has finished initializing the tls state. */
- pthread_mutex_lock(&clone_lock);
- pthread_mutex_unlock(&clone_lock);
- cpu_loop(env);
- /* never exits */
- 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)
{
@@ -5024,40 +4725,6 @@ static inline int tswapid(int id)
#endif /* USE_UID16 */
-/* We must do direct syscalls for setting UID/GID, because we want to
- * implement the Linux system call semantics of "change only for this thread",
- * not the libc/POSIX semantics of "change for all threads in process".
- * (See http://ewontfix.com/17/ for more details.)
- * We use the 32-bit version of the syscalls if present; if it is not
- * then either the host architecture supports 32-bit UIDs natively with
- * the standard syscall, or the 16-bit UID is the best we can do.
- */
-#ifdef __NR_setuid32
-#define __NR_sys_setuid __NR_setuid32
-#else
-#define __NR_sys_setuid __NR_setuid
-#endif
-#ifdef __NR_setgid32
-#define __NR_sys_setgid __NR_setgid32
-#else
-#define __NR_sys_setgid __NR_setgid
-#endif
-#ifdef __NR_setresuid32
-#define __NR_sys_setresuid __NR_setresuid32
-#else
-#define __NR_sys_setresuid __NR_setresuid
-#endif
-#ifdef __NR_setresgid32
-#define __NR_sys_setresgid __NR_setresgid32
-#else
-#define __NR_sys_setresgid __NR_setresgid
-#endif
-
-_syscall1(int, sys_setuid, uid_t, uid)
-_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;
@@ -5626,10 +5293,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return 0; /* avoid warning */
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));
-#endif
#ifdef TARGET_NR_waitpid
case TARGET_NR_waitpid:
{
@@ -5855,16 +5518,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
#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:
- ((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:
{
@@ -6205,16 +5858,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());
-#endif
- case TARGET_NR_setsid:
- return get_errno(setsid());
#ifdef TARGET_NR_sigaction
case TARGET_NR_sigaction:
{
@@ -7319,23 +6962,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:
@@ -8170,12 +7796,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:
{
@@ -8258,66 +7878,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, 0);
return ret;
#endif
-#ifdef TARGET_NR_getuid
- case TARGET_NR_getuid:
- return get_errno(high2lowuid(getuid()));
-#endif
-#ifdef TARGET_NR_getgid
- case TARGET_NR_getgid:
- return get_errno(high2lowgid(getgid()));
-#endif
-#ifdef TARGET_NR_geteuid
- case TARGET_NR_geteuid:
- return get_errno(high2lowuid(geteuid()));
-#endif
-#ifdef TARGET_NR_getegid
- case TARGET_NR_getegid:
- return get_errno(high2lowgid(getegid()));
-#endif
- case TARGET_NR_setreuid:
- return get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
- case TARGET_NR_setregid:
- return get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
- case TARGET_NR_getgroups:
- {
- int gidsetsize = arg1;
- target_id *target_grouplist;
- gid_t *grouplist;
- int i;
-
- grouplist = alloca(gidsetsize * sizeof(gid_t));
- ret = get_errno(getgroups(gidsetsize, grouplist));
- if (gidsetsize == 0)
- return ret;
- if (!is_error(ret)) {
- target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
- if (!target_grouplist)
- return -TARGET_EFAULT;
- for(i = 0;i < ret; i++)
- target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
- unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
- }
- }
- return ret;
- case TARGET_NR_setgroups:
- {
- int gidsetsize = arg1;
- target_id *target_grouplist;
- gid_t *grouplist = NULL;
- int i;
- if (gidsetsize) {
- grouplist = alloca(gidsetsize * sizeof(gid_t));
- target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
- if (!target_grouplist) {
- return -TARGET_EFAULT;
- }
- for (i = 0; i < gidsetsize; i++) {
- grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
- }
- unlock_user(target_grouplist, arg2, 0);
- }
- return get_errno(setgroups(gidsetsize, grouplist));
- }
case TARGET_NR_fchown:
return get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
#if defined(TARGET_NR_fchownat)
@@ -8329,46 +7889,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg2, 0);
return ret;
#endif
-#ifdef TARGET_NR_setresuid
- case TARGET_NR_setresuid:
- return get_errno(sys_setresuid(low2highuid(arg1),
- low2highuid(arg2),
- low2highuid(arg3)));
-#endif
-#ifdef TARGET_NR_getresuid
- case TARGET_NR_getresuid:
- {
- uid_t ruid, euid, suid;
- ret = get_errno(getresuid(&ruid, &euid, &suid));
- if (!is_error(ret)) {
- if (put_user_id(high2lowuid(ruid), arg1)
- || put_user_id(high2lowuid(euid), arg2)
- || put_user_id(high2lowuid(suid), arg3))
- return -TARGET_EFAULT;
- }
- }
- return ret;
-#endif
-#ifdef TARGET_NR_getresgid
- case TARGET_NR_setresgid:
- return get_errno(sys_setresgid(low2highgid(arg1),
- low2highgid(arg2),
- low2highgid(arg3)));
-#endif
-#ifdef TARGET_NR_getresgid
- case TARGET_NR_getresgid:
- {
- gid_t rgid, egid, sgid;
- ret = get_errno(getresgid(&rgid, &egid, &sgid));
- if (!is_error(ret)) {
- if (put_user_id(high2lowgid(rgid), arg1)
- || put_user_id(high2lowgid(egid), arg2)
- || put_user_id(high2lowgid(sgid), arg3))
- return -TARGET_EFAULT;
- }
- }
- return ret;
-#endif
#ifdef TARGET_NR_chown
case TARGET_NR_chown:
if (!(p = lock_user_string(arg1)))
@@ -8377,15 +7897,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, 0);
return ret;
#endif
- case TARGET_NR_setuid:
- return get_errno(sys_setuid(low2highuid(arg1)));
- case TARGET_NR_setgid:
- return get_errno(sys_setgid(low2highgid(arg1)));
- case TARGET_NR_setfsuid:
- return get_errno(setfsuid(arg1));
- case TARGET_NR_setfsgid:
- return get_errno(setfsgid(arg1));
-
#ifdef TARGET_NR_lchown32
case TARGET_NR_lchown32:
if (!(p = lock_user_string(arg1)))
@@ -8394,31 +7905,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, 0);
return ret;
#endif
-#ifdef TARGET_NR_getuid32
- case TARGET_NR_getuid32:
- return get_errno(getuid());
-#endif
-
-#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
- /* Alpha specific */
- case TARGET_NR_getxuid:
- {
- uid_t euid;
- euid=geteuid();
- ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
- }
- return get_errno(getuid());
-#endif
-#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
- /* Alpha specific */
- case TARGET_NR_getxgid:
- {
- uid_t egid;
- egid=getegid();
- ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
- }
- return get_errno(getgid());
-#endif
#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
/* Alpha specific */
case TARGET_NR_osf_getsysinfo:
@@ -8579,110 +8065,10 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
}
return ret;
#endif
-
-#ifdef TARGET_NR_getgid32
- case TARGET_NR_getgid32:
- return get_errno(getgid());
-#endif
-#ifdef TARGET_NR_geteuid32
- case TARGET_NR_geteuid32:
- return get_errno(geteuid());
-#endif
-#ifdef TARGET_NR_getegid32
- case TARGET_NR_getegid32:
- return get_errno(getegid());
-#endif
-#ifdef TARGET_NR_setreuid32
- case TARGET_NR_setreuid32:
- return get_errno(setreuid(arg1, arg2));
-#endif
-#ifdef TARGET_NR_setregid32
- case TARGET_NR_setregid32:
- return get_errno(setregid(arg1, arg2));
-#endif
-#ifdef TARGET_NR_getgroups32
- case TARGET_NR_getgroups32:
- {
- int gidsetsize = arg1;
- uint32_t *target_grouplist;
- gid_t *grouplist;
- int i;
-
- grouplist = alloca(gidsetsize * sizeof(gid_t));
- ret = get_errno(getgroups(gidsetsize, grouplist));
- if (gidsetsize == 0)
- return ret;
- if (!is_error(ret)) {
- target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
- if (!target_grouplist) {
- return -TARGET_EFAULT;
- }
- for(i = 0;i < ret; i++)
- target_grouplist[i] = tswap32(grouplist[i]);
- unlock_user(target_grouplist, arg2, gidsetsize * 4);
- }
- }
- return ret;
-#endif
-#ifdef TARGET_NR_setgroups32
- case TARGET_NR_setgroups32:
- {
- int gidsetsize = arg1;
- uint32_t *target_grouplist;
- gid_t *grouplist;
- int i;
-
- grouplist = alloca(gidsetsize * sizeof(gid_t));
- target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
- if (!target_grouplist) {
- return -TARGET_EFAULT;
- }
- for(i = 0;i < gidsetsize; i++)
- grouplist[i] = tswap32(target_grouplist[i]);
- unlock_user(target_grouplist, arg2, 0);
- return get_errno(setgroups(gidsetsize, grouplist));
- }
-#endif
#ifdef TARGET_NR_fchown32
case TARGET_NR_fchown32:
return get_errno(fchown(arg1, arg2, arg3));
#endif
-#ifdef TARGET_NR_setresuid32
- case TARGET_NR_setresuid32:
- return get_errno(sys_setresuid(arg1, arg2, arg3));
-#endif
-#ifdef TARGET_NR_getresuid32
- case TARGET_NR_getresuid32:
- {
- uid_t ruid, euid, suid;
- ret = get_errno(getresuid(&ruid, &euid, &suid));
- if (!is_error(ret)) {
- if (put_user_u32(ruid, arg1)
- || put_user_u32(euid, arg2)
- || put_user_u32(suid, arg3))
- return -TARGET_EFAULT;
- }
- }
- return ret;
-#endif
-#ifdef TARGET_NR_setresgid32
- case TARGET_NR_setresgid32:
- return get_errno(sys_setresgid(arg1, arg2, arg3));
-#endif
-#ifdef TARGET_NR_getresgid32
- case TARGET_NR_getresgid32:
- {
- gid_t rgid, egid, sgid;
- ret = get_errno(getresgid(&rgid, &egid, &sgid));
- if (!is_error(ret)) {
- if (put_user_u32(rgid, arg1)
- || put_user_u32(egid, arg2)
- || put_user_u32(sgid, arg3))
- return -TARGET_EFAULT;
- }
- }
- return ret;
-#endif
#ifdef TARGET_NR_chown32
case TARGET_NR_chown32:
if (!(p = lock_user_string(arg1)))
@@ -8691,22 +8077,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, 0);
return ret;
#endif
-#ifdef TARGET_NR_setuid32
- case TARGET_NR_setuid32:
- return get_errno(sys_setuid(arg1));
-#endif
-#ifdef TARGET_NR_setgid32
- case TARGET_NR_setgid32:
- return get_errno(sys_setgid(arg1));
-#endif
-#ifdef TARGET_NR_setfsuid32
- case TARGET_NR_setfsuid32:
- return get_errno(setfsuid(arg1));
-#endif
-#ifdef TARGET_NR_setfsgid32
- case TARGET_NR_setfsgid32:
- return get_errno(setfsgid(arg1));
-#endif
#ifdef TARGET_NR_mincore
case TARGET_NR_mincore:
{
@@ -8865,8 +8235,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_getpagesize:
return TARGET_PAGE_SIZE;
#endif
- case TARGET_NR_gettid:
- return get_errno(gettid());
#ifdef TARGET_NR_readahead
case TARGET_NR_readahead:
#if TARGET_ABI_BITS == 32
@@ -9043,44 +8411,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return ret;
#endif
#endif /* CONFIG_ATTR */
-#ifdef TARGET_NR_set_thread_area
- case TARGET_NR_set_thread_area:
-#if defined(TARGET_MIPS)
- ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
- return 0;
-#elif defined(TARGET_CRIS)
- if (arg1 & 0xff)
- ret = -TARGET_EINVAL;
- else {
- ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
- ret = 0;
- }
- return ret;
-#elif defined(TARGET_I386) && defined(TARGET_ABI32)
- return do_set_thread_area(cpu_env, arg1);
-#elif defined(TARGET_M68K)
- {
- TaskState *ts = cpu->opaque;
- ts->tp_value = arg1;
- return 0;
- }
-#else
- return -TARGET_ENOSYS;
-#endif
-#endif
-#ifdef TARGET_NR_get_thread_area
- case TARGET_NR_get_thread_area:
-#if defined(TARGET_I386) && defined(TARGET_ABI32)
- return do_get_thread_area(cpu_env, arg1);
-#elif defined(TARGET_M68K)
- {
- TaskState *ts = cpu->opaque;
- return ts->tp_value;
- }
-#else
- return -TARGET_ENOSYS;
-#endif
-#endif
#ifdef TARGET_NR_getdomainname
case TARGET_NR_getdomainname:
return -TARGET_ENOSYS;
@@ -9140,12 +8470,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return ret;
}
#endif
-
-#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
- case TARGET_NR_set_tid_address:
- return get_errno(set_tid_address((int *)g2h(arg1)));
-#endif
-
case TARGET_NR_tkill:
return get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
@@ -9845,6 +9169,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
diff --git a/linux-user/strace.list b/linux-user/strace.list
index ac7cf77021..58704fcb07 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -94,12 +94,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_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
@@ -226,9 +220,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
@@ -283,30 +274,6 @@
#ifdef TARGET_NR_getdtablesize
{ TARGET_NR_getdtablesize, "getdtablesize" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_getegid
-{ TARGET_NR_getegid, "getegid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_getegid32
-{ TARGET_NR_getegid32, "getegid32" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_geteuid
-{ TARGET_NR_geteuid, "geteuid" , "%s()", NULL, NULL },
-#endif
-#ifdef TARGET_NR_geteuid32
-{ TARGET_NR_geteuid32, "geteuid32" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_getgid
-{ TARGET_NR_getgid, "getgid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_getgid32
-{ TARGET_NR_getgid32, "getgid32" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_getgroups
-{ TARGET_NR_getgroups, "getgroups" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_getgroups32
-{ TARGET_NR_getgroups32, "getgroups32" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_gethostname
{ TARGET_NR_gethostname, "gethostname" , NULL, NULL, NULL },
#endif
@@ -325,39 +292,15 @@
#ifdef TARGET_NR_getpeername
{ TARGET_NR_getpeername, "getpeername" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_getpgid
-{ TARGET_NR_getpgid, "getpgid" , NULL, NULL, NULL },
-#endif
-#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
#ifdef TARGET_NR_getrandom
{ TARGET_NR_getrandom, "getrandom", NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_getresgid
-{ TARGET_NR_getresgid, "getresgid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_getresgid32
-{ TARGET_NR_getresgid32, "getresgid32" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_getresuid
-{ TARGET_NR_getresuid, "getresuid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_getresuid32
-{ TARGET_NR_getresuid32, "getresuid32" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_getrlimit
{ TARGET_NR_getrlimit, "getrlimit" , NULL, NULL, NULL },
#endif
@@ -367,9 +310,6 @@
#ifdef TARGET_NR_getrusage
{ TARGET_NR_getrusage, "getrusage" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_getsid
-{ TARGET_NR_getsid, "getsid" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_getsockname
{ TARGET_NR_getsockname, "getsockname" , NULL, NULL, NULL },
#endif
@@ -380,30 +320,12 @@
{ TARGET_NR_get_thread_area, "get_thread_area", "%s(0x"TARGET_ABI_FMT_lx")",
NULL, NULL },
#endif
-#ifdef TARGET_NR_gettid
-{ TARGET_NR_gettid, "gettid" , "%s()", NULL, NULL },
-#endif
#ifdef TARGET_NR_gettimeofday
{ TARGET_NR_gettimeofday, "gettimeofday" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_getuid
-{ TARGET_NR_getuid, "getuid" , "%s()", NULL, NULL },
-#endif
-#ifdef TARGET_NR_getuid32
-{ TARGET_NR_getuid32, "getuid32" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_getxattr
{ TARGET_NR_getxattr, "getxattr" , NULL, NULL, NULL },
#endif
-#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
#ifdef TARGET_NR_gtty
{ TARGET_NR_gtty, "gtty" , NULL, NULL, NULL },
#endif
@@ -641,9 +563,6 @@
#ifdef TARGET_NR_osf_alt_plock
{ TARGET_NR_osf_alt_plock, "osf_alt_plock" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_osf_alt_setsid
-{ TARGET_NR_osf_alt_setsid, "osf_alt_setsid" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_osf_alt_sigpending
{ TARGET_NR_osf_alt_sigpending, "osf_alt_sigpending" , NULL, NULL, NULL },
#endif
@@ -1172,30 +1091,6 @@
#ifdef TARGET_NR_setdomainname
{ TARGET_NR_setdomainname, "setdomainname" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_setfsgid
-{ TARGET_NR_setfsgid, "setfsgid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setfsgid32
-{ TARGET_NR_setfsgid32, "setfsgid32" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setfsuid
-{ TARGET_NR_setfsuid, "setfsuid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setfsuid32
-{ TARGET_NR_setfsuid32, "setfsuid32" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setgid
-{ TARGET_NR_setgid, "setgid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setgid32
-{ TARGET_NR_setgid32, "setgid32" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setgroups
-{ TARGET_NR_setgroups, "setgroups" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setgroups32
-{ TARGET_NR_setgroups32, "setgroups32" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_sethae
{ TARGET_NR_sethae, "sethae" , NULL, NULL, NULL },
#endif
@@ -1211,48 +1106,15 @@
#ifdef TARGET_NR_setns
{ TARGET_NR_setns, "setns" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_setpgid
-{ TARGET_NR_setpgid, "setpgid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setpgrp
-{ TARGET_NR_setpgrp, "setpgrp" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_setpriority
{ TARGET_NR_setpriority, "setpriority" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_setregid
-{ TARGET_NR_setregid, "setregid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setregid32
-{ TARGET_NR_setregid32, "setregid32" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setresgid
-{ TARGET_NR_setresgid, "setresgid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setresgid32
-{ TARGET_NR_setresgid32, "setresgid32" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setresuid
-{ TARGET_NR_setresuid, "setresuid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setresuid32
-{ TARGET_NR_setresuid32, "setresuid32" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setreuid
-{ TARGET_NR_setreuid, "setreuid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setreuid32
-{ TARGET_NR_setreuid32, "setreuid32" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_setrlimit
{ TARGET_NR_setrlimit, "setrlimit" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_set_robust_list
{ TARGET_NR_set_robust_list, "set_robust_list" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_setsid
-{ TARGET_NR_setsid, "setsid" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_setsockopt
{ TARGET_NR_setsockopt, "setsockopt" , NULL, NULL, NULL },
#endif
@@ -1266,12 +1128,6 @@
#ifdef TARGET_NR_settimeofday
{ TARGET_NR_settimeofday, "settimeofday" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_setuid
-{ TARGET_NR_setuid, "setuid" , NULL, NULL, NULL },
-#endif
-#ifdef TARGET_NR_setuid32
-{ TARGET_NR_setuid32, "setuid32" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_setxattr
{ TARGET_NR_setxattr, "setxattr" , NULL, NULL, NULL },
#endif
@@ -1506,9 +1362,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] 15+ messages in thread
* Re: [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall
2018-12-19 4:21 [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall Richard Henderson
` (7 preceding siblings ...)
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 8/8] linux-user: Split out some process syscalls Richard Henderson
@ 2018-12-25 3:19 ` no-reply
2019-01-09 9:50 ` Laurent Vivier
9 siblings, 0 replies; 15+ messages in thread
From: no-reply @ 2018-12-25 3:19 UTC (permalink / raw)
To: richard.henderson; +Cc: fam, qemu-devel, laurent
Patchew URL: https://patchew.org/QEMU/20181219042113.7364-1-richard.henderson@linaro.org/
Hi,
This series seems to have some coding style problems. See output below for
more information:
Message-id: 20181219042113.7364-1-richard.henderson@linaro.org
Type: series
Subject: [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall
=== TEST SCRIPT BEGIN ===
#!/bin/bash
BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
failed=1
echo
fi
n=$((n+1))
done
exit $failed
=== TEST SCRIPT END ===
Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
f3bfd9f linux-user: Split out some process syscalls
d97db89 linux-user: Split out memory syscalls
cb634c4 linux-user: Split out ipc syscalls
5659cc8 linux-user: Split out name_to_handle_at, open_by_handle_at
67a51d4 linux-user: Split out preadv, pwritev, readv, writev, pread64, pwrite64
677dbe4 linux-user: Reduce regpairs_aligned & target_offset64 ifdefs
caa6f94 linux-user: Split out some simple file syscalls
b9d74dd linux-user: Setup split syscall infrastructure
=== OUTPUT BEGIN ===
Checking PATCH 1/8: linux-user: Setup split syscall infrastructure...
ERROR: Macros with complex values should be enclosed in parenthesis
#568: FILE: linux-user/syscall.c:11530:
+#define SYSCALL_DEF(NAME, ...) case TARGET_NR_##NAME: return &def_##NAME
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#647:
new file mode 100644
total: 1 errors, 1 warnings, 706 lines checked
Your patch has style problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 2/8: linux-user: Split out some simple file syscalls...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#12:
new file mode 100644
total: 0 errors, 1 warnings, 882 lines checked
Your patch has style problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 3/8: linux-user: Reduce regpairs_aligned & target_offset64 ifdefs...
Checking PATCH 4/8: linux-user: Split out preadv, pwritev, readv, writev, pread64, pwrite64...
Checking PATCH 5/8: linux-user: Split out name_to_handle_at, open_by_handle_at...
Checking PATCH 6/8: linux-user: Split out ipc syscalls...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#259:
new file mode 100644
WARNING: architecture specific defines should be avoided
#283: FILE: linux-user/syscall-ipc.inc.c:20:
+#ifdef __NR_msgsnd
total: 0 errors, 2 warnings, 2320 lines checked
Your patch has style problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 7/8: linux-user: Split out memory syscalls...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#203:
new file mode 100644
total: 0 errors, 1 warnings, 474 lines checked
Your patch has style problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 8/8: linux-user: Split out some process syscalls...
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#476:
new file mode 100644
WARNING: architecture specific defines should be avoided
#509: FILE: linux-user/syscall-proc.inc.c:29:
+#ifdef __NR_setuid32
WARNING: architecture specific defines should be avoided
#514: FILE: linux-user/syscall-proc.inc.c:34:
+#ifdef __NR_setgid32
WARNING: architecture specific defines should be avoided
#519: FILE: linux-user/syscall-proc.inc.c:39:
+#ifdef __NR_setresuid32
WARNING: architecture specific defines should be avoided
#524: FILE: linux-user/syscall-proc.inc.c:44:
+#ifdef __NR_setresgid32
WARNING: architecture specific defines should be avoided
#535: FILE: linux-user/syscall-proc.inc.c:55:
+#ifndef __NR_gettid
WARNING: architecture specific defines should be avoided
#540: FILE: linux-user/syscall-proc.inc.c:60:
+#ifndef __NR_set_tid_address
total: 0 errors, 7 warnings, 2103 lines checked
Your patch has style problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
=== OUTPUT END ===
Test command exited with code: 1
The full log is available at
http://patchew.org/logs/20181219042113.7364-1-richard.henderson@linaro.org/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@redhat.com
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall
2018-12-19 4:21 [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall Richard Henderson
` (8 preceding siblings ...)
2018-12-25 3:19 ` [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall no-reply
@ 2019-01-09 9:50 ` Laurent Vivier
9 siblings, 0 replies; 15+ messages in thread
From: Laurent Vivier @ 2019-01-09 9:50 UTC (permalink / raw)
To: Richard Henderson, qemu-devel
On 19/12/2018 05:21, Richard Henderson wrote:
> Version 4 was back in August:
> https://lists.gnu.org/archive/html/qemu-devel/2018-08/msg03745.html
>
> Version 5 continues the file split via inclusion. This incorporates
> Laurent's suggestion to have a "def" file that is included twice to
> generate both SyscallDef structures and fill in syscall_table's switch.
>
> Again, this just converts a few syscalls as proof of concept.
This series breaks on all targets LTP tests: getgroups01, pwritev02,
pwritev02_64, and fixes: semop02.
It also breaks more tests only with arm target.
I will bisect and review...
Thanks,
Laurent
>
>
> r~
>
>
> Richard Henderson (8):
> linux-user: Setup split syscall infrastructure
> linux-user: Split out some simple file syscalls
> linux-user: Reduce regpairs_aligned & target_offset64 ifdefs
> linux-user: Split out preadv, pwritev, readv, writev, pread64,
> pwrite64
> 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 some process syscalls
>
> linux-user/syscall-defs.h | 231 +++
> linux-user/syscall.h | 93 ++
> linux-user/strace.c | 567 ++++----
> linux-user/syscall-file.inc.c | 638 +++++++++
> linux-user/syscall-ipc.inc.c | 1086 ++++++++++++++
> linux-user/syscall-mem.inc.c | 154 ++
> linux-user/syscall-proc.inc.c | 861 ++++++++++++
> linux-user/syscall.c | 2500 ++-------------------------------
> linux-user/strace.list | 243 ----
> 9 files changed, 3499 insertions(+), 2874 deletions(-)
> create mode 100644 linux-user/syscall-defs.h
> create mode 100644 linux-user/syscall.h
> create mode 100644 linux-user/syscall-file.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
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH v5 8/8] linux-user: Split out some process syscalls
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 8/8] linux-user: Split out some process syscalls Richard Henderson
@ 2019-01-10 14:17 ` Laurent Vivier
0 siblings, 0 replies; 15+ messages in thread
From: Laurent Vivier @ 2019-01-10 14:17 UTC (permalink / raw)
To: Richard Henderson, qemu-devel
On 19/12/2018 05:21, Richard Henderson wrote:
> This includes clone, getgroups, gettid, setfsgid, setfsuid,
> setgroups, setsid, setuid, fork, getegid, getegid32, geteuid,
> geteuid32, getgid, getgid32, getgroups32, getpgrp, getpid,
> getppid, getresgid, getresgid32, getresuid, getresuid32,
> getuid, getuid32, getxgid, getxpid, getxuid, setfsgid32,
> setgsuid32, setgid32, setgroups32, setregid, setregid32,
> setresgid, setresgid32, setresuid, setresuid32, setreuid,
> setreuid32, setuid32, vfork.
I have errors with getgroups.
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> linux-user/syscall-defs.h | 121 +++++
> linux-user/syscall.h | 1 +
> linux-user/strace.c | 36 +-
> linux-user/syscall-proc.inc.c | 861 ++++++++++++++++++++++++++++++++++
> linux-user/syscall.c | 677 +-------------------------
> linux-user/strace.list | 147 ------
> 6 files changed, 988 insertions(+), 855 deletions(-)
> create mode 100644 linux-user/syscall-proc.inc.c
...
> diff --git a/linux-user/syscall-proc.inc.c b/linux-user/syscall-proc.inc.c
> new file mode 100644
> index 0000000000..dee441b4ff
> --- /dev/null
> +++ b/linux-user/syscall-proc.inc.c
...
> +
> +SYSCALL_IMPL(getgroups)
> +{
> + int gidsetsize = arg1;
> + gid_t *grouplist;
> + abi_long ret;
> +
kernel checks for gidsetsize < 0 and returns EINVAL in this case
> + grouplist = g_try_new(gid_t, gidsetsize);
> + if (!grouplist) {
> + return -TARGET_ENOMEM;
> + }
gidsetsize == 0 is a valid case (see man) but it fails with g_try_new().
Moreover, ENOMEM is not a valid error value for getgroups().
> + ret = get_errno(getgroups(gidsetsize, grouplist));
> +
> + if (!is_error(ret) && gidsetsize != 0) {
> + size_t target_grouplist_size = gidsetsize * sizeof(target_id);
> + target_id *target_grouplist
> + = lock_user(VERIFY_WRITE, arg2, target_grouplist_size, 0);
> + if (target_grouplist) {
> + int i;
> + for (i = 0; i < ret; i++) {
> + target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
> + }
> + unlock_user(target_grouplist, arg2, target_grouplist_size);
> + } else {
> + ret = -TARGET_EFAULT;
> + }
> + }
> + g_free(grouplist);
> + return ret;
> +}
> +
> +#ifdef TARGET_NR_getgroups32
> +SYSCALL_IMPL(getgroups32)
likewise.
Thanks,
Laurent
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH v5 4/8] linux-user: Split out preadv, pwritev, readv, writev, pread64, pwrite64
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 4/8] linux-user: Split out preadv, pwritev, readv, writev, pread64, pwrite64 Richard Henderson
@ 2019-01-10 15:17 ` Laurent Vivier
2019-01-11 21:31 ` Richard Henderson
0 siblings, 1 reply; 15+ messages in thread
From: Laurent Vivier @ 2019-01-10 15:17 UTC (permalink / raw)
To: Richard Henderson, qemu-devel
On 19/12/2018 05:21, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> linux-user/syscall-defs.h | 14 ++++
> linux-user/syscall-file.inc.c | 124 ++++++++++++++++++++++++++++++++++
> linux-user/syscall.c | 93 -------------------------
> linux-user/strace.list | 18 -----
> 4 files changed, 138 insertions(+), 111 deletions(-)
>
...
> diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
> index 11e75044c1..410a763eee 100644
> --- a/linux-user/syscall-file.inc.c
> +++ b/linux-user/syscall-file.inc.c
> @@ -315,6 +315,104 @@ SYSCALL_IMPL(openat)
...
> +
> +/*
> + * 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] = ((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;
> +}
I have an error with preadv() on a 32bit target (powerpc, LTP test preadv02).
It works if I use:
static inline void host_offset64_low_high(unsigned long *hlow,
unsigned long *hhigh,
abi_ulong tlow,
abi_ulong thigh)
{
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;
}
> +
> +SYSCALL_IMPL(preadv)
> +{
> + struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
> + unsigned long lo, hi;
> + abi_long ret;
> +
> + if (vec == NULL) {
> + return -host_to_target_errno(errno);
> + }
> +
> + host_offset64_low_high(&lo, &hi, arg4);
> + ret = get_errno(safe_preadv(arg1, vec, arg3, lo, hi));
> + unlock_iovec(vec, arg2, arg3, 1);
> + return ret;
> +}
> +
> +SYSCALL_IMPL(pwritev)
> +{
> + struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
> + unsigned long lo, hi;
> + abi_long ret;
> +
> + if (vec == NULL) {
> + ret = -host_to_target_errno(errno);
return -host_to_target_errno(errno);
> + }
> +
> + host_offset64_low_high(&lo, &hi, arg4);
> + ret = get_errno(safe_pwritev(arg1, vec, arg3, lo, hi));
> + unlock_iovec(vec, arg2, arg3, 0);
> + return ret;
> +}
> +
> SYSCALL_IMPL(read)
> {
> abi_long ret;
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH v5 4/8] linux-user: Split out preadv, pwritev, readv, writev, pread64, pwrite64
2019-01-10 15:17 ` Laurent Vivier
@ 2019-01-11 21:31 ` Richard Henderson
2019-01-14 11:04 ` Laurent Vivier
0 siblings, 1 reply; 15+ messages in thread
From: Richard Henderson @ 2019-01-11 21:31 UTC (permalink / raw)
To: Laurent Vivier, qemu-devel
On 1/11/19 2:17 AM, Laurent Vivier wrote:
> On 19/12/2018 05:21, Richard Henderson wrote:
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>> linux-user/syscall-defs.h | 14 ++++
>> linux-user/syscall-file.inc.c | 124 ++++++++++++++++++++++++++++++++++
>> linux-user/syscall.c | 93 -------------------------
>> linux-user/strace.list | 18 -----
>> 4 files changed, 138 insertions(+), 111 deletions(-)
>>
> ...
>> diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
>> index 11e75044c1..410a763eee 100644
>> --- a/linux-user/syscall-file.inc.c
>> +++ b/linux-user/syscall-file.inc.c
>> @@ -315,6 +315,104 @@ SYSCALL_IMPL(openat)
> ...
>> +
>> +/*
>> + * 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] = ((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;
>> +}
>
>
> I have an error with preadv() on a 32bit target (powerpc, LTP test preadv02).
>
> It works if I use:
>
> static inline void host_offset64_low_high(unsigned long *hlow,
> unsigned long *hhigh,
> abi_ulong tlow,
> abi_ulong thigh)
> {
> 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;
> }
This doesn't make any sense. Where are "tlow" and "thigh" coming from?
I think the bug will be
SYSCALL_ARGS(preadv_pwritev)
{
/* We have already assigned out[0-2]. */
abi_ulong lo = in[3], hi = in[4];
- out[3] = ((hi << (TARGET_ABI_BITS - 1)) << 1) | lo;
+ out[3] = (((uint64_t)hi << (TARGET_ABI_BITS - 1)) << 1) | lo;
return def;
}
r~
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH v5 4/8] linux-user: Split out preadv, pwritev, readv, writev, pread64, pwrite64
2019-01-11 21:31 ` Richard Henderson
@ 2019-01-14 11:04 ` Laurent Vivier
0 siblings, 0 replies; 15+ messages in thread
From: Laurent Vivier @ 2019-01-14 11:04 UTC (permalink / raw)
To: Richard Henderson, qemu-devel
On 11/01/2019 22:31, Richard Henderson wrote:
> On 1/11/19 2:17 AM, Laurent Vivier wrote:
>> On 19/12/2018 05:21, Richard Henderson wrote:
>>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>>> ---
>>> linux-user/syscall-defs.h | 14 ++++
>>> linux-user/syscall-file.inc.c | 124 ++++++++++++++++++++++++++++++++++
>>> linux-user/syscall.c | 93 -------------------------
>>> linux-user/strace.list | 18 -----
>>> 4 files changed, 138 insertions(+), 111 deletions(-)
>>>
>> ...
>>> diff --git a/linux-user/syscall-file.inc.c b/linux-user/syscall-file.inc.c
>>> index 11e75044c1..410a763eee 100644
>>> --- a/linux-user/syscall-file.inc.c
>>> +++ b/linux-user/syscall-file.inc.c
>>> @@ -315,6 +315,104 @@ SYSCALL_IMPL(openat)
>> ...
>>> +
>>> +/*
>>> + * 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] = ((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;
>>> +}
>>
>>
>> I have an error with preadv() on a 32bit target (powerpc, LTP test preadv02).
>>
>> It works if I use:
>>
>> static inline void host_offset64_low_high(unsigned long *hlow,
>> unsigned long *hhigh,
>> abi_ulong tlow,
>> abi_ulong thigh)
>> {
>> 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;
>> }
>
> This doesn't make any sense. Where are "tlow" and "thigh" coming from?
>
> I think the bug will be
>
> SYSCALL_ARGS(preadv_pwritev)
> {
> /* We have already assigned out[0-2]. */
> abi_ulong lo = in[3], hi = in[4];
> - out[3] = ((hi << (TARGET_ABI_BITS - 1)) << 1) | lo;
> + out[3] = (((uint64_t)hi << (TARGET_ABI_BITS - 1)) << 1) | lo;
> return def;
> }
Yes, this change fixes the problem.
Thanks,
Laurent
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2019-01-14 11:04 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-12-19 4:21 [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 1/8] linux-user: Setup split syscall infrastructure Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 2/8] linux-user: Split out some simple file syscalls Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 3/8] linux-user: Reduce regpairs_aligned & target_offset64 ifdefs Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 4/8] linux-user: Split out preadv, pwritev, readv, writev, pread64, pwrite64 Richard Henderson
2019-01-10 15:17 ` Laurent Vivier
2019-01-11 21:31 ` Richard Henderson
2019-01-14 11:04 ` Laurent Vivier
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 5/8] linux-user: Split out name_to_handle_at, open_by_handle_at Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 6/8] linux-user: Split out ipc syscalls Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 7/8] linux-user: Split out memory syscalls Richard Henderson
2018-12-19 4:21 ` [Qemu-devel] [PATCH v5 8/8] linux-user: Split out some process syscalls Richard Henderson
2019-01-10 14:17 ` Laurent Vivier
2018-12-25 3:19 ` [Qemu-devel] [PATCH v5 0/8] linux-user: Split do_syscall no-reply
2019-01-09 9:50 ` Laurent Vivier
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).