Source code of Windows XP (NT5)
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.

668 lines
20 KiB

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