mirror of https://github.com/proxmox/mirror_qemu
linux-user: Add cpu_loop_exit_sigsegv
This is a new interface to be provided by the os emulator for raising SIGSEGV on fault. Use the new record_sigsegv target hook. Reviewed by: Warner Losh <imp@bsdimp.com> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>master
parent
09e94676ad
commit
72d2bbf9ff
|
@ -141,35 +141,38 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr,
|
||||||
int fault_size, MMUAccessType access_type,
|
int fault_size, MMUAccessType access_type,
|
||||||
bool nonfault, uintptr_t ra)
|
bool nonfault, uintptr_t ra)
|
||||||
{
|
{
|
||||||
int flags;
|
int acc_flag;
|
||||||
|
bool maperr;
|
||||||
|
|
||||||
switch (access_type) {
|
switch (access_type) {
|
||||||
case MMU_DATA_STORE:
|
case MMU_DATA_STORE:
|
||||||
flags = PAGE_WRITE;
|
acc_flag = PAGE_WRITE_ORG;
|
||||||
break;
|
break;
|
||||||
case MMU_DATA_LOAD:
|
case MMU_DATA_LOAD:
|
||||||
flags = PAGE_READ;
|
acc_flag = PAGE_READ;
|
||||||
break;
|
break;
|
||||||
case MMU_INST_FETCH:
|
case MMU_INST_FETCH:
|
||||||
flags = PAGE_EXEC;
|
acc_flag = PAGE_EXEC;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!guest_addr_valid_untagged(addr) ||
|
if (guest_addr_valid_untagged(addr)) {
|
||||||
page_check_range(addr, 1, flags) < 0) {
|
int page_flags = page_get_flags(addr);
|
||||||
if (nonfault) {
|
if (page_flags & acc_flag) {
|
||||||
return TLB_INVALID_MASK;
|
return 0; /* success */
|
||||||
} else {
|
|
||||||
CPUState *cpu = env_cpu(env);
|
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
|
||||||
cc->tcg_ops->tlb_fill(cpu, addr, fault_size, access_type,
|
|
||||||
MMU_USER_IDX, false, ra);
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
}
|
||||||
|
maperr = !(page_flags & PAGE_VALID);
|
||||||
|
} else {
|
||||||
|
maperr = true;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
if (nonfault) {
|
||||||
|
return TLB_INVALID_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_loop_exit_sigsegv(env_cpu(env), addr, access_type, maperr, ra);
|
||||||
}
|
}
|
||||||
|
|
||||||
int probe_access_flags(CPUArchState *env, target_ulong addr,
|
int probe_access_flags(CPUArchState *env, target_ulong addr,
|
||||||
|
|
|
@ -685,6 +685,21 @@ MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write);
|
||||||
bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
|
bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
|
||||||
uintptr_t host_pc, abi_ptr guest_addr);
|
uintptr_t host_pc, abi_ptr guest_addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_loop_exit_sigsegv:
|
||||||
|
* @cpu: the cpu context
|
||||||
|
* @addr: the guest address of the fault
|
||||||
|
* @access_type: access was read/write/execute
|
||||||
|
* @maperr: true for invalid page, false for permission fault
|
||||||
|
* @ra: host pc for unwinding
|
||||||
|
*
|
||||||
|
* Use the TCGCPUOps hook to record cpu state, do guest operating system
|
||||||
|
* specific things to raise SIGSEGV, and jump to the main cpu loop.
|
||||||
|
*/
|
||||||
|
void QEMU_NORETURN cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
|
||||||
|
MMUAccessType access_type,
|
||||||
|
bool maperr, uintptr_t ra);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static inline void mmap_lock(void) {}
|
static inline void mmap_lock(void) {}
|
||||||
static inline void mmap_unlock(void) {}
|
static inline void mmap_unlock(void) {}
|
||||||
|
|
|
@ -688,9 +688,27 @@ void force_sigsegv(int oldsig)
|
||||||
}
|
}
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
|
||||||
|
MMUAccessType access_type, bool maperr, uintptr_t ra)
|
||||||
|
{
|
||||||
|
const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
|
||||||
|
|
||||||
|
if (tcg_ops->record_sigsegv) {
|
||||||
|
tcg_ops->record_sigsegv(cpu, addr, access_type, maperr, ra);
|
||||||
|
} else if (tcg_ops->tlb_fill) {
|
||||||
|
tcg_ops->tlb_fill(cpu, addr, 0, access_type, MMU_USER_IDX, false, ra);
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
force_sig_fault(TARGET_SIGSEGV,
|
||||||
|
maperr ? TARGET_SEGV_MAPERR : TARGET_SEGV_ACCERR,
|
||||||
|
addr);
|
||||||
|
cpu->exception_index = EXCP_INTERRUPT;
|
||||||
|
cpu_loop_exit_restore(cpu, ra);
|
||||||
|
}
|
||||||
|
|
||||||
/* abort execution with signal */
|
/* abort execution with signal */
|
||||||
static void QEMU_NORETURN dump_core_and_abort(int target_sig)
|
static void QEMU_NORETURN dump_core_and_abort(int target_sig)
|
||||||
{
|
{
|
||||||
|
@ -806,7 +824,7 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
||||||
access_type = adjust_signal_pc(&pc, is_write);
|
access_type = adjust_signal_pc(&pc, is_write);
|
||||||
|
|
||||||
if (host_sig == SIGSEGV) {
|
if (host_sig == SIGSEGV) {
|
||||||
const struct TCGCPUOps *tcg_ops;
|
bool maperr = true;
|
||||||
|
|
||||||
if (info->si_code == SEGV_ACCERR && h2g_valid(host_addr)) {
|
if (info->si_code == SEGV_ACCERR && h2g_valid(host_addr)) {
|
||||||
/* If this was a write to a TB protected page, restart. */
|
/* If this was a write to a TB protected page, restart. */
|
||||||
|
@ -821,18 +839,14 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
||||||
* which means that we may get ACCERR when we want MAPERR.
|
* which means that we may get ACCERR when we want MAPERR.
|
||||||
*/
|
*/
|
||||||
if (page_get_flags(guest_addr) & PAGE_VALID) {
|
if (page_get_flags(guest_addr) & PAGE_VALID) {
|
||||||
/* maperr = false; */
|
maperr = false;
|
||||||
} else {
|
} else {
|
||||||
info->si_code = SEGV_MAPERR;
|
info->si_code = SEGV_MAPERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
|
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
|
||||||
|
cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc);
|
||||||
tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
|
|
||||||
tcg_ops->tlb_fill(cpu, guest_addr, 0, access_type,
|
|
||||||
MMU_USER_IDX, false, pc);
|
|
||||||
g_assert_not_reached();
|
|
||||||
} else {
|
} else {
|
||||||
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
|
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue