Leaked source code of windows server 2003
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.

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