mirror of https://github.com/xemu-project/xemu.git
linux-user: Split out host_sig{segv,bus}_handler
Make host_signal_handler slightly easier to read. Acked-by: Helge Deller <deller@gmx.de> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
58c4e36c4e
commit
f4e1168198
|
@ -811,47 +811,27 @@ void die_from_signal(siginfo_t *info)
|
||||||
die_with_signal(info->si_signo);
|
die_with_signal(info->si_signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
static void host_sigsegv_handler(CPUState *cpu, siginfo_t *info,
|
||||||
|
host_sigcontext *uc)
|
||||||
{
|
{
|
||||||
CPUState *cpu = thread_cpu;
|
uintptr_t host_addr = (uintptr_t)info->si_addr;
|
||||||
CPUArchState *env = cpu_env(cpu);
|
|
||||||
TaskState *ts = cpu->opaque;
|
|
||||||
target_siginfo_t tinfo;
|
|
||||||
host_sigcontext *uc = puc;
|
|
||||||
struct emulated_sigtable *k;
|
|
||||||
int guest_sig;
|
|
||||||
uintptr_t pc = 0;
|
|
||||||
bool sync_sig = false;
|
|
||||||
void *sigmask = host_signal_mask(uc);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
|
|
||||||
* handling wrt signal blocking and unwinding.
|
|
||||||
*/
|
|
||||||
if ((host_sig == SIGSEGV || host_sig == SIGBUS) && info->si_code > 0) {
|
|
||||||
MMUAccessType access_type;
|
|
||||||
uintptr_t host_addr;
|
|
||||||
abi_ptr guest_addr;
|
|
||||||
bool is_write;
|
|
||||||
|
|
||||||
host_addr = (uintptr_t)info->si_addr;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert forcefully to guest address space: addresses outside
|
* Convert forcefully to guest address space: addresses outside
|
||||||
* reserved_va are still valid to report via SEGV_MAPERR.
|
* reserved_va are still valid to report via SEGV_MAPERR.
|
||||||
*/
|
*/
|
||||||
guest_addr = h2g_nocheck(host_addr);
|
bool is_valid = h2g_valid(host_addr);
|
||||||
|
abi_ptr guest_addr = h2g_nocheck(host_addr);
|
||||||
pc = host_signal_pc(uc);
|
uintptr_t pc = host_signal_pc(uc);
|
||||||
is_write = host_signal_write(info, uc);
|
bool is_write = host_signal_write(info, uc);
|
||||||
access_type = adjust_signal_pc(&pc, is_write);
|
MMUAccessType access_type = adjust_signal_pc(&pc, is_write);
|
||||||
|
bool maperr;
|
||||||
|
|
||||||
/* If this was a write to a TB protected page, restart. */
|
/* If this was a write to a TB protected page, restart. */
|
||||||
if (is_write
|
if (is_write
|
||||||
&& host_sig == SIGSEGV
|
&& is_valid
|
||||||
&& info->si_code == SEGV_ACCERR
|
&& info->si_code == SEGV_ACCERR
|
||||||
&& h2g_valid(host_addr)
|
&& handle_sigsegv_accerr_write(cpu, host_signal_mask(uc),
|
||||||
&& handle_sigsegv_accerr_write(cpu, sigmask, pc, guest_addr)) {
|
pc, guest_addr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,10 +844,8 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
||||||
die_from_signal(info);
|
die_from_signal(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host_sig == SIGSEGV) {
|
maperr = true;
|
||||||
bool maperr = true;
|
if (is_valid && info->si_code == SEGV_ACCERR) {
|
||||||
|
|
||||||
if (info->si_code == SEGV_ACCERR && h2g_valid(host_addr)) {
|
|
||||||
/*
|
/*
|
||||||
* With reserved_va, the whole address space is PROT_NONE,
|
* With reserved_va, the whole address space is PROT_NONE,
|
||||||
* which means that we may get ACCERR when we want MAPERR.
|
* which means that we may get ACCERR when we want MAPERR.
|
||||||
|
@ -879,16 +857,62 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, sigmask, NULL);
|
sigprocmask(SIG_SETMASK, host_signal_mask(uc), NULL);
|
||||||
cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc);
|
cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc);
|
||||||
} else {
|
}
|
||||||
sigprocmask(SIG_SETMASK, sigmask, NULL);
|
|
||||||
|
static void host_sigbus_handler(CPUState *cpu, siginfo_t *info,
|
||||||
|
host_sigcontext *uc)
|
||||||
|
{
|
||||||
|
uintptr_t pc = host_signal_pc(uc);
|
||||||
|
bool is_write = host_signal_write(info, uc);
|
||||||
|
MMUAccessType access_type = adjust_signal_pc(&pc, is_write);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the access was not on behalf of the guest, within the executable
|
||||||
|
* mapping of the generated code buffer, then it is a host bug.
|
||||||
|
*/
|
||||||
|
if (!in_code_gen_buffer((void *)(pc - tcg_splitwx_diff))) {
|
||||||
|
die_from_signal(info);
|
||||||
|
}
|
||||||
|
|
||||||
if (info->si_code == BUS_ADRALN) {
|
if (info->si_code == BUS_ADRALN) {
|
||||||
|
uintptr_t host_addr = (uintptr_t)info->si_addr;
|
||||||
|
abi_ptr guest_addr = h2g_nocheck(host_addr);
|
||||||
|
|
||||||
|
sigprocmask(SIG_SETMASK, host_signal_mask(uc), NULL);
|
||||||
cpu_loop_exit_sigbus(cpu, guest_addr, access_type, pc);
|
cpu_loop_exit_sigbus(cpu, guest_addr, access_type, pc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
||||||
|
{
|
||||||
|
CPUState *cpu = thread_cpu;
|
||||||
|
CPUArchState *env = cpu_env(cpu);
|
||||||
|
TaskState *ts = cpu->opaque;
|
||||||
|
target_siginfo_t tinfo;
|
||||||
|
host_sigcontext *uc = puc;
|
||||||
|
struct emulated_sigtable *k;
|
||||||
|
int guest_sig;
|
||||||
|
uintptr_t pc = 0;
|
||||||
|
bool sync_sig = false;
|
||||||
|
void *sigmask;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
|
||||||
|
* handling wrt signal blocking and unwinding.
|
||||||
|
*/
|
||||||
|
if (info->si_code > 0) {
|
||||||
|
switch (host_sig) {
|
||||||
|
case SIGSEGV:
|
||||||
|
/* Only returns on handle_sigsegv_accerr_write success. */
|
||||||
|
host_sigsegv_handler(cpu, info, uc);
|
||||||
|
return;
|
||||||
|
case SIGBUS:
|
||||||
|
host_sigbus_handler(cpu, info, uc);
|
||||||
sync_sig = true;
|
sync_sig = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get target signal number */
|
/* get target signal number */
|
||||||
|
@ -929,6 +953,7 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
||||||
* would write 0xff bytes off the end of the structure and trash
|
* would write 0xff bytes off the end of the structure and trash
|
||||||
* data on the struct.
|
* data on the struct.
|
||||||
*/
|
*/
|
||||||
|
sigmask = host_signal_mask(uc);
|
||||||
memset(sigmask, 0xff, SIGSET_T_SIZE);
|
memset(sigmask, 0xff, SIGSET_T_SIZE);
|
||||||
sigdelset(sigmask, SIGSEGV);
|
sigdelset(sigmask, SIGSEGV);
|
||||||
sigdelset(sigmask, SIGBUS);
|
sigdelset(sigmask, SIGBUS);
|
||||||
|
|
Loading…
Reference in New Issue