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.

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