mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-11-18 18:05:21 +00:00
- new and updated SIGSEGV support functions:
+ configure script cleanups + possible support for Direct Addressing / VOSF on other platforms
This commit is contained in:
parent
8e93379eb4
commit
98192c4ba9
@ -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]
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 ?
|
||||
|
278
BasiliskII/src/Unix/sigsegv.cpp
Normal file
278
BasiliskII/src/Unix/sigsegv.cpp
Normal 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
|
42
BasiliskII/src/Unix/sigsegv.h
Normal file
42
BasiliskII/src/Unix/sigsegv.h
Normal 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 */
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user