aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--Makefile.target5
-rw-r--r--bsd-user/syscall.c9
-rwxr-xr-xconfigure8
-rw-r--r--linux-user/host/aarch64/hostdep.h38
-rw-r--r--linux-user/host/aarch64/safe-syscall.inc.S75
-rw-r--r--linux-user/host/arm/hostdep.h38
-rw-r--r--linux-user/host/arm/safe-syscall.inc.S90
-rw-r--r--linux-user/host/i386/hostdep.h38
-rw-r--r--linux-user/host/i386/safe-syscall.inc.S112
-rw-r--r--linux-user/host/ia64/hostdep.h (renamed from linux-user/host/generic/hostdep.h)7
-rw-r--r--linux-user/host/mips/hostdep.h15
-rw-r--r--linux-user/host/ppc/hostdep.h15
-rw-r--r--linux-user/host/ppc64/hostdep.h38
-rw-r--r--linux-user/host/ppc64/safe-syscall.inc.S92
-rw-r--r--linux-user/host/s390/hostdep.h15
-rw-r--r--linux-user/host/s390x/hostdep.h38
-rw-r--r--linux-user/host/s390x/safe-syscall.inc.S90
-rw-r--r--linux-user/host/sparc/hostdep.h15
-rw-r--r--linux-user/host/sparc64/hostdep.h15
-rw-r--r--linux-user/host/x32/hostdep.h15
-rw-r--r--linux-user/host/x86_64/safe-syscall.inc.S6
-rw-r--r--linux-user/qemu.h5
-rw-r--r--linux-user/signal.c23
-rw-r--r--linux-user/strace.c621
-rw-r--r--linux-user/strace.list10
-rw-r--r--linux-user/syscall.c421
-rw-r--r--linux-user/syscall_defs.h24
-rw-r--r--qemu-img.c56
-rw-r--r--qemu-img.texi13
-rw-r--r--qemu-io.c18
-rw-r--r--qemu-nbd.c19
-rw-r--r--qemu-nbd.texi3
-rw-r--r--qemu-option-trace.texi25
-rw-r--r--qemu-options.hx29
-rw-r--r--trace-events16
-rw-r--r--trace/control.c42
-rw-r--r--trace/control.h25
-rw-r--r--user-exec.c107
-rw-r--r--vl.c38
40 files changed, 1848 insertions, 428 deletions
diff --git a/Makefile b/Makefile
index 7087fc273b..9d12dc614f 100644
--- a/Makefile
+++ b/Makefile
@@ -564,8 +564,9 @@ qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
$(POD2MAN) --section=1 --center=" " --release=" " qemu.pod > $@, \
" GEN $@")
+qemu.1: qemu-option-trace.texi
-qemu-img.1: qemu-img.texi qemu-img-cmds.texi
+qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \
$(POD2MAN) --section=1 --center=" " --release=" " qemu-img.pod > $@, \
@@ -577,7 +578,7 @@ fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
$(POD2MAN) --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
" GEN $@")
-qemu-nbd.8: qemu-nbd.texi
+qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
$(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
@@ -595,7 +596,7 @@ info: qemu-doc.info qemu-tech.info
pdf: qemu-doc.pdf qemu-tech.pdf
qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
- qemu-img.texi qemu-nbd.texi qemu-options.texi \
+ qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \
qemu-monitor-info.texi
diff --git a/Makefile.target b/Makefile.target
index d720b3e733..a440bcb5b8 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -108,11 +108,8 @@ obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/dpd/decimal128.o
ifdef CONFIG_LINUX_USER
-# Note that we only add linux-user/host/$ARCH if it exists, and
-# that it must come before linux-user/host/generic in the search path.
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) \
- $(patsubst %,-I%,$(wildcard $(SRC_PATH)/linux-user/host/$(ARCH))) \
- -I$(SRC_PATH)/linux-user/host/generic \
+ -I$(SRC_PATH)/linux-user/host/$(ARCH) \
-I$(SRC_PATH)/linux-user
obj-y += linux-user/
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index a9fe8693c1..66492aaf5d 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -315,12 +315,14 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg5, abi_long arg6, abi_long arg7,
abi_long arg8)
{
+ CPUState *cpu = ENV_GET_CPU(cpu_env);
abi_long ret;
void *p;
#ifdef DEBUG
gemu_log("freebsd syscall %d\n", num);
#endif
+ trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
if(do_strace)
print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -400,6 +402,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
#endif
if (do_strace)
print_freebsd_syscall_ret(num, ret);
+ trace_guest_user_syscall_ret(cpu, num, ret);
return ret;
efault:
ret = -TARGET_EFAULT;
@@ -410,12 +413,14 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5, abi_long arg6)
{
+ CPUState *cpu = ENV_GET_CPU(cpu_env);
abi_long ret;
void *p;
#ifdef DEBUG
gemu_log("netbsd syscall %d\n", num);
#endif
+ trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
if(do_strace)
print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -472,6 +477,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
#endif
if (do_strace)
print_netbsd_syscall_ret(num, ret);
+ trace_guest_user_syscall_ret(cpu, num, ret);
return ret;
efault:
ret = -TARGET_EFAULT;
@@ -482,12 +488,14 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5, abi_long arg6)
{
+ CPUState *cpu = ENV_GET_CPU(cpu_env);
abi_long ret;
void *p;
#ifdef DEBUG
gemu_log("openbsd syscall %d\n", num);
#endif
+ trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
if(do_strace)
print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -544,6 +552,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
#endif
if (do_strace)
print_openbsd_syscall_ret(num, ret);
+ trace_guest_user_syscall_ret(cpu, num, ret);
return ret;
efault:
ret = -TARGET_EFAULT;
diff --git a/configure b/configure
index 8ead9754e9..93e4c95274 100755
--- a/configure
+++ b/configure
@@ -1216,6 +1216,13 @@ esac
QEMU_CFLAGS="$CPU_CFLAGS $QEMU_CFLAGS"
EXTRA_CFLAGS="$CPU_CFLAGS $EXTRA_CFLAGS"
+# For user-mode emulation the host arch has to be one we explicitly
+# support, even if we're using TCI.
+if [ "$ARCH" = "unknown" ]; then
+ bsd_user="no"
+ linux_user="no"
+fi
+
default_target_list=""
mak_wilds=""
@@ -1380,7 +1387,6 @@ fi
if test "$ARCH" = "unknown"; then
if test "$tcg_interpreter" = "yes" ; then
echo "Unsupported CPU = $cpu, will use TCG with TCI (experimental)"
- ARCH=tci
else
error_exit "Unsupported CPU = $cpu, try --enable-tcg-interpreter"
fi
diff --git a/linux-user/host/aarch64/hostdep.h b/linux-user/host/aarch64/hostdep.h
new file mode 100644
index 0000000000..b79eaf1811
--- /dev/null
+++ b/linux-user/host/aarch64/hostdep.h
@@ -0,0 +1,38 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HOSTDEP_H
+#define QEMU_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#ifndef __ASSEMBLER__
+
+/* These are defined by the safe-syscall.inc.S file */
+extern char safe_syscall_start[];
+extern char safe_syscall_end[];
+
+/* Adjust the signal context to rewind out of safe-syscall if we're in it */
+static inline void rewind_if_in_safe_syscall(void *puc)
+{
+ struct ucontext *uc = puc;
+ __u64 *pcreg = &uc->uc_mcontext.pc;
+
+ if (*pcreg > (uintptr_t)safe_syscall_start
+ && *pcreg < (uintptr_t)safe_syscall_end) {
+ *pcreg = (uintptr_t)safe_syscall_start;
+ }
+}
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/linux-user/host/aarch64/safe-syscall.inc.S b/linux-user/host/aarch64/safe-syscall.inc.S
new file mode 100644
index 0000000000..58a2329b37
--- /dev/null
+++ b/linux-user/host/aarch64/safe-syscall.inc.S
@@ -0,0 +1,75 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, #function
+ .type safe_syscall_start, #function
+ .type safe_syscall_end, #function
+
+ /* This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+safe_syscall_base:
+ .cfi_startproc
+ /* The syscall calling convention isn't the same as the
+ * C one:
+ * we enter with x0 == *signal_pending
+ * x1 == syscall number
+ * x2 ... x7, (stack) == syscall arguments
+ * and return the result in x0
+ * and the syscall instruction needs
+ * x8 == syscall number
+ * x0 ... x7 == syscall arguments
+ * and returns the result in x0
+ * Shuffle everything around appropriately.
+ */
+ mov x9, x0 /* signal_pending pointer */
+ mov x8, x1 /* syscall number */
+ mov x0, x2 /* syscall arguments */
+ mov x1, x3
+ mov x2, x4
+ mov x3, x5
+ mov x4, x6
+ mov x6, x7
+ ldr x7, [sp]
+
+ /* This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* if signal_pending is non-zero, don't do the call */
+ ldr w10, [x9]
+ cbnz w10, 0f
+ svc 0x0
+safe_syscall_end:
+ /* code path for having successfully executed the syscall */
+ ret
+
+0:
+ /* code path when we didn't execute the syscall */
+ mov x0, #-TARGET_ERESTARTSYS
+ ret
+ .cfi_endproc
+
+ .size safe_syscall_base, .-safe_syscall_base
diff --git a/linux-user/host/arm/hostdep.h b/linux-user/host/arm/hostdep.h
new file mode 100644
index 0000000000..8e1ff2ffc5
--- /dev/null
+++ b/linux-user/host/arm/hostdep.h
@@ -0,0 +1,38 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HOSTDEP_H
+#define QEMU_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#ifndef __ASSEMBLER__
+
+/* These are defined by the safe-syscall.inc.S file */
+extern char safe_syscall_start[];
+extern char safe_syscall_end[];
+
+/* Adjust the signal context to rewind out of safe-syscall if we're in it */
+static inline void rewind_if_in_safe_syscall(void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long *pcreg = &uc->uc_mcontext.arm_pc;
+
+ if (*pcreg > (uintptr_t)safe_syscall_start
+ && *pcreg < (uintptr_t)safe_syscall_end) {
+ *pcreg = (uintptr_t)safe_syscall_start;
+ }
+}
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/linux-user/host/arm/safe-syscall.inc.S b/linux-user/host/arm/safe-syscall.inc.S
new file mode 100644
index 0000000000..88c4958504
--- /dev/null
+++ b/linux-user/host/arm/safe-syscall.inc.S
@@ -0,0 +1,90 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, %function
+
+ .cfi_sections .debug_frame
+
+ .text
+ .syntax unified
+ .arm
+ .align 2
+
+ /* This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+safe_syscall_base:
+ .fnstart
+ .cfi_startproc
+ mov r12, sp /* save entry stack */
+ push { r4, r5, r6, r7, r8, lr }
+ .save { r4, r5, r6, r7, r8, lr }
+ .cfi_adjust_cfa_offset 24
+ .cfi_rel_offset r4, 0
+ .cfi_rel_offset r5, 4
+ .cfi_rel_offset r6, 8
+ .cfi_rel_offset r7, 12
+ .cfi_rel_offset r8, 16
+ .cfi_rel_offset lr, 20
+
+ /* The syscall calling convention isn't the same as the C one:
+ * we enter with r0 == *signal_pending
+ * r1 == syscall number
+ * r2, r3, [sp+0] ... [sp+12] == syscall arguments
+ * and return the result in r0
+ * and the syscall instruction needs
+ * r7 == syscall number
+ * r0 ... r6 == syscall arguments
+ * and returns the result in r0
+ * Shuffle everything around appropriately.
+ * Note the 16 bytes that we pushed to save registers.
+ */
+ mov r8, r0 /* copy signal_pending */
+ mov r7, r1 /* syscall number */
+ mov r0, r2 /* syscall args */
+ mov r1, r3
+ ldm r12, { r2, r3, r4, r5, r6 }
+
+ /* This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* if signal_pending is non-zero, don't do the call */
+ ldr r12, [r8] /* signal_pending */
+ tst r12, r12
+ bne 1f
+ swi 0
+safe_syscall_end:
+ /* code path for having successfully executed the syscall */
+ pop { r4, r5, r6, r7, r8, pc }
+
+1:
+ /* code path when we didn't execute the syscall */
+ ldr r0, =-TARGET_ERESTARTSYS
+ pop { r4, r5, r6, r7, r8, pc }
+ .fnend
+ .cfi_endproc
+
+ .size safe_syscall_base, .-safe_syscall_base
diff --git a/linux-user/host/i386/hostdep.h b/linux-user/host/i386/hostdep.h
new file mode 100644
index 0000000000..5a12f4adce
--- /dev/null
+++ b/linux-user/host/i386/hostdep.h
@@ -0,0 +1,38 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HOSTDEP_H
+#define QEMU_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#ifndef __ASSEMBLER__
+
+/* These are defined by the safe-syscall.inc.S file */
+extern char safe_syscall_start[];
+extern char safe_syscall_end[];
+
+/* Adjust the signal context to rewind out of safe-syscall if we're in it */
+static inline void rewind_if_in_safe_syscall(void *puc)
+{
+ struct ucontext *uc = puc;
+ greg_t *pcreg = &uc->uc_mcontext.gregs[REG_EIP];
+
+ if (*pcreg > (uintptr_t)safe_syscall_start
+ && *pcreg < (uintptr_t)safe_syscall_end) {
+ *pcreg = (uintptr_t)safe_syscall_start;
+ }
+}
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/linux-user/host/i386/safe-syscall.inc.S b/linux-user/host/i386/safe-syscall.inc.S
new file mode 100644
index 0000000000..766d0ded98
--- /dev/null
+++ b/linux-user/host/i386/safe-syscall.inc.S
@@ -0,0 +1,112 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, @function
+
+ /* This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+safe_syscall_base:
+ .cfi_startproc
+ push %ebp
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset ebp, 0
+ push %esi
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset esi, 0
+ push %edi
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset edi, 0
+ push %ebx
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset ebx, 0
+
+ /* The syscall calling convention isn't the same as the C one:
+ * we enter with 0(%esp) == return address
+ * 4(%esp) == *signal_pending
+ * 8(%esp) == syscall number
+ * 12(%esp) ... 32(%esp) == syscall arguments
+ * and return the result in eax
+ * and the syscall instruction needs
+ * eax == syscall number
+ * ebx, ecx, edx, esi, edi, ebp == syscall arguments
+ * and returns the result in eax
+ * Shuffle everything around appropriately.
+ * Note the 16 bytes that we pushed to save registers.
+ */
+ mov 12+16(%esp), %ebx /* the syscall arguments */
+ mov 16+16(%esp), %ecx
+ mov 20+16(%esp), %edx
+ mov 24+16(%esp), %esi
+ mov 28+16(%esp), %edi
+ mov 32+16(%esp), %ebp
+
+ /* This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* if signal_pending is non-zero, don't do the call */
+ mov 4+16(%esp), %eax /* signal_pending */
+ cmp $0, (%eax)
+ jnz 1f
+ mov 8+16(%esp), %eax /* syscall number */
+ int $0x80
+safe_syscall_end:
+ /* code path for having successfully executed the syscall */
+ pop %ebx
+ .cfi_remember_state
+ .cfi_def_cfa_offset -4
+ .cfi_restore ebx
+ pop %edi
+ .cfi_def_cfa_offset -4
+ .cfi_restore edi
+ pop %esi
+ .cfi_def_cfa_offset -4
+ .cfi_restore esi
+ pop %ebp
+ .cfi_def_cfa_offset -4
+ .cfi_restore ebp
+ ret
+
+1:
+ /* code path when we didn't execute the syscall */
+ .cfi_restore_state
+ mov $-TARGET_ERESTARTSYS, %eax
+ pop %ebx
+ .cfi_def_cfa_offset -4
+ .cfi_restore ebx
+ pop %edi
+ .cfi_def_cfa_offset -4
+ .cfi_restore edi
+ pop %esi
+ .cfi_def_cfa_offset -4
+ .cfi_restore esi
+ pop %ebp
+ .cfi_def_cfa_offset -4
+ .cfi_restore ebp
+ ret
+ .cfi_endproc
+
+ .size safe_syscall_base, .-safe_syscall_base
diff --git a/linux-user/host/generic/hostdep.h b/linux-user/host/ia64/hostdep.h
index cfabc3590b..7609bf5cd7 100644
--- a/linux-user/host/generic/hostdep.h
+++ b/linux-user/host/ia64/hostdep.h
@@ -1,6 +1,5 @@
/*
- * hostdep.h : fallback generic version of header for things
- * which are dependent on the host architecture
+ * hostdep.h : things which are dependent on the host architecture
*
* * Written by Peter Maydell <peter.maydell@linaro.org>
*
@@ -13,8 +12,4 @@
#ifndef QEMU_HOSTDEP_H
#define QEMU_HOSTDEP_H
-/* This is the fallback header which is only used if the host
- * architecture doesn't provide one in linux-user/host/$ARCH.
- */
-
#endif
diff --git a/linux-user/host/mips/hostdep.h b/linux-user/host/mips/hostdep.h
new file mode 100644
index 0000000000..7609bf5cd7
--- /dev/null
+++ b/linux-user/host/mips/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HOSTDEP_H
+#define QEMU_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/ppc/hostdep.h b/linux-user/host/ppc/hostdep.h
new file mode 100644
index 0000000000..7609bf5cd7
--- /dev/null
+++ b/linux-user/host/ppc/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HOSTDEP_H
+#define QEMU_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/ppc64/hostdep.h b/linux-user/host/ppc64/hostdep.h
new file mode 100644
index 0000000000..310e7d1b73
--- /dev/null
+++ b/linux-user/host/ppc64/hostdep.h
@@ -0,0 +1,38 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HOSTDEP_H
+#define QEMU_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#ifndef __ASSEMBLER__
+
+/* These are defined by the safe-syscall.inc.S file */
+extern char safe_syscall_start[];
+extern char safe_syscall_end[];
+
+/* Adjust the signal context to rewind out of safe-syscall if we're in it */
+static inline void rewind_if_in_safe_syscall(void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long *pcreg = &uc->uc_mcontext.gp_regs[PT_NIP];
+
+ if (*pcreg > (uintptr_t)safe_syscall_start
+ && *pcreg < (uintptr_t)safe_syscall_end) {
+ *pcreg = (uintptr_t)safe_syscall_start;
+ }
+}
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/linux-user/host/ppc64/safe-syscall.inc.S b/linux-user/host/ppc64/safe-syscall.inc.S
new file mode 100644
index 0000000000..d30050a67c
--- /dev/null
+++ b/linux-user/host/ppc64/safe-syscall.inc.S
@@ -0,0 +1,92 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, @function
+
+ .text
+
+ /* This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+#if _CALL_ELF == 2
+safe_syscall_base:
+ .cfi_startproc
+ .localentry safe_syscall_base,0
+#else
+ .section ".opd","aw"
+ .align 3
+safe_syscall_base:
+ .quad .L.safe_syscall_base,.TOC.@tocbase,0
+ .previous
+.L.safe_syscall_base:
+ .cfi_startproc
+#endif
+ /* We enter with r3 == *signal_pending
+ * r4 == syscall number
+ * r5 ... r10 == syscall arguments
+ * and return the result in r3
+ * and the syscall instruction needs
+ * r0 == syscall number
+ * r3 ... r8 == syscall arguments
+ * and returns the result in r3
+ * Shuffle everything around appropriately.
+ */
+ mr 11, 3 /* signal_pending */
+ mr 0, 4 /* syscall number */
+ mr 3, 5 /* syscall arguments */
+ mr 4, 6
+ mr 5, 7
+ mr 6, 8
+ mr 7, 9
+ mr 8, 10
+
+ /* This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* if signal_pending is non-zero, don't do the call */
+ lwz 12, 0(11)
+ cmpwi 0, 12, 0
+ bne- 0f
+ sc
+safe_syscall_end:
+ /* code path when we did execute the syscall */
+ bnslr+
+
+ /* syscall failed; return negative errno */
+ neg 3, 3
+ blr
+
+ /* code path when we didn't execute the syscall */
+0: addi 3, 0, -TARGET_ERESTARTSYS
+ blr
+ .cfi_endproc
+
+#if _CALL_ELF == 2
+ .size safe_syscall_base, .-safe_syscall_base
+#else
+ .size safe_syscall_base, .-.L.safe_syscall_base
+ .size .L.safe_syscall_base, .-.L.safe_syscall_base
+#endif
diff --git a/linux-user/host/s390/hostdep.h b/linux-user/host/s390/hostdep.h
new file mode 100644
index 0000000000..7609bf5cd7
--- /dev/null
+++ b/linux-user/host/s390/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HOSTDEP_H
+#define QEMU_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/s390x/hostdep.h b/linux-user/host/s390x/hostdep.h
new file mode 100644
index 0000000000..e95871c46a
--- /dev/null
+++ b/linux-user/host/s390x/hostdep.h
@@ -0,0 +1,38 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HOSTDEP_H
+#define QEMU_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#ifndef __ASSEMBLER__
+
+/* These are defined by the safe-syscall.inc.S file */
+extern char safe_syscall_start[];
+extern char safe_syscall_end[];
+
+/* Adjust the signal context to rewind out of safe-syscall if we're in it */
+static inline void rewind_if_in_safe_syscall(void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long *pcreg = &uc->uc_mcontext.psw.addr;
+
+ if (*pcreg > (uintptr_t)safe_syscall_start
+ && *pcreg < (uintptr_t)safe_syscall_end) {
+ *pcreg = (uintptr_t)safe_syscall_start;
+ }
+}
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/linux-user/host/s390x/safe-syscall.inc.S b/linux-user/host/s390x/safe-syscall.inc.S
new file mode 100644
index 0000000000..f1b446abf6
--- /dev/null
+++ b/linux-user/host/s390x/safe-syscall.inc.S
@@ -0,0 +1,90 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, @function
+
+ /* This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+safe_syscall_base:
+ .cfi_startproc
+ stmg %r6,%r15,48(%r15) /* save all call-saved registers */
+ .cfi_offset %r15,-40
+ .cfi_offset %r14,-48
+ .cfi_offset %r13,-56
+ .cfi_offset %r12,-64
+ .cfi_offset %r11,-72
+ .cfi_offset %r10,-80
+ .cfi_offset %r9,-88
+ .cfi_offset %r8,-96
+ .cfi_offset %r7,-104
+ .cfi_offset %r6,-112
+ lgr %r1,%r15
+ lg %r0,8(%r15) /* load eos */
+ aghi %r15,-160
+ .cfi_adjust_cfa_offset 160
+ stg %r1,0(%r15) /* store back chain */
+ stg %r0,8(%r15) /* store eos */
+
+ /* The syscall calling convention isn't the same as the
+ * C one:
+ * we enter with r2 == *signal_pending
+ * r3 == syscall number
+ * r4, r5, r6, (stack) == syscall arguments
+ * and return the result in r2
+ * and the syscall instruction needs
+ * r1 == syscall number
+ * r2 ... r7 == syscall arguments
+ * and returns the result in r2
+ * Shuffle everything around appropriately.
+ */
+ lgr %r8,%r2 /* signal_pending pointer */
+ lgr %r1,%r3 /* syscall number */
+ lgr %r2,%r4 /* syscall args */
+ lgr %r3,%r5
+ lgr %r4,%r6
+ lmg %r5,%r7,320(%r15)
+
+ /* This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* if signal_pending is non-zero, don't do the call */
+ lt %r0,0(%r8)
+ jne 2f
+ svc 0
+safe_syscall_end:
+
+1: lg %r15,0(%r15) /* load back chain */
+ .cfi_remember_state
+ .cfi_adjust_cfa_offset -160
+ lmg %r6,%r15,48(%r15) /* load saved registers */
+ br %r14
+ .cfi_restore_state
+2: lghi %r2, -TARGET_ERESTARTSYS
+ j 1b
+ .cfi_endproc
+
+ .size safe_syscall_base, .-safe_syscall_base
diff --git a/linux-user/host/sparc/hostdep.h b/linux-user/host/sparc/hostdep.h
new file mode 100644
index 0000000000..7609bf5cd7
--- /dev/null
+++ b/linux-user/host/sparc/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HOSTDEP_H
+#define QEMU_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/sparc64/hostdep.h b/linux-user/host/sparc64/hostdep.h
new file mode 100644
index 0000000000..7609bf5cd7
--- /dev/null
+++ b/linux-user/host/sparc64/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HOSTDEP_H
+#define QEMU_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/x32/hostdep.h b/linux-user/host/x32/hostdep.h
new file mode 100644
index 0000000000..7609bf5cd7
--- /dev/null
+++ b/linux-user/host/x32/hostdep.h
@@ -0,0 +1,15 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * * Written by Peter Maydell <peter.maydell@linaro.org>
+ *
+ * Copyright (C) 2016 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_HOSTDEP_H
+#define QEMU_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/x86_64/safe-syscall.inc.S b/linux-user/host/x86_64/safe-syscall.inc.S
index e09368d450..f36992daa3 100644
--- a/linux-user/host/x86_64/safe-syscall.inc.S
+++ b/linux-user/host/x86_64/safe-syscall.inc.S
@@ -67,8 +67,8 @@ safe_syscall_base:
*/
safe_syscall_start:
/* if signal_pending is non-zero, don't do the call */
- testl $1, (%rbp)
- jnz return_ERESTARTSYS
+ cmpl $0, (%rbp)
+ jnz 1f
syscall
safe_syscall_end:
/* code path for having successfully executed the syscall */
@@ -78,7 +78,7 @@ safe_syscall_end:
.cfi_restore rbp
ret
-return_ERESTARTSYS:
+1:
/* code path when we didn't execute the syscall */
.cfi_restore_state
mov $-TARGET_ERESTARTSYS, %rax
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 56f29c35b5..e8a5aede95 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -20,6 +20,11 @@
#define THREAD __thread
+/* This is the size of the host kernel's sigset_t, needed where we make
+ * direct system calls that take a sigset_t pointer and a size.
+ */
+#define SIGSET_T_SIZE (_NSIG / 8)
+
/* This struct is used to hold certain information about the image.
* Basically, it replicates in user space what would be certain
* task_struct fields in the kernel
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 1dadddf2dd..9d980456ec 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -278,6 +278,14 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
tinfo->si_errno = 0;
tinfo->si_code = info->si_code;
+ /* This memset serves two purposes:
+ * (1) ensure we don't leak random junk to the guest later
+ * (2) placate false positives from gcc about fields
+ * being used uninitialized if it chooses to inline both this
+ * function and tswap_siginfo() into host_to_target_siginfo().
+ */
+ memset(tinfo->_sifields._pad, 0, sizeof(tinfo->_sifields._pad));
+
/* This is awkward, because we have to use a combination of
* the si_code and si_signo to figure out which of the union's
* members are valid. (Within the host kernel it is always possible
@@ -397,8 +405,9 @@ static void tswap_siginfo(target_siginfo_t *tinfo,
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
{
- host_to_target_siginfo_noswap(tinfo, info);
- tswap_siginfo(tinfo, tinfo);
+ target_siginfo_t tgt_tmp;
+ host_to_target_siginfo_noswap(&tgt_tmp, info);
+ tswap_siginfo(tinfo, &tgt_tmp);
}
/* XXX: we support only POSIX RT signals are used. */
@@ -627,8 +636,16 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
* code in case the guest code provokes one in the window between
* now and it getting out to the main loop. Signals will be
* unblocked again in process_pending_signals().
+ *
+ * WARNING: we cannot use sigfillset() here because the uc_sigmask
+ * field is a kernel sigset_t, which is much smaller than the
+ * libc sigset_t which sigfillset() operates on. Using sigfillset()
+ * would write 0xff bytes off the end of the structure and trash
+ * data on the struct.
+ * We can't use sizeof(uc->uc_sigmask) either, because the libc
+ * headers define the struct field with the wrong (too large) type.
*/
- sigfillset(&uc->uc_sigmask);
+ memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE);
sigdelset(&uc->uc_sigmask, SIGSEGV);
sigdelset(&uc->uc_sigmask, SIGBUS);
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 4046b81705..cc10dc4703 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -5,6 +5,9 @@
#include <sys/shm.h>
#include <sys/select.h>
#include <sys/mount.h>
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <linux/if_packet.h>
#include <sched.h>
#include "qemu.h"
@@ -57,10 +60,15 @@ UNUSED static void print_open_flags(abi_long, int);
UNUSED static void print_syscall_prologue(const struct syscallname *);
UNUSED static void print_syscall_epilogue(const struct syscallname *);
UNUSED static void print_string(abi_long, int);
+UNUSED static void print_buf(abi_long addr, abi_long len, int last);
UNUSED static void print_raw_param(const char *, abi_long, int);
UNUSED static void print_timeval(abi_ulong, int);
UNUSED static void print_number(abi_long, int);
UNUSED static void print_signal(abi_ulong, int);
+UNUSED static void print_sockaddr(abi_ulong addr, abi_long addrlen);
+UNUSED static void print_socket_domain(int domain);
+UNUSED static void print_socket_type(int type);
+UNUSED static void print_socket_protocol(int domain, int type, int protocol);
/*
* Utility functions
@@ -146,6 +154,165 @@ print_signal(abi_ulong arg, int last)
gemu_log("%s%s", signal_name, get_comma(last));
}
+static void
+print_sockaddr(abi_ulong addr, abi_long addrlen)
+{
+ struct target_sockaddr *sa;
+ int i;
+ int sa_family;
+
+ sa = lock_user(VERIFY_READ, addr, addrlen, 1);
+ if (sa) {
+ sa_family = tswap16(sa->sa_family);
+ switch (sa_family) {
+ case AF_UNIX: {
+ struct target_sockaddr_un *un = (struct target_sockaddr_un *)sa;
+ int i;
+ gemu_log("{sun_family=AF_UNIX,sun_path=\"");
+ for (i = 0; i < addrlen -
+ offsetof(struct target_sockaddr_un, sun_path) &&
+ un->sun_path[i]; i++) {
+ gemu_log("%c", un->sun_path[i]);
+ }
+ gemu_log("\"}");
+ break;
+ }
+ case AF_INET: {
+ struct target_sockaddr_in *in = (struct target_sockaddr_in *)sa;
+ uint8_t *c = (uint8_t *)&in->sin_addr.s_addr;
+ gemu_log("{sin_family=AF_INET,sin_port=htons(%d),",
+ ntohs(in->sin_port));
+ gemu_log("sin_addr=inet_addr(\"%d.%d.%d.%d\")",
+ c[0], c[1], c[2], c[3]);
+ gemu_log("}");
+ break;
+ }
+ case AF_PACKET: {
+ struct target_sockaddr_ll *ll = (struct target_sockaddr_ll *)sa;
+ uint8_t *c = (uint8_t *)&ll->sll_addr;
+ gemu_log("{sll_family=AF_PACKET,"
+ "sll_protocol=htons(0x%04x),if%d,pkttype=",
+ ntohs(ll->sll_protocol), ll->sll_ifindex);
+ switch (ll->sll_pkttype) {
+ case PACKET_HOST:
+ gemu_log("PACKET_HOST");
+ break;
+ case PACKET_BROADCAST:
+ gemu_log("PACKET_BROADCAST");
+ break;
+ case PACKET_MULTICAST:
+ gemu_log("PACKET_MULTICAST");
+ break;
+ case PACKET_OTHERHOST:
+ gemu_log("PACKET_OTHERHOST");
+ break;
+ case PACKET_OUTGOING:
+ gemu_log("PACKET_OUTGOING");
+ break;
+ default:
+ gemu_log("%d", ll->sll_pkttype);
+ break;
+ }
+ gemu_log(",sll_addr=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
+ gemu_log("}");
+ break;
+ }
+ default:
+ gemu_log("{sa_family=%d, sa_data={", sa->sa_family);
+ for (i = 0; i < 13; i++) {
+ gemu_log("%02x, ", sa->sa_data[i]);
+ }
+ gemu_log("%02x}", sa->sa_data[i]);
+ gemu_log("}");
+ break;
+ }
+ unlock_user(sa, addr, 0);
+ } else {
+ print_raw_param("0x"TARGET_ABI_FMT_lx, addr, 0);
+ }
+ gemu_log(", "TARGET_ABI_FMT_ld, addrlen);
+}
+
+static void
+print_socket_domain(int domain)
+{
+ switch (domain) {
+ case PF_UNIX:
+ gemu_log("PF_UNIX");
+ break;
+ case PF_INET:
+ gemu_log("PF_INET");
+ break;
+ case PF_PACKET:
+ gemu_log("PF_PACKET");
+ break;
+ default:
+ gemu_log("%d", domain);
+ break;
+ }
+}
+
+static void
+print_socket_type(int type)
+{
+ switch (type) {
+ case TARGET_SOCK_DGRAM:
+ gemu_log("SOCK_DGRAM");
+ break;
+ case TARGET_SOCK_STREAM:
+ gemu_log("SOCK_STREAM");
+ break;
+ case TARGET_SOCK_RAW:
+ gemu_log("SOCK_RAW");
+ break;
+ case TARGET_SOCK_RDM:
+ gemu_log("SOCK_RDM");
+ break;
+ case TARGET_SOCK_SEQPACKET:
+ gemu_log("SOCK_SEQPACKET");
+ break;
+ case TARGET_SOCK_PACKET:
+ gemu_log("SOCK_PACKET");
+ break;
+ }
+}
+
+static void
+print_socket_protocol(int domain, int type, int protocol)
+{
+ if (domain == AF_PACKET ||
+ (domain == AF_INET && type == TARGET_SOCK_PACKET)) {
+ switch (protocol) {
+ case 0x0003:
+ gemu_log("ETH_P_ALL");
+ break;
+ default:
+ gemu_log("%d", protocol);
+ }
+ return;
+ }
+
+ switch (protocol) {
+ case IPPROTO_IP:
+ gemu_log("IPPROTO_IP");
+ break;
+ case IPPROTO_TCP:
+ gemu_log("IPPROTO_TCP");
+ break;
+ case IPPROTO_UDP:
+ gemu_log("IPPROTO_UDP");
+ break;
+ case IPPROTO_RAW:
+ gemu_log("IPPROTO_RAW");
+ break;
+ default:
+ gemu_log("%d", protocol);
+ break;
+ }
+}
+
+
#ifdef TARGET_NR__newselect
static void
print_fdset(int n, abi_ulong target_fds_addr)
@@ -497,6 +664,26 @@ UNUSED static struct flags clone_flags[] = {
FLAG_END,
};
+UNUSED static struct flags msg_flags[] = {
+ /* send */
+ FLAG_GENERIC(MSG_CONFIRM),
+ FLAG_GENERIC(MSG_DONTROUTE),
+ FLAG_GENERIC(MSG_DONTWAIT),
+ FLAG_GENERIC(MSG_EOR),
+ FLAG_GENERIC(MSG_MORE),
+ FLAG_GENERIC(MSG_NOSIGNAL),
+ FLAG_GENERIC(MSG_OOB),
+ /* recv */
+ FLAG_GENERIC(MSG_CMSG_CLOEXEC),
+ FLAG_GENERIC(MSG_ERRQUEUE),
+ FLAG_GENERIC(MSG_PEEK),
+ FLAG_GENERIC(MSG_TRUNC),
+ FLAG_GENERIC(MSG_WAITALL),
+ /* recvmsg */
+ FLAG_GENERIC(MSG_CTRUNC),
+ FLAG_END,
+};
+
/*
* print_xxx utility functions. These are used to print syscall
* parameters in certain format. All of these have parameter
@@ -618,6 +805,36 @@ print_string(abi_long addr, int last)
}
}
+#define MAX_PRINT_BUF 40
+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);
+ }
+}
+
/*
* Prints out raw parameter using given format. Caller needs
* to do byte swapping if needed.
@@ -740,33 +957,31 @@ print_chmod(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 arg0, abi_long arg1, abi_long arg2,
- abi_long arg3, abi_long arg4, abi_long arg5)
+ 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_M68K)
- print_flags(clone_flags, arg0, 0);
- print_raw_param("newsp=0x" TARGET_ABI_FMT_lx, arg1, 1);
-#elif defined(TARGET_SH4) || defined(TARGET_ALPHA)
- print_flags(clone_flags, arg0, 0);
- print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg1, 0);
- print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0);
- print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg3, 0);
- print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg4, 1);
-#elif defined(TARGET_CRIS)
- print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg0, 0);
- print_flags(clone_flags, arg1, 0);
- print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0);
- print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg3, 0);
- print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg4, 1);
+#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
- print_flags(clone_flags, arg0, 0);
- print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg1, 0);
- print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0);
- print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg3, 0);
- print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg4, 1);
+ do_print_clone(arg1, arg2, arg3, arg5, arg4);
#endif
print_syscall_epilogue(name);
}
@@ -918,6 +1133,13 @@ print_fcntl(const struct syscallname *name,
case TARGET_F_GETLEASE:
gemu_log("F_GETLEASE");
break;
+ case TARGET_F_SETPIPE_SZ:
+ gemu_log("F_SETPIPE_SZ,");
+ print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
+ break;
+ case TARGET_F_GETPIPE_SZ:
+ gemu_log("F_GETPIPE_SZ");
+ break;
case TARGET_F_DUPFD_CLOEXEC:
gemu_log("F_DUPFD_CLOEXEC,");
print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
@@ -1003,6 +1225,361 @@ print__llseek(const struct syscallname *name,
}
#endif
+#if defined(TARGET_NR_socket)
+static void
+print_socket(const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ abi_ulong domain = arg0, type = arg1, protocol = arg2;
+
+ print_syscall_prologue(name);
+ print_socket_domain(domain);
+ gemu_log(",");
+ print_socket_type(type);
+ gemu_log(",");
+ if (domain == AF_PACKET ||
+ (domain == AF_INET && type == TARGET_SOCK_PACKET)) {
+ protocol = tswap16(protocol);
+ }
+ print_socket_protocol(domain, type, protocol);
+ print_syscall_epilogue(name);
+}
+
+#endif
+
+#if defined(TARGET_NR_socketcall)
+
+#define get_user_ualx(x, gaddr, idx) \
+ get_user_ual(x, (gaddr) + (idx) * sizeof(abi_long))
+
+static void do_print_socket(const char *name, abi_long arg1)
+{
+ abi_ulong domain, type, protocol;
+
+ get_user_ualx(domain, arg1, 0);
+ get_user_ualx(type, arg1, 1);
+ get_user_ualx(protocol, arg1, 2);
+ gemu_log("%s(", name);
+ print_socket_domain(domain);
+ gemu_log(",");
+ print_socket_type(type);
+ gemu_log(",");
+ if (domain == AF_PACKET ||
+ (domain == AF_INET && type == TARGET_SOCK_PACKET)) {
+ protocol = tswap16(protocol);
+ }
+ print_socket_protocol(domain, type, protocol);
+ gemu_log(")");
+}
+
+static void do_print_sockaddr(const char *name, abi_long arg1)
+{
+ abi_ulong sockfd, addr, addrlen;
+
+ get_user_ualx(sockfd, arg1, 0);
+ get_user_ualx(addr, arg1, 1);
+ get_user_ualx(addrlen, arg1, 2);
+
+ gemu_log("%s(", name);
+ print_raw_param(TARGET_ABI_FMT_ld, sockfd, 0);
+ print_sockaddr(addr, addrlen);
+ gemu_log(")");
+}
+
+static void do_print_listen(const char *name, abi_long arg1)
+{
+ abi_ulong sockfd, backlog;
+
+ get_user_ualx(sockfd, arg1, 0);
+ get_user_ualx(backlog, arg1, 1);
+
+ gemu_log("%s(", name);
+ print_raw_param(TARGET_ABI_FMT_ld, sockfd, 0);
+ print_raw_param(TARGET_ABI_FMT_ld, backlog, 1);
+ gemu_log(")");
+}
+
+static void do_print_socketpair(const char *name, abi_long arg1)
+{
+ abi_ulong domain, type, protocol, tab;
+
+ get_user_ualx(domain, arg1, 0);
+ get_user_ualx(type, arg1, 1);
+ get_user_ualx(protocol, arg1, 2);
+ get_user_ualx(tab, arg1, 3);
+
+ gemu_log("%s(", name);
+ print_socket_domain(domain);
+ gemu_log(",");
+ print_socket_type(type);
+ gemu_log(",");
+ print_socket_protocol(domain, type, protocol);
+ gemu_log(",");
+ print_raw_param(TARGET_ABI_FMT_lx, tab, 1);
+ gemu_log(")");
+}
+
+static void do_print_sendrecv(const char *name, abi_long arg1)
+{
+ abi_ulong sockfd, msg, len, flags;
+
+ get_user_ualx(sockfd, arg1, 0);
+ get_user_ualx(msg, arg1, 1);
+ get_user_ualx(len, arg1, 2);
+ get_user_ualx(flags, arg1, 3);
+
+ gemu_log("%s(", name);
+ print_raw_param(TARGET_ABI_FMT_ld, sockfd, 0);
+ print_buf(msg, len, 0);
+ print_raw_param(TARGET_ABI_FMT_ld, len, 0);
+ print_flags(msg_flags, flags, 1);
+ gemu_log(")");
+}
+
+static void do_print_msgaddr(const char *name, abi_long arg1)
+{
+ abi_ulong sockfd, msg, len, flags, addr, addrlen;
+
+ get_user_ualx(sockfd, arg1, 0);
+ get_user_ualx(msg, arg1, 1);
+ get_user_ualx(len, arg1, 2);
+ get_user_ualx(flags, arg1, 3);
+ get_user_ualx(addr, arg1, 4);
+ get_user_ualx(addrlen, arg1, 5);
+
+ gemu_log("%s(", name);
+ print_raw_param(TARGET_ABI_FMT_ld, sockfd, 0);
+ print_buf(msg, len, 0);
+ print_raw_param(TARGET_ABI_FMT_ld, len, 0);
+ print_flags(msg_flags, flags, 0);
+ print_sockaddr(addr, addrlen);
+ gemu_log(")");
+}
+
+static void do_print_shutdown(const char *name, abi_long arg1)
+{
+ abi_ulong sockfd, how;
+
+ get_user_ualx(sockfd, arg1, 0);
+ get_user_ualx(how, arg1, 1);
+
+ gemu_log("shutdown(");
+ print_raw_param(TARGET_ABI_FMT_ld, sockfd, 0);
+ switch (how) {
+ case SHUT_RD:
+ gemu_log("SHUT_RD");
+ break;
+ case SHUT_WR:
+ gemu_log("SHUT_WR");
+ break;
+ case SHUT_RDWR:
+ gemu_log("SHUT_RDWR");
+ break;
+ default:
+ print_raw_param(TARGET_ABI_FMT_ld, how, 1);
+ break;
+ }
+ gemu_log(")");
+}
+
+static void do_print_msg(const char *name, abi_long arg1)
+{
+ abi_ulong sockfd, msg, flags;
+
+ get_user_ualx(sockfd, arg1, 0);
+ get_user_ualx(msg, arg1, 1);
+ get_user_ualx(flags, arg1, 2);
+
+ gemu_log("%s(", name);
+ print_raw_param(TARGET_ABI_FMT_ld, sockfd, 0);
+ print_pointer(msg, 0);
+ print_flags(msg_flags, flags, 1);
+ gemu_log(")");
+}
+
+static void do_print_sockopt(const char *name, abi_long arg1)
+{
+ abi_ulong sockfd, level, optname, optval, optlen;
+
+ get_user_ualx(sockfd, arg1, 0);
+ get_user_ualx(level, arg1, 1);
+ get_user_ualx(optname, arg1, 2);
+ get_user_ualx(optval, arg1, 3);
+ get_user_ualx(optlen, arg1, 4);
+
+ gemu_log("%s(", name);
+ print_raw_param(TARGET_ABI_FMT_ld, sockfd, 0);
+ switch (level) {
+ case SOL_TCP:
+ gemu_log("SOL_TCP,");
+ print_raw_param(TARGET_ABI_FMT_ld, optname, 0);
+ print_pointer(optval, 0);
+ break;
+ case SOL_IP:
+ gemu_log("SOL_IP,");
+ print_raw_param(TARGET_ABI_FMT_ld, optname, 0);
+ print_pointer(optval, 0);
+ break;
+ case SOL_RAW:
+ gemu_log("SOL_RAW,");
+ print_raw_param(TARGET_ABI_FMT_ld, optname, 0);
+ print_pointer(optval, 0);
+ break;
+ case TARGET_SOL_SOCKET:
+ gemu_log("SOL_SOCKET,");
+ switch (optname) {
+ case TARGET_SO_DEBUG:
+ gemu_log("SO_DEBUG,");
+print_optint:
+ print_number(optval, 0);
+ break;
+ case TARGET_SO_REUSEADDR:
+ gemu_log("SO_REUSEADDR,");
+ goto print_optint;
+ case TARGET_SO_TYPE:
+ gemu_log("SO_TYPE,");
+ goto print_optint;
+ case TARGET_SO_ERROR:
+ gemu_log("SO_ERROR,");
+ goto print_optint;
+ case TARGET_SO_DONTROUTE:
+ gemu_log("SO_DONTROUTE,");
+ goto print_optint;
+ case TARGET_SO_BROADCAST:
+ gemu_log("SO_BROADCAST,");
+ goto print_optint;
+ case TARGET_SO_SNDBUF:
+ gemu_log("SO_SNDBUF,");
+ goto print_optint;
+ case TARGET_SO_RCVBUF:
+ gemu_log("SO_RCVBUF,");
+ goto print_optint;
+ case TARGET_SO_KEEPALIVE:
+ gemu_log("SO_KEEPALIVE,");
+ goto print_optint;
+ case TARGET_SO_OOBINLINE:
+ gemu_log("SO_OOBINLINE,");
+ goto print_optint;
+ case TARGET_SO_NO_CHECK:
+ gemu_log("SO_NO_CHECK,");
+ goto print_optint;
+ case TARGET_SO_PRIORITY:
+ gemu_log("SO_PRIORITY,");
+ goto print_optint;
+ case TARGET_SO_BSDCOMPAT:
+ gemu_log("SO_BSDCOMPAT,");
+ goto print_optint;
+ case TARGET_SO_PASSCRED:
+ gemu_log("SO_PASSCRED,");
+ goto print_optint;
+ case TARGET_SO_TIMESTAMP:
+ gemu_log("SO_TIMESTAMP,");
+ goto print_optint;
+ case TARGET_SO_RCVLOWAT:
+ gemu_log("SO_RCVLOWAT,");
+ goto print_optint;
+ case TARGET_SO_RCVTIMEO:
+ gemu_log("SO_RCVTIMEO,");
+ print_timeval(optval, 0);
+ break;
+ case TARGET_SO_SNDTIMEO:
+ gemu_log("SO_SNDTIMEO,");
+ print_timeval(optval, 0);
+ break;
+ case TARGET_SO_ATTACH_FILTER: {
+ struct target_sock_fprog *fprog;
+
+ gemu_log("SO_ATTACH_FILTER,");
+
+ if (lock_user_struct(VERIFY_READ, fprog, optval, 0)) {
+ struct target_sock_filter *filter;
+ gemu_log("{");
+ if (lock_user_struct(VERIFY_READ, filter,
+ tswapal(fprog->filter), 0)) {
+ int i;
+ for (i = 0; i < tswap16(fprog->len) - 1; i++) {
+ gemu_log("[%d]{0x%x,%d,%d,0x%x},",
+ i, tswap16(filter[i].code),
+ filter[i].jt, filter[i].jf,
+ tswap32(filter[i].k));
+ }
+ gemu_log("[%d]{0x%x,%d,%d,0x%x}",
+ i, tswap16(filter[i].code),
+ filter[i].jt, filter[i].jf,
+ tswap32(filter[i].k));
+ } else {
+ gemu_log(TARGET_ABI_FMT_lx, tswapal(fprog->filter));
+ }
+ gemu_log(",%d},", tswap16(fprog->len));
+ unlock_user(fprog, optval, 0);
+ } else {
+ print_pointer(optval, 0);
+ }
+ break;
+ }
+ default:
+ print_raw_param(TARGET_ABI_FMT_ld, optname, 0);
+ print_pointer(optval, 0);
+ break;
+ }
+ break;
+ default:
+ print_raw_param(TARGET_ABI_FMT_ld, level, 0);
+ print_raw_param(TARGET_ABI_FMT_ld, optname, 0);
+ print_pointer(optval, 0);
+ break;
+ }
+ print_raw_param(TARGET_ABI_FMT_ld, optlen, 1);
+ gemu_log(")");
+}
+
+#define PRINT_SOCKOP(name, func) \
+ [SOCKOP_##name] = { #name, func }
+
+static struct {
+ const char *name;
+ void (*print)(const char *, abi_long);
+} scall[] = {
+ PRINT_SOCKOP(socket, do_print_socket),
+ PRINT_SOCKOP(bind, do_print_sockaddr),
+ PRINT_SOCKOP(connect, do_print_sockaddr),
+ PRINT_SOCKOP(listen, do_print_listen),
+ PRINT_SOCKOP(accept, do_print_sockaddr),
+ PRINT_SOCKOP(getsockname, do_print_sockaddr),
+ PRINT_SOCKOP(getpeername, do_print_sockaddr),
+ PRINT_SOCKOP(socketpair, do_print_socketpair),
+ PRINT_SOCKOP(send, do_print_sendrecv),
+ PRINT_SOCKOP(recv, do_print_sendrecv),
+ PRINT_SOCKOP(sendto, do_print_msgaddr),
+ PRINT_SOCKOP(recvfrom, do_print_msgaddr),
+ PRINT_SOCKOP(shutdown, do_print_shutdown),
+ PRINT_SOCKOP(sendmsg, do_print_msg),
+ PRINT_SOCKOP(recvmsg, do_print_msg),
+ PRINT_SOCKOP(setsockopt, do_print_sockopt),
+ PRINT_SOCKOP(getsockopt, do_print_sockopt),
+};
+
+static void
+print_socketcall(const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ if (arg0 >= 0 && arg0 < ARRAY_SIZE(scall) && scall[arg0].print) {
+ scall[arg0].print(scall[arg0].name, arg1);
+ return;
+ }
+ print_syscall_prologue(name);
+ print_raw_param(TARGET_ABI_FMT_ld, arg0, 0);
+ print_raw_param(TARGET_ABI_FMT_ld, arg1, 0);
+ print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
+ print_raw_param(TARGET_ABI_FMT_ld, arg3, 0);
+ print_raw_param(TARGET_ABI_FMT_ld, arg4, 0);
+ print_raw_param(TARGET_ABI_FMT_ld, arg5, 0);
+ print_syscall_epilogue(name);
+}
+#endif
+
#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) || \
defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64)
static void
diff --git a/linux-user/strace.list b/linux-user/strace.list
index aa0cd735cc..aa967a2475 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -337,7 +337,8 @@
{ TARGET_NR_getsockopt, "getsockopt" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_get_thread_area
-{ TARGET_NR_get_thread_area, "get_thread_area" , NULL, NULL, NULL },
+{ 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" , NULL, NULL, NULL },
@@ -1234,7 +1235,8 @@
{ TARGET_NR_setsockopt, "setsockopt" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_set_thread_area
-{ TARGET_NR_set_thread_area, "set_thread_area" , NULL, NULL, NULL },
+{ TARGET_NR_set_thread_area, "set_thread_area", "%s(0x"TARGET_ABI_FMT_lx")",
+ NULL, NULL },
#endif
#ifdef TARGET_NR_set_tid_address
{ TARGET_NR_set_tid_address, "set_tid_address" , NULL, NULL, NULL },
@@ -1291,10 +1293,10 @@
{ TARGET_NR_sigsuspend, "sigsuspend" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_socket
-{ TARGET_NR_socket, "socket" , NULL, NULL, NULL },
+{ TARGET_NR_socket, "socket" , NULL, print_socket, NULL },
#endif
#ifdef TARGET_NR_socketcall
-{ TARGET_NR_socketcall, "socketcall" , NULL, NULL, NULL },
+{ TARGET_NR_socketcall, "socketcall" , NULL, print_socketcall, NULL },
#endif
#ifdef TARGET_NR_socketpair
{ TARGET_NR_socketpair, "socketpair" , NULL, NULL, NULL },
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 1c17b741c2..28ee45a937 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -123,11 +123,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
-/* This is the size of the host kernel's sigset_t, needed where we make
- * direct system calls that take a sigset_t pointer and a size.
- */
-#define SIGSET_T_SIZE (_NSIG / 8)
-
#undef _syscall0
#undef _syscall1
#undef _syscall2
@@ -783,6 +778,16 @@ safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
* the libc function.
*/
#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
+/* Similarly for fcntl. Note that callers must always:
+ * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
+ * use the flock64 struct rather than unsuffixed flock
+ * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
+ */
+#ifdef __NR_fcntl64
+#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
+#else
+#define safe_fcntl(...) safe_syscall(__NR_fcntl, __VA_ARGS__)
+#endif
static inline int host_to_target_sock_type(int host_type)
{
@@ -1687,6 +1692,7 @@ static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh,
struct nlmsgerr *e = NLMSG_DATA(nlh);
e->error = tswap32(e->error);
tswap_nlmsghdr(&e->msg);
+ return 0;
}
default:
ret = target_to_host_nlmsg(nlh);
@@ -1942,29 +1948,35 @@ static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
case RTM_NEWLINK:
case RTM_DELLINK:
case RTM_GETLINK:
- ifi = NLMSG_DATA(nlh);
- ifi->ifi_type = tswap16(ifi->ifi_type);
- ifi->ifi_index = tswap32(ifi->ifi_index);
- ifi->ifi_flags = tswap32(ifi->ifi_flags);
- ifi->ifi_change = tswap32(ifi->ifi_change);
- host_to_target_link_rtattr(IFLA_RTA(ifi),
- nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
+ if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
+ ifi = NLMSG_DATA(nlh);
+ ifi->ifi_type = tswap16(ifi->ifi_type);
+ ifi->ifi_index = tswap32(ifi->ifi_index);
+ ifi->ifi_flags = tswap32(ifi->ifi_flags);
+ ifi->ifi_change = tswap32(ifi->ifi_change);
+ host_to_target_link_rtattr(IFLA_RTA(ifi),
+ nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
+ }
break;
case RTM_NEWADDR:
case RTM_DELADDR:
case RTM_GETADDR:
- ifa = NLMSG_DATA(nlh);
- ifa->ifa_index = tswap32(ifa->ifa_index);
- host_to_target_addr_rtattr(IFA_RTA(ifa),
- nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
+ if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
+ ifa = NLMSG_DATA(nlh);
+ ifa->ifa_index = tswap32(ifa->ifa_index);
+ host_to_target_addr_rtattr(IFA_RTA(ifa),
+ nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
+ }
break;
case RTM_NEWROUTE:
case RTM_DELROUTE:
case RTM_GETROUTE:
- rtm = NLMSG_DATA(nlh);
- rtm->rtm_flags = tswap32(rtm->rtm_flags);
- host_to_target_route_rtattr(RTM_RTA(rtm),
- nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
+ if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
+ rtm = NLMSG_DATA(nlh);
+ rtm->rtm_flags = tswap32(rtm->rtm_flags);
+ host_to_target_route_rtattr(RTM_RTA(rtm),
+ nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
+ }
break;
default:
return -TARGET_EINVAL;
@@ -2080,30 +2092,36 @@ static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
break;
case RTM_NEWLINK:
case RTM_DELLINK:
- ifi = NLMSG_DATA(nlh);
- ifi->ifi_type = tswap16(ifi->ifi_type);
- ifi->ifi_index = tswap32(ifi->ifi_index);
- ifi->ifi_flags = tswap32(ifi->ifi_flags);
- ifi->ifi_change = tswap32(ifi->ifi_change);
- target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
- NLMSG_LENGTH(sizeof(*ifi)));
+ if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) {
+ ifi = NLMSG_DATA(nlh);
+ ifi->ifi_type = tswap16(ifi->ifi_type);
+ ifi->ifi_index = tswap32(ifi->ifi_index);
+ ifi->ifi_flags = tswap32(ifi->ifi_flags);
+ ifi->ifi_change = tswap32(ifi->ifi_change);
+ target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len -
+ NLMSG_LENGTH(sizeof(*ifi)));
+ }
break;
case RTM_GETADDR:
case RTM_NEWADDR:
case RTM_DELADDR:
- ifa = NLMSG_DATA(nlh);
- ifa->ifa_index = tswap32(ifa->ifa_index);
- target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
- NLMSG_LENGTH(sizeof(*ifa)));
+ if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) {
+ ifa = NLMSG_DATA(nlh);
+ ifa->ifa_index = tswap32(ifa->ifa_index);
+ target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len -
+ NLMSG_LENGTH(sizeof(*ifa)));
+ }
break;
case RTM_GETROUTE:
break;
case RTM_NEWROUTE:
case RTM_DELROUTE:
- rtm = NLMSG_DATA(nlh);
- rtm->rtm_flags = tswap32(rtm->rtm_flags);
- target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
- NLMSG_LENGTH(sizeof(*rtm)));
+ if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) {
+ rtm = NLMSG_DATA(nlh);
+ rtm->rtm_flags = tswap32(rtm->rtm_flags);
+ target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len -
+ NLMSG_LENGTH(sizeof(*rtm)));
+ }
break;
default:
return -TARGET_EOPNOTSUPP;
@@ -2985,7 +3003,7 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
len = ret;
if (fd_trans_host_to_target_data(fd)) {
ret = fd_trans_host_to_target_data(fd)(msg.msg_iov->iov_base,
- msg.msg_iov->iov_len);
+ len);
} else {
ret = host_to_target_cmsg(msgp, &msg);
}
@@ -5541,11 +5559,11 @@ static int target_to_host_fcntl_cmd(int cmd)
case TARGET_F_SETFL:
return cmd;
case TARGET_F_GETLK:
- return F_GETLK;
- case TARGET_F_SETLK:
- return F_SETLK;
- case TARGET_F_SETLKW:
- return F_SETLKW;
+ return F_GETLK64;
+ case TARGET_F_SETLK:
+ return F_SETLK64;
+ case TARGET_F_SETLKW:
+ return F_SETLKW64;
case TARGET_F_GETOWN:
return F_GETOWN;
case TARGET_F_SETOWN:
@@ -5580,6 +5598,10 @@ static int target_to_host_fcntl_cmd(int cmd)
case TARGET_F_SETOWN_EX:
return F_SETOWN_EX;
#endif
+ case TARGET_F_SETPIPE_SZ:
+ return F_SETPIPE_SZ;
+ case TARGET_F_GETPIPE_SZ:
+ return F_GETPIPE_SZ;
default:
return -TARGET_EINVAL;
}
@@ -5596,12 +5618,134 @@ static const bitmask_transtbl flock_tbl[] = {
{ 0, 0, 0, 0 }
};
-static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
+static inline abi_long copy_from_user_flock(struct flock64 *fl,
+ abi_ulong target_flock_addr)
+{
+ struct target_flock *target_fl;
+ short l_type;
+
+ if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
+ return -TARGET_EFAULT;
+ }
+
+ __get_user(l_type, &target_fl->l_type);
+ fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
+ __get_user(fl->l_whence, &target_fl->l_whence);
+ __get_user(fl->l_start, &target_fl->l_start);
+ __get_user(fl->l_len, &target_fl->l_len);
+ __get_user(fl->l_pid, &target_fl->l_pid);
+ unlock_user_struct(target_fl, target_flock_addr, 0);
+ return 0;
+}
+
+static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
+ const struct flock64 *fl)
{
- struct flock fl;
struct target_flock *target_fl;
+ short l_type;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+
+ l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
+ __put_user(l_type, &target_fl->l_type);
+ __put_user(fl->l_whence, &target_fl->l_whence);
+ __put_user(fl->l_start, &target_fl->l_start);
+ __put_user(fl->l_len, &target_fl->l_len);
+ __put_user(fl->l_pid, &target_fl->l_pid);
+ unlock_user_struct(target_fl, target_flock_addr, 1);
+ return 0;
+}
+
+typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
+typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
+
+#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
+static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
+ abi_ulong target_flock_addr)
+{
+ struct target_eabi_flock64 *target_fl;
+ short l_type;
+
+ if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
+ return -TARGET_EFAULT;
+ }
+
+ __get_user(l_type, &target_fl->l_type);
+ fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
+ __get_user(fl->l_whence, &target_fl->l_whence);
+ __get_user(fl->l_start, &target_fl->l_start);
+ __get_user(fl->l_len, &target_fl->l_len);
+ __get_user(fl->l_pid, &target_fl->l_pid);
+ unlock_user_struct(target_fl, target_flock_addr, 0);
+ return 0;
+}
+
+static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
+ const struct flock64 *fl)
+{
+ struct target_eabi_flock64 *target_fl;
+ short l_type;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+
+ l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
+ __put_user(l_type, &target_fl->l_type);
+ __put_user(fl->l_whence, &target_fl->l_whence);
+ __put_user(fl->l_start, &target_fl->l_start);
+ __put_user(fl->l_len, &target_fl->l_len);
+ __put_user(fl->l_pid, &target_fl->l_pid);
+ unlock_user_struct(target_fl, target_flock_addr, 1);
+ return 0;
+}
+#endif
+
+static inline abi_long copy_from_user_flock64(struct flock64 *fl,
+ abi_ulong target_flock_addr)
+{
+ struct target_flock64 *target_fl;
+ short l_type;
+
+ if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
+ return -TARGET_EFAULT;
+ }
+
+ __get_user(l_type, &target_fl->l_type);
+ fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
+ __get_user(fl->l_whence, &target_fl->l_whence);
+ __get_user(fl->l_start, &target_fl->l_start);
+ __get_user(fl->l_len, &target_fl->l_len);
+ __get_user(fl->l_pid, &target_fl->l_pid);
+ unlock_user_struct(target_fl, target_flock_addr, 0);
+ return 0;
+}
+
+static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
+ const struct flock64 *fl)
+{
+ struct target_flock64 *target_fl;
+ short l_type;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+
+ l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
+ __put_user(l_type, &target_fl->l_type);
+ __put_user(fl->l_whence, &target_fl->l_whence);
+ __put_user(fl->l_start, &target_fl->l_start);
+ __put_user(fl->l_len, &target_fl->l_len);
+ __put_user(fl->l_pid, &target_fl->l_pid);
+ unlock_user_struct(target_fl, target_flock_addr, 1);
+ return 0;
+}
+
+static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
+{
struct flock64 fl64;
- struct target_flock64 *target_fl64;
#ifdef F_GETOWN_EX
struct f_owner_ex fox;
struct target_f_owner_ex *target_fox;
@@ -5614,94 +5758,60 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
switch(cmd) {
case TARGET_F_GETLK:
- if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
- return -TARGET_EFAULT;
- fl.l_type =
- target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
- fl.l_whence = tswap16(target_fl->l_whence);
- fl.l_start = tswapal(target_fl->l_start);
- fl.l_len = tswapal(target_fl->l_len);
- fl.l_pid = tswap32(target_fl->l_pid);
- unlock_user_struct(target_fl, arg, 0);
- ret = get_errno(fcntl(fd, host_cmd, &fl));
+ ret = copy_from_user_flock(&fl64, arg);
+ if (ret) {
+ return ret;
+ }
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
if (ret == 0) {
- if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
- return -TARGET_EFAULT;
- target_fl->l_type =
- host_to_target_bitmask(tswap16(fl.l_type), flock_tbl);
- target_fl->l_whence = tswap16(fl.l_whence);
- target_fl->l_start = tswapal(fl.l_start);
- target_fl->l_len = tswapal(fl.l_len);
- target_fl->l_pid = tswap32(fl.l_pid);
- unlock_user_struct(target_fl, arg, 1);
+ ret = copy_to_user_flock(arg, &fl64);
}
break;
case TARGET_F_SETLK:
case TARGET_F_SETLKW:
- if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1))
- return -TARGET_EFAULT;
- fl.l_type =
- target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl);
- fl.l_whence = tswap16(target_fl->l_whence);
- fl.l_start = tswapal(target_fl->l_start);
- fl.l_len = tswapal(target_fl->l_len);
- fl.l_pid = tswap32(target_fl->l_pid);
- unlock_user_struct(target_fl, arg, 0);
- ret = get_errno(fcntl(fd, host_cmd, &fl));
+ ret = copy_from_user_flock(&fl64, arg);
+ if (ret) {
+ return ret;
+ }
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
break;
case TARGET_F_GETLK64:
- if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
- return -TARGET_EFAULT;
- fl64.l_type =
- target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
- fl64.l_whence = tswap16(target_fl64->l_whence);
- fl64.l_start = tswap64(target_fl64->l_start);
- fl64.l_len = tswap64(target_fl64->l_len);
- fl64.l_pid = tswap32(target_fl64->l_pid);
- unlock_user_struct(target_fl64, arg, 0);
- ret = get_errno(fcntl(fd, host_cmd, &fl64));
+ ret = copy_from_user_flock64(&fl64, arg);
+ if (ret) {
+ return ret;
+ }
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
if (ret == 0) {
- if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
- return -TARGET_EFAULT;
- target_fl64->l_type =
- host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1;
- target_fl64->l_whence = tswap16(fl64.l_whence);
- target_fl64->l_start = tswap64(fl64.l_start);
- target_fl64->l_len = tswap64(fl64.l_len);
- target_fl64->l_pid = tswap32(fl64.l_pid);
- unlock_user_struct(target_fl64, arg, 1);
+ ret = copy_to_user_flock64(arg, &fl64);
}
break;
case TARGET_F_SETLK64:
case TARGET_F_SETLKW64:
- if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1))
- return -TARGET_EFAULT;
- fl64.l_type =
- target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1;
- fl64.l_whence = tswap16(target_fl64->l_whence);
- fl64.l_start = tswap64(target_fl64->l_start);
- fl64.l_len = tswap64(target_fl64->l_len);
- fl64.l_pid = tswap32(target_fl64->l_pid);
- unlock_user_struct(target_fl64, arg, 0);
- ret = get_errno(fcntl(fd, host_cmd, &fl64));
+ ret = copy_from_user_flock64(&fl64, arg);
+ if (ret) {
+ return ret;
+ }
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
break;
case TARGET_F_GETFL:
- ret = get_errno(fcntl(fd, host_cmd, arg));
+ ret = get_errno(safe_fcntl(fd, host_cmd, arg));
if (ret >= 0) {
ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
}
break;
case TARGET_F_SETFL:
- ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
+ ret = get_errno(safe_fcntl(fd, host_cmd,
+ target_to_host_bitmask(arg,
+ fcntl_flags_tbl)));
break;
#ifdef F_GETOWN_EX
case TARGET_F_GETOWN_EX:
- ret = get_errno(fcntl(fd, host_cmd, &fox));
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
if (ret >= 0) {
if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
return -TARGET_EFAULT;
@@ -5719,7 +5829,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
fox.type = tswap32(target_fox->type);
fox.pid = tswap32(target_fox->pid);
unlock_user_struct(target_fox, arg, 0);
- ret = get_errno(fcntl(fd, host_cmd, &fox));
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fox));
break;
#endif
@@ -5729,11 +5839,13 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
case TARGET_F_GETSIG:
case TARGET_F_SETLEASE:
case TARGET_F_GETLEASE:
- ret = get_errno(fcntl(fd, host_cmd, arg));
+ case TARGET_F_SETPIPE_SZ:
+ case TARGET_F_GETPIPE_SZ:
+ ret = get_errno(safe_fcntl(fd, host_cmd, arg));
break;
default:
- ret = get_errno(fcntl(fd, cmd, arg));
+ ret = get_errno(safe_fcntl(fd, cmd, arg));
break;
}
return ret;
@@ -6690,6 +6802,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef DEBUG
gemu_log("syscall %d", num);
#endif
+ trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
if(do_strace)
print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -7783,8 +7896,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_rt_sigqueueinfo:
{
siginfo_t uinfo;
- if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1)))
+
+ p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
+ if (!p) {
goto efault;
+ }
target_to_host_siginfo(&uinfo, p);
unlock_user(p, arg1, 0);
ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
@@ -10132,9 +10248,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
int cmd;
struct flock64 fl;
- struct target_flock64 *target_fl;
+ from_flock64_fn *copyfrom = copy_from_user_flock64;
+ to_flock64_fn *copyto = copy_to_user_flock64;
+
#ifdef TARGET_ARM
- struct target_eabi_flock64 *target_efl;
+ if (((CPUARMState *)cpu_env)->eabi) {
+ copyfrom = copy_from_user_eabi_flock64;
+ copyto = copy_to_user_eabi_flock64;
+ }
#endif
cmd = target_to_host_fcntl_cmd(arg2);
@@ -10145,80 +10266,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
switch(arg2) {
case TARGET_F_GETLK64:
-#ifdef TARGET_ARM
- if (((CPUARMState *)cpu_env)->eabi) {
- if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
- goto efault;
- fl.l_type = tswap16(target_efl->l_type);
- fl.l_whence = tswap16(target_efl->l_whence);
- fl.l_start = tswap64(target_efl->l_start);
- fl.l_len = tswap64(target_efl->l_len);
- fl.l_pid = tswap32(target_efl->l_pid);
- unlock_user_struct(target_efl, arg3, 0);
- } else
-#endif
- {
- if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
- goto efault;
- fl.l_type = tswap16(target_fl->l_type);
- fl.l_whence = tswap16(target_fl->l_whence);
- fl.l_start = tswap64(target_fl->l_start);
- fl.l_len = tswap64(target_fl->l_len);
- fl.l_pid = tswap32(target_fl->l_pid);
- unlock_user_struct(target_fl, arg3, 0);
+ ret = copyfrom(&fl, arg3);
+ if (ret) {
+ break;
}
ret = get_errno(fcntl(arg1, cmd, &fl));
- if (ret == 0) {
-#ifdef TARGET_ARM
- if (((CPUARMState *)cpu_env)->eabi) {
- if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0))
- goto efault;
- target_efl->l_type = tswap16(fl.l_type);
- target_efl->l_whence = tswap16(fl.l_whence);
- target_efl->l_start = tswap64(fl.l_start);
- target_efl->l_len = tswap64(fl.l_len);
- target_efl->l_pid = tswap32(fl.l_pid);
- unlock_user_struct(target_efl, arg3, 1);
- } else
-#endif
- {
- if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0))
- goto efault;
- target_fl->l_type = tswap16(fl.l_type);
- target_fl->l_whence = tswap16(fl.l_whence);
- target_fl->l_start = tswap64(fl.l_start);
- target_fl->l_len = tswap64(fl.l_len);
- target_fl->l_pid = tswap32(fl.l_pid);
- unlock_user_struct(target_fl, arg3, 1);
- }
- }
+ if (ret == 0) {
+ ret = copyto(arg3, &fl);
+ }
break;
case TARGET_F_SETLK64:
case TARGET_F_SETLKW64:
-#ifdef TARGET_ARM
- if (((CPUARMState *)cpu_env)->eabi) {
- if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1))
- goto efault;
- fl.l_type = tswap16(target_efl->l_type);
- fl.l_whence = tswap16(target_efl->l_whence);
- fl.l_start = tswap64(target_efl->l_start);
- fl.l_len = tswap64(target_efl->l_len);
- fl.l_pid = tswap32(target_efl->l_pid);
- unlock_user_struct(target_efl, arg3, 0);
- } else
-#endif
- {
- if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1))
- goto efault;
- fl.l_type = tswap16(target_fl->l_type);
- fl.l_whence = tswap16(target_fl->l_whence);
- fl.l_start = tswap64(target_fl->l_start);
- fl.l_len = tswap64(target_fl->l_len);
- fl.l_pid = tswap32(target_fl->l_pid);
- unlock_user_struct(target_fl, arg3, 0);
+ ret = copyfrom(&fl, arg3);
+ if (ret) {
+ break;
}
- ret = get_errno(fcntl(arg1, cmd, &fl));
+ ret = get_errno(safe_fcntl(arg1, cmd, &fl));
break;
default:
ret = do_fcntl(arg1, arg2, arg3);
@@ -11182,6 +11246,7 @@ fail:
#endif
if(do_strace)
print_syscall_ret(num, ret);
+ trace_guest_user_syscall_ret(cpu, num, ret);
return ret;
efault:
ret = -TARGET_EFAULT;
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 6ee9251c50..dce1bcc91d 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -135,6 +135,24 @@ struct target_sockaddr_ll {
uint8_t sll_addr[8]; /* Physical layer address */
};
+struct target_sockaddr_un {
+ uint16_t su_family;
+ uint8_t sun_path[108];
+};
+
+struct target_in_addr {
+ uint32_t s_addr; /* big endian */
+};
+
+struct target_sockaddr_in {
+ uint16_t sin_family;
+ int16_t sin_port; /* big endian */
+ struct target_in_addr sin_addr;
+ uint8_t __pad[sizeof(struct target_sockaddr) -
+ sizeof(uint16_t) - sizeof(int16_t) -
+ sizeof(struct target_in_addr)];
+};
+
struct target_sock_filter {
abi_ushort code;
uint8_t jt;
@@ -147,10 +165,6 @@ struct target_sock_fprog {
abi_ulong filter;
};
-struct target_in_addr {
- uint32_t s_addr; /* big endian */
-};
-
struct target_ip_mreq {
struct target_in_addr imr_multiaddr;
struct target_in_addr imr_address;
@@ -2166,6 +2180,8 @@ struct target_statfs64 {
#define TARGET_F_SETLEASE (TARGET_F_LINUX_SPECIFIC_BASE + 0)
#define TARGET_F_GETLEASE (TARGET_F_LINUX_SPECIFIC_BASE + 1)
#define TARGET_F_DUPFD_CLOEXEC (TARGET_F_LINUX_SPECIFIC_BASE + 6)
+#define TARGET_F_SETPIPE_SZ (TARGET_F_LINUX_SPECIFIC_BASE + 7)
+#define TARGET_F_GETPIPE_SZ (TARGET_F_LINUX_SPECIFIC_BASE + 8)
#define TARGET_F_NOTIFY (TARGET_F_LINUX_SPECIFIC_BASE+2)
#if defined(TARGET_ALPHA)
diff --git a/qemu-img.c b/qemu-img.c
index 14e2661a5c..3322a1e5fc 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -32,6 +32,7 @@
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/error-report.h"
+#include "qemu/log.h"
#include "qom/object_interfaces.h"
#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
@@ -39,6 +40,7 @@
#include "block/blockjob.h"
#include "block/qapi.h"
#include "crypto/init.h"
+#include "trace/control.h"
#include <getopt.h>
#define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION QEMU_PKGVERSION \
@@ -91,9 +93,14 @@ static void QEMU_NORETURN help(void)
{
const char *help_msg =
QEMU_IMG_VERSION
- "usage: qemu-img command [command options]\n"
+ "usage: qemu-img [standard options] command [command options]\n"
"QEMU disk image utility\n"
"\n"
+ " '-h', '--help' display this help and exit\n"
+ " '-V', '--version' output version information and exit\n"
+ " '-T', '--trace' [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
+ " specify tracing options\n"
+ "\n"
"Command syntax:\n"
#define DEF(option, callback, arg_string) \
" " arg_string "\n"
@@ -3803,10 +3810,12 @@ int main(int argc, char **argv)
const img_cmd_t *cmd;
const char *cmdname;
Error *local_error = NULL;
+ char *trace_file = NULL;
int c;
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
- {"version", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"trace", required_argument, NULL, 'T'},
{0, 0, 0, 0}
};
@@ -3829,27 +3838,48 @@ int main(int argc, char **argv)
if (argc < 2) {
error_exit("Not enough arguments");
}
- cmdname = argv[1];
qemu_add_opts(&qemu_object_opts);
qemu_add_opts(&qemu_source_opts);
+ qemu_add_opts(&qemu_trace_opts);
- /* find the command */
- for (cmd = img_cmds; cmd->name != NULL; cmd++) {
- if (!strcmp(cmdname, cmd->name)) {
- return cmd->handler(argc - 1, argv + 1);
+ while ((c = getopt_long(argc, argv, "+hVT:", long_options, NULL)) != -1) {
+ switch (c) {
+ case 'h':
+ help();
+ return 0;
+ case 'V':
+ printf(QEMU_IMG_VERSION);
+ return 0;
+ case 'T':
+ g_free(trace_file);
+ trace_file = trace_opt_parse(optarg);
+ break;
}
}
- c = getopt_long(argc, argv, "h", long_options, NULL);
+ cmdname = argv[optind];
- if (c == 'h') {
- help();
- }
- if (c == 'v') {
- printf(QEMU_IMG_VERSION);
+ /* reset getopt_long scanning */
+ argc -= optind;
+ if (argc < 1) {
return 0;
}
+ argv += optind;
+ optind = 1;
+
+ if (!trace_init_backends()) {
+ exit(1);
+ }
+ trace_init_file(trace_file);
+ qemu_set_log(LOG_TRACE);
+
+ /* find the command */
+ for (cmd = img_cmds; cmd->name != NULL; cmd++) {
+ if (!strcmp(cmdname, cmd->name)) {
+ return cmd->handler(argc, argv);
+ }
+ }
/* not found */
error_exit("Command not found: %s", cmdname);
diff --git a/qemu-img.texi b/qemu-img.texi
index cbe50e9b88..449a19c710 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -1,6 +1,6 @@
@example
@c man begin SYNOPSIS
-@command{qemu-img} @var{command} [@var{command} @var{options}]
+@command{qemu-img} [@var{standard} @var{options}] @var{command} [@var{command} @var{options}]
@c man end
@end example
@@ -16,6 +16,17 @@ inconsistent state.
@c man begin OPTIONS
+Standard options:
+@table @option
+@item -h, --help
+Display this help and exit
+@item -V, --version
+Display version information and exit
+@item -T, --trace [[enable=]@var{pattern}][,events=@var{file}][,file=@var{file}]
+@findex --trace
+@include qemu-option-trace.texi
+@end table
+
The following commands are supported:
@include qemu-img-cmds.texi
diff --git a/qemu-io.c b/qemu-io.c
index d977a6e553..db129eac5f 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -18,6 +18,7 @@
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qemu/readline.h"
+#include "qemu/log.h"
#include "qapi/qmp/qstring.h"
#include "qom/object_interfaces.h"
#include "sysemu/block-backend.h"
@@ -253,7 +254,9 @@ static void usage(const char *name)
" -k, --native-aio use kernel AIO implementation (on Linux only)\n"
" -t, --cache=MODE use the given cache mode for the image\n"
" -d, --discard=MODE use the given discard mode for the image\n"
-" -T, --trace FILE enable trace events listed in the given file\n"
+" -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
+" specify tracing options\n"
+" see qemu-img(1) man page for full description\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
"\n"
@@ -458,6 +461,7 @@ int main(int argc, char **argv)
Error *local_error = NULL;
QDict *opts = NULL;
const char *format = NULL;
+ char *trace_file = NULL;
#ifdef CONFIG_POSIX
signal(SIGPIPE, SIG_IGN);
@@ -470,6 +474,7 @@ int main(int argc, char **argv)
module_call_init(MODULE_INIT_QOM);
qemu_add_opts(&qemu_object_opts);
+ qemu_add_opts(&qemu_trace_opts);
bdrv_init();
while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
@@ -509,9 +514,8 @@ int main(int argc, char **argv)
}
break;
case 'T':
- if (!trace_init_backends()) {
- exit(1); /* error message will have been printed */
- }
+ g_free(trace_file);
+ trace_file = trace_opt_parse(optarg);
break;
case 'V':
printf("%s version %s\n", progname, QEMU_VERSION);
@@ -557,6 +561,12 @@ int main(int argc, char **argv)
exit(1);
}
+ if (!trace_init_backends()) {
+ exit(1);
+ }
+ trace_init_file(trace_file);
+ qemu_set_log(LOG_TRACE);
+
/* initialize commands */
qemuio_add_command(&quit_cmd);
qemuio_add_command(&open_cmd);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 9519db324b..321f02bd15 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -27,12 +27,14 @@
#include "qemu/error-report.h"
#include "qemu/config-file.h"
#include "qemu/bswap.h"
+#include "qemu/log.h"
#include "block/snapshot.h"
#include "qapi/util.h"
#include "qapi/qmp/qstring.h"
#include "qom/object_interfaces.h"
#include "io/channel-socket.h"
#include "crypto/init.h"
+#include "trace/control.h"
#include <getopt.h>
#include <libgen.h>
@@ -88,6 +90,8 @@ static void usage(const char *name)
"General purpose options:\n"
" --object type,id=ID,... define an object such as 'secret' for providing\n"
" passwords and/or encryption keys\n"
+" -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
+" specify tracing options\n"
#ifdef __linux__
"Kernel NBD client support:\n"
" -c, --connect=DEV connect FILE to the local NBD device DEV\n"
@@ -470,7 +474,7 @@ int main(int argc, char **argv)
off_t fd_size;
QemuOpts *sn_opts = NULL;
const char *sn_id_or_name = NULL;
- const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:";
+ const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:";
struct option lopt[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
@@ -498,6 +502,7 @@ int main(int argc, char **argv)
{ "export-name", required_argument, NULL, 'x' },
{ "tls-creds", required_argument, NULL, QEMU_NBD_OPT_TLSCREDS },
{ "image-opts", no_argument, NULL, QEMU_NBD_OPT_IMAGE_OPTS },
+ { "trace", required_argument, NULL, 'T' },
{ NULL, 0, NULL, 0 }
};
int ch;
@@ -518,6 +523,7 @@ int main(int argc, char **argv)
const char *tlscredsid = NULL;
bool imageOpts = false;
bool writethrough = true;
+ char *trace_file = NULL;
/* The client thread uses SIGTERM to interrupt the server. A signal
* handler ensures that "qemu-nbd -v -c" exits with a nice status code.
@@ -531,6 +537,7 @@ int main(int argc, char **argv)
module_call_init(MODULE_INIT_QOM);
qemu_add_opts(&qemu_object_opts);
+ qemu_add_opts(&qemu_trace_opts);
qemu_init_exec_dir(argv[0]);
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
@@ -703,6 +710,10 @@ int main(int argc, char **argv)
case QEMU_NBD_OPT_IMAGE_OPTS:
imageOpts = true;
break;
+ case 'T':
+ g_free(trace_file);
+ trace_file = trace_opt_parse(optarg);
+ break;
}
}
@@ -718,6 +729,12 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
+ if (!trace_init_backends()) {
+ exit(1);
+ }
+ trace_init_file(trace_file);
+ qemu_set_log(LOG_TRACE);
+
if (tlscredsid) {
if (sockpath) {
error_report("TLS is only supported with IPv4/IPv6");
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 9f23343450..91ebf04b5b 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -92,6 +92,9 @@ Display extra debugging information
Display this help and exit
@item -V, --version
Display version information and exit
+@item -T, --trace [[enable=]@var{pattern}][,events=@var{file}][,file=@var{file}]
+@findex --trace
+@include qemu-option-trace.texi
@end table
@c man end
diff --git a/qemu-option-trace.texi b/qemu-option-trace.texi
new file mode 100644
index 0000000000..693ab5a3e1
--- /dev/null
+++ b/qemu-option-trace.texi
@@ -0,0 +1,25 @@
+Specify tracing options.
+
+@table @option
+@item [enable=]@var{pattern}
+Immediately enable events matching @var{pattern}.
+The file must contain one event name (as listed in the @file{trace-events-all}
+file) per line; globbing patterns are accepted too. This option is only
+available if QEMU has been compiled with the @var{simple}, @var{stderr}
+or @var{ftrace} tracing backend. To specify multiple events or patterns,
+specify the @option{-trace} option multiple times.
+
+Use @code{-trace help} to print a list of names of trace points.
+
+@item events=@var{file}
+Immediately enable events listed in @var{file}.
+The file must contain one event name (as listed in the @file{trace-events-all}
+file) per line; globbing patterns are accepted too. This option is only
+available if QEMU has been compiled with the @var{simple}, @var{stderr} or
+@var{ftrace} tracing backend.
+
+@item file=@var{file}
+Log output traces to @var{file}.
+This option is only available if QEMU has been compiled with
+the @var{simple} tracing backend.
+@end table
diff --git a/qemu-options.hx b/qemu-options.hx
index 44c658fd4e..a95a936e55 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3669,34 +3669,9 @@ DEF("trace", HAS_ARG, QEMU_OPTION_trace,
STEXI
HXCOMM This line is not accurate, as some sub-options are backend-specific but
HXCOMM HX does not support conditional compilation of text.
-@item -trace [events=@var{file}][,file=@var{file}]
+@item -trace [[enable=]@var{pattern}][,events=@var{file}][,file=@var{file}]
@findex -trace
-
-Specify tracing options.
-
-@table @option
-@item [enable=]@var{pattern}
-Immediately enable events matching @var{pattern}.
-The file must contain one event name (as listed in the @file{trace-events-all}
-file) per line; globbing patterns are accepted too. This option is only
-available if QEMU has been compiled with the @var{simple}, @var{stderr}
-or @var{ftrace} tracing backend. To specify multiple events or patterns,
-specify the @option{-trace} option multiple times.
-
-Use @code{-trace help} to print a list of names of trace points.
-
-@item events=@var{file}
-Immediately enable events listed in @var{file}.
-The file must contain one event name (as listed in the @file{trace-events-all}
-file) per line; globbing patterns are accepted too. This option is only
-available if QEMU has been compiled with the @var{simple}, @var{stderr} or
-@var{ftrace} tracing backend.
-
-@item file=@var{file}
-Log output traces to @var{file}.
-This option is only available if QEMU has been compiled with
-the @var{simple} tracing backend.
-@end table
+@include qemu-option-trace.texi
ETEXI
HXCOMM Internal use
diff --git a/trace-events b/trace-events
index 9d76de8574..476705996b 100644
--- a/trace-events
+++ b/trace-events
@@ -156,3 +156,19 @@ memory_region_tb_write(int cpu_index, uint64_t addr, uint64_t value, unsigned si
#
# Targets: TCG(all)
disable vcpu tcg guest_mem_before(TCGv vaddr, uint8_t info) "info=%d", "vaddr=0x%016"PRIx64" info=%d"
+
+# @num: System call number.
+# @arg*: System call argument value.
+#
+# Start executing a guest system call in syscall emulation mode.
+#
+# Targets: TCG(all)
+disable vcpu guest_user_syscall(uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8) "num=0x%016"PRIx64" arg1=0x%016"PRIx64" arg2=0x%016"PRIx64" arg3=0x%016"PRIx64" arg4=0x%016"PRIx64" arg5=0x%016"PRIx64" arg6=0x%016"PRIx64" arg7=0x%016"PRIx64" arg8=0x%016"PRIx64
+
+# @num: System call number.
+# @ret: System call result value.
+#
+# Finish executing a guest system call in syscall emulation mode.
+#
+# Targets: TCG(all)
+disable vcpu guest_user_syscall_ret(uint64_t num, uint64_t ret) "num=0x%016"PRIx64" ret=0x%016"PRIx64
diff --git a/trace/control.c b/trace/control.c
index e1556a3570..86de8b9983 100644
--- a/trace/control.c
+++ b/trace/control.c
@@ -21,11 +21,33 @@
#endif
#include "qapi/error.h"
#include "qemu/error-report.h"
+#include "qemu/config-file.h"
#include "monitor/monitor.h"
int trace_events_enabled_count;
bool trace_events_dstate[TRACE_EVENT_COUNT];
+QemuOptsList qemu_trace_opts = {
+ .name = "trace",
+ .implied_opt_name = "enable",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
+ .desc = {
+ {
+ .name = "enable",
+ .type = QEMU_OPT_STRING,
+ },
+ {
+ .name = "events",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "file",
+ .type = QEMU_OPT_STRING,
+ },
+ { /* end of list */ }
+ },
+};
+
+
TraceEvent *trace_event_name(const char *name)
{
assert(name != NULL);
@@ -142,7 +164,7 @@ void trace_enable_events(const char *line_buf)
}
}
-void trace_init_events(const char *fname)
+static void trace_init_events(const char *fname)
{
Location loc;
FILE *fp;
@@ -217,3 +239,21 @@ bool trace_init_backends(void)
return true;
}
+
+char *trace_opt_parse(const char *optarg)
+{
+ char *trace_file;
+ QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("trace"),
+ optarg, true);
+ if (!opts) {
+ exit(1);
+ }
+ if (qemu_opt_get(opts, "enable")) {
+ trace_enable_events(qemu_opt_get(opts, "enable"));
+ }
+ trace_init_events(qemu_opt_get(opts, "events"));
+ trace_file = g_strdup(qemu_opt_get(opts, "file"));
+ qemu_opts_del(opts);
+
+ return trace_file;
+}
diff --git a/trace/control.h b/trace/control.h
index e2ba6d4de1..a2dd3eaedf 100644
--- a/trace/control.h
+++ b/trace/control.h
@@ -160,17 +160,6 @@ static void trace_event_set_state_dynamic(TraceEvent *ev, bool state);
bool trace_init_backends(void);
/**
- * trace_init_events:
- * @events: Name of file with events to be enabled at startup; may be NULL.
- * Corresponds to commandline option "-trace events=...".
- *
- * Read the list of enabled tracing events.
- *
- * Returns: Whether the backends could be successfully initialized.
- */
-void trace_init_events(const char *file);
-
-/**
* trace_init_file:
* @file: Name of trace output file; may be NULL.
* Corresponds to commandline option "-trace file=...".
@@ -197,6 +186,20 @@ void trace_list_events(void);
*/
void trace_enable_events(const char *line_buf);
+/**
+ * Definition of QEMU options describing trace subsystem configuration
+ */
+extern QemuOptsList qemu_trace_opts;
+
+/**
+ * trace_opt_parse:
+ * @optarg: A string argument of --trace command line argument
+ *
+ * Initialize tracing subsystem.
+ *
+ * Returns the filename to save trace to. It must be freed with g_free().
+ */
+char *trace_opt_parse(const char *optarg);
#include "trace/control-internal.h"
diff --git a/user-exec.c b/user-exec.c
index 50e95a68de..95f9f97c5c 100644
--- a/user-exec.c
+++ b/user-exec.c
@@ -117,14 +117,7 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
#if defined(__i386__)
-#if defined(__APPLE__)
-#include <sys/ucontext.h>
-
-#define EIP_sig(context) (*((unsigned long *)&(context)->uc_mcontext->ss.eip))
-#define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
-#define ERROR_sig(context) ((context)->uc_mcontext->es.err)
-#define MASK_sig(context) ((context)->uc_sigmask)
-#elif defined(__NetBSD__)
+#if defined(__NetBSD__)
#include <ucontext.h>
#define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP])
@@ -274,44 +267,6 @@ int cpu_signal_handler(int host_signum, void *pinfo,
#define TRAP_sig(context) ((context)->uc_mcontext.mc_exc)
#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
-#ifdef __APPLE__
-#include <sys/ucontext.h>
-typedef struct ucontext SIGCONTEXT;
-/* All Registers access - only for local access */
-#define REG_sig(reg_name, context) \
- ((context)->uc_mcontext->ss.reg_name)
-#define FLOATREG_sig(reg_name, context) \
- ((context)->uc_mcontext->fs.reg_name)
-#define EXCEPREG_sig(reg_name, context) \
- ((context)->uc_mcontext->es.reg_name)
-#define VECREG_sig(reg_name, context) \
- ((context)->uc_mcontext->vs.reg_name)
-/* Gpr Registers access */
-#define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
-/* Program counter */
-#define IAR_sig(context) REG_sig(srr0, context)
-/* Machine State Register (Supervisor) */
-#define MSR_sig(context) REG_sig(srr1, context)
-#define CTR_sig(context) REG_sig(ctr, context)
-/* Link register */
-#define XER_sig(context) REG_sig(xer, context)
-/* User's integer exception register */
-#define LR_sig(context) REG_sig(lr, context)
-/* Condition register */
-#define CR_sig(context) REG_sig(cr, context)
-/* Float Registers access */
-#define FLOAT_sig(reg_num, context) \
- FLOATREG_sig(fpregs[reg_num], context)
-#define FPSCR_sig(context) \
- ((double)FLOATREG_sig(fpscr, context))
-/* Exception Registers access */
-/* Fault registers for coredump */
-#define DAR_sig(context) EXCEPREG_sig(dar, context)
-#define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
-/* number of powerpc exception taken */
-#define TRAP_sig(context) EXCEPREG_sig(exception, context)
-#endif /* __APPLE__ */
-
int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
@@ -494,24 +449,6 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
is_write, &uc->uc_sigmask);
}
-#elif defined(__mc68000)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
- void *puc)
-{
- siginfo_t *info = pinfo;
- struct ucontext *uc = puc;
- unsigned long pc;
- int is_write;
-
- pc = uc->uc_mcontext.gregs[16];
- /* XXX: compute is_write */
- is_write = 0;
- return handle_cpu_signal(pc, (unsigned long)info->si_addr,
- is_write,
- &uc->uc_sigmask);
-}
-
#elif defined(__ia64)
#ifndef __ISR_VALID
@@ -616,48 +553,6 @@ int cpu_signal_handler(int host_signum, void *pinfo,
is_write, &uc->uc_sigmask);
}
-#elif defined(__hppa__)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
- void *puc)
-{
- siginfo_t *info = pinfo;
- struct ucontext *uc = puc;
- unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
- uint32_t insn = *(uint32_t *)pc;
- int is_write = 0;
-
- /* XXX: need kernel patch to get write flag faster. */
- switch (insn >> 26) {
- case 0x1a: /* STW */
- case 0x19: /* STH */
- case 0x18: /* STB */
- case 0x1b: /* STWM */
- is_write = 1;
- break;
-
- case 0x09: /* CSTWX, FSTWX, FSTWS */
- case 0x0b: /* CSTDX, FSTDX, FSTDS */
- /* Distinguish from coprocessor load ... */
- is_write = (insn >> 9) & 1;
- break;
-
- case 0x03:
- switch ((insn >> 6) & 15) {
- case 0xa: /* STWS */
- case 0x9: /* STHS */
- case 0x8: /* STBS */
- case 0xe: /* STWAS */
- case 0xc: /* STBYS */
- is_write = 1;
- }
- break;
- }
-
- return handle_cpu_signal(pc, (unsigned long)info->si_addr,
- is_write, &uc->uc_sigmask);
-}
-
#else
#error host CPU specific signal handler needed
diff --git a/vl.c b/vl.c
index 4c1f9aee1f..90cf638121 100644
--- a/vl.c
+++ b/vl.c
@@ -262,26 +262,6 @@ static QemuOptsList qemu_sandbox_opts = {
},
};
-static QemuOptsList qemu_trace_opts = {
- .name = "trace",
- .implied_opt_name = "enable",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
- .desc = {
- {
- .name = "enable",
- .type = QEMU_OPT_STRING,
- },
- {
- .name = "events",
- .type = QEMU_OPT_STRING,
- },{
- .name = "file",
- .type = QEMU_OPT_STRING,
- },
- { /* end of list */ }
- },
-};
-
static QemuOptsList qemu_option_rom_opts = {
.name = "option-rom",
.implied_opt_name = "romfile",
@@ -3864,23 +3844,9 @@ int main(int argc, char **argv, char **envp)
xen_mode = XEN_ATTACH;
break;
case QEMU_OPTION_trace:
- {
- opts = qemu_opts_parse_noisily(qemu_find_opts("trace"),
- optarg, true);
- if (!opts) {
- exit(1);
- }
- if (qemu_opt_get(opts, "enable")) {
- trace_enable_events(qemu_opt_get(opts, "enable"));
- }
- trace_init_events(qemu_opt_get(opts, "events"));
- if (trace_file) {
- g_free(trace_file);
- }
- trace_file = g_strdup(qemu_opt_get(opts, "file"));
- qemu_opts_del(opts);
+ g_free(trace_file);
+ trace_file = trace_opt_parse(optarg);
break;
- }
case QEMU_OPTION_readconfig:
{
int ret = qemu_read_config_file(optarg);