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:
Peter Maydell 2016-06-29 10:43:07 +01:00
commit 3e904d6ade
27 changed files with 1643 additions and 331 deletions

View File

@ -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/

8
configure vendored
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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 },

View File

@ -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);

View File

@ -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)

View File

@ -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