Back to index

plt-scheme  4.2.1
sighand.c
Go to the documentation of this file.
00001 /* 
00002    Provides:
00003       initialize_signal_handler();
00004       remove_signal_handler();
00005    Requires:
00006       generations_available - mutable int, Windows only
00007       designate_modified
00008       macosx_init_exception_handler() --- OS X, only
00009 */
00010 
00011 /******************************************************************************/
00012 /*                      platform-specific handlers                            */
00013 /******************************************************************************/
00014 
00015 /* ========== Linux signal handler ========== */
00016 #if defined(linux)
00017 #include <signal.h>
00018 #include <sys/types.h>
00019 #include <unistd.h>
00020 
00021 #ifndef WAIT_FOR_GDB
00022 # define WAIT_FOR_GDB 0
00023 #endif
00024 
00025 #if WAIT_FOR_GDB
00026 static void launchgdb() {
00027   pid_t pid = getpid();
00028   char inbuffer[10];
00029   
00030   fprintf(stderr, "pid # %i run gdb \"gdb ./mzscheme3m %i\" or kill process.\n", pid, pid);
00031   fflush(stderr);
00032 
00033   while(read(fileno(stdin), inbuffer, 10) <= 0){
00034     if(errno != EINTR){
00035       fprintf(stderr, "Error detected %i\n", errno);
00036     }
00037   }
00038 }
00039 #endif
00040 
00041 void fault_handler(int sn, struct siginfo *si, void *ctx)
00042 {
00043   void *p = si->si_addr;
00044   if (si->si_code != SEGV_ACCERR) { /*SEGV_MAPERR*/
00045     printf("SIGSEGV fault on %p\n", p);
00046 #if WAIT_FOR_GDB
00047     launchgdb();
00048 #endif
00049     abort();
00050   }
00051 
00052   if (!designate_modified(p)) {
00053     if (si->si_code == SEGV_ACCERR) {
00054       printf("mprotect fault on %p\n", p);
00055     }
00056     else {
00057       printf("?? %i fault on %p\n", si->si_code, p);
00058     }
00059     abort();
00060   }
00061 #  define NEED_SIGACTION
00062 #  define USE_SIGACTON_SIGNAL_KIND SIGSEGV
00063 }
00064 #endif
00065 
00066 /* ========== FreeBSD/NetBSD/OpenBSD signal handler ========== */
00067 /*  As of 2007/06/29, this is a guess for NetBSD!  */
00068 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
00069 # include <signal.h>
00070 # include <sys/param.h>
00071 void fault_handler(int sn, siginfo_t *si, void *ctx)
00072 {
00073   if (!designate_modified(si->si_addr))
00074     abort();
00075 }
00076 #  define NEED_SIGACTION
00077 #  if defined(__FreeBSD__) && (__FreeBSD_version < 700000)
00078 #    define USE_SIGACTON_SIGNAL_KIND SIGBUS
00079 #  else
00080 #    define USE_SIGACTON_SIGNAL_KIND SIGSEGV
00081 #  endif
00082 #endif
00083 
00084 /* ========== Solaris signal handler ========== */
00085 #if defined(sun)
00086 # include <signal.h>
00087 void fault_handler(int sn, struct siginfo *si, void *ctx)
00088 {
00089   if (!designate_modified(si->si_addr))
00090     abort();
00091 }
00092 # define NEED_SIGACTION
00093 # define USE_SIGACTON_SIGNAL_KIND SIGSEGV
00094 #endif
00095 
00096 /* ========== Windows signal handler ========== */
00097 #if defined(_WIN32)
00098 LONG WINAPI fault_handler(LPEXCEPTION_POINTERS e) 
00099 {
00100   if ((e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
00101       && (e->ExceptionRecord->ExceptionInformation[0] == 1)) {
00102     if (designate_modified((void *)e->ExceptionRecord->ExceptionInformation[1]))
00103       return EXCEPTION_CONTINUE_EXECUTION;
00104     else
00105       return EXCEPTION_CONTINUE_SEARCH;
00106   } else
00107     return EXCEPTION_CONTINUE_SEARCH;
00108 }
00109 # define NEED_SIGWIN
00110 typedef LONG (WINAPI*gcPVECTORED_EXCEPTION_HANDLER)(LPEXCEPTION_POINTERS e);
00111 #endif
00112 
00113 /* ========== Mac OS X signal handler ========== */
00114 #if defined(OS_X)
00115 /* Normally supplied by vm_osx.c: */
00116 # define NEED_OSX_MACH_HANDLER
00117 #endif
00118 
00119 /* ========== Generic Unix signal handler ========== */
00120 /* There's little guarantee that this will work, since
00121    Unix variants differ in the types of the arguments.
00122    When a platform doesn't match, make a special case
00123    for it, like all the others above. */
00124 #if !defined(NEED_SIGACTION) && !defined(NEED_SIGWIN) && !defined(NEED_OSX_MACH_HANDLER)
00125 # include <signal.h>
00126 void fault_handler(int sn, siginfo_t *si, void *ctx)
00127 {
00128   if (!designate_modified(si->si_addr))
00129     abort();
00130 #  define NEED_SIGACTION
00131 #  define USE_SIGACTON_SIGNAL_KIND SIGSEGV
00132 }
00133 #endif
00134 
00135 /******************************************************************************/
00136 /*                             init function                                  */
00137 /******************************************************************************/
00138 
00139 static void initialize_signal_handler(GCTYPE *gc)
00140 {
00141 # ifdef NEED_OSX_MACH_HANDLER
00142   macosx_init_exception_handler();
00143 # endif
00144 # ifdef NEED_SIGACTION
00145   {
00146     struct sigaction act, oact;
00147     memset(&act, 0, sizeof(sigaction));
00148     act.sa_sigaction = fault_handler;
00149     sigemptyset(&act.sa_mask);
00150     /* In MzScheme, SIGCHLD or SIGINT handling may trigger a write barrier: */
00151     sigaddset(&act.sa_mask, SIGINT);
00152     sigaddset(&act.sa_mask, SIGCHLD);
00153     act.sa_flags = SA_SIGINFO;
00154     sigaction(USE_SIGACTON_SIGNAL_KIND, &act, &oact);
00155   }
00156 # endif
00157 # ifdef NEED_SIGWIN
00158   {
00159     HMODULE hm;
00160     PVOID (WINAPI*aveh)(ULONG, gcPVECTORED_EXCEPTION_HANDLER);
00161 
00162     hm = LoadLibrary("kernel32.dll");
00163     if (hm)
00164       aveh = (PVOID (WINAPI*)(ULONG, gcPVECTORED_EXCEPTION_HANDLER))GetProcAddress(hm, "AddVectoredExceptionHandler");
00165     else
00166       aveh = NULL;
00167     
00168     if (aveh)
00169       aveh(TRUE, fault_handler);
00170     else  /* older than Windows XP */
00171       gc->generations_available = 0;
00172   }
00173 # endif
00174 }
00175 
00176 static void remove_signal_handler(GCTYPE *gc)
00177 {
00178 # ifdef NEED_OSX_MACH_HANDLER
00179 # endif
00180 # ifdef NEED_SIGACTION
00181   {
00182     struct sigaction act, oact;
00183     memset(&act, 0, sizeof(sigaction));
00184     act.sa_handler = SIG_DFL;
00185     sigemptyset(&act.sa_mask);
00186     act.sa_flags = SA_SIGINFO;
00187     sigaction(USE_SIGACTON_SIGNAL_KIND, &act, &oact);
00188   }
00189 # endif
00190 # ifdef NEED_SIGWIN
00191   if (gc->generations_available) {
00192     HMODULE hm;
00193 
00194     hm = LoadLibrary("kernel32.dll");
00195     if (hm) {
00196       ULONG (WINAPI*rveh)(gcPVECTORED_EXCEPTION_HANDLER);
00197       rveh = (ULONG (WINAPI*)(gcPVECTORED_EXCEPTION_HANDLER))GetProcAddress(hm, "RemoveVectoredExceptionHandler");
00198       rveh(fault_handler);
00199     }
00200   }
00201 # endif
00202 }