home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / Unix / sigsegv.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-05-21  |  7.9 KB  |  290 lines

  1. /*
  2.  *  sigsegv.cpp - SIGSEGV signals support
  3.  *
  4.  *  Derived from Bruno Haible's work on his SIGSEGV library for clisp
  5.  *  <http://clisp.sourceforge.net/>
  6.  *
  7.  *  Basilisk II (C) 1997-2001 Christian Bauer
  8.  *
  9.  *  This program is free software; you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License as published by
  11.  *  the Free Software Foundation; either version 2 of the License, or
  12.  *  (at your option) any later version.
  13.  *
  14.  *  This program is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *  GNU General Public License for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public License
  20.  *  along with this program; if not, write to the Free Software
  21.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22.  */
  23.  
  24. #ifdef HAVE_UNISTD_H
  25. #include <unistd.h>
  26. #endif
  27.  
  28. #ifdef HAVE_CONFIG_H
  29. #include "config.h"
  30. #endif
  31.  
  32. #include <signal.h>
  33. #include "sigsegv.h"
  34.  
  35. // Return value type of a signal handler (standard type if not defined)
  36. #ifndef RETSIGTYPE
  37. #define RETSIGTYPE void
  38. #endif
  39.  
  40. // Type of the system signal handler
  41. typedef RETSIGTYPE (*signal_handler)(int);
  42.  
  43. // User's SIGSEGV handler
  44. static sigsegv_handler_t sigsegv_user_handler = 0;
  45.  
  46. // Actual SIGSEGV handler installer
  47. static bool sigsegv_do_install_handler(int sig);
  48.  
  49.  
  50. /*
  51.  *  OS-dependant SIGSEGV signals support section
  52.  */
  53.  
  54. #if HAVE_SIGINFO_T
  55. // Generic extended signal handler
  56. #define SIGSEGV_ALL_SIGNALS                FAULT_HANDLER(SIGSEGV)
  57. #define SIGSEGV_FAULT_HANDLER_ARGLIST    int sig, siginfo_t *sip, void *
  58. #define SIGSEGV_FAULT_ADDRESS            sip->si_addr
  59. #endif
  60.  
  61. #if HAVE_SIGCONTEXT_SUBTERFUGE
  62. // Linux kernels prior to 2.4 ?
  63. #if defined(__linux__)
  64. #define SIGSEGV_ALL_SIGNALS                FAULT_HANDLER(SIGSEGV)
  65. #if (defined(i386) || defined(__i386__))
  66. #include <asm/sigcontext.h>
  67. #define SIGSEGV_FAULT_HANDLER_ARGLIST    int sig, struct sigcontext scs
  68. #define SIGSEGV_FAULT_ADDRESS            scs.cr2
  69. #define SIGSEGV_FAULT_INSTRUCTION        scs.eip
  70. #endif
  71. #if (defined(sparc) || defined(__sparc__))
  72. #include <asm/sigcontext.h>
  73. #define SIGSEGV_FAULT_HANDLER_ARGLIST    int sig, int code, struct sigcontext* scp, char* addr
  74. #define SIGSEGV_FAULT_ADDRESS            addr
  75. #endif
  76. #if (defined(powerpc) || defined(__powerpc__))
  77. #include <asm/sigcontext.h>
  78. #define SIGSEGV_FAULT_HANDLER_ARGLIST    int sig, struct sigcontext* scp
  79. #define SIGSEGV_FAULT_ADDRESS            scp->regs->dar
  80. #define SIGSEGV_FAULT_INSTRUCTION        scp->regs->nip
  81. #endif
  82. #endif
  83.  
  84. // Irix 5 or 6 on MIPS
  85. #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4))
  86. #define SIGSEGV_FAULT_HANDLER_ARGLIST    int sig, int code, struct sigcontext *scp
  87. #define SIGSEGV_FAULT_ADDRESS            scp->sc_badvaddr
  88. #define SIGSEGV_ALL_SIGNALS                FAULT_HANDLER(SIGSEGV)
  89. #endif
  90.  
  91. // OSF/1 on Alpha
  92. #if defined(__osf__)
  93. #define SIGSEGV_FAULT_HANDLER_ARGLIST    int sig, int code, struct sigcontext *scp
  94. #define SIGSEGV_FAULT_ADDRESS            scp->sc_traparg_a0
  95. #define SIGSEGV_ALL_SIGNALS                FAULT_HANDLER(SIGSEGV)
  96. #endif
  97.  
  98. // AIX
  99. #if defined(_AIX)
  100. #define SIGSEGV_FAULT_HANDLER_ARGLIST    int sig, int code, struct sigcontext *scp
  101. #define SIGSEGV_FAULT_ADDRESS            scp->sc_jmpbuf.jmp_context.o_vaddr
  102. #define SIGSEGV_ALL_SIGNALS                FAULT_HANDLER(SIGSEGV)
  103. #endif
  104.  
  105. // NetBSD or FreeBSD
  106. #if defined(__NetBSD__) || defined(__FreeBSD__)
  107. #if (defined(m68k) || defined(__m68k__))
  108. #include <m68k/frame.h>
  109. #define SIGSEGV_FAULT_HANDLER_ARGLIST    int sig, int code, struct sigcontext *scp
  110. #define SIGSEGV_FAULT_ADDRESS            ({                                                                \
  111.     struct sigstate {                                                                                    \
  112.         int ss_flags;                                                                                    \
  113.         struct frame ss_frame;                                                                            \
  114.     };                                                                                                    \
  115.     struct sigstate *state = (struct sigstate *)scp->sc_ap;                                                \
  116.     char *fault_addr;                                                                                    \
  117.     switch (state->ss_frame.f_format) {                                                                    \
  118.     case 7:        /* 68040 access error */                                                                \
  119.         /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */    \
  120.         fault_addr = state->ss_frame.f_fmt7.f_fa;                                                        \
  121.         break;                                                                                            \
  122.     default:                                                                                            \
  123.         fault_addr = (char *)code;                                                                        \
  124.         break;                                                                                            \
  125.     }                                                                                                    \
  126.     fault_addr;                                                                                            \
  127. })
  128. #define SIGSEGV_ALL_SIGNALS                FAULT_HANDLER(SIGSEGV)
  129. #else
  130. #define SIGSEGV_FAULT_HANDLER_ARGLIST    int sig, int code, void *scp, char *addr
  131. #define SIGSEGV_FAULT_ADDRESS            addr
  132. #define SIGSEGV_ALL_SIGNALS                FAULT_HANDLER(SIGBUS)
  133. #endif
  134. #endif
  135. #endif
  136.  
  137. // Fallbacks
  138. #ifndef SIGSEGV_FAULT_INSTRUCTION
  139. #define SIGSEGV_FAULT_INSTRUCTION        SIGSEGV_INVALID_PC
  140. #endif
  141.  
  142. // SIGSEGV recovery supported ?
  143. #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
  144. #define HAVE_SIGSEGV_RECOVERY
  145. #endif
  146.  
  147.  
  148. /*
  149.  *  SIGSEGV global handler
  150.  */
  151.  
  152. #ifdef HAVE_SIGSEGV_RECOVERY
  153. static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
  154. {
  155.     // Call user's handler and reinstall the global handler, if required
  156.     if (sigsegv_user_handler((sigsegv_address_t)SIGSEGV_FAULT_ADDRESS, (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION)) {
  157. #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
  158.         sigsegv_do_install_handler(sig);
  159. #endif
  160.     }
  161.     else {
  162.         // FAIL: reinstall default handler for "safe" crash
  163. #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
  164.         SIGSEGV_ALL_SIGNALS
  165. #undef FAULT_HANDLER
  166.     }
  167. }
  168. #endif
  169.  
  170.  
  171. /*
  172.  *  SIGSEGV handler initialization
  173.  */
  174.  
  175. #if defined(HAVE_SIGINFO_T)
  176. static bool sigsegv_do_install_handler(int sig)
  177. {
  178.     // Setup SIGSEGV handler to process writes to frame buffer
  179. #ifdef HAVE_SIGACTION
  180.     struct sigaction vosf_sa;
  181.     sigemptyset(&vosf_sa.sa_mask);
  182.     vosf_sa.sa_sigaction = sigsegv_handler;
  183.     vosf_sa.sa_flags = SA_SIGINFO;
  184.     return (sigaction(sig, &vosf_sa, 0) == 0);
  185. #else
  186.     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
  187. #endif
  188. }
  189. #endif
  190.  
  191. #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
  192. static bool sigsegv_do_install_handler(int sig)
  193. {
  194.     // Setup SIGSEGV handler to process writes to frame buffer
  195. #ifdef HAVE_SIGACTION
  196.     struct sigaction vosf_sa;
  197.     sigemptyset(&vosf_sa.sa_mask);
  198.     vosf_sa.sa_handler = (signal_handler)sigsegv_handler;
  199. #if !EMULATED_68K && defined(__NetBSD__)
  200.     sigaddset(&vosf_sa.sa_mask, SIGALRM);
  201.     vosf_sa.sa_flags = SA_ONSTACK;
  202. #else
  203.     vosf_sa.sa_flags = 0;
  204. #endif
  205.     return (sigaction(sig, &vosf_sa, 0) == 0);
  206. #else
  207.     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
  208. #endif
  209. }
  210. #endif
  211.  
  212. bool sigsegv_install_handler(sigsegv_handler_t handler)
  213. {
  214. #ifdef HAVE_SIGSEGV_RECOVERY
  215.     sigsegv_user_handler = handler;
  216.     bool success = true;
  217. #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
  218.     SIGSEGV_ALL_SIGNALS
  219. #undef FAULT_HANDLER
  220.     return success;
  221. #else
  222.     // FAIL: no siginfo_t nor sigcontext subterfuge is available
  223.     return false;
  224. #endif
  225. }
  226.  
  227.  
  228. /*
  229.  *  SIGSEGV handler deinitialization
  230.  */
  231.  
  232. void sigsegv_deinstall_handler(void)
  233. {
  234. #ifdef HAVE_SIGSEGV_RECOVERY
  235.     sigsegv_user_handler = 0;
  236. #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
  237.     SIGSEGV_ALL_SIGNALS
  238. #undef FAULT_HANDLER
  239. #endif
  240. }
  241.  
  242. /*
  243.  *  Test program used for configure/test
  244.  */
  245.  
  246. #ifdef CONFIGURE_TEST
  247. #include <stdio.h>
  248. #include <stdlib.h>
  249. #include <unistd.h>
  250. #include <fcntl.h>
  251. #include <sys/mman.h>
  252.  
  253. static caddr_t page = 0;
  254. static int page_size;
  255. static int handler_called = 0;
  256.  
  257. static bool sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
  258. {
  259.     handler_called++;
  260.     if ((fault_address - 123) != page)
  261.         exit(1);
  262.     if (mprotect((caddr_t)((unsigned long)fault_address & -page_size), page_size, PROT_READ | PROT_WRITE) != 0)
  263.         exit(1);
  264.     return true;
  265. }
  266.  
  267. int main(void)
  268. {
  269.     int zero_fd = open("/dev/zero", O_RDWR);
  270.     if (zero_fd < 0)
  271.         return 1;
  272.  
  273.     page_size = getpagesize();
  274.        page = (caddr_t)mmap(0, page_size, PROT_READ, MAP_PRIVATE, zero_fd, 0);
  275.     if (page == MAP_FAILED)
  276.         return 1;
  277.     
  278.     if (!sigsegv_install_handler(sigsegv_test_handler))
  279.         return 1;
  280.     
  281.     page[123] = 45;
  282.     page[123] = 45;
  283.     
  284.     if (handler_called != 1)
  285.         return 1;
  286.  
  287.     return 0;
  288. }
  289. #endif
  290.