home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / D / CLISP / CLISPSRC.TAR / clisp-1995-01-01 / unix / sigsegv.c < prev   
Encoding:
C/C++ Source or Header  |  1994-11-23  |  13.4 KB  |  472 lines

  1. /*
  2.  * Catching SIGSEGV and similar signals.
  3.  *
  4.  * Since this is highly non-portable, we provide a sample test program.
  5.  *
  6.  * Note: CLISP needs this facility only if the system also provides
  7.  *       getpagesize() and a working mprotect().
  8.  * Once you have extended this file, build the knowledge into src/unix.d.
  9.  */
  10.  
  11. /* How it works: We make a certain area read-only and write to it.
  12.  * We expect a SIGSEGV or similar. Then look at the signal handler's
  13.  * arguments, try to find the fault address.
  14.  *
  15.  * Sample session:
  16.  *   gcc -O -g sigsegv.c
  17.  *   gdb a.out
  18.  *   (gdb) handle SIGSEGV nostop
  19.  *   (gdb) break fault_handler
  20.  *   (gdb) run
  21.  *   (gdb) print fault_address
  22.  *   (gdb) print sig
  23.  *   (gdb) print arg1
  24.  *   (gdb) print *arg1
  25.  *   (gdb) print arg2
  26.  *   (gdb) print *arg2
  27.  *   (gdb) print arg3
  28.  *   (gdb) print *arg3
  29.  *
  30.  */
  31.  
  32.  
  33. #if 1
  34. /* Put your pathname to unixconf.h here if you have already run configure. */
  35. #include "unixconf.h"
  36. #endif
  37.  
  38. #ifndef UNIXCONF
  39.  
  40. /* The following bits of information can be copied from unixconf.h. */
  41.  
  42. /* CL_STDC_HEADERS */
  43. /* Define if you have the ANSI C header files
  44.    <stdlib.h>, <stdarg.h>, <string.h>, <float.h>, <limits.h>. */
  45. #undef STDC_HEADERS
  46.  
  47. /* CL_UNISTD_H */
  48. /* Define if you have <unistd.h>. */
  49. #undef HAVE_UNISTD_H
  50.  
  51. /* AC_SIZE_T */
  52. #ifndef size_t
  53. #undef size_t
  54. #endif
  55.  
  56. /* AC_RETSIGTYPE */
  57. /* Define as the return type of signal handlers (int or void). */
  58. #define RETSIGTYPE void
  59.  
  60. #endif
  61.  
  62.  
  63. /* Declarations. */
  64.  
  65. #ifdef STDC_HEADERS
  66. #include <stdlib.h>
  67. #endif
  68.  
  69. #ifdef HAVE_UNISTD_H
  70. #include <sys/types.h>
  71. #include <unistd.h>
  72. #endif
  73.  
  74. #include <signal.h>
  75. typedef RETSIGTYPE (*signal_handler) ();
  76. extern signal_handler signal (int sig, signal_handler handler);
  77. /* forward */ void install_signal (int sig, signal_handler handler);
  78.  
  79. #include <stdio.h>
  80.  
  81.  
  82. /* This is the database how to get the fault address. */
  83.  
  84.  
  85. #if (defined(i386) || defined(__i386) || defined(_I386)) && defined(linux)
  86.   /* This has been tested on Linux 1.1.38, but is likely to work for
  87.    * most i386 Unices because of iBCS compatibility.
  88.    *
  89.    * On Linux, the correct way to declare this would be
  90.    *   #define __KERNEL__
  91.    *   #include <linux/signal.h>
  92.    *   #define FAULT_ADDRESS  ((struct sigcontext_struct *)(&more))->cr2
  93.    */
  94. #define FAULT_HANDLER_ARGLIST  sig, more
  95. #define FAULT_HANDLER_ARGDECL  int sig; unsigned long more;
  96. #define FAULT_ADDRESS  ((unsigned long *) &more) [21]
  97. #define WP_SIGNAL  FAULT_HANDLER(SIGSEGV)
  98. #define CAN_HANDLE_WP_FAULT
  99. #endif
  100.  
  101. #if defined(sun) && defined(sparc) && 0 /* Sun4, SunOS 4.1 */
  102. #define FAULT_HANDLER_ARGLIST  sig, code, scp, addr
  103. #define FAULT_HANDLER_ARGDECL  int sig; int code; void* scp; char* addr;
  104. #define FAULT_ADDRESS  addr
  105. #define WP_SIGNAL  FAULT_HANDLER(SIGBUS)
  106. #define CAN_HANDLE_WP_FAULT
  107. #endif
  108.  
  109. #if defined(sun) && defined(sparc) && 0 /* Sun4, SunOS 4.1.3 */
  110. #define FAULT_HANDLER_ARGLIST  sig, code, scp, addr
  111. #define FAULT_HANDLER_ARGDECL  int sig; int code; void* scp; char* addr;
  112. #define FAULT_ADDRESS  addr
  113. #define WP_SIGNAL  FAULT_HANDLER(SIGSEGV)
  114. #define CAN_HANDLE_WP_FAULT
  115. #endif
  116.  
  117. #if defined(__sgi) && defined(__mips) && 0 /* SGI Mips, Irix 5.2 */
  118. #define FAULT_HANDLER_ARGLIST  sig, code, scp
  119. #define FAULT_HANDLER_ARGDECL  int sig; int code; struct sigcontext *scp;
  120. #define FAULT_ADDRESS  scp->sc_badvaddr
  121. #define WP_SIGNAL  FAULT_HANDLER(SIGSEGV)
  122. #define CAN_HANDLE_WP_FAULT
  123. #endif
  124.  
  125. #if defined(__osf__) && defined(__alpha__) /* DEC Alpha, OSF/1 2.0 */
  126. /* Note that this is not explicitly documented as being where the
  127.    fault address lives, so watch out for new releases. */
  128. #define FAULT_HANDLER_ARGLIST  sig, code, scp
  129. #define FAULT_HANDLER_ARGDECL  int sig; int code; struct sigcontext *scp;
  130. #define FAULT_ADDRESS  scp->sc_traparg_a0
  131. #define WP_SIGNAL  FAULT_HANDLER(SIGSEGV)
  132. #define CAN_HANDLE_WP_FAULT
  133. #endif
  134.  
  135. #if defined(_AIX) && defined(_AIX32) /* AIX 3.2, RS/6000, gcc */
  136. /* cf. AIX 3.2.5 Info Explorer,
  137.  * section "sigaction, sigvec, or signal Subroutine"
  138.  */
  139. #define FAULT_HANDLER_ARGLIST  sig, code, scp
  140. #define FAULT_HANDLER_ARGDECL  int sig; int code; struct sigcontext *scp;
  141. /* "Saved vaddr for vmexception", cf. <sys/mstsave.h> */
  142. #define FAULT_ADDRESS  scp->sc_jmpbuf.jmp_context.o_vaddr
  143. #define WP_SIGNAL  FAULT_HANDLER(SIGSEGV)
  144. #define CAN_HANDLE_WP_FAULT
  145. #endif
  146.  
  147. /* Oliver Laumann says on 11.8.1994:
  148.  *
  149.  * Determining the faulting address in a SIGSEGV or SIGBUS handler is
  150.  * definitely system dependent; it is even impossible on some platforms.
  151.  *
  152.  * In some UNIX variants, the third parameter passed to the signal handler
  153.  * is a `struct sigcontext *scp'; the address is available either as
  154.  * scp->sc_badvaddr (Ultrix), as scp->sc_jmpbuf.jmp_context.except[3]
  155.  * (AIX), as scp->sc_sl.sl_ss.ss_cr21 (HP-UX), or as scp->sc_traparg_a0
  156.  * (DEC/Alpha OSF/1).
  157.  *
  158.  * Or the address is passed to the handler as an additional, fourth
  159.  * argument (BSD, SunOS 4.x); or you can set the SA_SIGINFO flag in the
  160.  * sa_flags field of the `struct sigaction' argument to the sigaction()
  161.  * syscall to receive a `siginfo_t *' argument with a si_addr field in
  162.  * the handler (System V Release 4, SunOS 5.x, SGI Irix 5.1).
  163.  */
  164.  
  165. #if defined(sun) && defined(sparc) && 0 /* Sun4, SunOS 5.3 */
  166. #include <siginfo.h>
  167. #define FAULT_HANDLER_ARGLIST  sig, sip, ucp
  168. #define FAULT_HANDLER_ARGDECL  int sig; siginfo_t* sip; void* ucp;
  169. /* ucp is really of type ucontext_t*, which is defined in <ucontext.h>. */
  170. #define FAULT_ADDRESS  sip->si_addr
  171. /* If SA_SIGINFO isn't specified, sip will be a NULL pointer! */
  172. #define FAULT_ADDRESS_FROM_SIGINFO
  173. #define WP_SIGNAL  FAULT_HANDLER(SIGSEGV)
  174. #define CAN_HANDLE_WP_FAULT
  175. /* They don't have getpagesize(). This thing expands into sysconf(11). */
  176. #include <sys/param.h>
  177. #define getpagesize() PAGESIZE
  178. #endif
  179.  
  180. #if defined(__i386__) && defined(__NetBSD__) /* NetBSD 1.0 Beta */
  181. /* Douglas Crosher <dtc@scrooge.ee.swin.oz.au> says on 29 August 1994:
  182.  *
  183.  * There is no current support in NetBSD to save the needed CR2 register
  184.  * from which to obtain the fault address.
  185.  */
  186. #define WP_SIGNAL  FAULT_HANDLER(SIGBUS)
  187. #endif
  188.  
  189. #if defined(NeXT) /* NextStep 3.2 */
  190. /* The fault address is not passed to the signal handler. To get the fault
  191.  * address, a Mach exception handler has to be set up, which runs in a separate
  192.  * thread.
  193.  */
  194. #define WP_SIGNAL  FAULT_HANDLER(SIGBUS)
  195. #define CAN_HANDLE_WP_FAULT
  196. #endif
  197.  
  198. #if 0
  199. /* Ultrix ?? */
  200. #define FAULT_HANDLER_ARGLIST  sig, code, scp
  201. #define FAULT_HANDLER_ARGDECL  int sig; int code; struct sigcontext *scp;
  202. #define FAULT_ADDRESS  scp->sc_badvaddr
  203. #define WP_SIGNAL  FAULT_HANDLER(SIGSEGV)
  204. #define CAN_HANDLE_WP_FAULT
  205. #endif
  206.  
  207. #if 0
  208. /* HP-UX ?? */
  209. #define FAULT_HANDLER_ARGLIST  sig, code, scp
  210. #define FAULT_HANDLER_ARGDECL  int sig; int code; struct sigcontext *scp;
  211. #define FAULT_ADDRESS  scp->sc_sl.sl_ss.ss_cr21
  212. #define WP_SIGNAL  FAULT_HANDLER(SIGSEGV)
  213. /* They don't have getpagesize(). */
  214. #include <sys/param.h>
  215. #define getpagesize() sysconf(_SC_PAGE_SIZE)
  216. /* They don't have mprotect(). */
  217. #define CAN_HANDLE_WP_FAULT
  218. #endif
  219.  
  220. #if 0
  221. /* 386BSD, FreeBSD ?? */
  222. #define FAULT_HANDLER_ARGLIST  sig, code, scp, addr
  223. #define FAULT_HANDLER_ARGDECL  int sig; int code; void* scp; char* addr;
  224. #define FAULT_ADDRESS  addr
  225. #define WP_SIGNAL  FAULT_HANDLER(SIGBUS)
  226. #define CAN_HANDLE_WP_FAULT
  227. #endif
  228.  
  229. #if 0
  230. /* SysV R 4, Irix 5.1 ?? */
  231. #include <siginfo.h>
  232. #include <ucontext.h>
  233. #define FAULT_HANDLER_ARGLIST  sig, sip, ucp
  234. #define FAULT_HANDLER_ARGDECL  int sig; siginfo_t *sip; ucontext_t *ucp;
  235. #define FAULT_ADDRESS  sip->si_addr
  236. #endif
  237.  
  238.  
  239. #if !defined(CAN_HANDLE_WP_FAULT)
  240.  
  241.  
  242. /* A program for interactive debugging. */
  243.  
  244. char* fault_address;
  245. typedef void* (*something) [20];
  246. void do_nothing();
  247.  
  248. RETSIGTYPE fault_handler (sig, arg1, arg2, arg3, arg4, arg5, arg6)
  249.   int sig;
  250.   something arg1, arg2, arg3, arg4, arg5, arg6;
  251. { /* Set a breakpoint here! */
  252.   printf("Got signal sig=%d", sig);
  253.   if (sig==SIGSEGV)
  254.     printf("=SIGSEGV");
  255. #ifdef SIGBUS
  256.   if (sig==SIGBUS)
  257.     printf("=SIGBUS");
  258. #endif
  259. #ifdef SIGPROTV
  260.   if (sig==SIGPROTV)
  261.     printf("=SIGPROTV");
  262. #endif
  263.   printf(", with args 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, ...\n", arg1, arg2, arg3, arg4, arg5, arg6);
  264.   exit(0);
  265. }
  266.  
  267. int main ()
  268. { fault_address = (char*) 0x12345678;
  269.   printf("Look out for fault_address=0x%lx\n", (unsigned long)fault_address);
  270.  
  271.   install_signal(SIGSEGV,(signal_handler)fault_handler);
  272. #ifdef SIGBUS
  273.   install_signal(SIGBUS,(signal_handler)fault_handler);
  274. #endif
  275. #ifdef SIGPROTV
  276.   install_signal(SIGPROTV,(signal_handler)fault_handler);
  277. #endif
  278.  
  279.   do_nothing();
  280.   *(char *) fault_address = 'z';
  281.   do_nothing();
  282.  
  283.   printf("Got no exception!!\n");
  284.   exit(1);
  285. }
  286.  
  287. void do_nothing() { }
  288.  
  289.  
  290. #else /* CAN_HANDLE_WP_FAULT */
  291.  
  292.  
  293. /* Test the database entry. */
  294.  
  295.  
  296. #ifndef UNIXCONF
  297.  
  298. /* More information from unixconf.h */
  299.  
  300. /* CL_CADDR_T */
  301. #undef CADDR_T
  302.  
  303. /* CL_SIGNAL_REINSTALL */
  304. /* Define if signal handlers need to be reinstalled when they are activated. */
  305. #undef SIGNAL_NEED_REINSTALL
  306.  
  307. /* CL_GETPAGESIZE */
  308. /* Define if you have getpagesize(). */
  309. #undef HAVE_GETPAGESIZE
  310. /* Define as the return type of getpagesize(). */
  311. #undef RETGETPAGESIZETYPE
  312.  
  313. /* CL_MMAP */
  314. /* Define if you have <sys/mman.h> and the mmap() function. */
  315. #undef HAVE_MMAP
  316. /* Define as the return type of mmap(). */
  317. #undef RETMMAPTYPE
  318. /* Define as the type of `addr' in mmap() declaration. */
  319. #undef MMAP_ADDR_T
  320. /* Define as the type of `len' in mmap() declaration. */
  321. #undef MMAP_SIZE_T
  322.  
  323. #endif
  324.  
  325.  
  326. #ifndef getpagesize
  327. #ifdef HAVE_GETPAGESIZE
  328. extern RETGETPAGESIZETYPE getpagesize(/* void */);
  329. #else
  330. #error "Need getpagesize() for the test."
  331. #endif
  332. #endif
  333.  
  334. #ifdef NeXT /* NeXTstep has Mach VM. */
  335. #include <sys/types.h>
  336. #include <sys/resource.h>
  337. #include <mach/mach.h>
  338. #include <mach/machine/vm_param.h>
  339. #define mmap(addr,len,prot,unused_flags,unused_fd,unused_off) \
  340.   ({vm_address_t address = addr; \
  341.     vm_allocate(task_self(),&address,len,!(addr)); \
  342.     address; \
  343.   })
  344. #define mprotect(addr,len,prot) \
  345.   (vm_protect(task_self(),addr,len,0,prot)==KERN_SUCCESS ? 0 : -1)
  346. #define PROT_NONE 0
  347. #define PROT_READ VM_PROT_READ
  348. #define PROT_WRITE VM_PROT_WRITE
  349. #define PROT_EXEC VM_PROT_EXECUTE
  350. #else
  351. #ifdef HAVE_MMAP
  352. #include <sys/types.h>
  353. #include <sys/mman.h>
  354. extern RETMMAPTYPE mmap (/* MMAP_ADDR_T addr, MMAP_SIZE_T len, int prot, int flags, int fd, off_t off */);
  355. extern int mprotect (/* MMAP_ADDR_T addr, MMAP_SIZE_T len, int prot */);
  356. #else
  357. #error "Need mprotect() for the test."
  358. #endif
  359. #endif
  360.  
  361. #ifndef PROT_READ_WRITE
  362. #define PROT_READ_WRITE  PROT_READ | PROT_WRITE
  363. #endif
  364.  
  365.  
  366. unsigned long pagesize;
  367. #define page_align(address)  (char*)((unsigned long)(address) & -pagesize)
  368. char* fault_address;
  369. int signalled;
  370. int wp_sig_nr;
  371. void do_nothing();
  372.  
  373. void fault_handler (FAULT_HANDLER_ARGLIST)
  374.   FAULT_HANDLER_ARGDECL
  375. { char* address = (char*)(FAULT_ADDRESS);
  376.   printf("Entering handler, sig=%d, address=0x%lx, fault_address=0x%lx.\n",
  377.          sig, (unsigned long) address, (unsigned long) fault_address);
  378.   if (address != fault_address)
  379.     { printf("Doesn't work!!\n"); return; }
  380.   signalled = 1; wp_sig_nr = sig;
  381.   mprotect(page_align(address),pagesize,PROT_READ_WRITE);
  382.   install_signal(sig,(signal_handler)fault_handler);
  383.   printf("Exiting handler.\n");
  384.   return;
  385. }
  386.  
  387. int main ()
  388. { /* Get the page size. */
  389.   pagesize = getpagesize();
  390.   if ((pagesize-1) & pagesize)
  391.     { printf("Pagesize=0x%lx is not a power of 2.\n", (unsigned long) pagesize);
  392.       exit(1);
  393.     }
  394.   /* allocate some memory */
  395.  {char* area;
  396. #ifdef HAVE_MMAP
  397.   /* Try to allocate mmap()ed memory. On AIX 3.2 (and maybe HP-UX 9.0 and OSF/1
  398.    * as well) mprotect() does not work on normal malloc()ed memory.
  399.    */
  400. #ifdef _AIX
  401.   area = mmap(0,6*pagesize, PROT_READ_WRITE, MAP_ANONYMOUS | MAP_VARIABLE, -1, 0);
  402. #elif !defined(MAP_ANON)
  403.   area = mmap(0,6*pagesize, PROT_READ_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  404. #else
  405.   area = mmap(0,6*pagesize, PROT_READ_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
  406. #endif
  407.   if ((long)area < 0)
  408. #endif
  409.     { area = malloc(6*pagesize);
  410.       if (!area)
  411.         { printf("No memory.\n"); exit(1); }
  412.     }
  413.   fault_address = area + pagesize*7/2;
  414.   /* make it read-only */
  415.   if (mprotect(page_align(fault_address),pagesize,PROT_READ) < 0)
  416.     { perror("mprotect failed:"); exit(1); }
  417.   /* Install the handler */
  418. #define FAULT_HANDLER(sig)  install_signal(sig,(signal_handler)fault_handler);
  419.   WP_SIGNAL
  420. #undef FAULT_HANDLER
  421.   /* First test: write should provoke a signal */
  422.   signalled = 0;
  423.   do_nothing();
  424.   *(char*)fault_address = 'z';
  425.   do_nothing();
  426.   if (!signalled)
  427.     { printf("mprotect() didn't make the memory write-protected.\n"); exit(1); }
  428.   if (*(char*)fault_address != 'z')
  429.     { printf("Failed to resume write instruction correctly.\n"); exit(1); }
  430.   /* Second test: no signal please, this time */
  431.   signalled = 0;
  432.   do_nothing();
  433.   *(char*)fault_address = 'x';
  434.   do_nothing();
  435.   if (signalled)
  436.     { printf("mprotect() didn't make the memory read-write.\n"); exit(1); }
  437.   if (*(char*)fault_address != 'x')
  438.     { printf("This shouldn't be.\n"); exit(1); }
  439.   /* Everything worked. */
  440.   printf("Seems to work.\n");
  441.   exit(0);
  442. }}
  443.  
  444. void do_nothing() { }
  445.  
  446.  
  447. #endif /* CAN_HANDLE_WP_FAULT */
  448.  
  449.  
  450. /* Subroutine for installing the handler. */
  451. void install_signal (sig, handler)
  452.   int sig;
  453.   signal_handler handler;
  454. {
  455. #ifdef FAULT_ADDRESS_FROM_SIGINFO
  456.   struct sigaction action, dummy_action;
  457.   /* Get default action. */
  458.   dummy_action.sa_handler = handler;
  459.   dummy_action.sa_flags = 0;
  460.   sigemptyset(&dummy_action.sa_mask);
  461.   sigaction(sig,&dummy_action,&action);
  462.   /* Modify it. */
  463.   action.sa_handler = handler;
  464.   action.sa_flags |= SA_SIGINFO;
  465.   /* Activate it. */
  466.   sigaction(sig,&action,(struct sigaction *)0);
  467. #else
  468.   signal(sig,handler);
  469. #endif
  470. }
  471.  
  472.