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.

467 lines
16 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. * 12-07-01 BWT Remove NTSUBSET
  18. *
  19. ****/
  20. extern "C" {
  21. #include <windows.h>
  22. };
  23. #include <winnt.h>
  24. #include <mtdll.h>
  25. #include <ehassert.h>
  26. #include <ehdata.h>
  27. #include <trnsctrl.h>
  28. #include <ehstate.h>
  29. #include <eh.h>
  30. #include <ehhooks.h>
  31. #pragma hdrstop
  32. #ifdef _MT
  33. #define pFrameInfoChain (*((FRAMEINFO **) &(_getptd()->_pFrameInfoChain)))
  34. #define _ImageBase (_getptd()->_ImageBase)
  35. #define _ThrowImageBase (_getptd()->_ThrowImageBase)
  36. #define _pCurrentException (*((EHExceptionRecord **)&(_getptd()->_curexception)))
  37. #define _pForeignExcept (*((EHExceptionRecord **)&(_getptd()->_pForeignException)))
  38. #else
  39. static FRAMEINFO *pFrameInfoChain = NULL; // used to remember nested frames
  40. static unsigned __int64 _ImageBase = 0;
  41. static unsigned __int64 _ThrowImageBase = 0;
  42. extern EHExceptionRecord *_pCurrentException;
  43. extern EHExceptionRecord *_pForeignExcept;
  44. #endif
  45. // Should be used out of ntamd64.h, but can't figure out how to allow that with
  46. // existing dependencies.
  47. #define GetLanguageSpecificData(f, base) \
  48. (((PUNWIND_INFO)(f->UnwindInfoAddress + base))->UnwindCode + ((((PUNWIND_INFO)(f->UnwindInfoAddress + base))->CountOfCodes + 1)&~1) +1)
  49. extern "C" VOID RtlRestoreContext (PCONTEXT ContextRecord,PEXCEPTION_RECORD ExceptionRecord OPTIONAL);
  50. extern "C" void __FrameUnwindToState(EHRegistrationNode *, DispatcherContext *, FuncInfo *, __ehstate_t);
  51. //
  52. // Returns the establisher frame pointers. For catch handlers it is the parent's frame pointer.
  53. //
  54. EHRegistrationNode *_GetEstablisherFrame(
  55. EHRegistrationNode *pRN,
  56. DispatcherContext *pDC,
  57. FuncInfo *pFuncInfo,
  58. EHRegistrationNode *pEstablisher
  59. ) {
  60. TryBlockMapEntry *pEntry;
  61. HandlerType *pHandler;
  62. unsigned __int64 HandlerAdd, ImageBase;
  63. unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
  64. unsigned index, i;
  65. __ehstate_t curState;
  66. curState = __StateFromControlPc(pFuncInfo, pDC);
  67. *pEstablisher = *pRN;
  68. for (index = num_of_try_blocks; index > 0; index--) {
  69. pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index -1, pDC->ImageBase);
  70. if (curState > TBME_HIGH(*pEntry) && curState <= TBME_CATCHHIGH(*pEntry)) {
  71. // Get catch handler address.
  72. HandlerAdd = (*RtlLookupFunctionEntry(pDC->ControlPc, &ImageBase, pDC->HistoryTable)).BeginAddress;
  73. pHandler = TBME_PLIST(*pEntry, ImageBase);
  74. for ( i = 0;
  75. i < (unsigned)TBME_NCATCHES(*pEntry) &&
  76. pHandler[i].dispOfHandler != HandlerAdd
  77. ; i++);
  78. if ( i < (unsigned)TBME_NCATCHES(*pEntry)) {
  79. *pEstablisher = *(EHRegistrationNode *)OffsetToAddress(pHandler[i].dispFrame, *pRN);
  80. break;
  81. }
  82. }
  83. }
  84. return pEstablisher;
  85. }
  86. extern "C" unsigned __int64 _GetImageBase()
  87. {
  88. return _ImageBase;
  89. }
  90. extern "C" unsigned __int64 _GetThrowImageBase()
  91. {
  92. return _ThrowImageBase;
  93. }
  94. extern "C" VOID _SetThrowImageBase(unsigned __int64 NewThrowImageBase)
  95. {
  96. _ThrowImageBase = NewThrowImageBase;
  97. }
  98. extern "C" VOID _MoveContext(CONTEXT* pTarget, CONTEXT* pSource)
  99. {
  100. RtlMoveMemory(pTarget, pSource, sizeof(CONTEXT));
  101. }
  102. // This function returns the try block for the given state if the state is in a
  103. // catch; otherwise, NULL is returned.
  104. static __inline TryBlockMapEntry *_CatchTryBlock(
  105. FuncInfo *pFuncInfo,
  106. __ehstate_t curState
  107. ) {
  108. TryBlockMapEntry *pEntry;
  109. unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
  110. unsigned index;
  111. for (index = num_of_try_blocks; index > 0; index--) {
  112. pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index -1, _ImageBase);
  113. if (curState > TBME_HIGH(*pEntry) && curState <= TBME_CATCHHIGH(*pEntry)) {
  114. return pEntry;
  115. }
  116. }
  117. return NULL;
  118. }
  119. //
  120. // This routine returns TRUE if we are executing from within a catch. Otherwise, FALSE is returned.
  121. //
  122. BOOL _ExecutionInCatch(
  123. DispatcherContext *pDC,
  124. FuncInfo *pFuncInfo
  125. ) {
  126. __ehstate_t curState = __StateFromControlPc(pFuncInfo, pDC);
  127. return _CatchTryBlock(pFuncInfo, curState)? TRUE : FALSE;
  128. }
  129. // This function unwinds to the empty state.
  130. VOID __FrameUnwindToEmptyState(
  131. EHRegistrationNode *pRN,
  132. DispatcherContext *pDC,
  133. FuncInfo *pFuncInfo
  134. ) {
  135. __ehstate_t stateFromControlPC;
  136. TryBlockMapEntry *pEntry;
  137. EHRegistrationNode EstablisherFramePointers, *pEstablisher;
  138. pEstablisher = _GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFramePointers);
  139. stateFromControlPC = __StateFromControlPc(pFuncInfo, pDC);
  140. pEntry = _CatchTryBlock(pFuncInfo, stateFromControlPC);
  141. __FrameUnwindToState(pEstablisher, pDC, pFuncInfo,
  142. pEntry == NULL ? EH_EMPTY_STATE : TBME_HIGH(*pEntry));
  143. }
  144. //
  145. // Prototype for the internal handler
  146. //
  147. extern "C" EXCEPTION_DISPOSITION __InternalCxxFrameHandler(
  148. EHExceptionRecord *pExcept, // Information for this exception
  149. EHRegistrationNode *pRN, // Dynamic information for this frame
  150. CONTEXT *pContext, // Context info
  151. DispatcherContext *pDC, // More dynamic info for this frame
  152. FuncInfo *pFuncInfo, // Static information for this frame
  153. int CatchDepth, // How deeply nested are we?
  154. EHRegistrationNode *pMarkerRN, // Marker node for when checking inside catch block
  155. BOOL recursive); // True if this is a translation exception
  156. //
  157. // __CxxFrameHandler - Real entry point to the runtime
  158. //
  159. extern "C" _CRTIMP EXCEPTION_DISPOSITION __CxxFrameHandler(
  160. EHExceptionRecord *pExcept, // Information for this exception
  161. EHRegistrationNode RN, // Dynamic information for this frame
  162. CONTEXT *pContext, // Context info
  163. DispatcherContext *pDC // More dynamic info for this frame
  164. ) {
  165. FuncInfo *pFuncInfo;
  166. EXCEPTION_DISPOSITION result;
  167. EHRegistrationNode EstablisherFrame = RN;
  168. _ImageBase = pDC->ImageBase;
  169. _ThrowImageBase = (unsigned __int64)pExcept->params.pThrowImageBase;
  170. pFuncInfo = (FuncInfo*)(_ImageBase +*(PULONG)pDC->HandlerData);
  171. result = __InternalCxxFrameHandler( pExcept, &EstablisherFrame, pContext, pDC, pFuncInfo, 0, NULL, FALSE );
  172. return result;
  173. }
  174. // Call the SEH to EH translator.
  175. int __SehTransFilter( EXCEPTION_POINTERS *ExPtrs,
  176. EHExceptionRecord *pExcept,
  177. EHRegistrationNode *pRN,
  178. CONTEXT *pContext,
  179. DispatcherContext *pDC,
  180. FuncInfo *pFuncInfo,
  181. BOOL *pResult)
  182. {
  183. _pForeignExcept = pExcept;
  184. _ThrowImageBase = (unsigned __int64)((EHExceptionRecord *)ExPtrs->ExceptionRecord)->params.pThrowImageBase;
  185. __InternalCxxFrameHandler( (EHExceptionRecord *)ExPtrs->ExceptionRecord,
  186. pRN,
  187. pContext,
  188. pDC,
  189. pFuncInfo,
  190. 0,
  191. NULL,
  192. TRUE );
  193. _pForeignExcept = NULL;
  194. *pResult = TRUE;
  195. return EXCEPTION_EXECUTE_HANDLER;
  196. }
  197. BOOL _CallSETranslator(
  198. EHExceptionRecord *pExcept, // The exception to be translated
  199. EHRegistrationNode *pRN, // Dynamic info of function with catch
  200. CONTEXT *pContext, // Context info
  201. DispatcherContext *pDC, // More dynamic info of function with catch (ignored)
  202. FuncInfo *pFuncInfo, // Static info of function with catch
  203. ULONG CatchDepth, // How deeply nested in catch blocks are we?
  204. EHRegistrationNode *pMarkerRN // Marker for parent context
  205. ) {
  206. BOOL result = FALSE;
  207. pRN;
  208. pDC;
  209. pFuncInfo;
  210. CatchDepth;
  211. // Call the translator.
  212. _EXCEPTION_POINTERS excptr = { (PEXCEPTION_RECORD)pExcept, pContext };
  213. __try {
  214. __pSETranslator(PER_CODE(pExcept), &excptr);
  215. result = FALSE;
  216. } __except(__SehTransFilter( exception_info(),
  217. pExcept,
  218. pRN,
  219. pContext,
  220. pDC,
  221. pFuncInfo,
  222. &result
  223. )) {}
  224. // If we got back, then we were unable to translate it.
  225. return result;
  226. }
  227. /////////////////////////////////////////////////////////////////////////////
  228. //
  229. // _GetRangeOfTrysToCheck - determine which try blocks are of interest, given
  230. // the current catch block nesting depth. We only check the trys at a single
  231. // depth.
  232. //
  233. // Returns:
  234. // Address of first try block of interest is returned
  235. // pStart and pEnd get the indices of the range in question
  236. //
  237. TryBlockMapEntry* _GetRangeOfTrysToCheck(
  238. EHRegistrationNode *pRN,
  239. FuncInfo *pFuncInfo,
  240. int CatchDepth,
  241. __ehstate_t curState,
  242. unsigned *pStart,
  243. unsigned *pEnd,
  244. DispatcherContext *pDC
  245. ) {
  246. TryBlockMapEntry *pEntry, *pCurCatchEntry = NULL;
  247. unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
  248. unsigned int index;
  249. __ehstate_t ipState = __StateFromControlPc(pFuncInfo, pDC);
  250. DASSERT( num_of_try_blocks > 0 );
  251. *pStart = *pEnd = -1;
  252. for (index = num_of_try_blocks; index > 0; index--) {
  253. pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index -1, pDC->ImageBase);
  254. if (ipState > TBME_HIGH(*pEntry) && ipState <= TBME_CATCHHIGH(*pEntry)) {
  255. break;
  256. }
  257. }
  258. if (index) {
  259. pCurCatchEntry = FUNC_PTRYBLOCK(*pFuncInfo, index -1, pDC->ImageBase);
  260. }
  261. for(index = 0; index < num_of_try_blocks; index++ ) {
  262. pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index, pDC->ImageBase);
  263. // if in catch block, check for try-catch only in current block
  264. if (pCurCatchEntry) {
  265. if (TBME_LOW(*pEntry) <= TBME_HIGH(*pCurCatchEntry) ||
  266. TBME_HIGH(*pEntry) > TBME_CATCHHIGH(*pCurCatchEntry))
  267. continue;
  268. }
  269. if( curState >= TBME_LOW(*pEntry) && curState <= TBME_HIGH(*pEntry) ) {
  270. if (*pStart == -1) {
  271. *pStart = index;
  272. }
  273. *pEnd = index+1;
  274. }
  275. }
  276. if ( *pStart == -1){
  277. *pStart = 0;
  278. *pEnd = 0;
  279. return NULL;
  280. }
  281. else
  282. return FUNC_PTRYBLOCK(*pFuncInfo, *pStart, pDC->ImageBase);
  283. }
  284. FRAMEINFO * _CreateFrameInfo(
  285. FRAMEINFO * pFrameInfo,
  286. PVOID pExceptionObject
  287. ) {
  288. pFrameInfo->pExceptionObject = pExceptionObject;
  289. pFrameInfo->pNext = (pFrameInfo < pFrameInfoChain)? pFrameInfoChain : NULL;
  290. pFrameInfoChain = pFrameInfo;
  291. return pFrameInfo;
  292. }
  293. /////////////////////////////////////////////////////////////////////////////
  294. //
  295. // IsExceptionObjectToBeDestroyed - Determine if an exception object is still
  296. // in use by a more deeply nested catch frame, or if it unused and should be
  297. // destroyed on exiting from the current catch block.
  298. //
  299. // Returns:
  300. // TRUE if exception object not found and should be destroyed.
  301. //
  302. BOOL _IsExceptionObjectToBeDestroyed(
  303. PVOID pExceptionObject
  304. ) {
  305. FRAMEINFO * pFrameInfo;
  306. for (pFrameInfo = pFrameInfoChain; pFrameInfo != NULL; pFrameInfo = pFrameInfo->pNext ) {
  307. if( pFrameInfo->pExceptionObject == pExceptionObject ) {
  308. return FALSE;
  309. }
  310. }
  311. return TRUE;
  312. }
  313. /////////////////////////////////////////////////////////////////////////////
  314. //
  315. // _FindAndUnlinkFrame - Pop the frame information for this scope that was
  316. // pushed by _CreateFrameInfo. This should be the first frame in the list,
  317. // but the code will look for a nested frame and pop all frames, just in
  318. // case.
  319. //
  320. void _FindAndUnlinkFrame(
  321. FRAMEINFO * pFrameInfo
  322. ) {
  323. DASSERT(pFrameInfo == pFrameInfoChain);
  324. for (FRAMEINFO *pCurFrameInfo = pFrameInfoChain;
  325. pCurFrameInfo != NULL;
  326. pCurFrameInfo = pCurFrameInfo->pNext)
  327. {
  328. if (pFrameInfo == pCurFrameInfo) {
  329. pFrameInfoChain = pCurFrameInfo->pNext;
  330. return;
  331. }
  332. }
  333. // Should never be reached.
  334. DASSERT(0);
  335. }
  336. extern "C" void _UnwindNestedFrames(
  337. EHRegistrationNode *pFrame, // Unwind up to (but not including) this frame
  338. EHExceptionRecord *pExcept, // The exception that initiated this unwind
  339. CONTEXT *pContext, // Context info for current exception
  340. EHRegistrationNode *pEstablisher,
  341. void *Handler,
  342. __ehstate_t TargetUnwindState,
  343. FuncInfo *pFuncInfo,
  344. DispatcherContext *pDC,
  345. BOOLEAN recursive
  346. ) {
  347. static const EXCEPTION_RECORD ExceptionTemplate = { // A generic exception record
  348. 0x80000029L, // STATUS_UNWIND_CONSOLIDATE
  349. EXCEPTION_NONCONTINUABLE, // Exception flags (we don't do resume)
  350. NULL, // Additional record (none)
  351. NULL, // Address of exception (OS fills in)
  352. 15, // Number of parameters
  353. { EH_MAGIC_NUMBER1, // Our version control magic number
  354. NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  355. NULL, NULL, NULL, NULL, NULL, NULL, NULL
  356. } // pThrowInfo
  357. };
  358. CONTEXT Context;
  359. EXCEPTION_RECORD ExceptionRecord = ExceptionTemplate;
  360. ExceptionRecord.ExceptionInformation[0] = (ULONG_PTR)__CxxCallCatchBlock;
  361. // Address of call back function
  362. ExceptionRecord.ExceptionInformation[1] = (ULONG_PTR)pEstablisher;
  363. // Used by callback funciton
  364. ExceptionRecord.ExceptionInformation[2] = (ULONG_PTR)Handler;
  365. // Used by callback function to call catch block
  366. ExceptionRecord.ExceptionInformation[3] = (ULONG_PTR)TargetUnwindState;
  367. // Used by CxxFrameHandler to unwind to target_state
  368. ExceptionRecord.ExceptionInformation[4] = (ULONG_PTR)pContext;
  369. // used to set pCurrentExContext in callback function
  370. ExceptionRecord.ExceptionInformation[5] = (ULONG_PTR)pFuncInfo;
  371. // Used in callback function to set state on stack to -2
  372. ExceptionRecord.ExceptionInformation[6] = (ULONG_PTR)pExcept;
  373. // Used for passing currne t Exception
  374. ExceptionRecord.ExceptionInformation[7] = (ULONG_PTR)recursive;
  375. // Used for translated Exceptions
  376. RtlUnwindEx((void *)*pFrame,
  377. (void *)pDC->ControlPc, // Address where control left function
  378. &ExceptionRecord,
  379. NULL,
  380. &Context,
  381. pDC->HistoryTable);
  382. }
  383. typedef
  384. PVOID
  385. (*PCallSettingFrameHandler) (
  386. ULONG NonUsed,
  387. EHRegistrationNode Establisher
  388. );
  389. extern "C"
  390. PVOID
  391. _CallSettingFrame (
  392. PVOID Handler,
  393. EHRegistrationNode *Establisher,
  394. ULONG NLG_CODE
  395. )
  396. /*++
  397. Routine Description:
  398. This function calls a catch handler or destructor passing the establisher
  399. frame.
  400. Arguments:
  401. Handler - Supplies the address of the handler.
  402. Establisher - Supplies a pointer the establisher frame.
  403. NLG_CODE - Supplies a non-local goto code.
  404. Return Value:
  405. The continuation address is returned if catch handler returns.
  406. --*/
  407. {
  408. return ((PCallSettingFrameHandler)Handler)(0, *Establisher);
  409. }