diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5ef5176135..0eab5cc6ad 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3386,6 +3386,23 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, return ret; } +/* Convert target low/high pair representing file offset into the host + * low/high pair. This function doesn't handle offsets bigger than 64 bits + * as the kernel doesn't handle them either. + */ +static void target_to_host_low_high(abi_ulong tlow, + abi_ulong thigh, + unsigned long *hlow, + unsigned long *hhigh) +{ + uint64_t off = tlow | + ((unsigned long long)thigh << TARGET_LONG_BITS / 2) << + TARGET_LONG_BITS / 2; + + *hlow = off; + *hhigh = (off >> HOST_LONG_BITS / 2) >> HOST_LONG_BITS / 2; +} + static struct iovec *lock_iovec(int type, abi_ulong target_addr, abi_ulong count, int copy) { @@ -10449,7 +10466,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0); if (vec != NULL) { - ret = get_errno(safe_preadv(arg1, vec, arg3, arg4, arg5)); + unsigned long low, high; + + target_to_host_low_high(arg4, arg5, &low, &high); + ret = get_errno(safe_preadv(arg1, vec, arg3, low, high)); unlock_iovec(vec, arg2, arg3, 1); } else { ret = -host_to_target_errno(errno); @@ -10462,7 +10482,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1); if (vec != NULL) { - ret = get_errno(safe_pwritev(arg1, vec, arg3, arg4, arg5)); + unsigned long low, high; + + target_to_host_low_high(arg4, arg5, &low, &high); + ret = get_errno(safe_pwritev(arg1, vec, arg3, low, high)); unlock_iovec(vec, arg2, arg3, 0); } else { ret = -host_to_target_errno(errno);