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.

540 lines
19 KiB

  1. /***
  2. *trnsctrl.cpp -
  3. *
  4. * Copyright (c) 1990-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *Revision History:
  9. * 06-01-97 Created by TiborL.
  10. * 07-12-99 RDL Image relative fixes under CC_P7_SOFT25.
  11. * 10-07-99 SAH utc_p7#1126: fix ipsr.ri reset.
  12. * 10-19-99 TGL Miscellaneous unwind fixes.
  13. * 03-15-00 PML Remove CC_P7_SOFT25, which is now on permanently.
  14. * 03-30-00 SAH New version of GetLanguageSpecificData from ntia64.h.
  15. * 06-08-00 RDL VS#111429: IA64 workaround for AV while handling throw.
  16. * 06-05-01 GB AMD64 Eh support Added.
  17. *
  18. ****/
  19. #if defined(_NTSUBSET_)
  20. extern "C" {
  21. #include <nt.h>
  22. #include <ntrtl.h>
  23. #include <nturtl.h>
  24. #include <ntstatus.h> // STATUS_UNHANDLED_EXCEPTION
  25. #include <ntos.h>
  26. #include <ex.h> // ExRaiseException
  27. }
  28. #endif
  29. extern "C" {
  30. #include <windows.h>
  31. };
  32. #include <winnt.h>
  33. #include <mtdll.h>
  34. #include <ehassert.h>
  35. #include <ehdata.h>
  36. #include <trnsctrl.h>
  37. #include <ehstate.h>
  38. #include <eh.h>
  39. #include <ehhooks.h>
  40. #pragma hdrstop
  41. #ifdef _MT
  42. #define pFrameInfoChain (*((FRAMEINFO **) &(_getptd()->_pFrameInfoChain)))
  43. #define pUnwindContext (*((CONTEXT **) &(_getptd()->_pUnwindContext)))
  44. #define _ImageBase (_getptd()->_ImageBase)
  45. #define _ThrowImageBase (_getptd()->_ThrowImageBase)
  46. #define _pCurrentException (*((EHExceptionRecord **)&(_getptd()->_curexception)))
  47. #else
  48. static FRAMEINFO *pFrameInfoChain = NULL; // used to remember nested frames
  49. static CONTEXT *pUnwindContext = NULL; // context to assist the return to 'UnwindNestedFrames'
  50. static unsigned __int64 _ImageBase = 0;
  51. static unsigned __int64 _ThrowImageBase = 0;
  52. extern EHExceptionRecord *_pCurrentException;
  53. #endif
  54. // Should be used out of ntamd64.h, but can't figure out how to allow that with
  55. // existing dependencies.
  56. #define GetLanguageSpecificData(f, base) \
  57. (((PUNWIND_INFO)(f->UnwindInfoAddress + base))->UnwindCode + ((((PUNWIND_INFO)(f->UnwindInfoAddress + base))->CountOfCodes + 1)&~1) +1)
  58. extern "C" VOID RtlRestoreContext (PCONTEXT ContextRecord,PEXCEPTION_RECORD ExceptionRecord OPTIONAL);
  59. extern "C" void RtlCaptureContext(CONTEXT*);
  60. extern "C" void _GetNextInstrOffset(PVOID*);
  61. extern "C" void __FrameUnwindToState(EHRegistrationNode *, DispatcherContext *, FuncInfo *, __ehstate_t);
  62. //
  63. // Returns the establisher frame pointers. For catch handlers it is the parent's frame pointer.
  64. //
  65. EHRegistrationNode *_GetEstablisherFrame(
  66. EHRegistrationNode *pRN,
  67. DispatcherContext *pDC,
  68. FuncInfo *pFuncInfo,
  69. EHRegistrationNode *pEstablisher
  70. ) {
  71. TryBlockMapEntry *pEntry;
  72. HandlerType *pHandler;
  73. unsigned __int64 HandlerAdd, ImageBase;
  74. unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
  75. unsigned index, i;
  76. __ehstate_t curState;
  77. curState = _StateFromControlPc(pFuncInfo, pDC);
  78. *pEstablisher = *pRN;
  79. for (index = num_of_try_blocks-1; (int)index >= 0; index--) {
  80. pEntry = FUNC_PTRYBLOCK(*pFuncInfo, (index), pDC->ImageBase);
  81. if (curState > TBME_HIGH(*pEntry) && curState <= TBME_CATCHHIGH(*pEntry)) {
  82. // Get catch handler address.
  83. HandlerAdd = (*RtlLookupFunctionEntry(pDC->ControlPc, &ImageBase, pDC->HistoryTable)).BeginAddress;
  84. pHandler = TBME_PLIST(*pEntry, ImageBase);
  85. for ( i = 0;
  86. i < (unsigned)TBME_NCATCHES(*pEntry) &&
  87. pHandler[i].dispOfHandler != HandlerAdd
  88. ; i++);
  89. if ( i < (unsigned)TBME_NCATCHES(*pEntry)) {
  90. *pEstablisher = *(EHRegistrationNode *)OffsetToAddress(pHandler[i].dispFrame, *pRN);
  91. break;
  92. }
  93. }
  94. }
  95. return pEstablisher;
  96. }
  97. extern "C" VOID _SaveUnwindContext(CONTEXT* pContext)
  98. {
  99. pUnwindContext = pContext;
  100. }
  101. extern "C" CONTEXT* _GetUnwindContext()
  102. {
  103. return pUnwindContext;
  104. }
  105. extern "C" unsigned __int64 _GetImageBase()
  106. {
  107. return _ImageBase;
  108. }
  109. extern "C" unsigned __int64 _GetThrowImageBase()
  110. {
  111. return _ThrowImageBase;
  112. }
  113. extern "C" VOID _SetThrowImageBase(unsigned __int64 NewThrowImageBase)
  114. {
  115. _ThrowImageBase = NewThrowImageBase;
  116. }
  117. extern "C" VOID _MoveContext(CONTEXT* pTarget, CONTEXT* pSource)
  118. {
  119. RtlMoveMemory(pTarget, pSource, sizeof(CONTEXT));
  120. }
  121. // This function returns the try block for the given state if the state is in a
  122. // catch; otherwise, NULL is returned.
  123. static __inline TryBlockMapEntry *_CatchTryBlock(
  124. FuncInfo *pFuncInfo,
  125. __ehstate_t curState
  126. ) {
  127. TryBlockMapEntry *pEntry;
  128. unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
  129. unsigned index;
  130. for (index = 0; index < num_of_try_blocks; index++) {
  131. pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index, _ImageBase);
  132. if (curState > TBME_HIGH(*pEntry) && curState <= TBME_CATCHHIGH(*pEntry)) {
  133. return pEntry;
  134. }
  135. }
  136. return NULL;
  137. }
  138. //
  139. // This routine returns TRUE if we are executing from within a catch. Otherwise, FALSE is returned.
  140. //
  141. BOOL _ExecutionInCatch(
  142. DispatcherContext *pDC,
  143. FuncInfo *pFuncInfo
  144. ) {
  145. __ehstate_t curState = _StateFromControlPc(pFuncInfo, pDC);
  146. return _CatchTryBlock(pFuncInfo, curState)? TRUE : FALSE;
  147. }
  148. // This function unwinds to the empty state.
  149. VOID __FrameUnwindToEmptyState(
  150. EHRegistrationNode *pRN,
  151. DispatcherContext *pDC,
  152. FuncInfo *pFuncInfo
  153. ) {
  154. __ehstate_t stateFromControlPC;
  155. TryBlockMapEntry *pEntry;
  156. EHRegistrationNode EstablisherFramePointers, *pEstablisher;
  157. pEstablisher = _GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFramePointers);
  158. stateFromControlPC = _StateFromControlPc(pFuncInfo, pDC);
  159. pEntry = _CatchTryBlock(pFuncInfo, stateFromControlPC);
  160. __FrameUnwindToState(pEstablisher, pDC, pFuncInfo,
  161. pEntry == NULL ? EH_EMPTY_STATE : TBME_HIGH(*pEntry));
  162. }
  163. BOOL _IsExceptionObjectDestroyed(PVOID pExceptionObject,FRAMEINFO *pFrameInfo)
  164. {
  165. for (; pFrameInfo != NULL; pFrameInfo = pFrameInfo->pNext ) {
  166. if( pFrameInfo->pExceptionObjectDestroyed == pExceptionObject ) {
  167. return TRUE;
  168. }
  169. }
  170. return FALSE;
  171. }
  172. void _MarkExceptionObjectDestroyed(EHExceptionRecord *pExcept)
  173. {
  174. for (FRAMEINFO *pFrameInfo = pFrameInfoChain; pFrameInfo != NULL; pFrameInfo = pFrameInfo->pNext ) {
  175. if( pFrameInfo->pExcept == pExcept ) {
  176. pFrameInfo->pExceptionObjectDestroyed = PER_PEXCEPTOBJ(pExcept);
  177. }
  178. }
  179. }
  180. void _UnlinkFrame(FRAMEINFO *pFrameInfo)
  181. {
  182. FRAMEINFO *pPrevFrameInfo = pFrameInfoChain;
  183. if( pFrameInfoChain == pFrameInfo ) {
  184. pFrameInfoChain = pFrameInfoChain->pNext;
  185. return;
  186. }
  187. for (FRAMEINFO *pCurFrameInfo = pFrameInfoChain; pCurFrameInfo != NULL; pCurFrameInfo = pCurFrameInfo->pNext ) {
  188. if( pCurFrameInfo == pFrameInfo ) {
  189. pPrevFrameInfo->pNext = pCurFrameInfo->pNext;
  190. return;
  191. }
  192. pPrevFrameInfo = pCurFrameInfo;
  193. }
  194. }
  195. // Find the frame info structure corresponding to the given address. Return
  196. // NULL if the frame info structure does not exist.
  197. FRAMEINFO *_FindFrameInfo(
  198. PVOID pContinuation,
  199. FRAMEINFO *pFrameInfo
  200. ) {
  201. unsigned __int64 ImageBase;
  202. PRUNTIME_FUNCTION pContFunctionEntry = RtlLookupFunctionEntry((unsigned __int64)pContinuation, &ImageBase, NULL);
  203. PRUNTIME_FUNCTION pFrameFunctionEntry = pFrameInfo->pFunctionEntry;
  204. DASSERT(pFrameInfo != NULL);
  205. for (; pFrameInfo != NULL; pFrameInfo = pFrameInfo->pNext ) {
  206. if (pContFunctionEntry == pFrameInfo->pFunctionEntry &&
  207. (pContinuation > OffsetToAddress(pFrameInfo->pFunctionEntry->BeginAddress,ImageBase)) &&
  208. (pContinuation <= OffsetToAddress(pFrameInfo->pFunctionEntry->EndAddress,ImageBase))
  209. ){
  210. return pFrameInfo;
  211. }
  212. }
  213. return NULL;
  214. }
  215. BOOL __IsFramePdataMatch(
  216. PVOID pContinuation,
  217. RUNTIME_FUNCTION* pFrameRfe)
  218. {
  219. BOOL fRetVal = FALSE;
  220. unsigned __int64 ImageBase;
  221. PRUNTIME_FUNCTION pContRfe = RtlLookupFunctionEntry((unsigned __int64) pContinuation, &ImageBase, NULL);
  222. FuncInfo* pContFuncInfo = (FuncInfo*)(_ImageBase + *(PULONG)GetLanguageSpecificData(pContRfe,_ImageBase));
  223. FuncInfo* pFrameFuncInfo = (FuncInfo*)(ImageBase + *(PULONG)GetLanguageSpecificData(pFrameRfe,ImageBase));
  224. //
  225. // first see if there is a regular match, i.e. if the RFE registered with the frame
  226. // matches the RFE for the continuation address
  227. //
  228. fRetVal = (pContRfe == pFrameRfe) &&
  229. (pContinuation > OffsetToAddress(pFrameRfe->BeginAddress,ImageBase)) &&
  230. (pContinuation <= OffsetToAddress(pFrameRfe->EndAddress,ImageBase));
  231. if (!fRetVal && (pContFuncInfo->bbtFlags == BBT_UNIQUE_FUNCINFO)) {
  232. fRetVal = (pContFuncInfo == pFrameFuncInfo);
  233. }
  234. return fRetVal;
  235. }
  236. //
  237. // Given the address of a continuation point, return the corresponding context.
  238. // Each frame info was saved just before a catch handler was called.
  239. // The most recently encountered frame is at the head of the chain.
  240. // The routine starts out with the frame given as the second argument, and scans the
  241. // linked list for the frame that corresponds to the continuation point.
  242. //
  243. CONTEXT* _FindAndUnlinkFrame(PVOID pContinuation, FRAMEINFO *pFrameInfo)
  244. {
  245. DASSERT(pFrameInfo != NULL);
  246. for( ; pFrameInfo != NULL; pFrameInfo = pFrameInfo->pNext ) {
  247. if(__IsFramePdataMatch(pContinuation, pFrameInfo->pFunctionEntry)) {
  248. //
  249. // We found the frame.
  250. // All frames preceeding and including this one are gone. so unlink them.
  251. //
  252. CONTEXT *pExitContext = pFrameInfo->pExitContext;
  253. pFrameInfoChain = pFrameInfo->pNext;
  254. //
  255. // If there are no more exceptions pending get rid of unneeded frame info records.
  256. //
  257. if (_pCurrentException == NULL) {
  258. while(pFrameInfoChain != NULL && pFrameInfoChain->pExceptionObjectDestroyed) {
  259. pFrameInfoChain = pFrameInfoChain->pNext;
  260. }
  261. }
  262. return pExitContext;
  263. }
  264. }
  265. DASSERT(pFrameInfo != NULL);
  266. return NULL;
  267. }
  268. //
  269. // Save the frame information for this scope. Put it at the head of the linked-list.
  270. //
  271. FRAMEINFO* _CreateFrameInfo(
  272. FRAMEINFO *pFrameInfo,
  273. DispatcherContext *pDC,
  274. CONTEXT *pExitContext,
  275. __ehstate_t State,
  276. PVOID pExceptionObjectDestroyed,
  277. EHExceptionRecord *pExcept
  278. ) {
  279. pFrameInfo->pFunctionEntry = pDC->FunctionEntry;
  280. pFrameInfo->pExitContext = pExitContext;
  281. pFrameInfo->pExceptionObjectDestroyed = pExceptionObjectDestroyed;
  282. pFrameInfo->pExceptionObjectToBeDestroyed = NULL;
  283. pFrameInfo->pExcept = pExcept;
  284. pFrameInfo->State = State;
  285. pFrameInfo->dtorThrowFlag = FALSE;
  286. pFrameInfo->isRethrow = FALSE;
  287. if( pFrameInfoChain != NULL && pFrameInfoChain->dtorThrowFlag ) {
  288. pFrameInfoChain = pFrameInfoChain->pNext;
  289. }
  290. pFrameInfo->pNext = (pFrameInfo < pFrameInfoChain)? pFrameInfoChain : NULL;
  291. pFrameInfoChain = pFrameInfo;
  292. return pFrameInfo;
  293. }
  294. //
  295. // THIS ROUTINE IS USED ONLY TO JUMP TO THE CONTINUATION POINT
  296. //
  297. // Sets SP and jumps to specified code address.
  298. // Does not return.
  299. //
  300. void _JumpToContinuation(
  301. unsigned __int64 TargetAddress, // The target address to call
  302. CONTEXT *pContext, // Context of target function
  303. EHExceptionRecord *pExcept
  304. ) {
  305. pContext->Rip = TargetAddress;
  306. RtlRestoreContext(pContext, (PEXCEPTION_RECORD)pExcept);
  307. }
  308. //
  309. // Prototype for the internal handler
  310. //
  311. extern "C" EXCEPTION_DISPOSITION __InternalCxxFrameHandler(
  312. EHExceptionRecord *pExcept, // Information for this exception
  313. EHRegistrationNode *pRN, // Dynamic information for this frame
  314. CONTEXT *pContext, // Context info
  315. DispatcherContext *pDC, // More dynamic info for this frame
  316. FuncInfo *pFuncInfo, // Static information for this frame
  317. int CatchDepth, // How deeply nested are we?
  318. EHRegistrationNode *pMarkerRN, // Marker node for when checking inside catch block
  319. BOOL recursive); // True if this is a translation exception
  320. //
  321. // __CxxFrameHandler - Real entry point to the runtime
  322. //
  323. extern "C" _CRTIMP EXCEPTION_DISPOSITION __CxxFrameHandler(
  324. EHExceptionRecord *pExcept, // Information for this exception
  325. EHRegistrationNode RN, // Dynamic information for this frame
  326. CONTEXT *pContext, // Context info
  327. DispatcherContext *pDC // More dynamic info for this frame
  328. ) {
  329. FuncInfo *pFuncInfo;
  330. EXCEPTION_DISPOSITION result;
  331. EHRegistrationNode EstablisherFrame = RN;
  332. _ImageBase = pDC->ImageBase;
  333. _ThrowImageBase = (unsigned __int64)pExcept->params.pThrowImageBase;
  334. pFuncInfo = (FuncInfo*)(_ImageBase +*(PULONG)pDC->HandlerData);
  335. result = __InternalCxxFrameHandler( pExcept, &EstablisherFrame, pContext, pDC, pFuncInfo, 0, NULL, FALSE );
  336. return result;
  337. }
  338. // Call the SEH to EH translator.
  339. BOOL _CallSETranslator(
  340. EHExceptionRecord *pExcept, // The exception to be translated
  341. EHRegistrationNode *pRN, // Dynamic info of function with catch
  342. CONTEXT *pContext, // Context info
  343. DispatcherContext *pDC, // More dynamic info of function with catch (ignored)
  344. FuncInfo *pFuncInfo, // Static info of function with catch
  345. ULONG CatchDepth, // How deeply nested in catch blocks are we?
  346. EHRegistrationNode *pMarkerRN // Marker for parent context
  347. ) {
  348. pRN;
  349. pDC;
  350. pFuncInfo;
  351. CatchDepth;
  352. // Call the translator.
  353. _EXCEPTION_POINTERS excptr = { (PEXCEPTION_RECORD)pExcept, pContext };
  354. __pSETranslator(PER_CODE(pExcept), &excptr);
  355. // If we got back, then we were unable to translate it.
  356. return FALSE;
  357. }
  358. //
  359. // This structure is the FuncInfo (HandlerData) for handler __TranslatorGuardHandler
  360. //
  361. struct TransGuardRec {
  362. FuncInfo *pFuncInfo; // Static info for subject function
  363. EHRegistrationNode *pFrame; // Dynamic info for subject function
  364. ULONG CatchDepth; // How deeply nested are we?
  365. EHRegistrationNode *pMarkerFrame; // Marker for parent context
  366. PVOID pContinue; // Continuation address within CallSEHTranslator
  367. PVOID pSP; // SP within CallSEHTranslator
  368. BOOL DidUnwind; // True if this frame was unwound
  369. };
  370. #if 0
  371. //
  372. // This routine is the handler for CallSETranslator which is defined in handlers.s
  373. //
  374. extern "C" _CRTIMP EXCEPTION_DISPOSITION __TranslatorGuardHandler(
  375. EHExceptionRecord *pExcept, // Information for this exception
  376. EHRegistrationNode *pFrame, // The translator guard frame
  377. CONTEXT *pContext, // Context info
  378. DispatcherContext *pDC // Dynamic info for this frame
  379. ) {
  380. //
  381. // The handler data is a pointer to an integer that is an offset to the TGRN structure
  382. // relative to the frame pointer.
  383. //
  384. TransGuardRec *pTransGuardData = (TransGuardRec*)((char*)pFrame->MemoryStackFp - *(int*)(pDC->FunctionEntry->HandlerData));
  385. if (IS_UNWINDING(PER_FLAGS(pExcept)))
  386. {
  387. pTransGuardData->DidUnwind = TRUE;
  388. return ExceptionContinueSearch;
  389. }
  390. else {
  391. //
  392. // Check for a handler:
  393. //
  394. __InternalCxxFrameHandler( pExcept,
  395. pTransGuardData->pFrame,
  396. pContext,
  397. pDC,
  398. pTransGuardData->pFuncInfo,
  399. pTransGuardData->CatchDepth,
  400. pTransGuardData->pMarkerFrame,
  401. TRUE );
  402. // Unreached.
  403. return ExceptionContinueSearch;
  404. }
  405. }
  406. #endif
  407. /////////////////////////////////////////////////////////////////////////////
  408. //
  409. // _GetRangeOfTrysToCheck - determine which try blocks are of interest, given
  410. // the current catch block nesting depth. We only check the trys at a single
  411. // depth.
  412. //
  413. // Returns:
  414. // Address of first try block of interest is returned
  415. // pStart and pEnd get the indices of the range in question
  416. //
  417. TryBlockMapEntry* _GetRangeOfTrysToCheck(
  418. EHRegistrationNode *pRN,
  419. FuncInfo *pFuncInfo,
  420. int CatchDepth,
  421. __ehstate_t curState,
  422. unsigned *pStart,
  423. unsigned *pEnd,
  424. DispatcherContext *pDC
  425. ) {
  426. TryBlockMapEntry *pEntry;
  427. unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
  428. DASSERT( num_of_try_blocks > 0 );
  429. for( unsigned int index = 0; index < num_of_try_blocks; index++ ) {
  430. pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index, pDC->ImageBase);
  431. if( curState >= TBME_LOW(*pEntry) && curState <= TBME_HIGH(*pEntry) ) {
  432. *pStart = index;
  433. *pEnd = FUNC_NTRYBLOCKS(*pFuncInfo);
  434. DASSERT( *pEnd <= num_of_try_blocks && *pStart < *pEnd );
  435. int SavedState = GetUnwindTryBlock(pRN, pDC, pFuncInfo);
  436. if( SavedState != -1 && SavedState >= curState )
  437. continue;
  438. return pEntry;
  439. }
  440. }
  441. *pStart = *pEnd = 0;
  442. return NULL;
  443. }
  444. #pragma optimize("",off)
  445. extern "C" void _UnwindNestedFrames(
  446. EHRegistrationNode *pFrame, // Unwind up to (but not including) this frame
  447. EHExceptionRecord *pExcept, // The exception that initiated this unwind
  448. CONTEXT *pContext, // Context info for current exception
  449. DispatcherContext *pDC
  450. ) {
  451. CONTEXT LocalContext; // Create context for this routine to return from RtlUnwind
  452. CONTEXT ScratchContext; // Context record to pass to RtlUnwind2 to be used as scratch
  453. volatile int Unwound = FALSE; // Flag that assist to return from RtlUnwind2
  454. PVOID pReturnPoint = NULL; // The address we want to return from RtlUnwind2
  455. RtlCaptureContext(&LocalContext);
  456. //
  457. // set up the return label
  458. //
  459. _GetNextInstrOffset(&pReturnPoint);
  460. if(Unwound)
  461. goto LAB_UNWOUND;
  462. LocalContext.Rip = (ULONGLONG)pReturnPoint;
  463. pUnwindContext = &LocalContext;
  464. Unwound = TRUE;
  465. #ifdef _NT
  466. RtlUnwindEx((void *)*pFrame, (ULONG_PTR)pReturnPoint, (PEXCEPTION_RECORD)pExcept, NULL, &ScratchContext, pDC->HistoryTable);
  467. #else
  468. RtlUnwindEx((void *)*pFrame, pReturnPoint, (PEXCEPTION_RECORD)pExcept, NULL, &ScratchContext, pDC->HistoryTable);
  469. #endif
  470. LAB_UNWOUND:
  471. PER_FLAGS(pExcept) &= ~EXCEPTION_UNWINDING;
  472. pUnwindContext = NULL;
  473. }