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.

1565 lines
55 KiB

  1. /***
  2. *frame.cxx - The frame handler and everything associated with it.
  3. *
  4. * Copyright (c) 1993-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * The frame handler and everything associated with it.
  8. *
  9. * Entry points:
  10. * _CxxFrameHandler - the frame handler.
  11. *
  12. * Open issues:
  13. * Handling re-throw from dynamicly nested scope.
  14. * Fault-tolerance (checking for data structure validity).
  15. *
  16. *Revision History:
  17. * 05-20-93 BS Module created
  18. * 03-03-94 TL Added Mips specific code
  19. * 06-19-94 AD Added Alpha specific code (Al Dosser)
  20. * 10-17-94 BWT Disable code for PPC.
  21. * 11-23-94 JWM Removed obsolete 'hash' check in TypeMatch().
  22. * 11-29-94 JWM AdjustPointer() now adds in pdisp, not vdisp.
  23. * 01-13-95 JWM Added _NLG_Destination struct; dwCode set for catch
  24. * blocks & local destructors.
  25. * 02-09-95 JWM Mac merge.
  26. * 02-10-95 JWM UnhandledExceptionFilter() now called if exception
  27. * raised during stack unwind.
  28. * 03-22-95 PML Add const for read-only compiler-gen'd structs
  29. * 04-14-95 JWM Re-fix EH/SEH exception handling.
  30. * 04-17-95 JWM FrameUnwindFilter() must be #ifdef _WIN32.
  31. * 04-21-95 JWM _NLG_Destination moved to exsup3.asm (_M_X86 only).
  32. * 04-21-95 TGL Added Mips fixes.
  33. * 04-27-95 JWM EH_ABORT_FRAME_UNWIND_PART now #ifdef
  34. * ALLOW_UNWIND_ABORT.
  35. * 05-19-95 DAK Don't initialize the kernel handler
  36. * 06-07-95 JWM Various NLG additions.
  37. * 06-14-95 JWM Unneeded LastError calls removed.
  38. * 06-19-95 JWM NLG no longer uses per-thread data (X86 only).
  39. * 09-26-95 AMP PowerMac avoids re-throws to same catch clause
  40. * 08-06-95 JWM Typo fixed (Orion #6509); Alpha-specific.
  41. * 04-18-97 JWM In __InternalCxxFrameHandler(), 'recursive' changed to
  42. * BOOLEAN.
  43. * 06-01-97 TGL Added P7 specific code
  44. * 08-22-97 TGL More P7 fixes
  45. * 11-14-98 JWM Merge with P7 sources.
  46. * 02-11-99 TGL EH: correct catch in exe calling dll.
  47. * 05-17-99 PML Remove all Macintosh support.
  48. * 07-12-99 RDL Image relative fixes under CC_P7_SOFT25.
  49. * 10-17-99 PML Update EH state before each unwind action, instead of
  50. * once at end (vs7#5419)
  51. * 10-19-99 TGL More P7/Win64 fixes
  52. * 10-22-99 PML Add EHTRACE support
  53. * 12-10-99 GB Add Uncaught exception Support by adding a new function
  54. * __uncaught_exception();
  55. * 02-15-99 PML Can't put __try/__finally around call to
  56. * _UnwindNestedFrames (vs7#79460)
  57. * 03-03-00 GB made __DestructExceptionObject export from dll.
  58. * 03-21-00 KBF Check for C++ exception in __CxxExceptionFilter
  59. * 03-22-00 PML Remove CC_P7_SOFT25, which is now on permanently.
  60. * 03-28-00 GB Check for no buildobj in __CxxExceptionFilter.
  61. * 04-06-00 GB Added more functions for com+ eh support.
  62. * 04-19-00 GB ComPlus EH bug fixes.
  63. * 05-23-00 GB Don't catch BreakPoint generated Exceptions.
  64. * 05-30-00 GB ComPlus EH bug fixes.
  65. * 06-08-00 RDL VS#111429: IA64 workaround for AV while handling throw.
  66. * 06-21-00 GB Fix the difference in order of destruction and
  67. * construction depending on inlining.
  68. * 07-26-00 GB Fixed multiple destruction problem in COM+ eh.
  69. * 08-23-00 GB Fixed problem in BuildCatchObject when called from
  70. * __CxxExceptionFilter.
  71. * 02-23-01 PML Add __CxxCallUnwindDtor COM+ wrapper (vs7#217108)
  72. * 04-09-01 GB Add uncaught_exception support for COM+ C++ App.
  73. * 04-13-01 GB Fixed problems with Seh and catch(...). (vc7#236286)
  74. * 04-26-01 GB Fixed a problem with a rethrow without a throw
  75. * and catch(...)
  76. * 06-05-01 GB AMD64 Eh support Added.
  77. *
  78. ****/
  79. #include <stddef.h>
  80. #include <stdlib.h>
  81. #include <string.h>
  82. #include <malloc.h>
  83. #if defined(_NTSUBSET_)
  84. extern "C" {
  85. #include <nt.h>
  86. #include <ntrtl.h>
  87. #include <nturtl.h>
  88. #include <ntstatus.h> // STATUS_UNHANDLED_EXCEPTION
  89. #include <ntos.h>
  90. #include <ex.h> // ExRaiseException
  91. }
  92. #endif // defined(_NTSUBSET_)
  93. #include <windows.h>
  94. #include <internal.h>
  95. #include <mtdll.h> // CRT internal header file
  96. #include <ehassert.h> // This project's versions of standard assert macros
  97. #include <ehdata.h> // Declarations of all types used for EH
  98. #include <ehstate.h> // Declarations of state management stuff
  99. #include <eh.h> // User-visible routines for eh
  100. #include <ehhooks.h> // Declarations of hook variables and callbacks
  101. #include <trnsctrl.h> // Routines to handle transfer of control (trnsctrl.asm)
  102. #if defined(_M_IA64) /*IFSTRIP=IGN*/
  103. #include <kxia64.h>
  104. #include <ia64inst.h>
  105. #include <cvconst.h>
  106. #endif
  107. #pragma hdrstop // PCH is created from here
  108. ////////////////////////////////////////////////////////////////////////////////
  109. //
  110. // WIN64 specific definitions
  111. //
  112. #define __GetRangeOfTrysToCheck(a, b, c, d, e, f, g) \
  113. _GetRangeOfTrysToCheck(a, b, c, d, e, f, g)
  114. #define __CallSETranslator(a, b, c, d, e, f, g, h) \
  115. _CallSETranslator(a, b, c, d, e, f, g)
  116. #define __GetUnwindState(a, b, c) \
  117. GetCurrentState(a, b, c)
  118. #define __OffsetToAddress(a, b, c) \
  119. OffsetToAddress(a, b)
  120. #define __GetAddress(a, b) \
  121. (void*)(a)
  122. #define REAL_FP(a, b) \
  123. (a)
  124. #define __ResetException(a)
  125. #ifdef _MT
  126. #define pExitContext (*((CONTEXT **)&(_getptd()->_pExitContext)))
  127. #else
  128. static CONTEXT *pExitContext = NULL; // context to assist the return to the continuation point
  129. #endif // _MT
  130. // The throw site
  131. #undef CT_PTD
  132. #define CT_PTD(ct) (CT_PTD_IB(ct, _GetThrowImageBase()))
  133. #undef CT_COPYFUNC
  134. #define CT_COPYFUNC(ct) ((ct).copyFunction? CT_COPYFUNC_IB(ct, _GetThrowImageBase()):NULL)
  135. #undef THROW_FORWARDCOMPAT
  136. #define THROW_FORWARDCOMPAT(ti) ((ti).pForwardCompat? THROW_FORWARDCOMPAT_IB(ti, _GetThrowImageBase()):NULL)
  137. #undef THROW_COUNT
  138. #define THROW_COUNT(ti) THROW_COUNT_IB(ti, _GetThrowImageBase())
  139. #undef THROW_CTLIST
  140. #define THROW_CTLIST(ti) THROW_CTLIST_IB(ti, _GetThrowImageBase())
  141. // The catch site
  142. #undef HT_HANDLER
  143. #define HT_HANDLER(ht) (HT_HANDLER_IB(ht, _GetImageBase()))
  144. #undef UWE_ACTION
  145. #define UWE_ACTION(uwe) ((uwe).action? UWE_ACTION_IB(uwe, _GetImageBase()):NULL)
  146. #undef FUNC_UNWIND
  147. #define FUNC_UNWIND(fi,st) (FUNC_PUNWINDMAP(fi,_GetImageBase())[st])
  148. #undef TBME_CATCH
  149. #define TBME_CATCH(hm,n) (TBME_PLIST(hm,_GetImageBase())[n])
  150. #undef TBME_PCATCH
  151. #define TBME_PCATCH(hm,n) (&(TBME_PLIST(hm,_GetImageBase())[n]))
  152. #undef HT_PTD
  153. #define HT_PTD(ht) ((TypeDescriptor*)((ht).dispType? HT_PTD_IB(ht,_GetImageBase()):NULL))
  154. #undef abnormal_termination
  155. #define abnormal_termination() FALSE
  156. extern "C" {
  157. typedef struct {
  158. unsigned long dwSig;
  159. unsigned long uoffDestination;
  160. unsigned long dwCode;
  161. unsigned long uoffFramePointer;
  162. } _NLG_INFO;
  163. extern _NLG_INFO _NLG_Destination;
  164. }
  165. ////////////////////////////////////////////////////////////////////////////////
  166. //
  167. // Forward declaration of local functions:
  168. //
  169. // M00TODO: all these parameters should be declared const
  170. // The local unwinder must be external (see __CxxLongjmpUnwind in trnsctrl.cpp)
  171. extern "C" void __FrameUnwindToState(
  172. EHRegistrationNode *,
  173. DispatcherContext *,
  174. FuncInfo *,
  175. __ehstate_t
  176. );
  177. static void FindHandler(
  178. EHExceptionRecord *,
  179. EHRegistrationNode *,
  180. CONTEXT *,
  181. DispatcherContext *,
  182. FuncInfo *,
  183. BOOLEAN,
  184. int,
  185. EHRegistrationNode*
  186. );
  187. static void CatchIt(
  188. EHExceptionRecord *,
  189. EHRegistrationNode *,
  190. CONTEXT *,
  191. DispatcherContext *,
  192. FuncInfo *,
  193. HandlerType *,
  194. CatchableType *,
  195. TryBlockMapEntry *,
  196. int,
  197. EHRegistrationNode *,
  198. BOOLEAN
  199. );
  200. static void * CallCatchBlock(
  201. EHExceptionRecord *,
  202. EHRegistrationNode *,
  203. CONTEXT *,
  204. FuncInfo *,
  205. void *,
  206. int,
  207. unsigned long,
  208. FRAMEINFO *
  209. );
  210. static void BuildCatchObject(
  211. EHExceptionRecord *,
  212. void *,
  213. HandlerType *,
  214. CatchableType *
  215. );
  216. static __inline int TypeMatch(
  217. HandlerType *,
  218. CatchableType *,
  219. ThrowInfo *
  220. );
  221. static void * AdjustPointer(
  222. void *,
  223. const PMD&
  224. );
  225. static void FindHandlerForForeignException(
  226. EHExceptionRecord *,
  227. EHRegistrationNode *, CONTEXT *,
  228. DispatcherContext *,
  229. FuncInfo *,
  230. __ehstate_t,
  231. int,
  232. EHRegistrationNode *
  233. );
  234. static int FrameUnwindFilter(
  235. EXCEPTION_POINTERS *
  236. );
  237. static int ExFilterRethrow(
  238. EXCEPTION_POINTERS *
  239. );
  240. extern "C" void _CRTIMP __DestructExceptionObject(
  241. EHExceptionRecord *,
  242. BOOLEAN
  243. );
  244. //
  245. // Make sure the terminate wrapper is dragged in:
  246. //
  247. static void *pMyUnhandledExceptionFilter =
  248. #if defined(_NTSUBSET_)
  249. 0;
  250. #else
  251. &__CxxUnhandledExceptionFilter;
  252. #endif
  253. //
  254. // This describes the most recently handled exception, in case of a rethrow:
  255. //
  256. #ifdef _MT
  257. #define _pCurrentException (*((EHExceptionRecord **)&(_getptd()->_curexception)))
  258. #define _pCurrentExContext (*((CONTEXT **)&(_getptd()->_curcontext)))
  259. #define __ProcessingThrow _getptd()->_ProcessingThrow
  260. #else
  261. EHExceptionRecord *_pCurrentException = NULL;
  262. CONTEXT *_pCurrentExContext = NULL;
  263. int __ProcessingThrow = 0;
  264. #endif
  265. ////////////////////////////////////////////////////////////////////////////////
  266. //
  267. // __InternalCxxFrameHandler - the frame handler for all functions with C++ EH
  268. // information.
  269. //
  270. // If exception is handled, this doesn't return; otherwise, it returns
  271. // ExceptionContinueSearch.
  272. //
  273. // Note that this is called three ways:
  274. // From __CxxFrameHandler: primary usage, called to inspect whole function.
  275. // CatchDepth == 0, pMarkerRN == NULL
  276. // From CatchGuardHandler: If an exception occurred within a catch, this is
  277. // called to check for try blocks within that catch only, and does not
  278. // handle unwinds.
  279. // From TranslatorGuardHandler: Called to handle the translation of a
  280. // non-C++ EH exception. Context considered is that of parent.
  281. extern "C" EXCEPTION_DISPOSITION __cdecl __InternalCxxFrameHandler(
  282. EHExceptionRecord *pExcept, // Information for this exception
  283. EHRegistrationNode *pRN, // Dynamic information for this frame
  284. CONTEXT *pContext, // Context info
  285. DispatcherContext *pDC, // Context within subject frame
  286. FuncInfo *pFuncInfo, // Static information for this frame
  287. int CatchDepth, // How deeply nested are we?
  288. EHRegistrationNode *pMarkerRN, // Marker node for when checking inside
  289. // catch block
  290. BOOLEAN recursive // Are we handling a translation?
  291. ) {
  292. EHTRACE_ENTER_FMT2("%s, pRN = 0x%p",
  293. IS_UNWINDING(PER_FLAGS(pExcept)) ? "Unwinding" : "Searching",
  294. pRN);
  295. DASSERT(FUNC_MAGICNUM(*pFuncInfo) == EH_MAGIC_NUMBER1);
  296. if (IS_UNWINDING(PER_FLAGS(pExcept)))
  297. {
  298. // We're at the unwinding stage of things. Don't care about the
  299. // exception itself. (Check this first because it's easier)
  300. if (FUNC_MAXSTATE(*pFuncInfo) != 0 && CatchDepth == 0)
  301. {
  302. // Only unwind if there's something to unwind
  303. // AND we're being called through the primary RN.
  304. // If we are exiting to the continuation point, we don't want to
  305. // use the unwind map again. Unwinding continues until the
  306. // dispatcher finds the target frame, at which point the dispatcher
  307. // will jump to the continuation point
  308. //
  309. // Don't unwind the target frame if the unwind was initiated by
  310. // UnwindNestedFrames
  311. if (_GetUnwindContext() != NULL
  312. && IS_TARGET_UNWIND(PER_FLAGS(pExcept))) {
  313. // Save the target context to be used in 'CatchIt' to jump to
  314. // the continuation point.
  315. DASSERT(pExitContext != NULL);
  316. _MoveContext(pExitContext, pContext);
  317. // This is how we give control back to _UnwindNestedFrames
  318. _MoveContext(pContext, _GetUnwindContext());
  319. EHTRACE_HANDLER_EXIT(ExceptionContinueSearch);
  320. return ExceptionContinueSearch;
  321. }
  322. else if (IS_TARGET_UNWIND(PER_FLAGS(pExcept)) && PER_CODE(pExcept) == STATUS_LONGJUMP) {
  323. #if defined(_M_IA64)
  324. __ehstate_t target_state = _StateFromIp(pFuncInfo, pDC, pContext->StIIP);
  325. #elif defined(_M_AMD64)
  326. __ehstate_t target_state = _StateFromIp(pFuncInfo, pDC, pContext->Rip);
  327. #else
  328. #error "No Target Architecture"
  329. #endif
  330. DASSERT(target_state >= EH_EMPTY_STATE
  331. && target_state < FUNC_MAXSTATE(*pFuncInfo));
  332. __FrameUnwindToState(pRN, pDC, pFuncInfo, target_state);
  333. EHTRACE_HANDLER_EXIT(ExceptionContinueSearch);
  334. return ExceptionContinueSearch;
  335. }
  336. __FrameUnwindToEmptyState(pRN, pDC, pFuncInfo);
  337. }
  338. EHTRACE_HANDLER_EXIT(ExceptionContinueSearch);
  339. return ExceptionContinueSearch; // I don't think this value matters
  340. } else if (FUNC_NTRYBLOCKS(*pFuncInfo) != 0) {
  341. // NT is looking for handlers. We've got handlers.
  342. // Let's check this puppy out. Do we recognize it?
  343. int (__cdecl *pfn)(...);
  344. if (PER_CODE(pExcept) == EH_EXCEPTION_NUMBER
  345. && PER_MAGICNUM(pExcept) > EH_MAGIC_NUMBER1
  346. && (pfn = THROW_FORWARDCOMPAT(*PER_PTHROW(pExcept))) != NULL) {
  347. // Forward compatibility: The thrown object appears to have been
  348. // created by a newer version of our compiler. Let that version's
  349. // frame handler do the work (if one was specified).
  350. #if defined(DEBUG)
  351. if (_ValidateExecute((FARPROC)pfn)) {
  352. #endif
  353. EXCEPTION_DISPOSITION result =
  354. (EXCEPTION_DISPOSITION)pfn(pExcept, pRN, pContext, pDC,
  355. pFuncInfo, CatchDepth,
  356. pMarkerRN, recursive);
  357. EHTRACE_HANDLER_EXIT(result);
  358. return result;
  359. #if defined(DEBUG)
  360. } else {
  361. _inconsistency(); // Does not return; TKB
  362. }
  363. #endif
  364. } else {
  365. // Anything else: we'll handle it here.
  366. FindHandler(pExcept, pRN, pContext, pDC, pFuncInfo, recursive,
  367. CatchDepth, pMarkerRN);
  368. }
  369. // If it returned, we didn't have any matches.
  370. } // NT was looking for a handler
  371. // We had nothing to do with it or it was rethrown. Keep searching.
  372. EHTRACE_HANDLER_EXIT(ExceptionContinueSearch);
  373. return ExceptionContinueSearch;
  374. } // InternalCxxFrameHandler
  375. ////////////////////////////////////////////////////////////////////////////////
  376. //
  377. // FindHandler - find a matching handler on this frame, using all means
  378. // available.
  379. //
  380. // Description:
  381. // If the exception thrown was an MSC++ EH, search handlers for match.
  382. // Otherwise, if we haven't already recursed, try to translate.
  383. // If we have recursed (ie we're handling the translator's exception), and
  384. // it isn't a typed exception, call _inconsistency.
  385. //
  386. // Returns:
  387. // Returns iff exception was not handled.
  388. //
  389. // Assumptions:
  390. // Only called if there are handlers in this function.
  391. static void FindHandler(
  392. EHExceptionRecord *pExcept, // Information for this (logical)
  393. // exception
  394. EHRegistrationNode *pRN, // Dynamic information for subject frame
  395. CONTEXT *pContext, // Context info
  396. DispatcherContext *pDC, // Context within subject frame
  397. FuncInfo *pFuncInfo, // Static information for subject frame
  398. BOOLEAN recursive, // TRUE if we're handling the
  399. // translation
  400. int CatchDepth, // Level of nested catch that is being
  401. // checked
  402. EHRegistrationNode *pMarkerRN // Extra marker RN for nested catch
  403. // handling
  404. )
  405. {
  406. EHTRACE_ENTER;
  407. BOOLEAN IsRethrow = FALSE;
  408. // Get the current state (machine-dependent)
  409. __ehstate_t curState = _StateFromControlPc(pFuncInfo, pDC);
  410. #if defined(_M_AMD64) // Will be used when unwinding.
  411. EHRegistrationNode EstablisherFrame;
  412. _GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFrame);
  413. if (curState > GetUnwindTryBlock(pRN, pDC, pFuncInfo)) {
  414. SetState(&EstablisherFrame, pDC, pFuncInfo, curState);
  415. }
  416. #endif
  417. DASSERT(curState >= EH_EMPTY_STATE && curState < FUNC_MAXSTATE(*pFuncInfo));
  418. // Check if it's a re-throw. Use the exception we stashed away if it is.
  419. if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == NULL) {
  420. if (_pCurrentException == NULL) {
  421. // Oops! User re-threw a non-existant exception! Let it propogate.
  422. EHTRACE_EXIT;
  423. return;
  424. }
  425. pExcept = _pCurrentException;
  426. pContext = _pCurrentExContext;
  427. IsRethrow = TRUE;
  428. _SetThrowImageBase((unsigned __int64)pExcept->params.pThrowImageBase);
  429. DASSERT(_ValidateRead(pExcept));
  430. DASSERT(!PER_IS_MSVC_EH(pExcept) || PER_PTHROW(pExcept) != NULL);
  431. }
  432. if (PER_IS_MSVC_EH(pExcept)) {
  433. // Looks like it's ours. Let's see if we have a match:
  434. //
  435. // First, determine range of try blocks to consider:
  436. // Only try blocks which are at the current catch depth are of interest.
  437. unsigned curTry;
  438. unsigned end;
  439. TryBlockMapEntry *pEntry = __GetRangeOfTrysToCheck(pRN, pFuncInfo,
  440. CatchDepth, curState, &curTry, &end, pDC);
  441. // Scan the try blocks in the function:
  442. for (; curTry < end; curTry++, pEntry++) {
  443. HandlerType *pCatch;
  444. __int32 const *ppCatchable;
  445. CatchableType *pCatchable;
  446. int catches;
  447. int catchables;
  448. if (TBME_LOW(*pEntry) > curState || curState > TBME_HIGH(*pEntry)) {
  449. continue;
  450. }
  451. // Try block was in scope for current state. Scan catches for this
  452. // try:
  453. pCatch = TBME_PCATCH(*pEntry, 0);
  454. for (catches = TBME_NCATCHES(*pEntry); catches > 0; catches--,
  455. pCatch++) {
  456. // Scan all types that thrown object can be converted to:
  457. ppCatchable = THROW_CTLIST(*PER_PTHROW(pExcept));
  458. for (catchables = THROW_COUNT(*PER_PTHROW(pExcept));
  459. catchables > 0; catchables--, ppCatchable++) {
  460. pCatchable = (CatchableType *)(_GetThrowImageBase() + *ppCatchable);
  461. if (!TypeMatch(pCatch, pCatchable, PER_PTHROW(pExcept))) {
  462. continue;
  463. }
  464. // OK. We finally found a match. Activate the catch. If
  465. // control gets back here, the catch did a re-throw, so
  466. // keep searching.
  467. SetUnwindTryBlock(pRN, pDC, pFuncInfo, /*curTry*/ curState);
  468. CatchIt(pExcept, pRN, pContext, pDC, pFuncInfo, pCatch,
  469. pCatchable, pEntry, CatchDepth, pMarkerRN, IsRethrow);
  470. #if defined(_M_IA64) /*IFSTRIP=IGN*/
  471. goto EndOfTryScan;
  472. #else
  473. goto NextTryBlock;
  474. #endif
  475. } // Scan posible conversions
  476. } // Scan catch clauses
  477. #if !defined(_M_IA64) /*IFSTRIP=IGN*/
  478. NextTryBlock: ;
  479. #endif
  480. } // Scan try blocks
  481. #if defined(_M_IA64) /*IFSTRIP=IGN*/
  482. EndOfTryScan:
  483. #endif
  484. if (recursive) {
  485. // A translation was provided, but this frame didn't catch it.
  486. // Destruct the translated object before returning; if destruction
  487. // raises an exception, issue _inconsistency.
  488. __DestructExceptionObject(pExcept, TRUE);
  489. }
  490. } // It was a C++ EH exception
  491. else {
  492. // Not ours. But maybe someone told us how to make it ours.
  493. if (!recursive) {
  494. FindHandlerForForeignException(pExcept, pRN, pContext, pDC,
  495. pFuncInfo, curState, CatchDepth, pMarkerRN);
  496. } else {
  497. // We're recursive, and the exception wasn't a C++ EH!
  498. // Translator threw something uninteligable. We're outa here!
  499. // M00REVIEW: Two choices here actually: we could let the new
  500. // exception take over.
  501. terminate();
  502. }
  503. } // It wasn't our exception
  504. EHTRACE_EXIT;
  505. }
  506. ////////////////////////////////////////////////////////////////////////////////
  507. //
  508. // FindHandlerForForeignException - We've got an exception which wasn't ours.
  509. // Try to translate it into C++ EH, and also check for match with ellipsis.
  510. //
  511. // Description:
  512. // If an SE-to-EH translator has been installed, call it. The translator
  513. // must throw the appropriate typed exception or return. If the translator
  514. // throws, we invoke FindHandler again as the exception filter.
  515. //
  516. // Returns:
  517. // Returns if exception was not fully handled.
  518. // No return value.
  519. //
  520. // Assumptions:
  521. // Only called if there are handlers in this function.
  522. static void FindHandlerForForeignException(
  523. EHExceptionRecord *pExcept, // Information for this (logical)
  524. // exception
  525. EHRegistrationNode *pRN, // Dynamic information for subject frame
  526. CONTEXT *pContext, // Context info
  527. DispatcherContext *pDC, // Context within subject frame
  528. FuncInfo *pFuncInfo, // Static information for subject frame
  529. __ehstate_t curState, // Current state
  530. int CatchDepth, // Level of nested catch that is being
  531. // checked
  532. EHRegistrationNode *pMarkerRN // Extra marker RN for nested catch
  533. // handling
  534. )
  535. {
  536. EHTRACE_ENTER;
  537. unsigned curTry;
  538. unsigned end;
  539. TryBlockMapEntry *pEntry;
  540. // We don't want to touch BreakPoint generated Exception.
  541. if (PER_CODE(pExcept) == STATUS_BREAKPOINT) {
  542. EHTRACE_EXIT;
  543. return;
  544. }
  545. if (__pSETranslator != NULL) {
  546. // Call the translator. If the translator knows what to
  547. // make of it, it will throw an appropriate C++ exception.
  548. // We intercept it and use it (recursively) for this
  549. // frame. Don't recurse more than once.
  550. if (__CallSETranslator(pExcept, pRN, pContext, pDC, pFuncInfo,
  551. CatchDepth, pMarkerRN, TDTransOffset)) {
  552. EHTRACE_EXIT;
  553. return;
  554. }
  555. }
  556. // Didn't have a translator, or the translator returned normally (i.e.
  557. // didn't translate it). Still need to check for match with ellipsis:
  558. pEntry = __GetRangeOfTrysToCheck(pRN, pFuncInfo, CatchDepth, curState,
  559. &curTry, &end, pDC);
  560. // Scan the try blocks in the function:
  561. for (; curTry < end; curTry++, pEntry++) {
  562. // If the try-block was in scope *and* the last catch in that try is an
  563. // ellipsis (no other can be)
  564. if (curState < TBME_LOW(*pEntry) || curState > TBME_HIGH(*pEntry)
  565. || !HT_IS_TYPE_ELLIPSIS(TBME_CATCH(*pEntry, TBME_NCATCHES(*pEntry) - 1))) {
  566. continue;
  567. }
  568. // Found an ellipsis. Handle exception.
  569. SetUnwindTryBlock(pRN, pDC, pFuncInfo, /*curTry*/ curState);
  570. CatchIt(pExcept, pRN, pContext, pDC, pFuncInfo,
  571. TBME_PCATCH(*pEntry, TBME_NCATCHES(*pEntry) - 1), NULL, pEntry,
  572. CatchDepth, pMarkerRN, TRUE);
  573. // If it returns, handler re-threw. Keep searching.
  574. } // Search for try
  575. EHTRACE_EXIT;
  576. // If we got here, that means we didn't have anything to do with the
  577. // exception. Continue search.
  578. }
  579. ////////////////////////////////////////////////////////////////////////////////
  580. //
  581. // TypeMatch - Check if the catch type matches the given throw conversion.
  582. //
  583. // Returns:
  584. // TRUE if the catch can catch using this throw conversion, FALSE otherwise.
  585. static __inline int TypeMatch(
  586. HandlerType *pCatch, // Type of the 'catch' clause
  587. CatchableType *pCatchable, // Type conversion under consideration
  588. ThrowInfo *pThrow // General information about the thrown
  589. // type.
  590. ) {
  591. // First, check for match with ellipsis:
  592. if (HT_IS_TYPE_ELLIPSIS(*pCatch)) {
  593. return TRUE;
  594. }
  595. // Not ellipsis; the basic types match if it's the same record *or* the
  596. // names are identical.
  597. if (HT_PTD(*pCatch) != CT_PTD(*pCatchable)
  598. && strcmp(HT_NAME(*pCatch), CT_NAME(*pCatchable)) != 0) {
  599. return FALSE;
  600. }
  601. // Basic types match. The actual conversion is valid if:
  602. // caught by ref if ref required *and*
  603. // the qualifiers are compatible *and*
  604. // the alignments match *and*
  605. // the volatility matches
  606. return (!CT_BYREFONLY(*pCatchable) || HT_ISREFERENCE(*pCatch))
  607. && (!THROW_ISCONST(*pThrow) || HT_ISCONST(*pCatch))
  608. && (!THROW_ISUNALIGNED(*pThrow) || HT_ISUNALIGNED(*pCatch))
  609. && (!THROW_ISVOLATILE(*pThrow) || HT_ISVOLATILE(*pCatch));
  610. }
  611. ////////////////////////////////////////////////////////////////////////////////
  612. //
  613. // FrameUnwindFilter - Allows possibility of continuing through SEH during
  614. // unwind.
  615. //
  616. static int FrameUnwindFilter(
  617. EXCEPTION_POINTERS *pExPtrs
  618. ) {
  619. EHTRACE_ENTER;
  620. EHExceptionRecord *pExcept = (EHExceptionRecord *)pExPtrs->ExceptionRecord;
  621. switch (PER_CODE(pExcept)) {
  622. case EH_EXCEPTION_NUMBER:
  623. __ProcessingThrow = 0;
  624. terminate();
  625. #ifdef ALLOW_UNWIND_ABORT
  626. case EH_ABORT_FRAME_UNWIND_PART:
  627. EHTRACE_EXIT;
  628. return EXCEPTION_EXECUTE_HANDLER;
  629. #endif
  630. default:
  631. EHTRACE_EXIT;
  632. return EXCEPTION_CONTINUE_SEARCH;
  633. }
  634. }
  635. ////////////////////////////////////////////////////////////////////////////////
  636. //
  637. // __FrameUnwindToState - Unwind this frame until specified state is reached.
  638. //
  639. // Returns:
  640. // No return value.
  641. //
  642. // Side Effects:
  643. // All objects on frame which go out of scope as a result of the unwind are
  644. // destructed.
  645. // Registration node is updated to reflect new state.
  646. //
  647. // Usage:
  648. // This function is called both to do full-frame unwind during the unwind
  649. // phase (targetState = -1), and to do partial unwinding when the current
  650. // frame has an appropriate catch.
  651. extern "C" void __FrameUnwindToState (
  652. EHRegistrationNode *pRN, // Registration node for subject
  653. // function
  654. DispatcherContext *pDC, // Context within subject frame
  655. FuncInfo *pFuncInfo, // Static information for subject
  656. // function
  657. __ehstate_t targetState // State to unwind to
  658. ) {
  659. EHTRACE_ENTER;
  660. __ehstate_t curState = __GetUnwindState(pRN, pDC, pFuncInfo);
  661. __ProcessingThrow++;
  662. __try {
  663. while (curState != EH_EMPTY_STATE && curState > targetState)
  664. {
  665. DASSERT((curState > EH_EMPTY_STATE)
  666. && (curState < FUNC_MAXSTATE(*pFuncInfo)));
  667. // Get state after next unwind action
  668. __ehstate_t nxtState = UWE_TOSTATE(FUNC_UNWIND(*pFuncInfo, curState));
  669. __try {
  670. // Call the unwind action (if one exists):
  671. if (UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)) != NULL) {
  672. // Before calling unwind action, adjust state as if it were
  673. // already completed:
  674. SetState(pRN, pDC, pFuncInfo, nxtState);
  675. EHTRACE_FMT2("Unwind from state %d to state %d", curState, nxtState);
  676. _CallSettingFrame(__GetAddress(UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)), pDC),
  677. REAL_FP(pRN, pFuncInfo), 0x103);
  678. }
  679. } __except(EHTRACE_EXCEPT(FrameUnwindFilter(exception_info()))) {
  680. }
  681. curState = nxtState;
  682. }
  683. } __finally {
  684. if (__ProcessingThrow > 0) {
  685. __ProcessingThrow--;
  686. }
  687. }
  688. // Now that we're done, set the frame to reflect the final state.
  689. DASSERT(curState == EH_EMPTY_STATE || curState <= targetState);
  690. EHTRACE_FMT2("Move from state %d to state %d", __GetUnwindState(pRN, pDC, pFuncInfo), curState);
  691. SetState(pRN, pDC, pFuncInfo, curState);
  692. EHTRACE_EXIT;
  693. }
  694. ////////////////////////////////////////////////////////////////////////////////
  695. //
  696. // CatchIt - A handler has been found for the thrown type. Do the work to
  697. // transfer control.
  698. //
  699. // Description:
  700. // Builds the catch object
  701. // Unwinds the stack to the point of the try
  702. // Calls the address of the handler (funclet) with the frame set up for that
  703. // function but without resetting the stack.
  704. // Handler funclet returns address to continue execution, or NULL if the
  705. // handler re-threw ("throw;" lexically in handler)
  706. // If the handler throws an EH exception whose exception info is NULL, then
  707. // it's a re-throw from a dynamicly enclosed scope.
  708. //
  709. // M00REVIEW: It is still an open question whether the catch object is built
  710. // before or after the local unwind.
  711. //
  712. // Returns:
  713. // No return value. Returns iff handler re-throws.
  714. static void CatchIt(
  715. EHExceptionRecord *pExcept, // The exception thrown
  716. EHRegistrationNode *pRN, // Dynamic info of function with catch
  717. CONTEXT *pContext, // Context info
  718. DispatcherContext *pDC, // Context within subject frame
  719. FuncInfo *pFuncInfo, // Static info of function with catch
  720. HandlerType *pCatch, // The catch clause selected
  721. CatchableType *pConv, // The rules for making the conversion
  722. TryBlockMapEntry *pEntry, // Description of the try block
  723. int CatchDepth, // How many catches are we nested in?
  724. EHRegistrationNode *pMarkerRN, // Special node if nested in catch
  725. BOOLEAN IsRethrow // Is this a rethrow ?
  726. ) {
  727. EHTRACE_ENTER_FMT1("Catching object @ 0x%p", PER_PEXCEPTOBJ(pExcept));
  728. void *continuationAddress;
  729. EHRegistrationNode *pEstablisher = pRN;
  730. FRAMEINFO FrameInfo;
  731. FRAMEINFO *pFrameInfo;
  732. CONTEXT ExitContext;
  733. PVOID pExceptionObjectDestroyed = NULL;
  734. EHRegistrationNode EstablisherFramePointers;
  735. pEstablisher = _GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFramePointers);
  736. // Copy the thrown object into a buffer in the handler's stack frame,
  737. // unless the catch was by elipsis (no conversion) OR the catch was by
  738. // type without an actual 'catch object'.
  739. if (pConv != NULL) {
  740. BuildCatchObject(pExcept, pEstablisher, pCatch, pConv);
  741. }
  742. // Unwind stack objects to the entry of the try that caught this exception.
  743. pExitContext = &ExitContext;
  744. _UnwindNestedFrames(pRN,
  745. pExcept,
  746. pContext
  747. #ifdef _M_AMD64
  748. , pDC
  749. #endif
  750. );
  751. if( _pCurrentException != NULL && _ExecutionInCatch(pDC, pFuncInfo) && ! IsRethrow) {
  752. __DestructExceptionObject(_pCurrentException, TRUE);
  753. pExceptionObjectDestroyed = PER_PEXCEPTOBJ(_pCurrentException);
  754. }
  755. // Create FrameInfo before we attempt to unwind with __FrameUnwindToState()
  756. // pExitContext must be setup in advance just in case a DTOR throws a new exception. VS7:#202440
  757. pFrameInfo = _CreateFrameInfo(&FrameInfo, pDC, pExitContext, -2, pExceptionObjectDestroyed, pExcept);
  758. __FrameUnwindToState(pEstablisher, pDC, pFuncInfo, TBME_LOW(*pEntry));
  759. // Call the catch. Separated out because it introduces a new registration
  760. // node.
  761. #if defined(_M_IA64) /*IFSTRIP=IGN*/
  762. UNWINDSTATE(pEstablisher->MemoryStackFp, FUNC_DISPUNWINDHELP(*pFuncInfo)) = GetCurrentState(pEstablisher,pDC,pFuncInfo);
  763. #endif
  764. if(IsRethrow) {
  765. pFrameInfo->isRethrow = TRUE;
  766. }
  767. else if( pExcept != NULL && pExceptionObjectDestroyed == NULL ) {
  768. pFrameInfo->pExceptionObjectToBeDestroyed = PER_PEXCEPTOBJ(pExcept);
  769. }
  770. continuationAddress = CallCatchBlock(pExcept, pEstablisher, pContext,
  771. pFuncInfo, __GetAddress(HT_HANDLER(*pCatch), pDC), CatchDepth, 0x100, pFrameInfo
  772. );
  773. // Transfer control to the continuation address. If no continuation then
  774. // it's a re-throw, so return.
  775. if (continuationAddress != NULL) {
  776. #if defined(_M_AMD64)
  777. UNWINDHELP(*pEstablisher, FUNC_DISPUNWINDHELP(*pFuncInfo)) = -2;
  778. FRAMEINFO * pContFrameInfo = _FindFrameInfo(continuationAddress, pFrameInfo);
  779. if( pContFrameInfo != NULL && !pContFrameInfo->isRethrow
  780. && pContFrameInfo->pExceptionObjectToBeDestroyed
  781. && !_IsExceptionObjectDestroyed(pContFrameInfo->pExceptionObjectToBeDestroyed,pFrameInfo)
  782. ) {
  783. __DestructExceptionObject(pContFrameInfo->pExcept, TRUE);
  784. _MarkExceptionObjectDestroyed(pContFrameInfo->pExcept);
  785. }
  786. #elif defined(_M_IA64) /*IFSTRIP=IGN*/
  787. UNWINDHELP(pEstablisher->MemoryStackFp, FUNC_DISPUNWINDHELP(*pFuncInfo)) = -2;
  788. FRAMEINFO * pContFrameInfo = _FindFrameInfo(continuationAddress, pFrameInfo);
  789. if( pContFrameInfo != NULL && !pContFrameInfo->isRethrow
  790. && pContFrameInfo->pExceptionObjectToBeDestroyed
  791. && !_IsExceptionObjectDestroyed(pContFrameInfo->pExceptionObjectToBeDestroyed,pFrameInfo)
  792. ) {
  793. __DestructExceptionObject(pContFrameInfo->pExcept, TRUE);
  794. }
  795. else if( pFrameInfo != NULL && pFrameInfo != pContFrameInfo
  796. && !_IsExceptionObjectDestroyed(PER_PEXCEPTOBJ(pExcept),pFrameInfo)
  797. ) {
  798. __DestructExceptionObject(pExcept, TRUE);
  799. }
  800. #else
  801. #error "No Target Architecture:
  802. #endif
  803. __ResetException(pExcept);
  804. pExitContext = NULL;
  805. _JumpToContinuation((unsigned __int64)continuationAddress,
  806. _FindAndUnlinkFrame(continuationAddress, pFrameInfo), pExcept
  807. );
  808. } else {
  809. _UnlinkFrame(pFrameInfo);
  810. }
  811. EHTRACE_EXIT;
  812. }
  813. ////////////////////////////////////////////////////////////////////////////////
  814. //
  815. // CallCatchBlock - continuation of CatchIt.
  816. //
  817. // This is seperated from CatchIt because it needs to introduce an SEH/EH frame
  818. // in case the catch block throws. This frame cannot be added until unwind of
  819. // nested frames has been completed (otherwise this frame would be the first
  820. // to go).
  821. static void *CallCatchBlock(
  822. EHExceptionRecord *pExcept, // The exception thrown
  823. EHRegistrationNode *pRN, // Dynamic info of function with catch
  824. CONTEXT *pContext, // Context info
  825. FuncInfo *pFuncInfo, // Static info of function with catch
  826. void *handlerAddress, // Code address of handler
  827. int CatchDepth, // How deeply nested in catch blocks
  828. // are we?
  829. unsigned long NLGCode, // NLG destination code
  830. FRAMEINFO *pFrameInfo
  831. ) {
  832. EHTRACE_ENTER;
  833. // Address where execution resumes after exception handling completed.
  834. // Initialized to non-NULL (value doesn't matter) to distinguish from
  835. // re-throw in __finally.
  836. void *continuationAddress = handlerAddress;
  837. BOOL ExceptionObjectDestroyed = FALSE;
  838. // Save the current exception in case of a rethrow. Save the previous value
  839. // on the stack, to be restored when the catch exits.
  840. EHExceptionRecord *pSaveException = _pCurrentException;
  841. CONTEXT *pSaveExContext = _pCurrentExContext;
  842. _pCurrentException = pExcept;
  843. _pCurrentExContext = pContext;
  844. __try {
  845. __try {
  846. // Execute the handler as a funclet, whose return value is the
  847. // address to resume execution.
  848. continuationAddress = _CallSettingFrame(handlerAddress,
  849. REAL_FP(pRN, pFuncInfo), NLGCode);
  850. } __except(EHTRACE_EXCEPT(ExFilterRethrow(exception_info()))) {
  851. // If the handler threw a typed exception without exception info or
  852. // exception object, then it's a re-throw, so return. Otherwise
  853. // it's a new exception, which takes precedence over this one.
  854. continuationAddress = NULL;
  855. }
  856. } __finally {
  857. EHTRACE_SAVE_LEVEL;
  858. EHTRACE_FMT1("Executing __finally, %snormal termination", _abnormal_termination() ? "ab" : "");
  859. // Restore the 'current exception' for a possibly enclosing catch
  860. _pCurrentException = pSaveException;
  861. _pCurrentExContext = pSaveExContext;
  862. // Destroy the original exception object if we're not exiting on a
  863. // re-throw and the object isn't also in use by a more deeply nested
  864. // catch. Note that the catch handles destruction of its parameter.
  865. if (PER_IS_MSVC_EH(pExcept) && !ExceptionObjectDestroyed
  866. && continuationAddress != NULL
  867. && !_IsExceptionObjectDestroyed(PER_PEXCEPTOBJ(pExcept),pFrameInfo)
  868. && !pFrameInfo->isRethrow
  869. ) {
  870. pFrameInfo->dtorThrowFlag = TRUE;
  871. __DestructExceptionObject(pExcept, abnormal_termination());
  872. }
  873. EHTRACE_RESTORE_LEVEL(!!_abnormal_termination());
  874. }
  875. EHTRACE_EXIT;
  876. pFrameInfo->dtorThrowFlag = FALSE;
  877. return continuationAddress;
  878. }
  879. ////////////////////////////////////////////////////////////////////////////////
  880. //
  881. // ExFilterRethrow - Exception filter for re-throw exceptions.
  882. //
  883. // Returns:
  884. // EXCEPTION_EXECUTE_HANDLER - exception was a re-throw
  885. // EXCEPTION_CONTINUE_SEARCH - anything else
  886. //
  887. // Side-effects: NONE.
  888. static int ExFilterRethrow(
  889. EXCEPTION_POINTERS *pExPtrs
  890. ) {
  891. // Get the exception record thrown (don't care about other info)
  892. EHExceptionRecord *pExcept = (EHExceptionRecord *)pExPtrs->ExceptionRecord;
  893. // Check if it's ours and it's has no exception information.
  894. if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == NULL) {
  895. return EXCEPTION_EXECUTE_HANDLER;
  896. } else {
  897. return EXCEPTION_CONTINUE_SEARCH;
  898. }
  899. }
  900. ////////////////////////////////////////////////////////////////////////////////
  901. //
  902. // BuildCatchObject - Copy or construct the catch object from the object thrown.
  903. //
  904. // Returns:
  905. // nothing.
  906. //
  907. // Side-effects:
  908. // A buffer in the subject function's frame is initialized.
  909. //
  910. // Open issues:
  911. // What happens if the constructor throws? (or faults?)
  912. static void BuildCatchObject(
  913. EHExceptionRecord *pExcept, // Original exception thrown
  914. void *pRN, // This is a pointer to the object
  915. // that we want to build while doing
  916. // COM+ eh. If we are in our own eh,
  917. // then this is a Registration node of
  918. // catching function
  919. HandlerType *pCatch, // The catch clause that got it
  920. CatchableType *pConv // The conversion to use
  921. ) {
  922. EHTRACE_ENTER;
  923. // If the catch is by ellipsis, then there is no object to construct.
  924. // If the catch is by type(No Catch Object), then leave too!
  925. if (HT_IS_TYPE_ELLIPSIS(*pCatch) ||
  926. (!HT_DISPCATCH(*pCatch) && !HT_ISCOMPLUSEH(*pCatch))) {
  927. EHTRACE_EXIT;
  928. return;
  929. }
  930. void **pCatchBuffer;
  931. if ( HT_ISCOMPLUSEH(*pCatch))
  932. {
  933. pCatchBuffer = (void **)pRN;
  934. }
  935. else
  936. {
  937. #if defined(_M_IA64) /*IFSTRIP=IGN*/
  938. pCatchBuffer = (void **)__OffsetToAddress(
  939. HT_DISPCATCH(*pCatch),
  940. ((EHRegistrationNode *)pRN)->MemoryStackFp,
  941. HT_FRAMENEST(*pCatch)
  942. );
  943. #elif defined(_M_AMD64)
  944. pCatchBuffer = (void **)__OffsetToAddress(
  945. HT_DISPCATCH(*pCatch),
  946. *((EHRegistrationNode *)pRN),
  947. HT_FRAMENEST(*pCatch)
  948. );
  949. #else
  950. #error "No Target Architecture"
  951. #endif
  952. }
  953. __try {
  954. if (HT_ISREFERENCE(*pCatch)) {
  955. // The catch is of form 'reference to T'. At the throw point we
  956. // treat both 'T' and 'reference to T' the same, i.e.
  957. // pExceptionObject is a (machine) pointer to T. Adjust as
  958. // required.
  959. if (_ValidateRead(PER_PEXCEPTOBJ(pExcept))
  960. && _ValidateWrite(pCatchBuffer)) {
  961. *pCatchBuffer = PER_PEXCEPTOBJ(pExcept);
  962. *pCatchBuffer = AdjustPointer(*pCatchBuffer,
  963. CT_THISDISP(*pConv));
  964. } else {
  965. _inconsistency(); // Does not return; TKB
  966. }
  967. } else if (CT_ISSIMPLETYPE(*pConv)) {
  968. // Object thrown is of simple type (this including pointers) copy
  969. // specified number of bytes. Adjust the pointer as required. If
  970. // the thing is not a pointer, then this should be safe since all
  971. // the entries in the THISDISP are 0.
  972. if (_ValidateRead(PER_PEXCEPTOBJ(pExcept))
  973. && _ValidateWrite(pCatchBuffer)) {
  974. memmove(pCatchBuffer, PER_PEXCEPTOBJ(pExcept), CT_SIZE(*pConv));
  975. if (CT_SIZE(*pConv) == sizeof(void*) && *pCatchBuffer != NULL) {
  976. *pCatchBuffer = AdjustPointer(*pCatchBuffer,
  977. CT_THISDISP(*pConv));
  978. }
  979. } else {
  980. _inconsistency(); // Does not return; TKB
  981. }
  982. } else {
  983. // Object thrown is UDT.
  984. if (CT_COPYFUNC(*pConv) == NULL) {
  985. // The UDT had a simple ctor. Adjust in the thrown object,
  986. // then copy n bytes.
  987. if (_ValidateRead(PER_PEXCEPTOBJ(pExcept))
  988. && _ValidateWrite(pCatchBuffer)) {
  989. memmove(pCatchBuffer, AdjustPointer(PER_PEXCEPTOBJ(pExcept),
  990. CT_THISDISP(*pConv)), CT_SIZE(*pConv));
  991. } else {
  992. _inconsistency(); // Does not return; TKB
  993. }
  994. } else {
  995. // It's a UDT: make a copy using copy ctor
  996. #pragma warning(disable:4191)
  997. if (_ValidateRead(PER_PEXCEPTOBJ(pExcept))
  998. && _ValidateWrite(pCatchBuffer)
  999. && _ValidateExecute((FARPROC)CT_COPYFUNC(*pConv))) {
  1000. #pragma warning(default:4191)
  1001. if (CT_HASVB(*pConv)) {
  1002. _CallMemberFunction2((char *)pCatchBuffer,
  1003. CT_COPYFUNC(*pConv),
  1004. AdjustPointer(PER_PEXCEPTOBJ(pExcept),
  1005. CT_THISDISP(*pConv)), 1);
  1006. } else {
  1007. _CallMemberFunction1((char *)pCatchBuffer,
  1008. CT_COPYFUNC(*pConv),
  1009. AdjustPointer(PER_PEXCEPTOBJ(pExcept),
  1010. CT_THISDISP(*pConv)));
  1011. }
  1012. } else {
  1013. _inconsistency(); // Does not return; TKB
  1014. }
  1015. }
  1016. }
  1017. } __except(EHTRACE_EXCEPT(EXCEPTION_EXECUTE_HANDLER)) {
  1018. // Something went wrong when building the catch object.
  1019. terminate();
  1020. }
  1021. EHTRACE_EXIT;
  1022. }
  1023. ////////////////////////////////////////////////////////////////////////////////
  1024. //
  1025. // __DestructExceptionObject - Call the destructor (if any) of the original
  1026. // exception object.
  1027. //
  1028. // Returns: None.
  1029. //
  1030. // Side-effects:
  1031. // Original exception object is destructed.
  1032. //
  1033. // Notes:
  1034. // If destruction throws any exception, and we are destructing the exception
  1035. // object as a result of a new exception, we give up. If the destruction
  1036. // throws otherwise, we let it be.
  1037. extern "C" void _CRTIMP __DestructExceptionObject(
  1038. EHExceptionRecord *pExcept, // The original exception record
  1039. BOOLEAN fThrowNotAllowed // TRUE if destructor not allowed to
  1040. // throw
  1041. ) {
  1042. EHTRACE_ENTER_FMT1("Destroying object @ 0x%p", PER_PEXCEPTOBJ(pExcept));
  1043. if (pExcept != NULL && THROW_UNWINDFUNC(*PER_PTHROW(pExcept)) != NULL) {
  1044. __try {
  1045. // M00REVIEW: A destructor has additional hidden arguments, doesn't
  1046. // it?
  1047. _MarkExceptionObjectDestroyed(pExcept);
  1048. _CallMemberFunction0(PER_PEXCEPTOBJ(pExcept),
  1049. THROW_UNWINDFUNC_IB(*PER_PTHROW(pExcept),(unsigned __int64)PER_PTHROWIB(pExcept)));
  1050. __ResetException(pExcept);
  1051. } __except(EHTRACE_EXCEPT(fThrowNotAllowed
  1052. ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)) {
  1053. // Can't have new exceptions when we're unwinding due to another
  1054. // exception.
  1055. terminate();
  1056. }
  1057. }
  1058. EHTRACE_EXIT;
  1059. }
  1060. ////////////////////////////////////////////////////////////////////////////////
  1061. //
  1062. // AdjustPointer - Adjust the pointer to the exception object to a pointer to a
  1063. // base instance.
  1064. //
  1065. // Output:
  1066. // The address point of the base.
  1067. //
  1068. // Side-effects:
  1069. // NONE.
  1070. static void *AdjustPointer(
  1071. void *pThis, // Address point of exception object
  1072. const PMD& pmd // Generalized pointer-to-member
  1073. // descriptor
  1074. ) {
  1075. char *pRet = (char *)pThis + pmd.mdisp;
  1076. if (pmd.pdisp >= 0) {
  1077. pRet += *(__int32 *)((char *)*(ptrdiff_t *)((char *)pThis + pmd.pdisp)
  1078. + (unsigned _int64)pmd.vdisp);
  1079. pRet += pmd.pdisp;
  1080. }
  1081. return pRet;
  1082. }
  1083. ///////////////////////////////////////////////////////////////////////////////
  1084. //
  1085. // __uncaught_exception() - Returns true after completing of a throw-expression
  1086. // untils completing initialization of the
  1087. // exception-declaration in the matching handler.
  1088. //
  1089. bool __uncaught_exception()
  1090. {
  1091. return (__ProcessingThrow != 0);
  1092. }
  1093. #if !defined(_M_IA64) && !defined(_M_AMD64) // Enable&fix for IA64 when COM+ C++ EH support available there
  1094. ////////////////////////////////////////////////////////////////////////////////
  1095. // Model of C++ eh in COM+
  1096. //
  1097. // void func()
  1098. // {
  1099. // try {
  1100. // TryBody();
  1101. // } catch (cpp_object o)
  1102. // {
  1103. // CatchOBody();
  1104. // } catch (...)
  1105. // {
  1106. // CatchAllBody();
  1107. // }
  1108. // }
  1109. //
  1110. // Turns into this:
  1111. //
  1112. //
  1113. // void func()
  1114. // {
  1115. // int rethrow;
  1116. // // One per try block
  1117. // int isCxxException;
  1118. // // One per catch(...)
  1119. // __try {
  1120. // TryBody();
  1121. // }
  1122. // __except(__CxxExceptionFilter(exception,
  1123. // typeinfo(cpp_object),
  1124. // flags,
  1125. // &o))
  1126. // // This is how it's done already
  1127. // {
  1128. // // Begin catch(object) prefix
  1129. // char *storage = _alloca(__CxxQueryExceptionSize());
  1130. // rethrow = false;
  1131. // __CxxRegisterExceptionObject(exception,
  1132. // storage);
  1133. // __try {
  1134. // __try {
  1135. // // End catch(object) prefix
  1136. // CatchOBody();
  1137. // // Begin catch(object) suffix
  1138. // } __except(rethrow = __CxxDetectRethrow(exception),
  1139. // EXCEPTION_CONTINUE_SEARCH)
  1140. // {}
  1141. // }
  1142. // __finally
  1143. // {
  1144. // __CxxUnregisterExceptionObject(storage,
  1145. // rethrow);
  1146. // }
  1147. // // End catch(object) suffix
  1148. // }
  1149. // __except(1)
  1150. // {
  1151. // // Begin catch(...) prefix
  1152. // char *storage = _alloca(__CxxQueryExceptionSize());
  1153. // rethrow = false;
  1154. // isCxxException = __CxxRegisterExceptionObject(exception,
  1155. // storage);
  1156. // __try
  1157. // {
  1158. // __try
  1159. // {
  1160. // // End catch(...) prefix
  1161. // CatchAllBody();
  1162. // // Begin catch(...) suffix
  1163. // } __except(rethrow = __CxxDetectRethrow(exception),
  1164. // EXCEPTION_CONTINUE_SEARCH)
  1165. // {}
  1166. // } __finally
  1167. // {
  1168. // if (isCxxException)
  1169. // __CxxUnregisterExceptionObject(storage, rethrow);
  1170. // }
  1171. // // End catch(...) suffix
  1172. // }
  1173. // }
  1174. //
  1175. ////////////////////////////////////////////////////////////////////////////////
  1176. ////////////////////////////////////////////////////////////////////////////////
  1177. //
  1178. // __CxxExceptionFilter() - Returns EXCEPTION_EXECUTE_HANDLER when the pType
  1179. // matches with the objects we can catch. Returns
  1180. // EXCEPTION_CONTINUE_SEARCH when pType is not one of
  1181. // the catchable type for the thrown object. This
  1182. // function is made for use with COM+ EH, where they
  1183. // attempt to do C++ EH as well.
  1184. //
  1185. extern "C" int __cdecl __CxxExceptionFilter(
  1186. void *ppExcept, // Information for this (logical)
  1187. // exception
  1188. void *pType, // Info about the datatype.
  1189. int adjectives, // Extra Info about the datatype.
  1190. void *pBuildObj // Pointer to datatype.
  1191. )
  1192. {
  1193. struct _s_HandlerType pCatch;
  1194. __int32 const *ppCatchable;
  1195. CatchableType *pCatchable;
  1196. int catchables;
  1197. EHExceptionRecord *pExcept;
  1198. if (!ppExcept)
  1199. return EXCEPTION_CONTINUE_SEARCH;
  1200. pExcept = *(EHExceptionRecord **)ppExcept;
  1201. // If catch all, always return EXCEPTION_EXECUTE_HANDLER
  1202. if ( TD_IS_TYPE_ELLIPSIS((TypeDescriptor *)pType))
  1203. {
  1204. if (PER_IS_MSVC_EH(pExcept))
  1205. {
  1206. if ( PER_PTHROW(pExcept) == NULL)
  1207. {
  1208. if ( _pCurrentException != NULL)
  1209. *(EHExceptionRecord **)ppExcept = _pCurrentException;
  1210. else
  1211. return EXCEPTION_CONTINUE_SEARCH;
  1212. }
  1213. }
  1214. __ProcessingThrow++;
  1215. return EXCEPTION_EXECUTE_HANDLER;
  1216. }
  1217. if (PER_IS_MSVC_EH(pExcept))
  1218. {
  1219. if ( PER_PTHROW(pExcept) == NULL) {
  1220. if (_pCurrentException == NULL)
  1221. return EXCEPTION_CONTINUE_SEARCH;
  1222. pExcept = _pCurrentException;
  1223. }
  1224. pCatch.pType = (TypeDescriptor *)pType;
  1225. pCatch.adjectives = adjectives;
  1226. SET_HT_ISCOMPLUSEH(pCatch);
  1227. // Scan all types that thrown object can be converted to:
  1228. ppCatchable = THROW_CTLIST(*PER_PTHROW(pExcept));
  1229. for (catchables = THROW_COUNT(*PER_PTHROW(pExcept));
  1230. catchables > 0; catchables--, ppCatchable++) {
  1231. pCatchable = (CatchableType *)(_GetThrowImageBase() + *ppCatchable);
  1232. if (TypeMatch(&pCatch, pCatchable, PER_PTHROW(pExcept))) {
  1233. // SucessFull. Now build the object.
  1234. __ProcessingThrow++;
  1235. if (pBuildObj != NULL)
  1236. BuildCatchObject(pExcept, pBuildObj, &pCatch, pCatchable);
  1237. // We set the current exception.
  1238. if ( PER_PTHROW(*(EHExceptionRecord **)ppExcept) == NULL)
  1239. *(EHExceptionRecord **)ppExcept = _pCurrentException;
  1240. return EXCEPTION_EXECUTE_HANDLER;
  1241. }
  1242. } // Scan posible conversions
  1243. }
  1244. return EXCEPTION_CONTINUE_SEARCH;
  1245. }
  1246. ////////////////////////////////////////////////////////////////////////////////
  1247. //
  1248. // __CxxRgisterExceptionObject() - Registers Exception Object and saves it to
  1249. // This is same as first part of
  1250. // CallCatchBlock.
  1251. //
  1252. extern "C" int __cdecl __CxxRegisterExceptionObject(
  1253. void *ppExcept,
  1254. void *pStorage
  1255. )
  1256. {
  1257. // This function is only called for C++ EH.
  1258. EHExceptionRecord *pExcept;
  1259. FRAMEINFO *pFrameInfo = (FRAMEINFO *)pStorage;
  1260. EHExceptionRecord **ppSaveException;
  1261. CONTEXT **ppSaveExContext;
  1262. ppSaveException = (EHExceptionRecord **)(&pFrameInfo[1]);
  1263. ppSaveExContext = (CONTEXT **)(&ppSaveException[1]);
  1264. pExcept = *(EHExceptionRecord **)ppExcept;
  1265. pFrameInfo = _CreateFrameInfo(pFrameInfo, PER_PEXCEPTOBJ(pExcept));
  1266. *ppSaveException = _pCurrentException;
  1267. *ppSaveExContext = _pCurrentExContext;
  1268. _pCurrentException = pExcept;
  1269. __ProcessingThrow--;
  1270. if ( __ProcessingThrow < 0)
  1271. __ProcessingThrow = 0;
  1272. return 1;
  1273. }
  1274. ////////////////////////////////////////////////////////////////////////////////
  1275. //
  1276. // __CxxDetectRethrow() - Looks at the Exception and returns true if rethrow,
  1277. // false if not a rethrow. This is then used for
  1278. // destructing the exception object in
  1279. // __CxxUnregisterExceptionObject().
  1280. //
  1281. extern "C" int __cdecl __CxxDetectRethrow(
  1282. void *ppExcept
  1283. )
  1284. {
  1285. EHExceptionRecord *pExcept;
  1286. if (!ppExcept)
  1287. return 0;
  1288. pExcept = *(EHExceptionRecord **)ppExcept;
  1289. if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == NULL) {
  1290. *(EHExceptionRecord **)ppExcept = _pCurrentException;
  1291. return 1;
  1292. } else if (*(EHExceptionRecord **)ppExcept == _pCurrentException)
  1293. return 1;
  1294. return 0;
  1295. }
  1296. ////////////////////////////////////////////////////////////////////////////////
  1297. //
  1298. // __CxxUnregisterExceptionObject - Destructs Exception Objects if rethrow ==
  1299. // true. Also set __pCurrentException and
  1300. // __pCurrentExContext() to current value.
  1301. //
  1302. extern "C" void __cdecl __CxxUnregisterExceptionObject(
  1303. void *pStorage,
  1304. int rethrow
  1305. )
  1306. {
  1307. FRAMEINFO *pFrameInfo = (FRAMEINFO *)pStorage;
  1308. EHExceptionRecord **ppSaveException;
  1309. CONTEXT **ppSaveExContext;
  1310. ppSaveException = (EHExceptionRecord **)(&pFrameInfo[1]);
  1311. ppSaveExContext = (CONTEXT **)(&ppSaveException[1]);
  1312. _FindAndUnlinkFrame(pFrameInfo);
  1313. if ( !rethrow && PER_IS_MSVC_EH(_pCurrentException) && IsExceptionObjectToBeDestroyed(PER_PEXCEPTOBJ(_pCurrentException))) {
  1314. __DestructExceptionObject(_pCurrentException, TRUE);
  1315. }
  1316. _pCurrentException = *ppSaveException;
  1317. _pCurrentExContext = *ppSaveExContext;
  1318. }
  1319. ////////////////////////////////////////////////////////////////////////////////
  1320. //
  1321. // __CxxQueryExceptionSize - returns the value of Storage needed to save
  1322. // FrameInfo + two pointers.
  1323. //
  1324. extern "C" int __cdecl __CxxQueryExceptionSize(
  1325. void
  1326. )
  1327. {
  1328. return sizeof(FRAMEINFO) + sizeof(void *) + sizeof(void *);
  1329. }
  1330. ////////////////////////////////////////////////////////////////////////////////
  1331. //
  1332. // __CxxCallUnwindDtor - Calls a destructor during unwind. For COM+, the dtor
  1333. // call needs to be wrapped inside a __try/__except to
  1334. // get correct terminate() behavior when an exception
  1335. // occurs during the dtor call.
  1336. //
  1337. extern "C" void __cdecl __CxxCallUnwindDtor(
  1338. void (__thiscall * pDtor)(void*),
  1339. void *pThis
  1340. )
  1341. {
  1342. __try
  1343. {
  1344. (*pDtor)(pThis);
  1345. }
  1346. __except(FrameUnwindFilter(exception_info()))
  1347. {
  1348. }
  1349. }
  1350. #endif // !defined(_M_IA64) && !defined(_AMD64_)