summaryrefslogtreecommitdiffstats
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c161
1 files changed, 105 insertions, 56 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index cec8428589..925ae11ea6 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -238,6 +238,7 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
#define __NR_sys_getdents64 __NR_getdents64
#define __NR_sys_getpriority __NR_getpriority
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
+#define __NR_sys_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo
#define __NR_sys_syslog __NR_syslog
#define __NR_sys_futex __NR_futex
#define __NR_sys_inotify_init __NR_inotify_init
@@ -274,7 +275,9 @@ _syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, co
_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
#endif
-_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
+_syscall3(int, sys_rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t *, uinfo)
+_syscall4(int, sys_rt_tgsigqueueinfo, pid_t, pid, pid_t, tid, int, sig,
+ siginfo_t *, uinfo)
_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
#ifdef __NR_exit_group
_syscall1(int,exit_group,int,error_code)
@@ -7358,52 +7361,19 @@ int host_to_target_waitstatus(int status)
static int open_self_cmdline(void *cpu_env, int fd)
{
- int fd_orig = -1;
- bool word_skipped = false;
-
- fd_orig = open("/proc/self/cmdline", O_RDONLY);
- if (fd_orig < 0) {
- return fd_orig;
- }
+ CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
+ struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
+ int i;
- while (true) {
- ssize_t nb_read;
- char buf[128];
- char *cp_buf = buf;
+ for (i = 0; i < bprm->argc; i++) {
+ size_t len = strlen(bprm->argv[i]) + 1;
- nb_read = read(fd_orig, buf, sizeof(buf));
- if (nb_read < 0) {
- int e = errno;
- fd_orig = close(fd_orig);
- errno = e;
+ if (write(fd, bprm->argv[i], len) != len) {
return -1;
- } else if (nb_read == 0) {
- break;
- }
-
- if (!word_skipped) {
- /* Skip the first string, which is the path to qemu-*-static
- instead of the actual command. */
- cp_buf = memchr(buf, 0, nb_read);
- if (cp_buf) {
- /* Null byte found, skip one string */
- cp_buf++;
- nb_read -= cp_buf - buf;
- word_skipped = true;
- }
- }
-
- if (word_skipped) {
- if (write(fd, cp_buf, nb_read) != nb_read) {
- int e = errno;
- close(fd_orig);
- errno = e;
- return -1;
- }
}
}
- return close(fd_orig);
+ return 0;
}
static int open_self_maps(void *cpu_env, int fd)
@@ -7671,6 +7641,55 @@ static target_timer_t get_timer_id(abi_long arg)
return timerid;
}
+static abi_long swap_data_eventfd(void *buf, size_t len)
+{
+ uint64_t *counter = buf;
+ int i;
+
+ if (len < sizeof(uint64_t)) {
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i += sizeof(uint64_t)) {
+ *counter = tswap64(*counter);
+ counter++;
+ }
+
+ return len;
+}
+
+static TargetFdTrans target_eventfd_trans = {
+ .host_to_target_data = swap_data_eventfd,
+ .target_to_host_data = swap_data_eventfd,
+};
+
+#if (defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)) || \
+ (defined(CONFIG_INOTIFY1) && defined(TARGET_NR_inotify_init1) && \
+ defined(__NR_inotify_init1))
+static abi_long host_to_target_data_inotify(void *buf, size_t len)
+{
+ struct inotify_event *ev;
+ int i;
+ uint32_t name_len;
+
+ for (i = 0; i < len; i += sizeof(struct inotify_event) + name_len) {
+ ev = (struct inotify_event *)((char *)buf + i);
+ name_len = ev->len;
+
+ ev->wd = tswap32(ev->wd);
+ ev->mask = tswap32(ev->mask);
+ ev->cookie = tswap32(ev->cookie);
+ ev->len = tswap32(name_len);
+ }
+
+ return len;
+}
+
+static TargetFdTrans target_inotify_trans = {
+ .host_to_target_data = host_to_target_data_inotify,
+};
+#endif
+
/* do_syscall() should always have a single exit point at the end so
that actions, such as logging of syscall results, can be performed.
All errnos that do_syscall() returns must be -TARGET_<errcode>. */
@@ -7767,7 +7786,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_write:
if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
goto efault;
- ret = get_errno(safe_write(arg1, p, arg3));
+ 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);
break;
#ifdef TARGET_NR_open
@@ -7926,8 +7955,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
envc++;
}
- argp = alloca((argc + 1) * sizeof(void *));
- envp = alloca((envc + 1) * sizeof(void *));
+ argp = g_new0(char *, argc + 1);
+ envp = g_new0(char *, envc + 1);
for (gp = guest_argp, q = argp; gp;
gp += sizeof(abi_ulong), q++) {
@@ -7988,6 +8017,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break;
unlock_user(*q, addr, 0);
}
+
+ g_free(argp);
+ g_free(envp);
}
break;
case TARGET_NR_chdir:
@@ -8592,17 +8624,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_ssetmask /* not on alpha */
case TARGET_NR_ssetmask:
{
- sigset_t set, oset, cur_set;
+ sigset_t set, oset;
abi_ulong target_set = arg1;
- /* We only have one word of the new mask so we must read
- * the rest of it with do_sigprocmask() and OR in this word.
- * We are guaranteed that a do_sigprocmask() that only queries
- * the signal mask will not fail.
- */
- ret = do_sigprocmask(0, NULL, &cur_set);
- assert(!ret);
target_to_host_old_sigset(&set, &target_set);
- sigorset(&set, &set, &cur_set);
ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
if (!ret) {
host_to_target_old_sigset(&target_set, &oset);
@@ -8847,10 +8871,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
goto efault;
}
target_to_host_siginfo(&uinfo, p);
- unlock_user(p, arg1, 0);
+ unlock_user(p, arg3, 0);
ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
}
break;
+ case TARGET_NR_rt_tgsigqueueinfo:
+ {
+ siginfo_t uinfo;
+
+ p = lock_user(VERIFY_READ, arg4, sizeof(target_siginfo_t), 1);
+ if (!p) {
+ goto efault;
+ }
+ target_to_host_siginfo(&uinfo, p);
+ unlock_user(p, arg4, 0);
+ ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
+ }
+ break;
#ifdef TARGET_NR_sigreturn
case TARGET_NR_sigreturn:
if (block_signals()) {
@@ -11229,6 +11266,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_fadvise64_64
case TARGET_NR_fadvise64_64:
+#if defined(TARGET_PPC)
+ /* 6 args: fd, advice, offset (high, low), len (high, low) */
+ ret = arg2;
+ arg2 = arg3;
+ arg3 = arg4;
+ arg4 = arg5;
+ arg5 = arg6;
+ arg6 = ret;
+#else
/* 6 args: fd, offset (high, low), len (high, low), advice */
if (regpairs_aligned(cpu_env)) {
/* offset is in (3,4), len in (5,6) and advice in 7 */
@@ -11238,6 +11284,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
arg5 = arg6;
arg6 = arg7;
}
+#endif
ret = -host_to_target_errno(posix_fadvise(arg1,
target_offset64(arg2, arg3),
target_offset64(arg4, arg5),
@@ -11694,6 +11741,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
case TARGET_NR_inotify_init:
ret = get_errno(sys_inotify_init());
+ fd_trans_register(ret, &target_inotify_trans);
break;
#endif
#ifdef CONFIG_INOTIFY1
@@ -11701,6 +11749,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_inotify_init1:
ret = get_errno(sys_inotify_init1(target_to_host_bitmask(arg1,
fcntl_flags_tbl)));
+ fd_trans_register(ret, &target_inotify_trans);
break;
#endif
#endif
@@ -11866,7 +11915,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#if defined(TARGET_NR_eventfd)
case TARGET_NR_eventfd:
ret = get_errno(eventfd(arg1, 0));
- fd_trans_unregister(ret);
+ fd_trans_register(ret, &target_eventfd_trans);
break;
#endif
#if defined(TARGET_NR_eventfd2)
@@ -11880,7 +11929,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
host_flags |= O_CLOEXEC;
}
ret = get_errno(eventfd(arg1, host_flags));
- fd_trans_unregister(ret);
+ fd_trans_register(ret, &target_eventfd_trans);
break;
}
#endif