mirror of https://github.com/xemu-project/xemu.git
Drop building linux-user targets on HPPA or m68k host systems
and add safe_syscall support for i386, aarch64, arm, ppc64 and s390x. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIVAwUAV3LCdLRIkN7ePJvAAQhVsQ/6AjcR308zzZzJAhYnk7eQYl7pQLpqokbl XDdZqXZf3qts5z9CUNZGxoCesPb+MTxIRWGZy13QHeJ3hcewMegcZny7b9xN2OaP SNRbPhkIZe9p+ImI2sZ4Unnb4NFssGdB/9e4I5aQQovrnXbbZqT3tAHqwoPwaI6c N4ub+HYkIqd7MnRG00PLdLbbrzMVIpbwENYxnb6AwBgYDsE01QL6USsyRVoSGK3i AHJz5jg/KiTaQJs4Bk8/NmrbfCnVtGpVz03FWsClm1LZ9BO3fpiHajbd9TNPhh3O v+M5S1UyCejvy+CiyZsIJnq29pYFJF1Yj+IviowQnwIRdSYtz9KI241UXdlrlVYK Ooadukgsgur+fNKl3I0SxGAqkDbRN3yjy6sCiRJSNNTuV2DWF92XPlrIBNVFQ0rP p4o2ZhuS9euerfuQ2bu8qFgAV/vyBA2A6XCY0NZYbYgZ/dwVqmuyvtTyPZhsy7Rq QvsOYKwmWkCM3FDY6oiJBNAwo/jOl28FR4WmtqbjEgtTgelZibW2HPVNc769XujG +qN+bphgyHUnSIMYcxS2csMsx6FjFz4Kst8TWbXTWG7HzlEbC73ShbQjS6MVDZ7H h0XbbQ8gWxLl540xLFv8BcjlXUSOth1iNtraWq60lwphhuT5lr1sMu+bu+27SPXm k3cNZHml3vY= =zonM -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/riku/tags/pull-linux-user-20160628' into staging Drop building linux-user targets on HPPA or m68k host systems and add safe_syscall support for i386, aarch64, arm, ppc64 and s390x. # gpg: Signature made Tue 28 Jun 2016 19:31:16 BST # gpg: using RSA key 0xB44890DEDE3C9BC0 # gpg: Good signature from "Riku Voipio <riku.voipio@iki.fi>" # gpg: aka "Riku Voipio <riku.voipio@linaro.org>" # Primary key fingerprint: FF82 03C8 C391 98AE 0581 41EF B448 90DE DE3C 9BC0 * remotes/riku/tags/pull-linux-user-20160628: (24 commits) linux-user: Provide safe_syscall for ppc64 linux-user: Provide safe_syscall for s390x linux-user: Provide safe_syscall for aarch64 linux-user: Provide safe_syscall for arm linux-user: Provide safe_syscall for i386 linux-user: fix x86_64 safe_syscall linux-user: don't swap NLMSG_DATA() fields linux-user: fd_trans_host_to_target_data() must process only received data linux-user: add missing return in netlink switch statement linux-user: update get_thread_area/set_thread_area strace linux-user: fix clone() strace linux-user: add socket() strace linux-user: add socketcall() strace linux-user: Support F_GETPIPE_SZ and F_SETPIPE_SZ fcntls linux-user: Fix wrong type used for argument to rt_sigqueueinfo linux-user: Create a hostdep.h for each host architecture user-exec: Remove unused code for OSX hosts user-exec: Delete now-unused hppa and m68k cpu_signal_handler() code configure: Don't allow user-only targets for unknown CPU architectures configure: Don't override ARCH=unknown if enabling TCI ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
3e904d6ade
|
@ -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/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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 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 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 flock fl;
|
||||
struct target_flock *target_fl;
|
||||
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;
|
||||
|
@ -7783,8 +7895,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 +10247,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 +10265,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);
|
||||
|
|
|
@ -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)
|
||||
|
|
107
user-exec.c
107
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
|
||||
|
|
Loading…
Reference in New Issue