Most linux-user targets so far do not distinguish between SEGV_MAPERR and SEGV_ACCERR. This function will be used to fix that.
Signed-off-by: Richard Henderson <richard.hender...@linaro.org> --- linux-user/signal-common.h | 1 + linux-user/signal.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h index 536c7ac2c2..9090bbb315 100644 --- a/linux-user/signal-common.h +++ b/linux-user/signal-common.h @@ -40,6 +40,7 @@ void tswap_siginfo(target_siginfo_t *tinfo, void set_sigmask(const sigset_t *set); void force_sig(int sig); void force_sigsegv(int oldsig); +void force_sigsegv_for_addr(abi_ulong addr); void force_sig_fault(int sig, int code, abi_ulong addr); #if defined(TARGET_ARCH_HAS_SETUP_FRAME) void setup_frame(int sig, struct target_sigaction *ka, diff --git a/linux-user/signal.c b/linux-user/signal.c index 5ea8e4584a..0bb369c888 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -663,6 +663,24 @@ void force_sig_fault(int sig, int code, abi_ulong addr) queue_signal(env, sig, QEMU_SI_FAULT, &info); } +/* + * Force a synchronously taken SIGSEGV signal for @addr. + * Distinguish between SEGV_MAPERR and SEGV_ACCERR here, + * in preference to doing that for each target. + */ +void force_sigsegv_for_addr(abi_ulong addr) +{ + /* + * MAPERR indicates the page is not present at all. + * Otherwise, it must have been a permission problem. + */ + int si_code = TARGET_SEGV_MAPERR; + if (page_get_flags(addr) & PAGE_VALID) { + si_code = TARGET_SEGV_ACCERR; + } + force_sig_fault(TARGET_SIGSEGV, si_code, addr); +} + /* Force a SIGSEGV if we couldn't write to memory trying to set * up the signal frame. oldsig is the signal we were trying to handle * at the point of failure. -- 2.25.1