aboutsummaryrefslogtreecommitdiff
path: root/linux-user/signal.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2021-09-17 17:32:56 -0700
committerRichard Henderson <richard.henderson@linaro.org>2021-11-02 07:00:52 -0400
commit72d2bbf9ff3e1edf5d57b53149eeaa36f19fb891 (patch)
tree6a99451d40f398e90b2421aec5da2a30c591e4b2 /linux-user/signal.c
parent09e94676ade52708cbece8fd4bd255a25b6ee475 (diff)
downloadqemu-72d2bbf9ff3e1edf5d57b53149eeaa36f19fb891.zip
qemu-72d2bbf9ff3e1edf5d57b53149eeaa36f19fb891.tar.gz
qemu-72d2bbf9ff3e1edf5d57b53149eeaa36f19fb891.tar.bz2
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>
Diffstat (limited to 'linux-user/signal.c')
-rw-r--r--linux-user/signal.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/linux-user/signal.c b/linux-user/signal.c
index b816678..1359837 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -688,9 +688,27 @@ void force_sigsegv(int oldsig)
}
force_sig(TARGET_SIGSEGV);
}
-
#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 */
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);
if (host_sig == SIGSEGV) {
- const struct TCGCPUOps *tcg_ops;
+ bool maperr = true;
if (info->si_code == SEGV_ACCERR && h2g_valid(host_addr)) {
/* 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.
*/
if (page_get_flags(guest_addr) & PAGE_VALID) {
- /* maperr = false; */
+ maperr = false;
} else {
info->si_code = SEGV_MAPERR;
}
}
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
-
- 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();
+ cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc);
} else {
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
}