182 changes: 141 additions & 41 deletions linux-user/sparc/cpu_loop.c
Expand Up @@ -149,6 +149,69 @@ static void flush_windows(CPUSPARCState *env)
#endif
}

static void next_instruction(CPUSPARCState *env)
{
env->pc = env->npc;
env->npc = env->npc + 4;
}

static uint32_t do_getcc(CPUSPARCState *env)
{
#ifdef TARGET_SPARC64
return cpu_get_ccr(env) & 0xf;
#else
return extract32(cpu_get_psr(env), 20, 4);
#endif
}

static void do_setcc(CPUSPARCState *env, uint32_t icc)
{
#ifdef TARGET_SPARC64
cpu_put_ccr(env, (cpu_get_ccr(env) & 0xf0) | (icc & 0xf));
#else
cpu_put_psr(env, deposit32(cpu_get_psr(env), 20, 4, icc));
#endif
}

static uint32_t do_getpsr(CPUSPARCState *env)
{
#ifdef TARGET_SPARC64
const uint64_t TSTATE_CWP = 0x1f;
const uint64_t TSTATE_ICC = 0xfull << 32;
const uint64_t TSTATE_XCC = 0xfull << 36;
const uint32_t PSR_S = 0x00000080u;
const uint32_t PSR_V8PLUS = 0xff000000u;
uint64_t tstate = sparc64_tstate(env);

/* See <asm/psrcompat.h>, tstate_to_psr. */
return ((tstate & TSTATE_CWP) |
PSR_S |
((tstate & TSTATE_ICC) >> 12) |
((tstate & TSTATE_XCC) >> 20) |
PSR_V8PLUS);
#else
return (cpu_get_psr(env) & (PSR_ICC | PSR_CWP)) | PSR_S;
#endif
}

/* Avoid ifdefs below for the abi32 and abi64 paths. */
#ifdef TARGET_ABI32
#define TARGET_TT_SYSCALL (TT_TRAP + 0x10) /* t_linux */
#define syscall_cc psr
#else
#define TARGET_TT_SYSCALL (TT_TRAP + 0x6d) /* tl0_linux64 */
#define syscall_cc xcc
#endif

/* Avoid ifdefs below for the v9 and pre-v9 hw traps. */
#ifdef TARGET_SPARC64
#define TARGET_TT_SPILL TT_SPILL
#define TARGET_TT_FILL TT_FILL
#else
#define TARGET_TT_SPILL TT_WIN_OVF
#define TARGET_TT_FILL TT_WIN_UNF
#endif

void cpu_loop (CPUSPARCState *env)
{
CPUState *cs = env_cpu(env);
Expand All @@ -167,13 +230,7 @@ void cpu_loop (CPUSPARCState *env)
}

switch (trapnr) {
#ifndef TARGET_SPARC64
case 0x88:
case 0x90:
#else
case 0x110:
case 0x16d:
#endif
case TARGET_TT_SYSCALL:
ret = do_syscall (env, env->gregs[1],
env->regwptr[0], env->regwptr[1],
env->regwptr[2], env->regwptr[3],
Expand All @@ -183,67 +240,110 @@ void cpu_loop (CPUSPARCState *env)
break;
}
if ((abi_ulong)ret >= (abi_ulong)(-515)) {
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
env->xcc |= PSR_CARRY;
#else
env->psr |= PSR_CARRY;
#endif
env->syscall_cc |= PSR_CARRY;
ret = -ret;
} else {
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
env->xcc &= ~PSR_CARRY;
#else
env->psr &= ~PSR_CARRY;
#endif
env->syscall_cc &= ~PSR_CARRY;
}
env->regwptr[0] = ret;
/* next instruction */
env->pc = env->npc;
env->npc = env->npc + 4;
break;
case 0x83: /* flush windows */
#ifdef TARGET_ABI32
case 0x103:
#endif
flush_windows(env);
/* next instruction */
env->pc = env->npc;
env->npc = env->npc + 4;

case TT_TRAP + 0x01: /* breakpoint */
case EXCP_DEBUG:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
#ifndef TARGET_SPARC64
case TT_WIN_OVF: /* window overflow */
save_window(env);

case TT_TRAP + 0x02: /* div0 */
case TT_DIV_ZERO:
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
break;
case TT_WIN_UNF: /* window underflow */
restore_window(env);

case TT_TRAP + 0x03: /* flush windows */
flush_windows(env);
next_instruction(env);
break;
#else
case TT_SPILL: /* window overflow */
save_window(env);

case TT_TRAP + 0x20: /* getcc */
env->gregs[1] = do_getcc(env);
next_instruction(env);
break;
case TT_FILL: /* window underflow */
restore_window(env);
case TT_TRAP + 0x21: /* setcc */
do_setcc(env, env->gregs[1]);
next_instruction(env);
break;
case TT_TRAP + 0x22: /* getpsr */
env->gregs[1] = do_getpsr(env);
next_instruction(env);
break;
#ifndef TARGET_ABI32
case 0x16e:

#ifdef TARGET_SPARC64
case TT_TRAP + 0x6e:
flush_windows(env);
sparc64_get_context(env);
break;
case 0x16f:
case TT_TRAP + 0x6f:
flush_windows(env);
sparc64_set_context(env);
break;
#endif
#endif

case TARGET_TT_SPILL: /* window overflow */
save_window(env);
break;
case TARGET_TT_FILL: /* window underflow */
restore_window(env);
break;

case TT_FP_EXCP:
{
int code = TARGET_FPE_FLTUNK;
target_ulong fsr = env->fsr;

if ((fsr & FSR_FTT_MASK) == FSR_FTT_IEEE_EXCP) {
if (fsr & FSR_NVC) {
code = TARGET_FPE_FLTINV;
} else if (fsr & FSR_OFC) {
code = TARGET_FPE_FLTOVF;
} else if (fsr & FSR_UFC) {
code = TARGET_FPE_FLTUND;
} else if (fsr & FSR_DZC) {
code = TARGET_FPE_FLTDIV;
} else if (fsr & FSR_NXC) {
code = TARGET_FPE_FLTRES;
}
}
force_sig_fault(TARGET_SIGFPE, code, env->pc);
}
break;

case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
case TT_ILL_INSN:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc);
break;
case EXCP_DEBUG:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
case TT_PRIV_INSN:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc);
break;
case TT_TOVF:
force_sig_fault(TARGET_SIGEMT, TARGET_EMT_TAGOVF, env->pc);
break;
#ifdef TARGET_SPARC64
case TT_PRIV_ACT:
/* Note do_privact defers to do_privop. */
force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc);
break;
#else
case TT_NCP_INSN:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_COPROC, env->pc);
break;
case TT_UNIMP_FLUSH:
next_instruction(env);
break;
#endif
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
Expand Down
36 changes: 19 additions & 17 deletions linux-user/sparc/signal.c
Expand Up @@ -503,7 +503,23 @@ long do_rt_sigreturn(CPUSPARCState *env)
return -QEMU_ESIGRETURN;
}

#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
#ifdef TARGET_ABI32
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
assert(tramp != NULL);

default_sigreturn = sigtramp_page;
install_sigtramp(tramp, TARGET_NR_sigreturn);

default_rt_sigreturn = sigtramp_page + 8;
install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn);

unlock_user(tramp, sigtramp_page, 2 * 8);
}
#endif

#ifdef TARGET_SPARC64
#define SPARC_MC_TSTATE 0
#define SPARC_MC_PC 1
#define SPARC_MC_NPC 2
Expand Down Expand Up @@ -575,7 +591,7 @@ void sparc64_set_context(CPUSPARCState *env)
struct target_ucontext *ucp;
target_mc_gregset_t *grp;
target_mc_fpu_t *fpup;
abi_ulong pc, npc, tstate;
target_ulong pc, npc, tstate;
unsigned int i;
unsigned char fenab;

Expand Down Expand Up @@ -773,18 +789,4 @@ void sparc64_get_context(CPUSPARCState *env)
unlock_user_struct(ucp, ucp_addr, 1);
force_sig(TARGET_SIGSEGV);
}
#else
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
assert(tramp != NULL);

default_sigreturn = sigtramp_page;
install_sigtramp(tramp, TARGET_NR_sigreturn);

default_rt_sigreturn = sigtramp_page + 8;
install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn);

unlock_user(tramp, sigtramp_page, 2 * 8);
}
#endif
#endif /* TARGET_SPARC64 */
2 changes: 1 addition & 1 deletion linux-user/sparc/target_signal.h
Expand Up @@ -8,7 +8,7 @@
#define TARGET_SIGTRAP 5
#define TARGET_SIGABRT 6
#define TARGET_SIGIOT 6
#define TARGET_SIGSTKFLT 7 /* actually EMT */
#define TARGET_SIGEMT 7
#define TARGET_SIGFPE 8
#define TARGET_SIGKILL 9
#define TARGET_SIGBUS 10
Expand Down
109 changes: 105 additions & 4 deletions linux-user/strace.c
Expand Up @@ -81,6 +81,7 @@ 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_raw_param64(const char *, long long, int last);
UNUSED static void print_timeval(abi_ulong, int);
UNUSED static void print_timespec(abi_ulong, int);
UNUSED static void print_timespec64(abi_ulong, int);
Expand Down Expand Up @@ -1115,6 +1116,7 @@ UNUSED static const struct flags clone_flags[] = {
FLAG_GENERIC(CLONE_FS),
FLAG_GENERIC(CLONE_FILES),
FLAG_GENERIC(CLONE_SIGHAND),
FLAG_GENERIC(CLONE_PIDFD),
FLAG_GENERIC(CLONE_PTRACE),
FLAG_GENERIC(CLONE_VFORK),
FLAG_GENERIC(CLONE_PARENT),
Expand Down Expand Up @@ -1642,6 +1644,19 @@ print_raw_param(const char *fmt, abi_long param, int last)
qemu_log(format, param);
}

/*
* Same as print_raw_param() but prints out raw 64-bit parameter.
*/
static void
print_raw_param64(const char *fmt, long long param, int last)
{
char format[64];

(void) snprintf(format, sizeof (format), "%s%s", fmt, get_comma(last));
qemu_log(format, param);
}


static void
print_pointer(abi_long p, int last)
{
Expand Down Expand Up @@ -1718,10 +1733,8 @@ print_timespec64(abi_ulong ts_addr, int last)
print_pointer(ts_addr, last);
return;
}
qemu_log("{tv_sec = %lld"
",tv_nsec = %lld}%s",
(long long)tswap64(ts->tv_sec), (long long)tswap64(ts->tv_nsec),
get_comma(last));
print_raw_param64("{tv_sec=%" PRId64, tswap64(ts->tv_sec), 0);
print_raw_param64("tv_nsec=%" PRId64 "}", tswap64(ts->tv_nsec), last);
unlock_user(ts, ts_addr, 0);
} else {
qemu_log("NULL%s", get_comma(last));
Expand Down Expand Up @@ -3854,6 +3867,94 @@ print_futex(CPUArchState *cpu_env, const struct syscallname *name,
}
#endif

#ifdef TARGET_NR_prlimit64
static const char *target_ressource_string(abi_ulong r)
{
#define RET_RES_ENTRY(res) case TARGET_##res: return #res;
switch (r) {
RET_RES_ENTRY(RLIMIT_AS);
RET_RES_ENTRY(RLIMIT_CORE);
RET_RES_ENTRY(RLIMIT_CPU);
RET_RES_ENTRY(RLIMIT_DATA);
RET_RES_ENTRY(RLIMIT_FSIZE);
RET_RES_ENTRY(RLIMIT_LOCKS);
RET_RES_ENTRY(RLIMIT_MEMLOCK);
RET_RES_ENTRY(RLIMIT_MSGQUEUE);
RET_RES_ENTRY(RLIMIT_NICE);
RET_RES_ENTRY(RLIMIT_NOFILE);
RET_RES_ENTRY(RLIMIT_NPROC);
RET_RES_ENTRY(RLIMIT_RSS);
RET_RES_ENTRY(RLIMIT_RTPRIO);
#ifdef RLIMIT_RTTIME
RET_RES_ENTRY(RLIMIT_RTTIME);
#endif
RET_RES_ENTRY(RLIMIT_SIGPENDING);
RET_RES_ENTRY(RLIMIT_STACK);
default:
return NULL;
}
#undef RET_RES_ENTRY
}

static void
print_rlimit64(abi_ulong rlim_addr, int last)
{
if (rlim_addr) {
struct target_rlimit64 *rl;

rl = lock_user(VERIFY_READ, rlim_addr, sizeof(*rl), 1);
if (!rl) {
print_pointer(rlim_addr, last);
return;
}
print_raw_param64("{rlim_cur=%" PRId64, tswap64(rl->rlim_cur), 0);
print_raw_param64("rlim_max=%" PRId64 "}", tswap64(rl->rlim_max),
last);
unlock_user(rl, rlim_addr, 0);
} else {
qemu_log("NULL%s", get_comma(last));
}
}

static void
print_prlimit64(CPUArchState *cpu_env, const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,
abi_long arg3, abi_long arg4, abi_long arg5)
{
const char *rlim_name;

print_syscall_prologue(name);
print_raw_param("%d", arg0, 0);
rlim_name = target_ressource_string(arg1);
if (rlim_name) {
qemu_log("%s,", rlim_name);
} else {
print_raw_param("%d", arg1, 0);
}
print_rlimit64(arg2, 0);
print_pointer(arg3, 1);
print_syscall_epilogue(name);
}

static void
print_syscall_ret_prlimit64(CPUArchState *cpu_env,
const struct syscallname *name,
abi_long ret, abi_long arg0, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5)
{
if (!print_syscall_err(ret)) {
qemu_log(TARGET_ABI_FMT_ld, ret);
if (arg3) {
qemu_log(" (");
print_rlimit64(arg3, 1);
qemu_log(")");
}
}
qemu_log("\n");
}
#endif

#ifdef TARGET_NR_kill
static void
print_kill(CPUArchState *cpu_env, const struct syscallname *name,
Expand Down
5 changes: 3 additions & 2 deletions linux-user/strace.list
Expand Up @@ -656,7 +656,7 @@
{ TARGET_NR_msgsnd, "msgsnd" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_msync
{ TARGET_NR_msync, "msync" , NULL, NULL, NULL },
{ TARGET_NR_msync, "msync" , "%s(%p,%u,%d)", NULL, NULL },
#endif
#ifdef TARGET_NR_multiplexer
{ TARGET_NR_multiplexer, "multiplexer" , NULL, NULL, NULL },
Expand Down Expand Up @@ -1074,7 +1074,8 @@
{ TARGET_NR_preadv, "preadv" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_prlimit64
{ TARGET_NR_prlimit64, "prlimit64" , NULL, NULL, NULL },
{ TARGET_NR_prlimit64, "prlimit64" , NULL, print_prlimit64,
print_syscall_ret_prlimit64 },
#endif
#ifdef TARGET_NR_process_vm_readv
{ TARGET_NR_process_vm_readv, "process_vm_readv" , NULL, NULL, NULL },
Expand Down
166 changes: 100 additions & 66 deletions linux-user/syscall.c
Expand Up @@ -22,6 +22,7 @@
#include "qemu/path.h"
#include "qemu/memfd.h"
#include "qemu/queue.h"
#include "target_mman.h"
#include <elf.h>
#include <endian.h>
#include <grp.h>
Expand Down Expand Up @@ -170,7 +171,7 @@

/* Flags for fork which we can implement within QEMU itself */
#define CLONE_OPTIONAL_FORK_FLAGS \
(CLONE_SETTLS | CLONE_PARENT_SETTID | \
(CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_PIDFD | \
CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID)

/* Flags for thread creation which we can implement within QEMU itself */
Expand Down Expand Up @@ -795,49 +796,52 @@ static inline int host_to_target_sock_type(int host_type)
}

static abi_ulong target_brk;
static abi_ulong target_original_brk;
static abi_ulong brk_page;

void target_set_brk(abi_ulong new_brk)
{
target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
target_brk = new_brk;
brk_page = HOST_PAGE_ALIGN(target_brk);
}

//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
#define DEBUGF_BRK(message, args...)

/* do_brk() must return target values and target errnos. */
abi_long do_brk(abi_ulong new_brk)
abi_long do_brk(abi_ulong brk_val)
{
abi_long mapped_addr;
abi_ulong new_alloc_size;
abi_ulong new_brk, new_host_brk_page;

/* brk pointers are always untagged */

DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);

if (!new_brk) {
DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
/* return old brk value if brk_val unchanged or zero */
if (!brk_val || brk_val == target_brk) {
return target_brk;
}
if (new_brk < target_original_brk) {
DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
target_brk);

new_brk = TARGET_PAGE_ALIGN(brk_val);
new_host_brk_page = HOST_PAGE_ALIGN(brk_val);

/* brk_val and old target_brk might be on the same page */
if (new_brk == TARGET_PAGE_ALIGN(target_brk)) {
if (brk_val > target_brk) {
/* empty remaining bytes in (possibly larger) host page */
memset(g2h_untagged(target_brk), 0, new_host_brk_page - target_brk);
}
target_brk = brk_val;
return target_brk;
}

/* If the new brk is less than the highest page reserved to the
* target heap allocation, set it and we're almost done... */
if (new_brk <= brk_page) {
/* Heap contents are initialized to zero, as for anonymous
* mapped pages. */
if (new_brk > target_brk) {
memset(g2h_untagged(target_brk), 0, new_brk - target_brk);
}
target_brk = new_brk;
DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
return target_brk;
/* Release heap if necesary */
if (new_brk < target_brk) {
/* empty remaining bytes in (possibly larger) host page */
memset(g2h_untagged(brk_val), 0, new_host_brk_page - brk_val);

/* free unused host pages and set new brk_page */
target_munmap(new_host_brk_page, brk_page - new_host_brk_page);
brk_page = new_host_brk_page;

target_brk = brk_val;
return target_brk;
}

/* We need to allocate more memory after the brk... Note that
Expand All @@ -846,10 +850,14 @@ abi_long do_brk(abi_ulong new_brk)
* itself); instead we treat "mapped but at wrong address" as
* a failure and unmap again.
*/
new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
new_alloc_size = new_host_brk_page - brk_page;
if (new_alloc_size) {
mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_PRIVATE, 0, 0));
} else {
mapped_addr = brk_page;
}

if (mapped_addr == brk_page) {
/* Heap contents are initialized to zero, as for anonymous
Expand All @@ -861,21 +869,15 @@ abi_long do_brk(abi_ulong new_brk)
* then shrunken). */
memset(g2h_untagged(target_brk), 0, brk_page - target_brk);

target_brk = new_brk;
brk_page = HOST_PAGE_ALIGN(target_brk);
DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
target_brk);
target_brk = brk_val;
brk_page = new_host_brk_page;
return target_brk;
} else if (mapped_addr != -1) {
/* Mapped but at wrong address, meaning there wasn't actually
* enough space for this brk.
*/
target_munmap(mapped_addr, new_alloc_size);
mapped_addr = -1;
DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
}
else {
DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
}

#if defined(TARGET_ALPHA)
Expand Down Expand Up @@ -1713,6 +1715,11 @@ static inline abi_long target_to_host_sockaddr(int fd, struct sockaddr *addr,
lladdr = (struct target_sockaddr_ll *)addr;
lladdr->sll_ifindex = tswap32(lladdr->sll_ifindex);
lladdr->sll_hatype = tswap16(lladdr->sll_hatype);
} else if (sa_family == AF_INET6) {
struct sockaddr_in6 *in6addr;

in6addr = (struct sockaddr_in6 *)addr;
in6addr->sin6_scope_id = tswap32(in6addr->sin6_scope_id);
}
unlock_user(target_saddr, target_addr, 0);

Expand Down Expand Up @@ -6723,6 +6730,17 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
return -TARGET_EINVAL;
}

#if !defined(__NR_pidfd_open) || !defined(TARGET_NR_pidfd_open)
if (flags & CLONE_PIDFD) {
return -TARGET_EINVAL;
}
#endif

/* Can not allow CLONE_PIDFD with CLONE_PARENT_SETTID */
if ((flags & CLONE_PIDFD) && (flags & CLONE_PARENT_SETTID)) {
return -TARGET_EINVAL;
}

if (block_signals()) {
return -QEMU_ERESTARTSYS;
}
Expand Down Expand Up @@ -6750,6 +6768,20 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
ts->child_tidptr = child_tidptr;
} else {
cpu_clone_regs_parent(env, flags);
if (flags & CLONE_PIDFD) {
int pid_fd = 0;
#if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open)
int pid_child = ret;
pid_fd = pidfd_open(pid_child, 0);
if (pid_fd >= 0) {
fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL)
| FD_CLOEXEC);
} else {
pid_fd = 0;
}
#endif
put_user_u32(pid_fd, parent_tidptr);
}
fork_end(0);
}
g_assert(!cpu_in_exclusive_context(cpu));
Expand Down Expand Up @@ -7606,6 +7638,14 @@ static inline int target_to_host_mlockall_arg(int arg)
}
#endif

static inline int target_to_host_msync_arg(abi_long arg)
{
return ((arg & TARGET_MS_ASYNC) ? MS_ASYNC : 0) |
((arg & TARGET_MS_INVALIDATE) ? MS_INVALIDATE : 0) |
((arg & TARGET_MS_SYNC) ? MS_SYNC : 0) |
(arg & ~(TARGET_MS_ASYNC | TARGET_MS_INVALIDATE | TARGET_MS_SYNC));
}

#if (defined(TARGET_NR_stat64) || defined(TARGET_NR_lstat64) || \
defined(TARGET_NR_fstat64) || defined(TARGET_NR_fstatat64) || \
defined(TARGET_NR_newfstatat))
Expand Down Expand Up @@ -8079,6 +8119,9 @@ static int open_self_stat(CPUArchState *cpu_env, int fd)
gchar *bin = g_strrstr(ts->bprm->argv[0], "/");
bin = bin ? bin + 1 : ts->bprm->argv[0];
g_string_printf(buf, "(%.15s) ", bin);
} else if (i == 2) {
/* task state */
g_string_assign(buf, "R "); /* we are running right now */
} else if (i == 3) {
/* ppid */
g_string_printf(buf, FMT_pid " ", getppid());
Expand Down Expand Up @@ -9989,18 +10032,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
/* Short circuit this for the magic exe check. */
ret = -TARGET_EINVAL;
} else if (is_proc_myself((const char *)p, "exe")) {
char real[PATH_MAX], *temp;
temp = realpath(exec_path, real);
/* Return value is # of bytes that we wrote to the buffer. */
if (temp == NULL) {
ret = get_errno(-1);
} else {
/* Don't worry about sign mismatch as earlier mapping
* logic would have thrown a bad address error. */
ret = MIN(strlen(real), arg3);
/* We cannot NUL terminate the string. */
memcpy(p2, real, ret);
}
/* Don't worry about sign mismatch as earlier mapping
* logic would have thrown a bad address error. */
ret = MIN(strlen(exec_path), arg3);
/* We cannot NUL terminate the string. */
memcpy(p2, exec_path, ret);
} else {
ret = get_errno(readlink(path(p), p2, arg3));
}
Expand All @@ -10021,18 +10057,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
/* Short circuit this for the magic exe check. */
ret = -TARGET_EINVAL;
} else if (is_proc_myself((const char *)p, "exe")) {
char real[PATH_MAX], *temp;
temp = realpath(exec_path, real);
/* Return value is # of bytes that we wrote to the buffer. */
if (temp == NULL) {
ret = get_errno(-1);
} else {
/* Don't worry about sign mismatch as earlier mapping
* logic would have thrown a bad address error. */
ret = MIN(strlen(real), arg4);
/* We cannot NUL terminate the string. */
memcpy(p2, real, ret);
}
/* Don't worry about sign mismatch as earlier mapping
* logic would have thrown a bad address error. */
ret = MIN(strlen(exec_path), arg4);
/* We cannot NUL terminate the string. */
memcpy(p2, exec_path, ret);
} else {
ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
}
Expand Down Expand Up @@ -10129,7 +10158,8 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
/* ??? msync/mlock/munlock are broken for softmmu. */
#ifdef TARGET_NR_msync
case TARGET_NR_msync:
return get_errno(msync(g2h(cpu, arg1), arg2, arg3));
return get_errno(msync(g2h(cpu, arg1), arg2,
target_to_host_msync_arg(arg3)));
#endif
#ifdef TARGET_NR_mlock
case TARGET_NR_mlock:
Expand Down Expand Up @@ -12886,8 +12916,8 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
return -TARGET_EFAULT;
}
rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
rnew.rlim_max = tswap64(target_rnew->rlim_max);
__get_user(rnew.rlim_cur, &target_rnew->rlim_cur);
__get_user(rnew.rlim_max, &target_rnew->rlim_max);
unlock_user_struct(target_rnew, arg3, 0);
rnewp = &rnew;
}
Expand All @@ -12897,8 +12927,8 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
return -TARGET_EFAULT;
}
target_rold->rlim_cur = tswap64(rold.rlim_cur);
target_rold->rlim_max = tswap64(rold.rlim_max);
__put_user(rold.rlim_cur, &target_rold->rlim_cur);
__put_user(rold.rlim_max, &target_rold->rlim_max);
unlock_user_struct(target_rold, arg4, 1);
}
return ret;
Expand Down Expand Up @@ -13118,8 +13148,12 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,

#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
case TARGET_NR_timerfd_create:
return get_errno(timerfd_create(arg1,
target_to_host_bitmask(arg2, fcntl_flags_tbl)));
ret = get_errno(timerfd_create(arg1,
target_to_host_bitmask(arg2, fcntl_flags_tbl)));
if (ret >= 0) {
fd_trans_register(ret, &target_timerfd_trans);
}
return ret;
#endif

#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
Expand Down
5 changes: 5 additions & 0 deletions linux-user/syscall_defs.h
Expand Up @@ -717,6 +717,11 @@ typedef struct target_siginfo {
#define TARGET_TRAP_HWBKPT (4) /* hardware breakpoint/watchpoint */
#define TARGET_TRAP_UNK (5) /* undiagnosed trap */

/*
* SIGEMT si_codes
*/
#define TARGET_EMT_TAGOVF 1 /* tag overflow */

#include "target_resource.h"

struct target_pollfd {
Expand Down
3 changes: 1 addition & 2 deletions target/sparc/cpu.h
Expand Up @@ -197,8 +197,7 @@ enum {
#define FSR_FTT2 (1ULL << 16)
#define FSR_FTT1 (1ULL << 15)
#define FSR_FTT0 (1ULL << 14)
//gcc warns about constant overflow for ~FSR_FTT_MASK
//#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
#ifdef TARGET_SPARC64
#define FSR_FTT_NMASK 0xfffffffffffe3fffULL
#define FSR_FTT_CEXC_NMASK 0xfffffffffffe3fe0ULL
Expand Down