- new and updated SIGSEGV support functions:

+ configure script cleanups
  + possible support for Direct Addressing / VOSF on other platforms
This commit is contained in:
gbeauche 2001-05-20 20:31:50 +00:00
parent 8e93379eb4
commit 98192c4ba9
8 changed files with 420 additions and 238 deletions

View File

@ -5,6 +5,9 @@ V0.9 - <insert date here>
[Kolja Waschk]
- Unix: some performance improvements to VOSF screen update code
[Brian J. Johnson]
- Unix: renewed SIGSEGV support functions. Side effect: configure
script cleanups and probable Direct Addressing/VOSF support for
other platforms (NetBSD, AIX, OSF/1, Irix) [Gwenole Beauchesne]
- Unix: -Ofast option is supplied to MIPSPro compiler [Brian J. Johnson]
- Unix: workaround for IRIX pthreads bug in Delay_usec()
[Brian J. Johnson]

View File

@ -33,8 +33,8 @@ SRCS = ../main.cpp main_unix.cpp ../prefs.cpp ../prefs_items.cpp prefs_unix.cpp
../emul_op.cpp ../macos_util.cpp ../xpram.cpp xpram_unix.cpp ../timer.cpp \
timer_unix.cpp clip_unix.cpp ../adb.cpp ../serial.cpp ../ether.cpp \
../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp ../video.cpp video_blit.cpp \
video_x.cpp ../audio.cpp ../extfs.cpp extfs_unix.cpp ../user_strings.cpp \
user_strings_unix.cpp \
video_x.cpp sigsegv.cpp ../audio.cpp ../extfs.cpp extfs_unix.cpp \
../user_strings.cpp user_strings_unix.cpp \
$(SYSSRCS) $(CPUSRCS)
APP = BasiliskII

View File

@ -44,6 +44,12 @@
/* Define if using video enabled on SEGV signals */
#undef ENABLE_VOSF
/* Define if your system requires signals to be reinstalled */
#undef SIGNAL_NEED_REINSTALL
/* Define if your system requires sigactions to be reinstalled */
#undef SIGACTION_NEED_REINSTALL
/* Define if your system support extended signals */
#undef HAVE_SIGINFO_T

View File

@ -212,6 +212,7 @@ AC_STRUCT_TM
dnl Checks for library functions.
AC_CHECK_FUNCS(strdup cfmakeraw)
AC_CHECK_FUNCS(clock_gettime timer_create)
AC_CHECK_FUNCS(sigaction signal)
dnl Select system-dependant source files.
SERIALSRC=serial_unix.cpp
@ -328,33 +329,74 @@ AC_CACHE_CHECK("whether we can map Low Memory area 0x0000-0x2000",
]
)
dnl Check signal handlers need to be reinstalled
AC_CACHE_CHECK("whether signal handlers need to be reinstalled",
ac_cv_signal_need_reinstall, [
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
AC_TRY_RUN([
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <signal.h>
static int handled_signal = 0;
RETSIGTYPE sigusr1_handler(int) { handled_signal++; }
int main(void) { /* returns 0 if signals need not to be reinstalled */
signal(SIGUSR1, sigusr1_handler); raise(SIGUSR1); raise(SIGUSR1);
exit(handled_signal == 2);
}
],
[ac_cv_signal_need_reinstall=yes],
[ac_cv_signal_need_reinstall=no]
)
AC_LANG_RESTORE
]
)
AC_TRANSLATE_DEFINE(SIGNAL_NEED_REINSTALL, "$ac_cv_signal_need_reinstall")
dnl Check if sigaction handlers need to be reinstalled
AC_CACHE_CHECK("whether sigaction handlers need to be reinstalled",
ac_cv_sigaction_need_reinstall, [
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
AC_TRY_RUN([
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <signal.h>
static int handled_signal = 0;
RETSIGTYPE sigusr1_handler(int) { handled_signal++; }
typedef RETSIGTYPE (*signal_handler)(int);
static signal_handler mysignal(int sig, signal_handler handler) {
struct sigaction old_sa;
struct sigaction new_sa;
new_sa.sa_handler = handler;
return ((sigaction(sig,&new_sa,&old_sa) < 0) ? SIG_IGN : old_sa.sa_handler);
}
int main(void) { /* returns 0 if signals need not to be reinstalled */
mysignal(SIGUSR1, sigusr1_handler); raise(SIGUSR1); raise(SIGUSR1);
exit(handled_signal == 2);
}
],
[ac_cv_sigaction_need_reinstall=yes],
[ac_cv_sigaction_need_reinstall=no]
)
AC_LANG_RESTORE
]
)
AC_TRANSLATE_DEFINE(SIGACTION_NEED_REINSTALL, "$ac_cv_sigaction_need_reinstall")
dnl Check if extended signals are supported.
AC_CACHE_CHECK("whether your system supports extended signal handlers",
ac_cv_have_extended_signals, [
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
AC_TRY_RUN([
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/mman.h>
static volatile caddr_t mem = 0;
static int zero_fd = -1;
static RETSIGTYPE segfault_handler(int, siginfo_t * sip, void *)
{ if ((caddr_t)(sip->si_addr) != mem) exit(1);
munmap(mem, getpagesize()); close(zero_fd); exit(0); }
int main()
{ if ((zero_fd = open("/dev/zero", O_RDWR)) < 0) exit(1);
if ((mem = (caddr_t)mmap(0, getpagesize(), PROT_READ, MAP_PRIVATE, zero_fd, 0)) == (caddr_t)MAP_FAILED) exit(1);
struct sigaction sa; sa.sa_sigaction = segfault_handler; sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, 0);
mem[0] = 0;
exit(1); // should not be reached
}
#define HAVE_SIGINFO_T 1
#define CONFIGURE_TEST
#include "sigsegv.cpp"
],
[ac_cv_have_extended_signals=yes],
[ac_cv_have_extended_signals=no]
@ -366,116 +408,21 @@ AC_TRANSLATE_DEFINE(HAVE_SIGINFO_T, "$ac_cv_have_extended_signals")
dnl Otherwise, check for subterfuges.
if [[ "x$ac_cv_have_extended_signals" = "xno" ]]; then
case "$target_os" in
linux*)
if [[ "x$HAVE_I386" = "xyes" ]]; then
AC_CACHE_CHECK("whether we then have a subterfuge for your system",
ac_cv_have_sigcontext_hack, [
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
AC_TRY_RUN([
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/mman.h>
static volatile caddr_t mem = 0;
static int zero_fd = -1;
static RETSIGTYPE segfault_handler(int, struct sigcontext scs)
{ if ((caddr_t)(scs.cr2) != mem) exit(1);
munmap(mem, getpagesize()); close(zero_fd); exit(0); }
int main()
{ if ((zero_fd = open("/dev/zero", O_RDWR)) < 0) exit(1);
if ((mem = (caddr_t)mmap(0, getpagesize(), PROT_READ, MAP_PRIVATE, zero_fd, 0)) == (caddr_t)MAP_FAILED) exit(1);
struct sigaction sa; sa.sa_flags = 0;
sa.sa_handler = (RETSIGTYPE (*)(int))segfault_handler;
sigaction(SIGSEGV, &sa, 0);
mem[0] = 0;
exit(1); // should not be reached
}
],
[ac_cv_have_sigcontext_hack=yes],
[ac_cv_have_sigcontext_hack=no]
)
AC_LANG_RESTORE
])
AC_TRANSLATE_DEFINE(HAVE_SIGCONTEXT_SUBTERFUGE, $ac_cv_have_sigcontext_hack)
elif [[ "x$HAVE_POWERPC" = "xyes" ]]; then
AC_CACHE_CHECK("whether we then have a subterfuge for your system",
ac_cv_have_sigcontext_hack, [
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
AC_TRY_RUN([
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/mman.h>
static volatile caddr_t mem = 0;
static int zero_fd = -1;
static RETSIGTYPE segfault_handler(int, struct sigcontext_struct *scs)
{ if ((caddr_t)(scs->regs->dar) != mem) exit(1);
munmap(mem, getpagesize()); close(zero_fd); exit(0); }
int main()
{ if ((zero_fd = open("/dev/zero", O_RDWR)) < 0) exit(1);
if ((mem = (caddr_t)mmap(0, getpagesize(), PROT_READ, MAP_PRIVATE, zero_fd, 0)) == (caddr_t)MAP_FAILED) exit(1);
struct sigaction sa; sa.sa_flags = 0;
sa.sa_handler = (RETSIGTYPE (*)(int))segfault_handler;
sigaction(SIGSEGV, &sa, 0);
mem[0] = 0;
exit(1); // should not be reached
}
],
[ac_cv_have_sigcontext_hack=yes],
[ac_cv_have_sigcontext_hack=no]
)
AC_LANG_RESTORE
])
AC_TRANSLATE_DEFINE(HAVE_SIGCONTEXT_SUBTERFUGE, $ac_cv_have_sigcontext_hack)
fi
;;
netbsd*)
if [[ "x$HAVE_M68K" = "xyes" ]]; then
AC_CACHE_CHECK("whether we then have a subterfuge for your system",
ac_cv_have_sigcontext_hack, [
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
AC_TRY_RUN([
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/mman.h>
static volatile caddr_t mem = 0;
static int zero_fd = -1;
static RETSIGTYPE segfault_handler(int, int code)
{ if ((caddr_t)code != mem) exit(1);
munmap(mem, getpagesize()); close(zero_fd); exit(0); }
int main()
{ if ((zero_fd = open("/dev/zero", O_RDWR)) < 0) exit(1);
if ((mem = (caddr_t)mmap(0, getpagesize(), PROT_READ, MAP_PRIVATE, zero_fd, 0)) == (caddr_t)MAP_FAILED) exit(1);
struct sigaction sa; sa.sa_flags = 0;
sa.sa_handler = (RETSIGTYPE (*)(int))segfault_handler;
sigaction(SIGSEGV, &sa, 0);
mem[0] = 0;
exit(1); // should not be reached
}
],
[ac_cv_have_sigcontext_hack=yes],
[ac_cv_have_sigcontext_hack=no]
)
AC_LANG_RESTORE
])
AC_TRANSLATE_DEFINE(HAVE_SIGCONTEXT_SUBTERFUGE, $ac_cv_have_sigcontext_hack)
fi
;;
esac
AC_CACHE_CHECK("whether we then have a subterfuge for your system",
ac_cv_have_sigcontext_hack, [
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
AC_TRY_RUN([
#define HAVE_SIGCONTEXT_SUBTERFUGE 1
#define CONFIGURE_TEST
#include "sigsegv.cpp"
],
[ac_cv_have_sigcontext_hack=yes],
[ac_cv_have_sigcontext_hack=no]
)
AC_LANG_RESTORE
])
AC_TRANSLATE_DEFINE(HAVE_SIGCONTEXT_SUBTERFUGE, "$ac_cv_have_sigcontext_hack")
fi
dnl Can we do Video on SEGV Signals ?

View File

@ -0,0 +1,278 @@
/*
* sigsegv.cpp - SIGSEGV signals support
*
* Derived from Bruno Haible's work on his SIGSEGV library for clisp
* <http://clisp.sourceforge.net/>
*
* Basilisk II (C) 1997-2001 Christian Bauer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <signal.h>
#include "sigsegv.h"
// Return value type of a signal handler (standard type if not defined)
#ifndef RETSIGTYPE
#define RETSIGTYPE void
#endif
// Type of the system signal handler
typedef RETSIGTYPE (*signal_handler)(int);
// User's SIGSEGV handler
static sigsegv_handler_t sigsegv_user_handler = 0;
// Actual SIGSEGV handler installer
static bool sigsegv_do_install_handler(int sig);
/*
* OS-dependant SIGSEGV signals support section
*/
#if HAVE_SIGINFO_T
// Generic extended signal handler
#define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *
#define SIGSEGV_FAULT_ADDRESS sip->si_addr
#endif
#if HAVE_SIGCONTEXT_SUBTERFUGE
// Linux kernels prior to 2.4 ?
#if defined(__linux__)
#define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
#if (defined(i386) || defined(__i386__))
#include <asm/sigcontext.h>
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs
#define SIGSEGV_FAULT_ADDRESS scs.cr2
#define SIGSEGV_FAULT_INSTRUCTION scs.eip
#endif
#if (defined(sparc) || defined(__sparc__))
#include <asm/sigcontext.h>
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext* scp, char* addr
#define SIGSEGV_FAULT_ADDRESS addr
#endif
#if (defined(powerpc) || defined(__powerpc__))
#include <asm/sigcontext.h>
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext* scp
#define SIGSEGV_FAULT_ADDRESS scp->regs->dar
#define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
#endif
#endif
// Irix 5 or 6 on MIPS
#if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4))
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
#define SIGSEGV_FAULT_ADDRESS scp->sc_badvaddr
#define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
#endif
// OSF/1 on Alpha
#if defined(__osf__)
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
#define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0
#define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
#endif
// AIX
#if defined(_AIX)
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
#define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr
#define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
#endif
// NetBSD or FreeBSD
#if defined(__NetBSD__) || defined(__FreeBSD__)
#if (defined(m68k) || defined(__m68k__))
#include <m68k/frame.h>
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
#define SIGSEGV_FAULT_ADDRESS ({ \
struct sigstate { \
int ss_flags; \
struct frame ss_frame; \
}; \
struct sigstate *state = (struct sigstate *)scp->sc_ap; \
char *fault_addr; \
switch (state->ss_frame.f_format) { \
case 7: /* 68040 access error */ \
/* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */ \
fault_addr = state->ss_frame.f_fmt7.f_fa; \
break; \
default: \
fault_addr = (char *)code; \
break; \
} \
fault_addr; \
})
#define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
#else
#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, void *scp, char *addr
#define SIGSEGV_FAULT_ADDRESS addr
#define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
#endif
#endif
#endif
// Fallbacks
#ifndef SIGSEGV_FAULT_INSTRUCTION
#define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
#endif
/*
* SIGSEGV global handler
*/
static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
{
// Call user's handler and reinstall the global handler, if required
if (sigsegv_user_handler((sigsegv_address_t)SIGSEGV_FAULT_ADDRESS, (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION)) {
#if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
sigsegv_do_install_handler(sig);
#endif
}
else {
// FAIL: reinstall default handler for "safe" crash
#define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
SIGSEGV_ALL_SIGNALS
#undef FAULT_HANDLER
}
}
/*
* SIGSEGV handler initialization
*/
#if defined(HAVE_SIGINFO_T)
static bool sigsegv_do_install_handler(int sig)
{
// Setup SIGSEGV handler to process writes to frame buffer
#ifdef HAVE_SIGACTION
struct sigaction vosf_sa;
sigemptyset(&vosf_sa.sa_mask);
vosf_sa.sa_sigaction = sigsegv_handler;
vosf_sa.sa_flags = SA_SIGINFO;
return (sigaction(sig, &vosf_sa, 0) == 0);
#else
return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
#endif
}
#elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
static bool sigsegv_do_install_handler(int sig)
{
// Setup SIGSEGV handler to process writes to frame buffer
#ifdef HAVE_SIGACTION
struct sigaction vosf_sa;
sigemptyset(&vosf_sa.sa_mask);
vosf_sa.sa_handler = (signal_handler)sigsegv_handler;
#if !EMULATED_68K && defined(__NetBSD__)
sigaddset(&vosf_sa.sa_mask, SIGALRM);
vosf_sa.sa_flags = SA_ONSTACK;
#else
vosf_sa.sa_flags = 0;
#endif
return (sigaction(sig, &vosf_sa, 0) == 0);
#else
return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
#endif
}
#endif
bool sigsegv_install_handler(sigsegv_handler_t handler)
{
#if defined(HAVE_SIGINFO_T) || defined(HAVE_SIGCONTEXT_SUBTERFUGE)
sigsegv_user_handler = handler;
bool success = true;
#define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
SIGSEGV_ALL_SIGNALS
#undef FAULT_HANDLER
return success;
#else
// FAIL: no siginfo_t nor sigcontext subterfuge is available
return false;
#endif
}
/*
* SIGSEGV handler deinitialization
*/
void sigsegv_deinstall_handler(void)
{
sigsegv_user_handler = 0;
#define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
SIGSEGV_ALL_SIGNALS
#undef FAULT_HANDLER
}
/*
* Test program used for configure/test
*/
#ifdef CONFIGURE_TEST
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
static caddr_t page = 0;
static int page_size;
static int handler_called = 0;
static bool sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
{
handler_called++;
if ((fault_address - 123) != page)
exit(1);
if (mprotect((caddr_t)((unsigned long)fault_address & -page_size), page_size, PROT_READ | PROT_WRITE) != 0)
exit(1);
return true;
}
int main(void)
{
int zero_fd = open("/dev/zero", O_RDWR);
if (zero_fd < 0)
return 1;
page_size = getpagesize();
page = (caddr_t)mmap(0, page_size, PROT_READ, MAP_PRIVATE, zero_fd, 0);
if (page == MAP_FAILED)
return 1;
if (!sigsegv_install_handler(sigsegv_test_handler))
return 1;
page[123] = 45;
page[123] = 45;
if (handler_called != 1)
return 1;
return 0;
}
#endif

View File

@ -0,0 +1,42 @@
/*
* sigsegv.h - SIGSEGV signals support
*
* Derived from Bruno Haible's work on his SIGSEGV library for clisp
* <http://clisp.sourceforge.net/>
*
* Basilisk II (C) 1997-2001 Christian Bauer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SIGSEGV_H
#define SIGSEGV_H
// Address type
typedef char * sigsegv_address_t;
// Type of a SIGSEGV handler. Returns boolean expressing successful operation
typedef bool (*sigsegv_handler_t)(sigsegv_address_t fault_address, sigsegv_address_t instruction_address);
// Install a SIGSEGV handler. Returns boolean expressing success
extern bool sigsegv_install_handler(sigsegv_handler_t handler);
// Remove the user SIGSEGV handler, revert to default behavior
extern void sigsegv_uninstall_handler(void);
// Define an address that is bound to be invalid for a program counter
const sigsegv_address_t SIGSEGV_INVALID_PC = (sigsegv_address_t)(-1);
#endif /* SIGSEGV_H */

View File

@ -43,15 +43,12 @@ static void * allocate_framebuffer(uint32 size, uint8 * hint = 0)
return mmap((caddr_t)hint, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero_fd, 0);
}
/*
* Screen fault handler
*/
const uintptr INVALID_PC = (uintptr)-1;
static inline void do_handle_screen_fault(uintptr addr, uintptr pc = INVALID_PC)
// Screen fault handler
static bool screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
{
D(bug("screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", fault_address, fault_instruction));
const uintptr addr = (uintptr)fault_address;
/* Someone attempted to write to the frame buffer. Make it writeable
* now so that the data could actually be written. It will be made
* read-only back in one of the screen update_*() functions.
@ -64,105 +61,17 @@ static inline void do_handle_screen_fault(uintptr addr, uintptr pc = INVALID_PC)
mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE);
mainBuffer.dirty = true;
UNLOCK_VOSF;
return;
return true;
}
/* Otherwise, we don't know how to handle the fault, let it crash */
fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr);
if (pc != INVALID_PC)
fprintf(stderr, " [IP=0x%08X]", pc);
if (fault_instruction != SIGSEGV_INVALID_PC)
fprintf(stderr, " [IP=0x%08X]", fault_instruction);
fprintf(stderr, "\n");
signal(SIGSEGV, SIG_DFL);
return false;
}
#if defined(HAVE_SIGINFO_T)
static void Screen_fault_handler(int, siginfo_t * sip, void *)
{
D(bug("Screen_fault_handler: ADDR=0x%08X\n", sip->si_addr));
do_handle_screen_fault((uintptr)sip->si_addr);
}
#elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
# if defined(__i386__) && defined(__linux__)
static void Screen_fault_handler(int, struct sigcontext scs)
{
D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip));
do_handle_screen_fault((uintptr)scs.cr2, (uintptr)scs.eip);
}
# elif defined(__m68k__) && defined(__NetBSD__)
# include <m68k/frame.h>
static void Screen_fault_handler(int, int code, struct sigcontext *scp)
{
D(bug("Screen_fault_handler: ADDR=0x%08X\n", code));
struct sigstate {
int ss_flags;
struct frame ss_frame;
};
struct sigstate *state = (struct sigstate *)scp->sc_ap;
uintptr fault_addr;
switch (state->ss_frame.f_format) {
case 7: // 68040 access error
// "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown
fault_addr = state->ss_frame.f_fmt7.f_fa;
break;
default:
fault_addr = (uintptr)code;
break;
}
do_handle_screen_fault(fault_addr);
}
# elif defined(__powerpc__) && defined(__linux__)
static void Screen_fault_handler(int, struct sigcontext_struct *scs)
{
D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs->regs->dar, scs->regs->nip));
do_handle_screen_fault((uintptr)scs->regs->dar, (uintptr)scs->regs->nip);
}
# else
# error "No suitable subterfuge for Video on SEGV signals"
# endif
#else
# error "Can't do Video on SEGV signals"
#endif
/*
* Screen fault handler initialization
*/
#if defined(HAVE_SIGINFO_T)
static bool Screen_fault_handler_init()
{
// Setup SIGSEGV handler to process writes to frame buffer
sigemptyset(&vosf_sa.sa_mask);
vosf_sa.sa_sigaction = Screen_fault_handler;
vosf_sa.sa_flags = SA_SIGINFO;
return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
}
#elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
static bool Screen_fault_handler_init()
{
// Setup SIGSEGV handler to process writes to frame buffer
sigemptyset(&vosf_sa.sa_mask);
vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler;
#if !EMULATED_68K && defined(__NetBSD__)
sigaddset(&vosf_sa.sa_mask, SIGALRM);
vosf_sa.sa_flags = SA_ONSTACK;
#else
vosf_sa.sa_flags = 0;
#endif
return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
}
#endif
/*
* Update display for Windowed mode and VOSF
*/

View File

@ -53,10 +53,9 @@
#endif
#ifdef ENABLE_VOSF
# include <unistd.h>
# include <signal.h>
# include <fcntl.h>
# include <sys/mman.h>
# include "sigsegv.h"
#endif
#include "cpu_emulation.h"
@ -278,8 +277,6 @@ static inline int find_next_page_clear(int page)
}
static int zero_fd = -1;
static bool Screen_fault_handler_init();
static struct sigaction vosf_sa;
#ifdef HAVE_PTHREADS
static pthread_mutex_t vosf_lock = PTHREAD_MUTEX_INITIALIZER; // Mutex to protect frame buffer (dirtyPages in fact)
@ -1172,7 +1169,7 @@ bool VideoInit(bool classic)
}
// Initialize the handler for SIGSEGV
if (!Screen_fault_handler_init()) {
if (!sigsegv_install_handler(screen_fault_handler)) {
// TODO: STR_VOSF_INIT_ERR ?
ErrorAlert("Could not initialize Video on SEGV signals");
return false;