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.

769 lines
27 KiB

  1. /***
  2. *trnsctrl.cxx - Routines for doing control transfers
  3. *
  4. * Copyright (c) 1993-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Routines for doing control transfers; written using inline
  8. * assembly in naked functions. Contains the public routine
  9. * _CxxFrameHandler, the entry point for the frame handler
  10. *
  11. *Revision History:
  12. * 05-24-93 BES Module created
  13. * 01-13-95 JWM NLG notifications now called from _CallSettingFrame().
  14. * 04-10-95 JWM _CallSettingFrame() moved to lowhelpr.asm
  15. * 10-22-99 PML Add EHTRACE support
  16. * 11-30-99 PML Compile /Wp64 clean.
  17. * 01-31-00 PML Disable new warning C4851
  18. * 02-14-00 PML C4851 in VC6PP is C4731 in VC7
  19. * 03-02-00 PML Preserve callee-save regs across RtlUnwind (VS7#83643).
  20. * 03-03-00 PML No more C4851, it's only C4731
  21. *
  22. ****/
  23. #include <windows.h>
  24. #include <mtdll.h>
  25. #include <ehdata.h>
  26. #include <trnsctrl.h>
  27. #include <eh.h>
  28. #include <ehhooks.h>
  29. #include <ehassert.h>
  30. #pragma hdrstop
  31. #include <setjmp.h>
  32. #pragma warning(disable:4311 4312) // x86 specific, ignore /Wp64 warnings
  33. #pragma warning(disable:4731) // ignore EBP mod in inline-asm warning
  34. #ifdef _MT
  35. #define pFrameInfoChain (*((FRAMEINFO **) &(_getptd()->_pFrameInfoChain)))
  36. #else
  37. static FRAMEINFO *pFrameInfoChain = NULL; // used to remember nested frames
  38. #endif
  39. /////////////////////////////////////////////////////////////////////////////
  40. //
  41. // _JumpToContinuation - sets up EBP and jumps to specified code address.
  42. //
  43. // Does not return.
  44. //
  45. // NT leaves a marker registration node at the head of the list, under the
  46. // assumption that RtlUnwind will remove it. As it happens, we need to keep
  47. // it in case of a rethrow (see below). We only remove the current head
  48. // (assuming it is NT's), because there may be other nodes that we still
  49. // need.
  50. //
  51. void __stdcall _JumpToContinuation(
  52. void *target, // The funclet to call
  53. EHRegistrationNode *pRN // Registration node, represents location of frame
  54. ) {
  55. EHTRACE_ENTER_FMT1("Transfer to 0x%p", target);
  56. EHTRACE_RESET;
  57. register long targetEBP;
  58. #if !CC_EXPLICITFRAME
  59. targetEBP = (long)pRN + FRAME_OFFSET;
  60. #else
  61. targetEBP = pRN->frame;
  62. #endif
  63. __asm {
  64. //
  65. // Unlink NT's marker node:
  66. //
  67. mov ebx, FS:[0]
  68. mov eax, [ebx]
  69. mov FS:[0], eax
  70. //
  71. // Transfer control to the continuation point
  72. //
  73. mov eax, target // Load target address
  74. mov ebx, pRN // Restore target esp
  75. mov esp, [ebx-4]
  76. mov ebp, targetEBP // Load target frame pointer
  77. jmp eax // Call the funclet
  78. }
  79. }
  80. /////////////////////////////////////////////////////////////////////////////
  81. //
  82. // _CallMemberFunction0 - call a parameterless member function using __thiscall
  83. // calling convention, with 0 parameters.
  84. //
  85. __declspec(naked) void __stdcall _CallMemberFunction0(
  86. void *pthis, // Value for 'this' pointer
  87. void *pmfn // Pointer to the member function
  88. ) {
  89. __asm {
  90. pop eax // Save return address
  91. pop ecx // Get 'this'
  92. xchg [esp],eax // Get function address, stash return address
  93. jmp eax // jump to the function (function will return
  94. // to caller of this func)
  95. }
  96. }
  97. /////////////////////////////////////////////////////////////////////////////
  98. //
  99. // _CallMemberFunction1 - call a member function using __thiscall
  100. // calling convention, with 1 parameter.
  101. //
  102. __declspec(naked) void __stdcall _CallMemberFunction1(
  103. void *pthis, // Value for 'this' pointer
  104. void *pmfn, // Pointer to the member function
  105. void *pthat // Value of 1st parameter (type assumes copy ctor)
  106. ) {
  107. __asm {
  108. pop eax // Save return address
  109. pop ecx // Get 'this'
  110. xchg [esp],eax // Get function address, stash return address
  111. jmp eax // jump to the function (function will return
  112. // to caller of this func)
  113. }
  114. }
  115. /////////////////////////////////////////////////////////////////////////////
  116. //
  117. // _CallMemberFunction2 - call a member function using __thiscall
  118. // calling convention, with 2 parameter.
  119. //
  120. __declspec(naked) void __stdcall _CallMemberFunction2(
  121. void *pthis, // Value for 'this' pointer
  122. void *pmfn, // Pointer to the member function
  123. void *pthat, // Value of 1st parameter (type assumes copy ctor)
  124. int val2 // Value of 2nd parameter (type assumes copy ctor w/vb)
  125. ) {
  126. __asm {
  127. pop eax // Save return address
  128. pop ecx // Get 'this'
  129. xchg [esp],eax // Get function address, stash return address
  130. jmp eax // jump to the function (function will return
  131. // to caller of this func)
  132. }
  133. }
  134. /////////////////////////////////////////////////////////////////////////////
  135. //
  136. // _UnwindNestedFrames - Call RtlUnwind, passing the address after the call
  137. // as the continuation address.
  138. //
  139. // Win32 assumes that after a frame has called RtlUnwind, it will never return
  140. // to the dispatcher.
  141. //
  142. // Let me explain:
  143. // When the dispatcher calls a frame handler while searching
  144. // for the appropriate handler, it pushes an extra guard registration node
  145. // onto the list. When the handler returns to the dispatcher, the dispatcher
  146. // assumes that its node is at the head of the list, restores esp from the
  147. // address of the head node, and then unlinks that node from the chain.
  148. // However, if RtlUnwind removes ALL nodes below the specified node, including
  149. // the dispatcher's node, so without intervention the result is that the
  150. // current subject node gets poped from the list, and the stack pointer gets
  151. // reset to somewhere within the frame of that node, which is totally bogus
  152. // (this last side effect is not a problem, because esp is then immediately
  153. // restored from the ebp chain, which is still valid).
  154. //
  155. // So:
  156. // To get arround this, WE ASSUME that the registration node at the head of
  157. // the list is the dispatcher's marker node (which it is in NT 1.0), and
  158. // we keep a handle to it when we call RtlUnwind, and then link it back in
  159. // after RtlUnwind has done its stuff. That way, the dispatcher restores
  160. // its stack exactly as it expected to, and leave our registration node alone.
  161. //
  162. // What happens if there is an exception during the unwind?
  163. // We can't put a registration node here, because it will be removed
  164. // immediately.
  165. //
  166. // RtlUnwind:
  167. // RtlUnwind is evil. It trashes all the registers except EBP and ESP.
  168. // Because of that, EBX, ESI, and EDI must be preserved by this function,
  169. // and the compiler may not assume that any callee-save register can be used
  170. // across the call to RtlUnwind. To accomplish the former, inline-asm code
  171. // here uses EBX, ESI, and EDI, so they will be saved in the prologue. For
  172. // the latter, optimizations are disabled for the duration of this function.
  173. //
  174. #pragma optimize("g", off) // WORKAROUND for DOLPH:3322
  175. void __stdcall _UnwindNestedFrames(
  176. EHRegistrationNode *pRN, // Unwind up to (but not including) this frame
  177. EHExceptionRecord *pExcept // The exception that initiated this unwind
  178. ) {
  179. EHTRACE_ENTER;
  180. void* pReturnPoint;
  181. EHRegistrationNode *pDispatcherRN; // Magic!
  182. __asm {
  183. //
  184. // Save the dispatcher's marker node
  185. //
  186. // NOTE: RtlUnwind will trash the callee-save regs EBX, ESI, and EDI.
  187. // We explicitly use them here in the inline-asm so they get preserved
  188. // and restored by the function prologue/epilogue.
  189. //
  190. mov esi, dword ptr FS:[0] // use ESI
  191. mov pDispatcherRN, esi
  192. }
  193. __asm mov pReturnPoint, offset ReturnPoint
  194. RtlUnwind(pRN, pReturnPoint, (PEXCEPTION_RECORD)pExcept, NULL);
  195. ReturnPoint:
  196. PER_FLAGS(pExcept) &= ~EXCEPTION_UNWINDING; // Clear the 'Unwinding' flag
  197. // in case exception is rethrown
  198. __asm {
  199. //
  200. // Re-link the dispatcher's marker node
  201. //
  202. mov edi, dword ptr FS:[0] // Get the current head (use EDI)
  203. mov ebx, pDispatcherRN // Get the saved head (use EBX)
  204. mov [ebx], edi // Link saved head to current head
  205. mov dword ptr FS:[0], ebx // Make saved head current head
  206. }
  207. EHTRACE_EXIT;
  208. return;
  209. }
  210. #pragma optimize("", on)
  211. /////////////////////////////////////////////////////////////////////////////
  212. //
  213. // __CxxFrameHandler - Real entry point to the runtime; this thunk fixes up
  214. // the parameters, and then calls the workhorse.
  215. //
  216. extern "C" EXCEPTION_DISPOSITION __cdecl __InternalCxxFrameHandler(
  217. EHExceptionRecord *pExcept, // Information for this exception
  218. EHRegistrationNode *pRN, // Dynamic information for this frame
  219. void *pContext, // Context info (we don't care what's in it)
  220. DispatcherContext *pDC, // More dynamic info for this frame (ignored on Intel)
  221. FuncInfo *pFuncInfo, // Static information for this frame
  222. int CatchDepth, // How deeply nested are we?
  223. EHRegistrationNode *pMarkerRN, // Marker node for when checking inside
  224. // catch block
  225. BOOL recursive); // True if this is a translation exception
  226. extern "C" _CRTIMP __declspec(naked) EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler(
  227. /*
  228. EAX=FuncInfo *pFuncInfo, // Static information for this frame
  229. */
  230. EHExceptionRecord *pExcept, // Information for this exception
  231. EHRegistrationNode *pRN, // Dynamic information for this frame
  232. void *pContext, // Context info (we don't care what's in it)
  233. DispatcherContext *pDC // More dynamic info for this frame (ignored on Intel)
  234. ) {
  235. FuncInfo *pFuncInfo;
  236. EXCEPTION_DISPOSITION result;
  237. __asm {
  238. //
  239. // Standard function prolog
  240. //
  241. push ebp
  242. mov ebp, esp
  243. sub esp, __LOCAL_SIZE
  244. push ebx
  245. push esi
  246. push edi
  247. cld // A bit of paranoia -- Our code-gen assumes this
  248. //
  249. // Save the extra parameter
  250. //
  251. mov pFuncInfo, eax
  252. }
  253. EHTRACE_ENTER_FMT1("pRN = 0x%p", pRN);
  254. result = __InternalCxxFrameHandler( pExcept, pRN, pContext, pDC, pFuncInfo, 0, NULL, FALSE );
  255. EHTRACE_HANDLER_EXIT(result);
  256. __asm {
  257. pop edi
  258. pop esi
  259. pop ebx
  260. mov eax, result
  261. mov esp, ebp
  262. pop ebp
  263. ret 0
  264. }
  265. }
  266. /////////////////////////////////////////////////////////////////////////////
  267. //
  268. // __CxxLongjmpUnwind - Entry point for local unwind required by longjmp
  269. // when setjmp used in same function as C++ EH.
  270. //
  271. extern "C" void __FrameUnwindToState( // in frame.cpp
  272. EHRegistrationNode *pRN, // Dynamic information for this frame
  273. DispatcherContext *pDC, // More dynamic info for this frame (ignored on Intel)
  274. FuncInfo *pFuncInfo, // Static information for this frame
  275. __ehstate_t targetState); // State to unwind to
  276. extern "C" void __stdcall __CxxLongjmpUnwind(
  277. _JUMP_BUFFER *jbuf
  278. ) {
  279. EHTRACE_ENTER;
  280. __FrameUnwindToState((EHRegistrationNode *)jbuf->Registration,
  281. (DispatcherContext*)NULL,
  282. (FuncInfo *)jbuf->UnwindData[0],
  283. (__ehstate_t)jbuf->TryLevel);
  284. EHTRACE_EXIT;
  285. }
  286. /////////////////////////////////////////////////////////////////////////////
  287. //
  288. // _CallCatchBlock2 - The nitty-gritty details to get the catch called
  289. // correctly.
  290. //
  291. // We need to guard the call to the catch block with a special registration
  292. // node, so that if there is an exception which should be handled by a try
  293. // block within the catch, we handle it without unwinding the SEH node
  294. // in CallCatchBlock.
  295. //
  296. struct CatchGuardRN {
  297. EHRegistrationNode *pNext; // Frame link
  298. void *pFrameHandler; // Frame Handler
  299. FuncInfo *pFuncInfo; // Static info for subject function
  300. EHRegistrationNode *pRN; // Dynamic info for subject function
  301. int CatchDepth; // How deeply nested are we?
  302. #if defined(ENABLE_EHTRACE) && (_MSC_VER >= 1300)
  303. int trace_level; // Trace level to restore in handler
  304. #endif
  305. };
  306. static EXCEPTION_DISPOSITION __cdecl CatchGuardHandler( EHExceptionRecord*, CatchGuardRN *, void *, void * );
  307. void *_CallCatchBlock2(
  308. EHRegistrationNode *pRN, // Dynamic info of function with catch
  309. FuncInfo *pFuncInfo, // Static info of function with catch
  310. void *handlerAddress, // Code address of handler
  311. int CatchDepth, // How deeply nested in catch blocks are we?
  312. unsigned long NLGCode
  313. ) {
  314. EHTRACE_ENTER;
  315. //
  316. // First, create and link in our special guard node:
  317. //
  318. CatchGuardRN CGRN = { NULL,
  319. (void*)CatchGuardHandler,
  320. pFuncInfo,
  321. pRN,
  322. CatchDepth + 1
  323. #if defined(ENABLE_EHTRACE) && (_MSC_VER >= 1300)
  324. , __ehtrace_level
  325. #endif
  326. };
  327. __asm {
  328. mov eax, FS:[0] // Fetch frame list head
  329. mov CGRN.pNext, eax // Link this node in
  330. lea eax, CGRN // Put this node at the head
  331. mov FS:[0], eax
  332. }
  333. //
  334. // Call the catch
  335. //
  336. void *continuationAddress = _CallSettingFrame( handlerAddress, pRN, NLGCode );
  337. //
  338. // Unlink our registration node
  339. //
  340. __asm {
  341. mov eax, CGRN.pNext // Get parent node
  342. mov FS:[0], eax // Put it at the head
  343. }
  344. EHTRACE_EXIT;
  345. return continuationAddress;
  346. }
  347. /////////////////////////////////////////////////////////////////////////////
  348. //
  349. // CatchGuardHandler - frame handler for the catch guard node.
  350. //
  351. // This function will attempt to find a handler for the exception within
  352. // the current catch block (ie any nested try blocks). If none is found,
  353. // or the handler rethrows, returns ExceptionContinueSearch; otherwise does
  354. // not return.
  355. //
  356. // Does nothing on an unwind.
  357. //
  358. static EXCEPTION_DISPOSITION __cdecl CatchGuardHandler(
  359. EHExceptionRecord *pExcept, // Information for this exception
  360. CatchGuardRN *pRN, // The special marker frame
  361. void *pContext, // Context info (we don't care what's in it)
  362. void * // (ignored)
  363. ) {
  364. #if defined(ENABLE_EHTRACE) && (_MSC_VER >= 1300)
  365. EHTracePushLevel(pRN->trace_level);
  366. #endif
  367. EHTRACE_ENTER_FMT1("pRN = 0x%p", pRN);
  368. __asm cld; // Our code-gen assumes this
  369. EXCEPTION_DISPOSITION result =
  370. __InternalCxxFrameHandler( pExcept,
  371. pRN->pRN,
  372. pContext,
  373. NULL,
  374. pRN->pFuncInfo,
  375. pRN->CatchDepth,
  376. (EHRegistrationNode*)pRN,
  377. FALSE );
  378. EHTRACE_HANDLER_EXIT(result);
  379. EHTRACE_RESTORE_LEVEL(true);
  380. return result;
  381. }
  382. /////////////////////////////////////////////////////////////////////////////
  383. //
  384. // CallSEHTranslator - calls the SEH translator, and handles the translation
  385. // exception.
  386. //
  387. // Assumes that a valid translator exists.
  388. //
  389. // Method:
  390. // Sets up a special guard node, whose handler handles the translation
  391. // exception, and remembers NT's marker node (See _UnwindNestedFrames above).
  392. // If the exception is not fully handled, the handler returns control to here,
  393. // so that this function can return to resume the normal search for a handler
  394. // for the original exception.
  395. //
  396. // Returns: TRUE if translator had a translation (handled or not)
  397. // FALSE if there was no translation
  398. // Does not return if translation was fully handled
  399. //
  400. struct TranslatorGuardRN /*: CatchGuardRN */ {
  401. EHRegistrationNode *pNext; // Frame link
  402. void *pFrameHandler; // Frame Handler
  403. FuncInfo *pFuncInfo; // Static info for subject function
  404. EHRegistrationNode *pRN; // Dynamic info for subject function
  405. int CatchDepth; // How deeply nested are we?
  406. EHRegistrationNode *pMarkerRN; // Marker for parent context
  407. void *pContinue; // Continuation address within CallSEHTranslator
  408. void *ESP; // ESP within CallSEHTranslator
  409. void *EBP; // EBP within CallSEHTranslator
  410. BOOL DidUnwind; // True if this frame was unwound
  411. #if defined(ENABLE_EHTRACE) && (_MSC_VER >= 1300)
  412. int trace_level; // Trace level to restore in handler
  413. #endif
  414. };
  415. static EXCEPTION_DISPOSITION __cdecl TranslatorGuardHandler( EHExceptionRecord*, TranslatorGuardRN *, void *, void * );
  416. #pragma optimize("g", off) // WORKAROUND for DOLPH:3322
  417. BOOL _CallSETranslator(
  418. EHExceptionRecord *pExcept, // The exception to be translated
  419. EHRegistrationNode *pRN, // Dynamic info of function with catch
  420. void *pContext, // Context info (we don't care what's in it)
  421. DispatcherContext *pDC, // More dynamic info of function with catch (ignored)
  422. FuncInfo *pFuncInfo, // Static info of function with catch
  423. int CatchDepth, // How deeply nested in catch blocks are we?
  424. EHRegistrationNode *pMarkerRN // Marker for parent context
  425. ) {
  426. EHTRACE_ENTER;
  427. //
  428. // Create and link in our special guard node:
  429. //
  430. TranslatorGuardRN TGRN = { NULL, // Frame link
  431. (void*)TranslatorGuardHandler,
  432. pFuncInfo,
  433. pRN,
  434. CatchDepth,
  435. pMarkerRN,
  436. NULL, // Continue
  437. NULL, // ESP
  438. NULL, // EBP
  439. FALSE // DidUnwind
  440. #if defined(ENABLE_EHTRACE) && (_MSC_VER >= 1300)
  441. , __ehtrace_level
  442. #endif
  443. };
  444. __asm {
  445. //
  446. // Fill in the blanks:
  447. //
  448. mov TGRN.pContinue, offset ExceptionContinuation
  449. mov TGRN.ESP, esp
  450. mov TGRN.EBP, ebp
  451. //
  452. // Link this node in:
  453. //
  454. mov eax, FS:[0] // Fetch frame list head
  455. mov TGRN.pNext, eax // Link this node in
  456. lea eax, TGRN // Put this node at the head
  457. mov FS:[0], eax
  458. }
  459. //
  460. // Call the translator; assume it will give a translation.
  461. //
  462. BOOL DidTranslate = TRUE;
  463. _EXCEPTION_POINTERS pointers = {
  464. (PEXCEPTION_RECORD)pExcept,
  465. (PCONTEXT)pContext };
  466. __pSETranslator(PER_CODE(pExcept), &pointers);
  467. //
  468. // If translator returned normally, that means it didn't translate the
  469. // exception.
  470. //
  471. DidTranslate = FALSE;
  472. //
  473. // Here's where we pick up if the translator threw something.
  474. // Note that ESP and EBP were restored by our frame handler.
  475. //
  476. ExceptionContinuation:
  477. if (TGRN.DidUnwind) {
  478. //
  479. // If the translated exception was partially handled (ie caught but
  480. // rethrown), then the frame list has the NT guard for the translation
  481. // exception context instead of the one for the original exception
  482. // context. Correct that sequencing problem. Note that our guard
  483. // node was unlinked by RtlUnwind.
  484. //
  485. __asm {
  486. mov ebx, FS:[0] // Get the node below the (bad) NT marker
  487. mov eax, [ebx] // (it was the target of the unwind)
  488. mov ebx, TGRN.pNext // Get the node we saved (the 'good' marker)
  489. mov [ebx], eax // Link the good node to the unwind target
  490. mov FS:[0], ebx // Put the good node at the head of the list
  491. }
  492. }
  493. else {
  494. //
  495. // Translator returned normally or translation wasn't handled.
  496. // unlink our registration node and exit
  497. //
  498. __asm {
  499. mov eax, TGRN.pNext // Get parent node
  500. mov FS:[0], eax // Put it at the head
  501. }
  502. }
  503. EHTRACE_EXIT;
  504. return DidTranslate;
  505. }
  506. #pragma optimize("g", on)
  507. /////////////////////////////////////////////////////////////////////////////
  508. //
  509. // TranslatorGuardHandler - frame handler for the translator guard node.
  510. //
  511. // On search:
  512. // This frame handler will check if there is a catch at the current level
  513. // for the translated exception. If there is no handler or the handler
  514. // did a re-throw, control is transfered back into CallSEHTranslator, based
  515. // on the values saved in the registration node.
  516. //
  517. // Does not return.
  518. //
  519. // On unwind:
  520. // Sets the DidUnwind flag in the registration node, and returns.
  521. //
  522. static EXCEPTION_DISPOSITION __cdecl TranslatorGuardHandler(
  523. EHExceptionRecord *pExcept, // Information for this exception
  524. TranslatorGuardRN *pRN, // The translator guard frame
  525. void *pContext, // Context info (we don't care what's in it)
  526. void * // (ignored)
  527. ) {
  528. #if defined(ENABLE_EHTRACE) && (_MSC_VER >= 1300)
  529. EHTracePushLevel(pRN->trace_level);
  530. #endif
  531. EHTRACE_ENTER_FMT1("pRN = 0x%p", pRN);
  532. __asm cld; // Our code-gen assumes this
  533. if (IS_UNWINDING(PER_FLAGS(pExcept)))
  534. {
  535. pRN->DidUnwind = TRUE;
  536. EHTRACE_HANDLER_EXIT(ExceptionContinueSearch);
  537. EHTRACE_RESTORE_LEVEL(true);
  538. return ExceptionContinueSearch;
  539. }
  540. else {
  541. //
  542. // Check for a handler:
  543. //
  544. __InternalCxxFrameHandler( pExcept, pRN->pRN, pContext, NULL, pRN->pFuncInfo, pRN->CatchDepth, pRN->pMarkerRN, TRUE );
  545. if (!pRN->DidUnwind) {
  546. //
  547. // If no match was found, unwind the context of the translator
  548. //
  549. _UnwindNestedFrames( (EHRegistrationNode*)pRN, pExcept );
  550. }
  551. //
  552. // Transfer control back to establisher:
  553. //
  554. EHTRACE_FMT1("Transfer to establisher @ 0x%p", pRN->pContinue);
  555. EHTRACE_RESTORE_LEVEL(false);
  556. EHTRACE_EXIT;
  557. __asm {
  558. mov ebx, pRN // Get address of registration node
  559. mov esp, [ebx]TranslatorGuardRN.ESP
  560. mov ebp, [ebx]TranslatorGuardRN.EBP
  561. jmp [ebx]TranslatorGuardRN.pContinue
  562. }
  563. // Unreached.
  564. return ExceptionContinueSearch;
  565. }
  566. }
  567. /////////////////////////////////////////////////////////////////////////////
  568. //
  569. // _GetRangeOfTrysToCheck - determine which try blocks are of interest, given
  570. // the current catch block nesting depth. We only check the trys at a single
  571. // depth.
  572. //
  573. // Returns:
  574. // Address of first try block of interest is returned
  575. // pStart and pEnd get the indices of the range in question
  576. //
  577. TryBlockMapEntry* _GetRangeOfTrysToCheck(
  578. FuncInfo *pFuncInfo,
  579. int CatchDepth,
  580. __ehstate_t curState,
  581. unsigned *pStart,
  582. unsigned *pEnd
  583. ) {
  584. TryBlockMapEntry *pEntry = FUNC_PTRYBLOCK(*pFuncInfo, 0);
  585. unsigned start = FUNC_NTRYBLOCKS(*pFuncInfo);
  586. unsigned end = start;
  587. unsigned end1 = end;
  588. while (CatchDepth >= 0) {
  589. DASSERT(start != -1);
  590. start--;
  591. if ( TBME_HIGH(pEntry[start]) < curState && curState <= TBME_CATCHHIGH(pEntry[start])
  592. || (start == -1)
  593. ) {
  594. CatchDepth--;
  595. end = end1;
  596. end1 = start;
  597. }
  598. }
  599. *pStart = ++start; // We always overshoot by 1 (we may even wrap around)
  600. *pEnd = end;
  601. DASSERT( end <= FUNC_NTRYBLOCKS(*pFuncInfo) && start <= end );
  602. return &(pEntry[start]);
  603. }
  604. /////////////////////////////////////////////////////////////////////////////
  605. //
  606. // _CreateFrameInfo - Save the frame information for this scope just before
  607. // calling the catch block. Put it at the head of the linked list. For
  608. // x86, all we need to save is the pointer to the exception object, so we
  609. // can determine when that object is no longer used by any nested catch
  610. // handler and can thus be destroyed on exiting from a catch.
  611. //
  612. // Returns:
  613. // Pointer to the frame info (the first input argument).
  614. //
  615. FRAMEINFO * _CreateFrameInfo(
  616. FRAMEINFO * pFrameInfo,
  617. PVOID pExceptionObject
  618. ) {
  619. pFrameInfo->pExceptionObject = pExceptionObject;
  620. pFrameInfo->pNext = (pFrameInfo < pFrameInfoChain)? pFrameInfoChain : NULL;
  621. pFrameInfoChain = pFrameInfo;
  622. return pFrameInfo;
  623. }
  624. /////////////////////////////////////////////////////////////////////////////
  625. //
  626. // IsExceptionObjectToBeDestroyed - Determine if an exception object is still
  627. // in use by a more deeply nested catch frame, or if it unused and should be
  628. // destroyed on exiting from the current catch block.
  629. //
  630. // Returns:
  631. // TRUE if exception object not found and should be destroyed.
  632. //
  633. BOOL IsExceptionObjectToBeDestroyed(
  634. PVOID pExceptionObject
  635. ) {
  636. FRAMEINFO * pFrameInfo;
  637. for (pFrameInfo = pFrameInfoChain; pFrameInfo != NULL; pFrameInfo = pFrameInfo->pNext ) {
  638. if( pFrameInfo->pExceptionObject == pExceptionObject ) {
  639. return FALSE;
  640. }
  641. }
  642. return TRUE;
  643. }
  644. /////////////////////////////////////////////////////////////////////////////
  645. //
  646. // _FindAndUnlinkFrame - Pop the frame information for this scope that was
  647. // pushed by _CreateFrameInfo. This should be the first frame in the list,
  648. // but the code will look for a nested frame and pop all frames, just in
  649. // case.
  650. //
  651. void _FindAndUnlinkFrame(
  652. FRAMEINFO * pFrameInfo
  653. ) {
  654. DASSERT(pFrameInfo == pFrameInfoChain);
  655. for (FRAMEINFO *pCurFrameInfo = pFrameInfoChain;
  656. pCurFrameInfo != NULL;
  657. pCurFrameInfo = pCurFrameInfo->pNext)
  658. {
  659. if (pFrameInfo == pCurFrameInfo) {
  660. pFrameInfoChain = pCurFrameInfo->pNext;
  661. return;
  662. }
  663. }
  664. // Should never be reached.
  665. DASSERT(0);
  666. }