diff options
author | Paul Burton <paul@archlinuxmips.org> | 2014-06-22 11:25:33 +0100 |
---|---|---|
committer | Riku Voipio <riku.voipio@linaro.org> | 2014-06-29 14:19:58 +0300 |
commit | 8289d112811adfd609c1e3d855427a96418564b0 (patch) | |
tree | 2847284d80a3a6d03764baa7ec1faaedde010093 /linux-user | |
parent | 76b94245507881a0621c5bb3b144c3c19dcbcb4d (diff) |
linux-user: translate the result of getsockopt SO_TYPE
QEMU previously passed the result of the host syscall directly to the
target program. This is a problem if the host & target have different
representations of socket types, as is the case when running a MIPS
target program on an x86 host. Introduce a host_to_target_sock_type
helper function mirroring the existing target_to_host_sock_type, and
call it to translate the value provided by getsockopt when called for
the SO_TYPE option.
Signed-off-by: Paul Burton <paul@archlinuxmips.org>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/syscall.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5c175ba13a..8d13781bf8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -592,6 +592,37 @@ char *target_strerror(int err) return strerror(target_to_host_errno(err)); } +static inline int host_to_target_sock_type(int host_type) +{ + int target_type; + + switch (host_type & 0xf /* SOCK_TYPE_MASK */) { + case SOCK_DGRAM: + target_type = TARGET_SOCK_DGRAM; + break; + case SOCK_STREAM: + target_type = TARGET_SOCK_STREAM; + break; + default: + target_type = host_type & 0xf /* SOCK_TYPE_MASK */; + break; + } + +#if defined(SOCK_CLOEXEC) + if (host_type & SOCK_CLOEXEC) { + target_type |= TARGET_SOCK_CLOEXEC; + } +#endif + +#if defined(SOCK_NONBLOCK) + if (host_type & SOCK_NONBLOCK) { + target_type |= TARGET_SOCK_NONBLOCK; + } +#endif + + return target_type; +} + static abi_ulong target_brk; static abi_ulong target_original_brk; static abi_ulong brk_page; @@ -1636,6 +1667,9 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); if (ret < 0) return ret; + if (optname == SO_TYPE) { + val = host_to_target_sock_type(val); + } if (len > lv) len = lv; if (len == 4) { |