Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

618 lines
18 KiB

4 years ago
  1. /***
  2. *winxfltr.c - startup exception filter
  3. *
  4. * Copyright (c) 1990-1993, Microsoft Corporation. All rights reserved
  5. *
  6. *Purpose:
  7. * Defines _XcptFilter(), the function called by the exception filter
  8. * expression in the startup code.
  9. *
  10. *Revision History:
  11. * 10-31-91 GJF Module created. Copied from the original xcptfltr.c
  12. * then extensively revised.
  13. * 11-08-91 GJF Cleaned up header files usage.
  14. * 12-13-91 GJF Fixed multi-thread build.
  15. * 01-17-92 GJF Changed default handling under Win32 - unhandled
  16. * exceptions are now passed to UnhandledExceptionFilter.
  17. * Dosx32 behavior in unchanged. Also, used a couple of
  18. * local macros to simplify handling of single-thread vs
  19. * multi-thread code [_Win32_].
  20. * 02-16-93 GJF Changed for new _getptd().
  21. * 04-27-93 GJF Removed (commented out) entries in _XcptActTab which
  22. * corresponded to C RTEs. These will now simply be
  23. * passed on through to the system exception handler.
  24. *
  25. *******************************************************************************/
  26. #ifndef _POSIX_
  27. #include <cruntime.h>
  28. #include <float.h>
  29. #include <os2dll.h>
  30. #include <oscalls.h>
  31. #include <signal.h>
  32. #include <stddef.h>
  33. /*
  34. * special code denoting no signal.
  35. */
  36. #define NOSIG -1
  37. struct _XCPT_ACTION _VARTYPE1 _XcptActTab[] = {
  38. /*
  39. * Exceptions corresponding to the same signal (e.g., SIGFPE) must be grouped
  40. * together.
  41. *
  42. * XcptNum SigNum XcptAction
  43. * -------------------------------------------------------------------
  44. */
  45. { (unsigned long)STATUS_ACCESS_VIOLATION, SIGSEGV, SIG_DFL },
  46. { (unsigned long)STATUS_ILLEGAL_INSTRUCTION, SIGILL, SIG_DFL },
  47. { (unsigned long)STATUS_PRIVILEGED_INSTRUCTION, SIGILL, SIG_DFL },
  48. /* { (unsigned long)STATUS_NONCONTINUABLE_EXCEPTION, NOSIG, SIG_DIE },
  49. */
  50. /* { (unsigned long)STATUS_INVALID_DISPOSITION, NOSIG, SIG_DIE },
  51. */
  52. { (unsigned long)STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE, SIG_DFL },
  53. { (unsigned long)STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE, SIG_DFL },
  54. { (unsigned long)STATUS_FLOAT_INEXACT_RESULT, SIGFPE, SIG_DFL },
  55. { (unsigned long)STATUS_FLOAT_INVALID_OPERATION, SIGFPE, SIG_DFL },
  56. { (unsigned long)STATUS_FLOAT_OVERFLOW, SIGFPE, SIG_DFL },
  57. { (unsigned long)STATUS_FLOAT_STACK_CHECK, SIGFPE, SIG_DFL },
  58. { (unsigned long)STATUS_FLOAT_UNDERFLOW, SIGFPE, SIG_DFL },
  59. /* { (unsigned long)STATUS_INTEGER_DIVIDE_BY_ZERO, NOSIG, SIG_DIE },
  60. */
  61. /* { (unsigned long)STATUS_STACK_OVERFLOW, NOSIG, SIG_DIE }
  62. */
  63. };
  64. /*
  65. * size of the exception-action table (in bytes)
  66. */
  67. int _CRTVAR1 _XcptActTabSize = sizeof _XcptActTab;
  68. /*
  69. * number of entries in the exception-action table
  70. */
  71. int _CRTVAR1 _XcptActTabCount = (sizeof _XcptActTab)/sizeof(_XcptActTab[0]);
  72. #ifdef MTHREAD
  73. /*
  74. * the FPECODE and PXCPTINFOPTRS macros are intended to simplify some of
  75. * single vs multi-thread code in the filter function. basically, each macro
  76. * is conditionally defined to be a global variable or the corresponding
  77. * field in the per-thread data structure. NOTE THE ASSUMPTION THAT THE
  78. * _ptiddata VARIABLE IS ALWAYS NAMED ptd!!!!
  79. */
  80. #define FPECODE ptd->_tfpecode
  81. #define PXCPTINFOPTRS ptd->_tpxcptinfoptrs
  82. #else
  83. /*
  84. * global variable containing the floating point exception code
  85. */
  86. int _VARTYPE1 _fpecode = _FPE_EXPLICITGEN;
  87. #define FPECODE _fpecode
  88. /*
  89. * global variable holding _PEXCEPTION_INFO_PTRS value
  90. */
  91. void * _VARTYPE1 _pxcptinfoptrs = NULL;
  92. #define PXCPTINFOPTRS _pxcptinfoptrs
  93. #endif /* MTHREAD */
  94. /*
  95. * function to look up the exception action table (_XcptActTab[]) corresponding
  96. * to the given exception
  97. */
  98. #ifdef MTHREAD
  99. static struct _XCPT_ACTION * _CRTAPI3 xcptlookup(
  100. unsigned long,
  101. struct _XCPT_ACTION *
  102. );
  103. #else /* ndef MTHREAD */
  104. static struct _XCPT_ACTION * _CRTAPI3 xcptlookup(
  105. unsigned long
  106. );
  107. #endif /* MTHREAD */
  108. #ifdef DEBUG
  109. /*
  110. * prototypes for debugging routines
  111. */
  112. void prXcptActTabEntry(struct _XCPT_ACTION *);
  113. void prXcptActTab(void);
  114. #endif /* DEBUG */
  115. /***
  116. *int _XcptFilter(xcptnum, pxcptptrs) - Identify exception and the action to
  117. * be taken with it
  118. *
  119. *Purpose:
  120. * _XcptFilter() is called by the exception filter expression of the
  121. * _try - _except statement, in the startup code, which guards the call
  122. * to the user's main(). _XcptFilter() consults the _XcptActTab[] table
  123. * to identify the exception and determine its disposition. The
  124. * is disposition of an exception corresponding to a C signal may be
  125. * modified by a call to signal(). There are three broad cases:
  126. *
  127. * (1) Unrecognized exceptions and exceptions for which the XcptAction
  128. * value is SIG_DFL.
  129. *
  130. #ifndef DOSX32
  131. * In both of these cases, UnhandledExceptionFilter() is called and
  132. * its return value is returned.
  133. #else
  134. * In both of these cases, EXCEPTION_CONTINUE_SEARCH is returned to
  135. * cause the OS exception dispatcher to pass the exception onto the
  136. * next exception handler in the chain (usually a system default
  137. * handler).
  138. #endif
  139. *
  140. * (2) Exceptions corresponding to C signals with an XcptAction value
  141. * NOT equal to SIG_DFL.
  142. *
  143. * These are the C signals whose disposition has been affected by a
  144. * call to signal() or whose default semantics differ slightly from
  145. * from the corresponding OS exception. In all cases, the appropriate
  146. * disposition of the C signal is made by the function (e.g., calling
  147. * a user-specified signal handler). Then, EXCEPTION_CONTINUE_EXECU-
  148. * TION is returned to cause the OS exception dispatcher to dismiss
  149. * the exception and resume execution at the point where the
  150. * exception occurred.
  151. *
  152. * (3) Exceptions for which the XcptAction value is SIG_DIE.
  153. *
  154. * These are the exceptions corresponding to fatal C runtime errors.
  155. * _XCPT_HANDLE is returned to cause control to pass into the
  156. * _except-block of the _try - _except statement. There, the runtime
  157. * error is identified, an appropriate error message is printed out
  158. * and the program is terminated.
  159. *
  160. *Entry:
  161. *
  162. *Exit:
  163. *
  164. *Exceptions:
  165. * That's what it's all about!
  166. *
  167. *******************************************************************************/
  168. int _CRTAPI1 _XcptFilter (
  169. unsigned long xcptnum,
  170. PEXCEPTION_POINTERS pxcptinfoptrs
  171. )
  172. {
  173. struct _XCPT_ACTION * pxcptact;
  174. _PHNDLR phandler;
  175. void *oldpxcptinfoptrs;
  176. int oldfpecode;
  177. #ifdef MTHREAD
  178. _ptiddata ptd = _getptd();
  179. #endif /* MTHREAD */
  180. /*
  181. * first, take care of all unrecognized exceptions and exceptions with
  182. * XcptAction values of SIG_DFL.
  183. */
  184. #ifdef MTHREAD
  185. if ( ((pxcptact = xcptlookup(xcptnum, ptd->_pxcptacttab)) == NULL)
  186. || (pxcptact->XcptAction == SIG_DFL) )
  187. #else /* not MTHREAD */
  188. if ( ((pxcptact = xcptlookup(xcptnum)) == NULL) ||
  189. (pxcptact->XcptAction == SIG_DFL) )
  190. #endif /* MTHREAD */
  191. #ifndef DOSX32
  192. /*
  193. * pass the buck to the UnhandledExceptionFilter
  194. */
  195. return( UnhandledExceptionFilter(pxcptinfoptrs) );
  196. #else
  197. /*
  198. * pass the buck to the next level exception handler
  199. */
  200. return(EXCEPTION_CONTINUE_SEARCH);
  201. #endif
  202. #ifdef DEBUG
  203. prXcptActTabEntry(pxcptact);
  204. #endif /* DEBUG */
  205. /*
  206. * next, weed out all of the exceptions that need to be handled by
  207. * dying, perhaps with a runtime error message
  208. */
  209. if ( pxcptact->XcptAction == SIG_DIE ) {
  210. /*
  211. * reset XcptAction (in case of recursion) and drop into the
  212. * except-clause.
  213. */
  214. pxcptact->XcptAction = SIG_DFL;
  215. return(EXCEPTION_EXECUTE_HANDLER);
  216. }
  217. /*
  218. * next, weed out all of the exceptions that are simply ignored
  219. */
  220. if ( pxcptact->XcptAction == SIG_IGN )
  221. /*
  222. * resume execution
  223. */
  224. return(EXCEPTION_CONTINUE_EXECUTION);
  225. /*
  226. * the remaining exceptions all correspond to C signals which have
  227. * signal handlers associated with them. for some, special setup
  228. * is required before the signal handler is called. in all cases,
  229. * if the signal handler returns, -1 is returned by this function
  230. * to resume execution at the point where the exception occurred.
  231. *
  232. * before calling the signal handler, the XcptAction field of the
  233. * exception-action table entry must be reset.
  234. */
  235. phandler = pxcptact->XcptAction;
  236. /*
  237. * reset the action to be the default
  238. */
  239. pxcptact->XcptAction = SIG_DFL;
  240. /*
  241. * save the old value of _pxcptinfoptrs (in case this is a nested
  242. * exception/signal) and store the current one.
  243. */
  244. oldpxcptinfoptrs = PXCPTINFOPTRS;
  245. PXCPTINFOPTRS = pxcptinfoptrs;
  246. /*
  247. * call the user-supplied signal handler
  248. *
  249. * floating point exceptions must be handled specially since, from
  250. * the C point-of-view, there is only one signal. the exact identity
  251. * of the exception is passed in the global variable _fpecode.
  252. */
  253. if ( pxcptact->SigNum == SIGFPE ) {
  254. /*
  255. * Save the current _fpecode in case it is a nested floating
  256. * point exception (not clear that we need to support this,
  257. * but it's easy).
  258. */
  259. oldfpecode = FPECODE;
  260. /*
  261. * there are no exceptions corresponding to
  262. * following _FPE_xxx codes:
  263. *
  264. * _FPE_UNEMULATED
  265. * _FPE_SQRTNEG
  266. *
  267. * futhermore, STATUS_FLOATING_STACK_CHECK is
  268. * raised for both floating point stack under-
  269. * flow and overflow. thus, the exception does
  270. * not distinguish between _FPE_STACKOVERLOW
  271. * and _FPE_STACKUNDERFLOW. arbitrarily, _fpecode
  272. * is set to the former value.
  273. *
  274. * the following should be a switch statement but, alas, the
  275. * compiler doesn't like switching on unsigned longs...
  276. */
  277. if ( pxcptact->XcptNum == STATUS_FLOAT_DIVIDE_BY_ZERO )
  278. FPECODE = _FPE_ZERODIVIDE;
  279. else if ( pxcptact->XcptNum == STATUS_FLOAT_INVALID_OPERATION )
  280. FPECODE = _FPE_INVALID;
  281. else if ( pxcptact->XcptNum == STATUS_FLOAT_OVERFLOW )
  282. FPECODE = _FPE_OVERFLOW;
  283. else if ( pxcptact->XcptNum == STATUS_FLOAT_UNDERFLOW )
  284. FPECODE = _FPE_UNDERFLOW;
  285. else if ( pxcptact->XcptNum == STATUS_FLOAT_DENORMAL_OPERAND )
  286. FPECODE = _FPE_DENORMAL;
  287. else if ( pxcptact->XcptNum == STATUS_FLOAT_INEXACT_RESULT )
  288. FPECODE = _FPE_INEXACT;
  289. else if ( pxcptact->XcptNum == STATUS_FLOAT_STACK_CHECK )
  290. FPECODE = _FPE_STACKOVERFLOW;
  291. /*
  292. * call the SIGFPE handler. note the special hack to support
  293. * old MS-C programs whose SIGFPE handlers expect two args.
  294. *
  295. * NOTE: THE CAST AND CALL BELOW DEPEND ON _CRTAPI1 BEING
  296. * CALLER CLEANUP!
  297. */
  298. (*(void (* _CRTAPI1)(int, int))phandler)(SIGFPE, FPECODE);
  299. /*
  300. * restore the old value of _fpecode
  301. */
  302. FPECODE = oldfpecode;
  303. }
  304. else
  305. (*phandler)(pxcptact->SigNum);
  306. /*
  307. * restore the old value of _pxcptinfoptrs
  308. */
  309. PXCPTINFOPTRS = oldpxcptinfoptrs;
  310. return(EXCEPTION_CONTINUE_EXECUTION);
  311. }
  312. /***
  313. *struct _XCPT_ACTION * xcptlookup(xcptnum, pxcptrec) - look up exception-action
  314. * table entry for xcptnum
  315. *
  316. *Purpose:
  317. * Find the in _XcptActTab[] whose Xcptnum field is xcptnum.
  318. *
  319. *Entry:
  320. * unsigned long xcptnum - exception type
  321. *
  322. * _PEXCEPTIONREPORTRECORD pxcptrec - pointer to exception report record
  323. * (used only to distinguish different types of XCPT_SIGNAL)
  324. *
  325. *Exit:
  326. * If successful, pointer to the table entry. If no such entry, NULL is
  327. * returned.
  328. *
  329. *Exceptions:
  330. *
  331. *******************************************************************************/
  332. #ifdef MTHREAD
  333. static struct _XCPT_ACTION * _CRTAPI3 xcptlookup (
  334. unsigned long xcptnum,
  335. struct _XCPT_ACTION * pxcptacttab
  336. )
  337. #else /* not MTHREAD */
  338. static struct _XCPT_ACTION * _CRTAPI3 xcptlookup (
  339. unsigned long xcptnum
  340. )
  341. #endif /* MTHREAD */
  342. {
  343. #ifdef MTHREAD
  344. struct _XCPT_ACTION *pxcptact = pxcptacttab;
  345. #else /* ndef MTHREAD */
  346. struct _XCPT_ACTION *pxcptact = _XcptActTab;
  347. #endif /* MTHREAD */
  348. /*
  349. * walk thru the _xcptactab table looking for the proper entry
  350. */
  351. #ifdef MTHREAD
  352. while ( (pxcptact->XcptNum != xcptnum) && (++pxcptact <
  353. pxcptacttab + _XcptActTabCount) ) ;
  354. #else /* not MTHREAD */
  355. while ( (pxcptact->XcptNum != xcptnum) && (++pxcptact <
  356. _XcptActTab + _XcptActTabCount) ) ;
  357. #endif /* MTHREAD */
  358. /*
  359. * if no table entry was found corresponding to xcptnum, return NULL
  360. */
  361. if ( pxcptact->XcptNum != xcptnum )
  362. return(NULL);
  363. return(pxcptact);
  364. }
  365. #ifdef DEBUG
  366. /*
  367. * DEBUGGING TOOLS!
  368. */
  369. struct xcptnumstr {
  370. unsigned long num;
  371. char *str;
  372. };
  373. struct xcptnumstr XcptNumStr[] = {
  374. { (unsigned long)STATUS_DATATYPE_MISALIGNMENT,
  375. "STATUS_DATATYPE_MISALIGNMENT" },
  376. { (unsigned long)STATUS_ACCESS_VIOLATION,
  377. "STATUS_ACCESS_VIOLATION" },
  378. { (unsigned long)STATUS_ILLEGAL_INSTRUCTION,
  379. "STATUS_ILLEGAL_INSTRUCTION" },
  380. { (unsigned long)STATUS_NONCONTINUABLE_EXCEPTION,
  381. "STATUS_NONCONTINUABLE_EXCEPTION" },
  382. { (unsigned long)STATUS_INVALID_DISPOSITION,
  383. "STATUS_INVALID_DISPOSITION" },
  384. { (unsigned long)STATUS_FLOAT_DENORMAL_OPERAND,
  385. "STATUS_FLOAT_DENORMAL_OPERAND" },
  386. { (unsigned long)STATUS_FLOAT_DIVIDE_BY_ZERO,
  387. "STATUS_FLOAT_DIVIDE_BY_ZERO" },
  388. { (unsigned long)STATUS_FLOAT_INEXACT_RESULT,
  389. "STATUS_FLOAT_INEXACT_RESULT" },
  390. { (unsigned long)STATUS_FLOAT_INVALID_OPERATION,
  391. "STATUS_FLOAT_INVALID_OPERATION" },
  392. { (unsigned long)STATUS_FLOAT_OVERFLOW,
  393. "STATUS_FLOAT_OVERFLOW" },
  394. { (unsigned long)STATUS_FLOAT_STACK_CHECK,
  395. "STATUS_FLOAT_STACK_CHECK" },
  396. { (unsigned long)STATUS_FLOAT_UNDERFLOW,
  397. "STATUS_FLOAT_UNDERFLOW" },
  398. { (unsigned long)STATUS_INTEGER_DIVIDE_BY_ZERO,
  399. "STATUS_INTEGER_DIVIDE_BY_ZERO" },
  400. { (unsigned long)STATUS_PRIVILEGED_INSTRUCTION,
  401. "STATUS_PRIVILEGED_INSTRUCTION" },
  402. { (unsigned long)_STATUS_STACK_OVERFLOW,
  403. "_STATUS_STACK_OVERFLOW" }
  404. };
  405. #define XCPTNUMSTR_SZ ( sizeof XcptNumStr / sizeof XcptNumStr[0] )
  406. /*
  407. * return string mnemonic for exception
  408. */
  409. char * XcptNumToStr (
  410. unsigned long xcptnum
  411. )
  412. {
  413. int indx;
  414. for ( indx = 0 ; indx < XCPTNUMSTR_SZ ; indx++ )
  415. if ( XcptNumStr[indx].num == xcptnum )
  416. return(XcptNumStr[indx].str);
  417. return(NULL);
  418. }
  419. struct signumstr {
  420. int num;
  421. char *str;
  422. };
  423. struct signumstr SigNumStr[] = {
  424. { SIGINT, "SIGINT" },
  425. { SIGILL, "SIGILL" },
  426. { SIGFPE, "SIGFPE" },
  427. { SIGSEGV, "SIGSEGV" },
  428. { SIGTERM, "SIGTERM" },
  429. { SIGBREAK, "SIGBREAK" },
  430. { SIGABRT, "SIGABRT" }
  431. };
  432. #define SIGNUMSTR_SZ ( sizeof SigNumStr / sizeof SigNumStr[0] )
  433. /*
  434. * return string mnemonic for signal
  435. */
  436. char * SigNumToStr (
  437. int signum
  438. )
  439. {
  440. int indx;
  441. for ( indx = 0 ; indx < SIGNUMSTR_SZ ; indx++ )
  442. if ( SigNumStr[indx].num == signum )
  443. return(SigNumStr[indx].str);
  444. return(NULL);
  445. }
  446. struct actcodestr {
  447. _PHNDLR code;
  448. char *str;
  449. };
  450. struct actcodestr ActCodeStr[] = {
  451. { SIG_DFL, "SIG_DFL" },
  452. { SIG_IGN, "SIG_IGN" },
  453. { SIG_DIE, "SIG_DIE" }
  454. };
  455. #define ACTCODESTR_SZ ( sizeof ActCodeStr / sizeof ActCodeStr[0] )
  456. /*
  457. * return string mnemonic for action code
  458. */
  459. char * ActCodeToStr (
  460. _PHNDLR action
  461. )
  462. {
  463. int indx;
  464. for ( indx = 0 ; indx < ACTCODESTR_SZ ; indx++ )
  465. if ( ActCodeStr[indx].code == action)
  466. return(ActCodeStr[indx].str);
  467. return("FUNCTION ADDRESS");
  468. }
  469. /*
  470. * print out exception-action table entry
  471. */
  472. void prXcptActTabEntry (
  473. struct _XCPT_ACTION *pxcptact
  474. )
  475. {
  476. printf("XcptNum = %s\n", XcptNumToStr(pxcptact->XcptNum));
  477. printf("SigNum = %s\n", SigNumToStr(pxcptact->SigNum));
  478. printf("XcptAction = %s\n", ActCodeToStr(pxcptact->XcptAction));
  479. }
  480. /*
  481. * print out all entries in the exception-action table
  482. */
  483. void prXcptActTab (
  484. void
  485. )
  486. {
  487. int indx;
  488. for ( indx = 0 ; indx < _XcptActTabCount ; indx++ ) {
  489. printf("\n_XcptActTab[%d] = \n", indx);
  490. prXcptActTabEntry(&_XcptActTab[indx]);
  491. }
  492. }
  493. #endif /* DEBUG */
  494. #endif /* _POSIX_ */