* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
-#include <sys/mman.h>
+#include "qemu-version.h"
#include <sys/syscall.h>
#include <sys/resource.h>
+#include "qapi/error.h"
#include "qemu.h"
#include "qemu/path.h"
+#include "qemu/config-file.h"
#include "qemu/cutils.h"
#include "qemu/help_option.h"
#include "cpu.h"
#include "qemu/envlist.h"
#include "elf.h"
#include "exec/log.h"
+#include "trace/control.h"
+#include "glib-compat.h"
char *exec_path;
Discard information about the parent threads. */
CPU_FOREACH_SAFE(cpu, next_cpu) {
if (cpu != thread_cpu) {
- QTAILQ_REMOVE(&cpus, thread_cpu, node);
+ QTAILQ_REMOVE(&cpus, cpu, node);
}
}
pending_cpus = 0;
}
/* Start an exclusive operation.
- Must only be called from outside cpu_arm_exec. */
+ Must only be called from outside cpu_exec. */
static inline void start_exclusive(void)
{
CPUState *other_cpu;
CPUState *cs = CPU(x86_env_get_cpu(env));
int trapnr;
abi_ulong pc;
+ abi_ulong ret;
target_siginfo_t info;
for(;;) {
cpu_exec_start(cs);
- trapnr = cpu_x86_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch(trapnr) {
case 0x80:
/* linux syscall from int $0x80 */
- env->regs[R_EAX] = do_syscall(env,
- env->regs[R_EAX],
- env->regs[R_EBX],
- env->regs[R_ECX],
- env->regs[R_EDX],
- env->regs[R_ESI],
- env->regs[R_EDI],
- env->regs[R_EBP],
- 0, 0);
+ ret = do_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EBX],
+ env->regs[R_ECX],
+ env->regs[R_EDX],
+ env->regs[R_ESI],
+ env->regs[R_EDI],
+ env->regs[R_EBP],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->eip -= 2;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[R_EAX] = ret;
+ }
break;
#ifndef TARGET_ABI32
case EXCP_SYSCALL:
/* linux syscall from syscall instruction */
- env->regs[R_EAX] = do_syscall(env,
- env->regs[R_EAX],
- env->regs[R_EDI],
- env->regs[R_ESI],
- env->regs[R_EDX],
- env->regs[10],
- env->regs[8],
- env->regs[9],
- 0, 0);
+ ret = do_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EDI],
+ env->regs[R_ESI],
+ env->regs[R_EDX],
+ env->regs[10],
+ env->regs[8],
+ env->regs[9],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->eip -= 2;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[R_EAX] = ret;
+ }
break;
#endif
case EXCP0B_NOSEG:
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP0D_GPF:
/* XXX: potential problem if ABI32 */
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP0E_PAGE:
else
info.si_code = TARGET_SEGV_ACCERR;
info._sifields._sigfault._addr = env->cr[2];
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP00_DIVZ:
#ifndef TARGET_X86_64
info.si_errno = 0;
info.si_code = TARGET_FPE_INTDIV;
info._sifields._sigfault._addr = env->eip;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP01_DB:
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
}
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP04_INTO:
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP06_ILLOP:
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->eip;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
}
break;
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->exception.vaddress;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
/* Handle a jump to the kernel code page. */
unsigned int n, insn;
target_siginfo_t info;
uint32_t addr;
+ abi_ulong ret;
for(;;) {
cpu_exec_start(cs);
- trapnr = cpu_arm_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch(trapnr) {
case EXCP_UDEF:
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->regs[15];
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
} else if (rc < 0) { /* FP exception */
int arm_fpe=0;
if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV;
info._sifields._sigfault._addr = env->regs[15];
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
} else {
env->regs[15] += 4;
}
break;
}
} else {
- env->regs[0] = do_syscall(env,
- n,
- env->regs[0],
- env->regs[1],
- env->regs[2],
- env->regs[3],
- env->regs[4],
- env->regs[5],
- 0, 0);
+ ret = do_syscall(env,
+ n,
+ env->regs[0],
+ env->regs[1],
+ env->regs[2],
+ env->regs[3],
+ env->regs[4],
+ env->regs[5],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->regs[15] -= env->thumb ? 2 : 4;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[0] = ret;
+ }
}
} else {
goto error;
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = addr;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP_DEBUG:
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
}
break;
{
CPUState *cs = CPU(arm_env_get_cpu(env));
int trapnr, sig;
+ abi_long ret;
target_siginfo_t info;
for (;;) {
cpu_exec_start(cs);
- trapnr = cpu_arm_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
case EXCP_SWI:
- env->xregs[0] = do_syscall(env,
- env->xregs[8],
- env->xregs[0],
- env->xregs[1],
- env->xregs[2],
- env->xregs[3],
- env->xregs[4],
- env->xregs[5],
- 0, 0);
+ ret = do_syscall(env,
+ env->xregs[8],
+ env->xregs[0],
+ env->xregs[1],
+ env->xregs[2],
+ env->xregs[3],
+ env->xregs[4],
+ env->xregs[5],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 4;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->xregs[0] = ret;
+ }
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_STREX:
if (!do_strex_a64(env)) {
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->exception.vaddress;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_DEBUG:
case EXCP_BKPT:
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP_SEMIHOST:
for (;;) {
cpu_exec_start(cs);
- trapnr = uc32_cpu_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
case UC32_EXCP_PRIV:
cpu_set_tls(env, env->regs[0]);
env->regs[0] = 0;
} else {
- env->regs[0] = do_syscall(env,
+ abi_long ret = do_syscall(env,
n,
env->regs[0],
env->regs[1],
env->regs[4],
env->regs[5],
0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->regs[31] -= 4;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[0] = ret;
+ }
}
} else {
goto error;
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->cp0.c4_faultaddr;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
}
break;
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_sparc_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
/* Compute PSR before exposing state. */
env->regwptr[2], env->regwptr[3],
env->regwptr[4], env->regwptr[5],
0, 0);
+ if (ret == -TARGET_ERESTARTSYS || ret == -TARGET_QEMU_ESIGRETURN) {
+ break;
+ }
if ((abi_ulong)ret >= (abi_ulong)(-515)) {
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
env->xcc |= PSR_CARRY;
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->mmuregs[4];
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
#else
info._sifields._sigfault._addr = env->dmmuregs[4];
else
info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
#ifndef TARGET_ABI32
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPC;
info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP_DEBUG:
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
}
break;
for(;;) {
cpu_exec_start(cs);
- trapnr = cpu_ppc_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch(trapnr) {
case POWERPC_EXCP_NONE:
"Aborting\n");
break;
case POWERPC_EXCP_DSI: /* Data storage exception */
- EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n",
- env->spr[SPR_DAR]);
/* XXX: check this. Seems bugged */
switch (env->error_code & 0xFF000000) {
case 0x40000000:
+ case 0x42000000:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
break;
}
info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
- EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx
- "\n", env->spr[SPR_SRR0]);
/* XXX: check this */
switch (env->error_code & 0xFF000000) {
case 0x40000000:
break;
}
info._sifields._sigfault._addr = env->nip - 4;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case POWERPC_EXCP_EXTERNAL: /* External input */
cpu_abort(cs, "External interrupt while in user mode. "
"Aborting\n");
break;
case POWERPC_EXCP_ALIGN: /* Alignment exception */
- EXCP_DUMP(env, "Unaligned memory access\n");
/* XXX: check this */
info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_BUS_ADRALN;
info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case POWERPC_EXCP_PROGRAM: /* Program exception */
+ case POWERPC_EXCP_HV_EMU: /* HV emulation */
/* XXX: check this */
switch (env->error_code & ~0xF) {
case POWERPC_EXCP_FP:
- EXCP_DUMP(env, "Floating point program exception\n");
info.si_signo = TARGET_SIGFPE;
info.si_errno = 0;
switch (env->error_code & 0xF) {
}
break;
case POWERPC_EXCP_INVAL:
- EXCP_DUMP(env, "Invalid instruction\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
switch (env->error_code & 0xF) {
}
break;
case POWERPC_EXCP_PRIV:
- EXCP_DUMP(env, "Privilege violation\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
switch (env->error_code & 0xF) {
env->error_code);
break;
}
- info._sifields._sigfault._addr = env->nip - 4;
- queue_signal(env, info.si_signo, &info);
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
- EXCP_DUMP(env, "No floating point allowed\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip - 4;
- queue_signal(env, info.si_signo, &info);
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case POWERPC_EXCP_SYSCALL: /* System call exception */
cpu_abort(cs, "Syscall exception while in user mode. "
"Aborting\n");
break;
case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
- EXCP_DUMP(env, "No APU instruction allowed\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip - 4;
- queue_signal(env, info.si_signo, &info);
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case POWERPC_EXCP_DECR: /* Decrementer exception */
cpu_abort(cs, "Decrementer interrupt while in user mode. "
"Aborting\n");
break;
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */
- EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip - 4;
- queue_signal(env, info.si_signo, &info);
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */
cpu_abort(cs, "Embedded floating-point data IRQ not handled\n");
"while in user mode. Aborting\n");
break;
case POWERPC_EXCP_VPU: /* Vector unavailable exception */
- EXCP_DUMP(env, "No Altivec instructions allowed\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip - 4;
- queue_signal(env, info.si_signo, &info);
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */
cpu_abort(cs, "Programmable interval timer interrupt "
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8], 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ break;
+ }
+ env->nip += 4;
if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
/* Returning from a successful sigreturn syscall.
Avoid corrupting register state. */
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP_DEBUG:
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
}
break;
/* just indicate that signals should be handled asap */
break;
default:
- cpu_abort(cs, "Unknown exception 0x%d. Aborting\n", trapnr);
+ cpu_abort(cs, "Unknown exception 0x%x. Aborting\n", trapnr);
break;
}
process_pending_signals(env);
info->si_signo = TARGET_SIGFPE;
info->si_errno = 0;
info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV;
- queue_signal(env, info->si_signo, &*info);
+ queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
ret = 0;
break;
default:
info->si_signo = TARGET_SIGTRAP;
info->si_errno = 0;
- queue_signal(env, info->si_signo, &*info);
+ queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
ret = 0;
break;
}
for(;;) {
cpu_exec_start(cs);
- trapnr = cpu_mips_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch(trapnr) {
case EXCP_SYSCALL:
env->active_tc.gpr[8], env->active_tc.gpr[9],
env->active_tc.gpr[10], env->active_tc.gpr[11]);
# endif /* O32 */
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->active_tc.PC -= 4;
+ break;
+ }
if (ret == -TARGET_QEMU_ESIGRETURN) {
/* Returning from a successful sigreturn syscall.
Avoid clobbering register state. */
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->CP0_BadVAddr;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_CpU:
case EXCP_RI:
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = 0;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
}
break;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->active_tc.PC;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP_DSPDIS:
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPC;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
/* The code below was inspired by the MIPS Linux kernel trap
* handling code in arch/mips/kernel/traps.c.
{
CPUState *cs = CPU(openrisc_env_get_cpu(env));
int trapnr, gdbsig;
+ abi_long ret;
for (;;) {
cpu_exec_start(cs);
- trapnr = cpu_openrisc_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
gdbsig = 0;
break;
case EXCP_SYSCALL:
env->pc += 4; /* 0xc00; */
- env->gpr[11] = do_syscall(env,
- env->gpr[11], /* return value */
- env->gpr[3], /* r3 - r7 are params */
- env->gpr[4],
- env->gpr[5],
- env->gpr[6],
- env->gpr[7],
- env->gpr[8], 0, 0);
+ ret = do_syscall(env,
+ env->gpr[11], /* return value */
+ env->gpr[3], /* r3 - r7 are params */
+ env->gpr[4],
+ env->gpr[5],
+ env->gpr[6],
+ env->gpr[7],
+ env->gpr[8], 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 4;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->gpr[11] = ret;
+ }
break;
case EXCP_FPE:
qemu_log_mask(CPU_LOG_INT, "\nFloating point error\n");
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_sh4_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
env->gregs[0],
env->gregs[1],
0, 0);
- env->gregs[0] = ret;
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 2;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->gregs[0] = ret;
+ }
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
}
break;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->tea;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
default:
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_cris_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
case 0xaa:
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->pregs[PR_EDA];
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP_INTERRUPT:
env->pregs[7],
env->pregs[11],
0, 0);
- env->regs[10] = ret;
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 2;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[10] = ret;
+ }
break;
case EXCP_DEBUG:
{
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
}
break;
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_mb_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
case 0xaa:
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP_INTERRUPT:
env->regs[9],
env->regs[10],
0, 0);
- env->regs[3] = ret;
+ if (ret == -TARGET_ERESTARTSYS) {
+ /* Wind back to before the syscall. */
+ env->sregs[SR_PC] -= 4;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[3] = ret;
+ }
+ /* All syscall exits result in guest r14 being equal to the
+ * PC we return to, because the kernel syscall exit "rtbd" does
+ * this. (This is true even for sigreturn(); note that r14 is
+ * not a userspace-usable register, as the kernel may clobber it
+ * at any point.)
+ */
+ env->regs[14] = env->sregs[SR_PC];
break;
case EXCP_HW_EXCP:
env->regs[17] = env->sregs[SR_PC] + 4;
info.si_errno = 0;
info.si_code = TARGET_FPE_FLTDIV;
info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case ESR_EC_FPU:
info.si_signo = TARGET_SIGFPE;
info.si_code = TARGET_FPE_FLTDIV;
}
info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
default:
printf ("Unhandled hw-exception: 0x%x\n",
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
}
break;
for(;;) {
cpu_exec_start(cs);
- trapnr = cpu_m68k_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch(trapnr) {
case EXCP_ILLEGAL:
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_TRAP0:
{
+ abi_long ret;
ts->sim_syscalls = 0;
n = env->dregs[0];
env->pc += 2;
- env->dregs[0] = do_syscall(env,
- n,
- env->dregs[1],
- env->dregs[2],
- env->dregs[3],
- env->dregs[4],
- env->dregs[5],
- env->aregs[0],
- 0, 0);
+ ret = do_syscall(env,
+ n,
+ env->dregs[1],
+ env->dregs[2],
+ env->dregs[3],
+ env->dregs[4],
+ env->dregs[5],
+ env->aregs[0],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 2;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->dregs[0] = ret;
+ }
}
break;
case EXCP_INTERRUPT:
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->mmu.ar;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP_DEBUG:
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
}
break;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = addr;
- queue_signal(env, TARGET_SIGSEGV, &info);
+ queue_signal(env, TARGET_SIGSEGV, QEMU_SI_FAULT, &info);
}
void cpu_loop(CPUAlphaState *env)
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_alpha_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
/* All of the traps imply a transition through PALcode, which
info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
info._sifields._sigfault._addr = env->trap_arg0;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_UNALIGN:
env->lock_addr = -1;
info.si_errno = 0;
info.si_code = TARGET_BUS_ADRALN;
info._sifields._sigfault._addr = env->trap_arg0;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_OPCDEC:
do_sigill:
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPC;
info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_ARITH:
env->lock_addr = -1;
info.si_errno = 0;
info.si_code = TARGET_FPE_FLTINV;
info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_FEN:
/* No-op. Linux simply re-enables the FPU. */
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case 0x81:
/* BUGCHK */
info.si_errno = 0;
info.si_code = 0;
info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case 0x83:
/* CALLSYS */
env->ir[IR_A2], env->ir[IR_A3],
env->ir[IR_A4], env->ir[IR_A5],
0, 0);
- if (trapnr == TARGET_NR_sigreturn
- || trapnr == TARGET_NR_rt_sigreturn) {
+ if (sysret == -TARGET_ERESTARTSYS) {
+ env->pc -= 4;
+ break;
+ }
+ if (sysret == -TARGET_QEMU_ESIGRETURN) {
break;
}
/* Syscall writes 0 to V0 to bypass error check, similar
}
info.si_errno = 0;
info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
default:
goto do_sigill;
env->lock_addr = -1;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP_STL_C:
int trapnr, n, sig;
target_siginfo_t info;
target_ulong addr;
+ abi_long ret;
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_s390x_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
case EXCP_INTERRUPT:
n = env->regs[1];
}
env->psw.addr += env->int_svc_ilen;
- env->regs[2] = do_syscall(env, n, env->regs[2], env->regs[3],
- env->regs[4], env->regs[5],
- env->regs[6], env->regs[7], 0, 0);
+ ret = do_syscall(env, n, env->regs[2], env->regs[3],
+ env->regs[4], env->regs[5],
+ env->regs[6], env->regs[7], 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->psw.addr -= env->int_svc_ilen;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[2] = ret;
+ }
break;
case EXCP_DEBUG:
info.si_errno = 0;
info.si_code = n;
info._sifields._sigfault._addr = addr;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
default:
info.si_errno = 0;
info.si_code = TARGET_ILL_PRVREG;
info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
static void do_signal(CPUTLGState *env, int signo, int sigcode)
}
info.si_code = sigcode;
- queue_signal(env, info.si_signo, &info);
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
static void gen_sigsegv_maperr(CPUTLGState *env, target_ulong addr)
while (1) {
cpu_exec_start(cs);
- trapnr = cpu_tilegx_exec(cs);
+ trapnr = cpu_exec(cs);
cpu_exec_end(cs);
switch (trapnr) {
case TILEGX_EXCP_SYSCALL:
- env->regs[TILEGX_R_RE] = do_syscall(env, env->regs[TILEGX_R_NR],
- env->regs[0], env->regs[1],
- env->regs[2], env->regs[3],
- env->regs[4], env->regs[5],
- env->regs[6], env->regs[7]);
- env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(env->regs[TILEGX_R_RE])
- ? - env->regs[TILEGX_R_RE]
- : 0;
+ {
+ abi_ulong ret = do_syscall(env, env->regs[TILEGX_R_NR],
+ env->regs[0], env->regs[1],
+ env->regs[2], env->regs[3],
+ env->regs[4], env->regs[5],
+ env->regs[6], env->regs[7]);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 8;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[TILEGX_R_RE] = ret;
+ env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(ret) ? -ret : 0;
+ }
break;
+ }
case TILEGX_EXCP_OPCODE_EXCH:
do_exch(env, true, false);
break;
/* Assumes contents are already zeroed. */
void init_task_state(TaskState *ts)
{
- int i;
-
ts->used = 1;
- ts->first_free = ts->sigqueue_table;
- for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
- ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
- }
- ts->sigqueue_table[i].next = NULL;
}
CPUArchState *cpu_copy(CPUArchState *env)
static void handle_arg_log_filename(const char *arg)
{
- qemu_set_log_filename(arg);
+ qemu_set_log_filename(arg, &error_fatal);
}
static void handle_arg_set_env(const char *arg)
static void handle_arg_version(const char *arg)
{
printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
- ", Copyright (c) 2003-2008 Fabrice Bellard\n");
+ ", " QEMU_COPYRIGHT "\n");
exit(EXIT_SUCCESS);
}
+static char *trace_file;
+static void handle_arg_trace(const char *arg)
+{
+ g_free(trace_file);
+ trace_file = trace_opt_parse(arg);
+}
+
struct qemu_argument {
const char *argv;
const char *env;
"", "log system calls"},
{"seed", "QEMU_RAND_SEED", true, handle_arg_randseed,
"", "Seed for pseudo-random number generator"},
+ {"trace", "QEMU_TRACE", true, handle_arg_trace,
+ "", "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
{"version", "QEMU_VERSION", false, handle_arg_version,
"", "display version information and exit"},
{NULL, NULL, false, NULL, NULL, NULL}
}
cpu_model = NULL;
-#if defined(cpudef_setup)
- cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
-#endif
srand(time(NULL));
+ qemu_add_opts(&qemu_trace_opts);
+
optind = parse_args(argc, argv);
+ if (!trace_init_backends()) {
+ exit(1);
+ }
+ trace_init_file(trace_file);
+
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
int i;
#if defined(TARGET_PPC64)
+ int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF;
#if defined(TARGET_ABI32)
- env->msr &= ~((target_ulong)1 << MSR_SF);
+ env->msr &= ~((target_ulong)1 << flag);
#else
- env->msr |= (target_ulong)1 << MSR_SF;
+ env->msr |= (target_ulong)1 << flag;
#endif
#endif
env->nip = regs->nip;
if (regs->cp0_epc & 1) {
env->hflags |= MIPS_HFLAG_M16;
}
+ if (((info->elf_flags & EF_MIPS_NAN2008) != 0) !=
+ ((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) != 0)) {
+ if ((env->active_fpu.fcr31_rw_bitmask &
+ (1 << FCR31_NAN2008)) == 0) {
+ fprintf(stderr, "ELF binary's NaN mode not supported by CPU\n");
+ exit(1);
+ }
+ if ((info->elf_flags & EF_MIPS_NAN2008) != 0) {
+ env->active_fpu.fcr31 |= (1 << FCR31_NAN2008);
+ } else {
+ env->active_fpu.fcr31 &= ~(1 << FCR31_NAN2008);
+ }
+ restore_snan_bit_mode(env);
+ }
}
#elif defined(TARGET_OPENRISC)
{
}
gdb_handlesig(cpu, 0);
}
+ trace_init_vcpu_events();
cpu_loop(env);
/* never exits */
return 0;