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.

196 lines
5.6 KiB

  1. /*****************************************************************************
  2. *
  3. * Seh.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Structured exception handling.
  10. *
  11. *****************************************************************************/
  12. #ifdef _M_IX86
  13. #include <windows.h>
  14. #include <sehcall.h>
  15. typedef void *PV;
  16. /*****************************************************************************
  17. *
  18. * SEHFRAME
  19. *
  20. * Special stack frame used by lightweight structured exception
  21. * handling.
  22. *
  23. *****************************************************************************/
  24. typedef struct SEHFRAME {
  25. PV pvSEH; /* Link to previous frame */
  26. FARPROC Handler; /* MyExceptionFilter */
  27. FARPROC sehTarget; /* Where to jump on error */
  28. INEXCEPTION InException; /* In-exception handler */
  29. } SEHFRAME, *PSEHFRAME;
  30. /***************************************************************************
  31. *
  32. * @doc INTERNAL
  33. *
  34. * @func BOOL | _MyExceptionFilter |
  35. *
  36. * My tiny exception filter.
  37. *
  38. * @parm LPEXCEPTION_RECORD | pExceptionRecord |
  39. *
  40. * Exception record describing why we were called.
  41. *
  42. * @parm PV | EstablisherFrame |
  43. *
  44. * The exception frame (pNext, pHandler)
  45. * on the stack which is being handled. This is used so that
  46. * the handler can access its local variables and knows how
  47. * far to smash the stack if the exception is being eaten.
  48. *
  49. * @parm PCONTEXT | pContextRecord |
  50. *
  51. * Client context at time of exception.
  52. *
  53. * @parm PV | DispatcherContext |
  54. *
  55. * Not used. Which is good, because I don't know what it means.
  56. *
  57. ***************************************************************************/
  58. #define EXCEPTION_UNWINDING 0x00000002
  59. #define EXCEPTION_EXIT_UNWIND 0x00000004
  60. WINBASEAPI void WINAPI
  61. RtlUnwind(PV TargetFrame, PV TargetIp, PEXCEPTION_RECORD per, PV ReturnValue);
  62. EXCEPTION_DISPOSITION
  63. __cdecl
  64. _MyExceptionFilter(
  65. LPEXCEPTION_RECORD pExceptionRecord,
  66. PV EstablisherFrame,
  67. PCONTEXT pContextRecord,
  68. PV DispatcherContext
  69. )
  70. {
  71. DispatcherContext;
  72. pContextRecord;
  73. /* Don't interfere with an unwind */
  74. if ((pExceptionRecord->ExceptionFlags &
  75. (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) == 0) {
  76. PSEHFRAME pseh = EstablisherFrame;
  77. BOOL fRc = pseh->InException(pExceptionRecord, pContextRecord);
  78. /*
  79. * RtlUnwind will tell all exception frames that may have
  80. * been created underneath us that they are about to be
  81. * blown away and should do their __finally handling.
  82. *
  83. * On return, the nested frames have been unlinked.
  84. */
  85. RtlUnwind(EstablisherFrame, 0, 0, 0);
  86. /*
  87. * And jump back to the caller. It is the caller's
  88. * responsibility to restore nonvolatile registers!
  89. *
  90. * We also assume that the caller has nothing on the
  91. * stack beneath the exception record!
  92. *
  93. * And the handler address is right after the exception
  94. * record!
  95. */
  96. __asm {
  97. mov eax, fRc; /* Get return value */
  98. mov esp, EstablisherFrame; /* Restore ESP */
  99. // jmp [esp].sehTarget; /* Back to CallWithSEH */
  100. //We should be doing the above, but it faults VC4.2. Gotta love it.
  101. jmp DWORD ptr [esp+8]
  102. }
  103. }
  104. /*
  105. * We are unwinding. Don't interfere.
  106. */
  107. return EXCEPTION_CONTINUE_SEARCH;
  108. }
  109. /***************************************************************************
  110. *
  111. * @doc INTERNAL
  112. *
  113. * @func DWORD | CallWithSEH |
  114. *
  115. * Call the function with an exception frame active.
  116. *
  117. * If the procedure raises an exception, then call
  118. * InException and propagate whatever InException returns.
  119. *
  120. ***************************************************************************/
  121. #pragma warning(disable:4035) /* no return value (duh) */
  122. __declspec(naked) DWORD WINAPI
  123. CallWithSEH(EXCEPTPROC pfn, PV pv, INEXCEPTION InException)
  124. {
  125. __asm {
  126. /* Function prologue */
  127. push ebp;
  128. mov ebp, esp; /* To keep C compiler happy */
  129. push ebx;
  130. push edi;
  131. push esi;
  132. /*
  133. * Build a SEHFRAME.
  134. */
  135. push InException; /* What to handle */
  136. push offset Exit; /* Where to go on error */
  137. xor edx, edx; /* Keep zero handy */
  138. push offset _MyExceptionFilter; /* My handler */
  139. push dword ptr fs:[edx]; /* Build frame */
  140. mov fs:[edx], esp; /* Link in */
  141. }
  142. pfn(pv); /* Call the victim */
  143. __asm {
  144. /*
  145. * The validation layer jumps here (all registers in a random
  146. * state except for ESP) if something went wrong.
  147. *
  148. * We don't need to restore nonvolatile registers now;
  149. * that will be done as part of the procedure exit.
  150. */
  151. Exit:;
  152. xor edx, edx; /* Keep zero handy */
  153. pop dword ptr fs:[edx]; /* Remove frame */
  154. /*
  155. * Discard MyExceptionFilter, Exit, and InException.
  156. */
  157. add esp, 12;
  158. pop esi;
  159. pop edi;
  160. pop ebx;
  161. pop ebp;
  162. ret 12;
  163. }
  164. }
  165. #pragma warning(default:4035)
  166. #endif