home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c065 / 1.ddi / CLIB1.ZIP / SIGNAL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-07  |  16.6 KB  |  432 lines

  1. /*----------------------------------------------------------------------*
  2.  * filename - signal.c                          *
  3.  *                                    *
  4.  * function(s) signal(), raise()                    *
  5.  * usage                                *
  6.  *        Function prototypes are in SIGNAL.H            *
  7.  *                                    *
  8.  *    oldcatcher = signal(sig, newcatcher);                *
  9.  *        void (*oldcatcher)(int) Ptr to previous signal catcher    *
  10.  *        int  sig                Signal # to install catcher for    *
  11.  *    void (*newcatcher)(int) Address of new signal catcher        *
  12.  *                                    *
  13.  *    rc = raise(sig);                        *
  14.  *    int  rc            Return code, success=0, error=!0    *
  15.  *    int  sig        Signal number to raise            *
  16.  *----------------------------------------------------------------------*/
  17.  
  18. /*[]------------------------------------------------------------[]*/
  19. /*|                                                              |*/
  20. /*|     Turbo C Run Time Library - Version 3.0                   |*/
  21. /*|                                                              |*/
  22. /*|                                                              |*/
  23. /*|     Copyright (c) 1987,1988,1990 by Borland International    |*/
  24. /*|     All Rights Reserved.                                     |*/
  25. /*|                                                              |*/
  26. /*[]------------------------------------------------------------[]*/
  27.  
  28. #include <process.h>    /* Get definition for _exit() */
  29. #include <errno.h>
  30. #include <dos.h>
  31. #include <float.h>    /* Get definition for FPE_nn SEGV_nn ILL_nn types */
  32. #include <signal.h>
  33.  
  34. #pragma warn -pro
  35.  
  36. #undef ANSI_CONFORMING
  37. #undef BOUNDS_TRAP
  38. #undef ILLEGALOP_TRAP
  39.  
  40. #define ANSI_CONFORMING
  41. #define BOUNDS_TRAP
  42. #define ILLEGALOP_TRAP
  43.  
  44. /*----------------------------- NOTE ! ---------------------------------
  45.  
  46. Normal ANSI operation resets ALL signals,  Microsoft(R) doesn't reset SIGFPE.
  47. Remove ANSI_CONFORMING define for MS style SIGFPE operation.
  48. Remove BOUNDS_TRAP define disables SIGSEGV bound violations.
  49. Remove ILLEGALOP_TRAP define disables SIGILL illegal op violations.
  50. Default configuration is ANSI conforming SIGFPE operation.
  51. Default configuration enables SIGSEGV to detect BOUND violations.
  52. Default configuration enables SIGSILL to detect illegal operations.
  53.  
  54.   ----------------------------- NOTE ! -------------------------------*/
  55.  
  56. typedef void _Cdecl (* CatcherPTR)();
  57.  
  58. typedef unsigned char UCHAR;
  59.  
  60. static void interrupt Int0Catcher(unsigned);
  61. static void interrupt Int4Catcher(unsigned);
  62.  
  63. #ifdef BOUNDS_TRAP
  64. typedef unsigned U;
  65.  
  66. static void interrupt (*BiosPrtScr)();    /* Old BIOS Int 5 vector */
  67.  
  68. static char GotInt5 = 0;
  69. static void interrupt Int5Catcher(U, U, U, U, U, U, U, U, U, U, U, U);
  70. #endif
  71.  
  72. #ifdef ILLEGALOP_TRAP
  73. static void interrupt Int6Catcher(unsigned);
  74. #endif
  75.  
  76. static void interrupt Int23Catcher(void);
  77. static int GetIndex(int);
  78.  
  79. CatcherPTR signal(int, CatcherPTR);
  80. int raise(int);
  81.  
  82. extern    CatcherPTR     (*__SignalPtr)();
  83. static    char        SignalPtrSet=0;
  84.  
  85. #define BogusSignal    -1    /* Flags a bogus signal type    */
  86.  
  87. /*+----------------------------------------------------------------------+
  88.   |       Signal Dispatch, Index Generator & Signal Default Tables       |
  89.   | *** Note : Ordering of constants in these tables MUST match          |
  90.   +----------------------------------------------------------------------+*/
  91. #define SIGINT_INDEX    0
  92. #define SIGILL_INDEX    1
  93. #define SIGFPE_INDEX    2
  94. #define SIGSEGV_INDEX    3
  95. #define SIGTERM_INDEX    4
  96. #define SIGABRT_INDEX    5
  97.  
  98. static CatcherPTR Dispatch[] = 
  99. {
  100.     (CatcherPTR)SIG_DFL,    /* SIGINT   (2) */
  101.     (CatcherPTR)SIG_DFL,    /* SIGILL   (4) */
  102.     (CatcherPTR)SIG_DFL,    /* SIGFPE   (8) */
  103.     (CatcherPTR)SIG_DFL,    /* SIGSEGV  (11)*/
  104.     (CatcherPTR)SIG_DFL,    /* SIGTERM  (15)*/
  105.     (CatcherPTR)SIG_DFL     /* SIGABRT  (22)*/
  106. };
  107.  
  108. static const UCHAR IxGen[] =
  109. {
  110. /* NEVER! change the ordering of these */
  111.  
  112.     SIGINT,            /* Index 0 */
  113.     SIGILL,            /* Index 1 */
  114.     SIGFPE,            /* Index 2 */
  115.     SIGSEGV,        /* Index 3 */
  116.     SIGTERM,        /* Index 4 */
  117.         SIGABRT                 /* Index 5 */
  118. };
  119.  
  120. /*+----------------------------------------------------------------------+
  121.   |            Table of values for EXPLICITLY raised signals             |
  122.   |  For SIGILL, SIGFPE & SIGSEGV explicit generation may have special   |
  123.   |  meaning to applications.  For the others use dummy 0's.             |
  124.   +----------------------------------------------------------------------+*/
  125. static const UCHAR ExplicitVal[] =
  126. {
  127.     0,            /* SIGINT  */
  128.     ILL_EXPLICITGEN,    /* SIGILL  */
  129.     FPE_EXPLICITGEN,    /* SIGFPE  */
  130.     SEGV_EXPLICITGEN,    /* SIGSEGV */
  131.     0,            /* SIGTERM */
  132.     0            /* SIGABRT */
  133. };
  134.  
  135.  
  136. #ifdef BOUNDS_TRAP
  137. /*+----------------------------------------------------------------------+
  138.   |  Int5Catcher() - Int 5 catcher for detecting BOUND violations on     |
  139.   |                  80188/80186/80286/80386 & NEC V Series processors.  |
  140.   |                                                                      |
  141.   |  This routine is installed when any call to signal with SIGSEGV is   |
  142.   |  specified.  THIS ROUTINE REMAINS INSTALLED AS THE INT 5 HANDLER FOR |
  143.   |  THE REST OF THE PROGRAM DURATION.                                   |
  144.   |  When activated this routine checks where the interrupt came from.   |
  145.   |  If the return CS:IP points to a BOUND instruction it is assumed the |
  146.   |  bounds check done by that instruction failed.  If the return CS:IP  |
  147.   |  points to something other than a BOUND instruction then we assume   |
  148.   |  that the user wanted to do a BIOS Prt-screen.  We call the old BIOS |
  149.   |  handler in this case.                                               |
  150.   |                                                                      |
  151.   +----------------------------------------------------------------------+
  152.   |                                                                      |
  153.   |  There are some EXTREMELY rare cases where this scheme fails.        |
  154.   |  One is when somebody does the following instruction sequence in     |
  155.   |  their code (which I doubt has EVER been done ANYWHERE by anybody):  |
  156.   |                                                                      |
  157.   |               INT 5           ; Do a prt-screen                      |
  158.   |               BOUND  ...      ; Check bounds                         |
  159.   |                                                                      |
  160.   |  Here the return CS:IP on the interrupt handlers stack DOES point to |
  161.   |  a BOUND instruction, but one that hasn't been executed yet!  We     |
  162.   |  might think the heuristic "if it's a BOUND instruction proceeded by |
  163.   |  an INT 5 then it's not a REAL violation." would serve us well here, |
  164.   |  but alas it doesn't because the following situation can exist.      |
  165.   |  A program jumps to a BOUND instruction that is preceded by some     |
  166.   |  DATA that happens to LOOK like an INT 5 instruction by accident ex: |
  167.   |                                                                      |
  168.   |              JMP   DOBOUND                                           |
  169.   |  SOMEDATA    DB    0CDH, 5   ; Data that looks like an INT 5         |
  170.   |  DOBOUND :   BOUND  ...      ; Check bounds                          |
  171.   |                                                                      |
  172.   |  In the above example the heuristic fails us completely.             |
  173.   |                                                                      |
  174.   |  Thus, we're left solidly impaled on the horns of a dilemma.  Do we  |
  175.   |  recognize a BOUND violation where none exists, or do we ignore a    |
  176.   |  possibly genuine BOUND violation?  Hmm... if only Prt-Scr wasn't on |
  177.   |  INT 5.                                                              |
  178.   |                                                                      |
  179.   |  So... what do we do here, eh?                                       |
  180.   |  For the sake of expedience we'll punt.  A quick look at the         |
  181.   |  instruction pointed to by the return CS:IP will be done. If we      |
  182.   |  see a BOUND instruction we call the handler.                        |
  183.   |                                                                      |
  184.   |  Avoiding these situations amounts to putting a NOP before           |
  185.   |  any BOUND instruction that is in one of these rare situations.      |
  186.   |  Not exactly a tough a work around!                                  |
  187.   +----------------------------------------------------------------------+*/
  188.  
  189. #pragma argsused
  190. static void interrupt Int5Catcher(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags)
  191. unsigned bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags;
  192. {
  193.     register CatcherPTR    action;
  194.  
  195. #define    BND_OPCODE    0x62
  196.  
  197.     if (*(*((UCHAR far * far *)((unsigned far *)&ip))) != BND_OPCODE)
  198.                 (*BiosPrtScr)();                     // Hand off Prt-Sc request
  199.         else                                         // Process BOUND violation
  200.         if ((action = Dispatch[3]) != SIG_IGN)
  201.         {
  202.             if ((action == SIG_DFL) || (action == SIG_ERR))
  203.                 _exit(1);
  204.                         Dispatch[3] = SIG_DFL;        // Reset signal
  205.                         (*action)(SIGSEGV, SEGV_BOUND, &bp); // Call handler
  206.         }
  207. }
  208. #endif    /*** BOUNDS_TRAP ***/
  209.  
  210. #ifdef ILLEGALOP_TRAP
  211. /*+----------------------------------------------------------------------+
  212.   |  Int6Catcher() - Int 6 catcher for detecting illegal operations on   |
  213.   |                  80188/80186/80286/80386 & NEC V Series processors.  |
  214.   |                                                                      |
  215.   |  This routine is installed when any call to signal with SIGILL is    |
  216.   |  specified.  THIS ROUTINE REMAINS INSTALLED AS THE INT 6 HANDLER FOR |
  217.   |  THE REST OF THE PROGRAM DURATION.                                   |
  218.   +----------------------------------------------------------------------+*/
  219. static void interrupt Int6Catcher(bp)
  220. unsigned bp;
  221. {
  222.     register CatcherPTR    action;
  223.  
  224.     if ((action = Dispatch[1]) != SIG_IGN)
  225.     {
  226.         if ((action == SIG_DFL) || (action == SIG_ERR))
  227.             _exit(1);
  228.         Dispatch[1] = SIG_DFL;        /* Reset signal    */
  229.         (*action)(SIGILL, ILL_EXECUTION, &bp);    /* Call handler    */
  230.     }
  231. }
  232. #endif    /*** ILLEGALOP_TRAP ***/
  233.  
  234. /*+----------------------------------------------------------------------+
  235.   |  Int0Catcher() - Integer divide by zero exception handler.           |
  236.   |                  This routine is part of the extensions to SIGFPE    |
  237.   |                  handling to include integer arithmetic exceptions.  |
  238.   |                  ANSI doesn't restrict SIGFPE to just floats!        |
  239.   |                                                                      |
  240.   |  This routine is installed when any call to signal with SIGFPE is    |
  241.   |  specified.  When activated this routine does the equivalent of      |
  242.   |  raise(SIGFPE, ...).  THIS ROUTINE REMAINS INSTALLED AS THE DIVIDE   |
  243.   |  BY ZERO HANDLER FOR THE REST OF THE PROGRAM DURATION.  If the       |
  244.   |  application never installs a SIGFPE handler then the default action |
  245.   |  setup by the 'C' startup code will be used.  If the app steals      |
  246.   |  INT 0 back from us the only way the INT 0 SIGFPE code can be        |
  247.   |  reactivated is signal(SIGFPE, ....) again!                          |
  248.   +----------------------------------------------------------------------+*/
  249. static void interrupt Int0Catcher(bp)
  250. unsigned bp;
  251. {
  252.     register CatcherPTR    action;
  253.  
  254.     if ((action = Dispatch[2]) != SIG_IGN)
  255.     {
  256.         if ((action == SIG_DFL) || (action == SIG_ERR))
  257.             _exit(1);
  258. #ifdef ANSI_CONFORMING
  259.         Dispatch[2] = SIG_DFL;         /* Reset signal */
  260. #endif
  261.         (*action)(SIGFPE, FPE_INTDIV0, &bp);    /* Call handler */
  262.     }
  263. }
  264.  
  265. /*+----------------------------------------------------------------------+
  266.   |  Int4Catcher() - Interrupt on overflow handler.                      |
  267.   |                  This routine is part of the extensions to SIGFPE    |
  268.   |                  handling to include integer arithmetic exceptions.  |
  269.   |                  ANSI doesn't restrict SIGFPE to just floats!        |
  270.   |                                                                      |
  271.   |  This routine is installed when any call to signal with SIGFPE is    |
  272.   |  specified.  When activated this routine does the equivalent of      |
  273.   |  raise(SIGFPE, ...).  THIS ROUTINE REMAINS INSTALLED AS THE Int 4    |
  274.   |  HANDLER FOR THE REST OF THE PROGRAM DURATION.  If the               |
  275.   |  application never installs a SIGFPE handler then the default actions|
  276.   |  apply. If the app steals INT 4 back from us the only way the INT 4  |
  277.   |  SIGFPE code can be reactivated is call signal(SIGFPE, ....) again!  |
  278.   +----------------------------------------------------------------------+*/
  279. static void interrupt Int4Catcher(bp)
  280. unsigned bp;
  281. {
  282.     register CatcherPTR    action;
  283.  
  284.     if ((action = Dispatch[2]) != SIG_IGN) 
  285.     {
  286.         if ((action == SIG_DFL) || (action == SIG_ERR))
  287.             _exit(1);
  288. #ifdef ANSI_CONFORMING
  289.         Dispatch[2] = SIG_DFL;         /* Reset signal */
  290. #endif
  291.         (*action)(SIGFPE, FPE_INTOVFLOW, &bp);    /* Call handler */
  292.     }
  293. }
  294.  
  295. /*+----------------------------------------------------------------------+
  296.   |          Routine intercepts int 23H and routes to user handler       |
  297.   +----------------------------------------------------------------------+*/
  298. static void interrupt Int23Catcher()
  299. {
  300.     register CatcherPTR    action;
  301.  
  302.     if ((action = Dispatch[0]) != SIG_IGN) 
  303.     {
  304.         if ((action == SIG_DFL) || (action == SIG_ERR))
  305.             _exit(1);
  306.         Dispatch[0] = SIG_DFL;            /* Reset signal */
  307.                 (*action)(SIGINT);                      /* Call handler */
  308.     }
  309. }
  310.  
  311. /*+----------------------------------------------------------------------+
  312.   |   GetIndex()  Get a DispatchTable index for specified signal type    |
  313.   +----------------------------------------------------------------------+*/
  314. static int GetIndex(int SigType)
  315. {
  316.     register int i;
  317.  
  318.     for (i = 0; i < sizeof(IxGen); i++)
  319.         if (IxGen[i] == SigType)
  320.             return i;
  321.     return -1;
  322. }
  323.  
  324. /*+----------------------------------------------------------------------+
  325.   |                Signal() - Install new signal catchers                |
  326.   +----------------------------------------------------------------------+*/
  327. void (* _Cdecl signal(sig, New))(int)
  328. int sig;
  329. CatcherPTR New;
  330.  
  331. /* CatcherPTR signal(register int sig, CatcherPTR New) */
  332. {
  333.     register int    Index;
  334.     CatcherPTR    OldVal;
  335.  
  336.     if (!SignalPtrSet)    /* let _fperr() know where signal is */
  337.     {
  338.         __SignalPtr = signal;
  339.         SignalPtrSet = 1;
  340.     }
  341.  
  342. #define    DISPATCH_SETTING New
  343.  
  344.     /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  345.          Get an index for the signal type, if its bad exit.
  346.     - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  347.     if ((Index = GetIndex(sig)) == BogusSignal) 
  348.     {
  349.         errno = EINVAL;        /* Bogus 'sig' parm was passed  */
  350.         return SIG_ERR;
  351.     }
  352.  
  353.     /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  354.     Install handler (SIGINT, SIGFPE & SIGSEGV are special)
  355.     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  356.     OldVal = Dispatch[Index];         /* Save the OLD handler    */
  357.     Dispatch[Index] = DISPATCH_SETTING;    /* Set the NEW handler    */
  358.     if (sig == SIGINT)
  359.     {
  360.                 setvect(0x23, Int23Catcher); /* Take INT 23H */
  361.     }
  362.     else if (sig == SIGFPE)
  363.     {
  364.                 setvect(0, Int0Catcher);     /* Take INT 0  */
  365.                 setvect(4, Int4Catcher);     /* Take INT 4  */
  366.     }
  367. #ifdef BOUNDS_TRAP
  368.     else if (sig == SIGSEGV)
  369.         if (!GotInt5)
  370.         {
  371.                         BiosPrtScr = getvect(5); /* Save old INT 5  */
  372.                         setvect(5, Int5Catcher); /* Take INT 5      */
  373.             GotInt5 = 1;
  374.         } else;
  375. #endif
  376. #ifdef ILLEGALOP_TRAP
  377.     else  if (sig == SIGILL)
  378.     {
  379.                 setvect(6, Int6Catcher); /* Take INT 6  */
  380.     }
  381. #endif
  382.  
  383.     return OldVal;
  384. }
  385.  
  386. /*+----------------------------------------------------------------------+
  387.   |                raise() - generate a software 'event'                 |
  388.   +----------------------------------------------------------------------+*/
  389. int raise(int SigType)
  390. {
  391.     int        Index;
  392.     CatcherPTR    action;
  393.  
  394.     if ((Index = GetIndex(SigType)) == BogusSignal)
  395.         return 1;
  396.     
  397.     if ((action = Dispatch[Index]) != SIG_IGN)
  398.         if (action == SIG_DFL)
  399.             switch (SigType)
  400.             {
  401.             case SIGABRT    :
  402.                 _exit(3);
  403.             case SIGINT    :
  404.                 geninterrupt( 0x23 );
  405.                 break;
  406.             case SIGILL     :
  407.             case SIGSEGV    :
  408.             case SIGTERM    :
  409.             case SIGFPE    :
  410.             default        :
  411.                 _exit(1);
  412.             }
  413.         else 
  414.         {    /*
  415.             Call user routine. Add optional parameter
  416.             specifing that the signal was raised explicitly
  417.             rather than asynchronously.
  418.             */
  419. #ifdef ANSI_CONFORMING
  420.             Dispatch[Index] = SIG_DFL; /* Always default (ANSI) */
  421. #else
  422.             if (SigType != SIGFPE)     /* Maybe default (MS) */
  423.                 Dispatch[Index] = SIG_DFL;
  424. #endif
  425.             (*action)(SigType, ExplicitVal[Index]);
  426.         }
  427.     return 0;
  428. }
  429.  
  430. #pragma warn .pro
  431.  
  432.