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