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.

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