Windows NT 4.0 source code leak
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.

436 lines
14 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1993 Digital Equipment Corporation
  3. Module Name:
  4. ghandler.c
  5. Abstract:
  6. This module implements the C specific exception handler that provides
  7. structured exception handling for code generated by the GEM compiler.
  8. Author:
  9. John Parks (parks) 12-Jan-1993
  10. Thomas Van Baak (tvb) 28-Jan-1993
  11. Environment:
  12. Any mode.
  13. Revision History:
  14. --*/
  15. #include "nt.h"
  16. //
  17. // Define procedure prototypes for exception filter and termination handler
  18. // execution routines defined in jmpunwnd.s.
  19. //
  20. LONG
  21. __C_ExecuteExceptionFilter (
  22. PEXCEPTION_POINTERS ExceptionPointers,
  23. EXCEPTION_FILTER ExceptionFilter,
  24. ULONG EstablisherFrame
  25. );
  26. ULONG
  27. __C_ExecuteTerminationHandler (
  28. BOOLEAN AbnormalTermination,
  29. TERMINATION_HANDLER TerminationHandler,
  30. ULONG EstablisherFrame
  31. );
  32. //
  33. // Define local procedure prototypes.
  34. //
  35. EXCEPTION_DISPOSITION
  36. _OtsCSpecificHandler (
  37. IN PEXCEPTION_RECORD ExceptionRecord,
  38. IN PVOID EstablisherFrame,
  39. IN OUT PCONTEXT ContextRecord,
  40. IN OUT PDISPATCHER_CONTEXT DispatcherContext
  41. );
  42. ULONG
  43. _OtsLocalFinallyUnwind (
  44. IN PSEH_CONTEXT SehContext,
  45. IN PSEH_BLOCK TargetSeb,
  46. IN PVOID RealFramePointer
  47. );
  48. //
  49. // Define local macros.
  50. //
  51. #define IS_EXCEPT(Seb) ((Seb)->JumpTarget != 0)
  52. #define IS_FINALLY(Seb) ((Seb)->JumpTarget == 0)
  53. //
  54. // Initialize an exception record for the unwind with the SEB of the target
  55. // included as one information parameter. This is done so that the target
  56. // frame of the unwind may execute all the finally handlers necessary given
  57. // the SEB pointer at the unwind target.
  58. //
  59. #define MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord, Seb) { \
  60. ExceptionRecord->ExceptionCode = STATUS_UNWIND; \
  61. ExceptionRecord->ExceptionFlags = EXCEPTION_UNWINDING; \
  62. ExceptionRecord->ExceptionRecord = NULL; \
  63. ExceptionRecord->ExceptionAddress = 0; \
  64. ExceptionRecord->NumberParameters = 1; \
  65. ExceptionRecord->ExceptionInformation[0] = (ULONG)(Seb); \
  66. }
  67. EXCEPTION_DISPOSITION
  68. _OtsCSpecificHandler (
  69. IN PEXCEPTION_RECORD ExceptionRecord,
  70. IN PVOID EstablisherFrame,
  71. IN OUT PCONTEXT ContextRecord,
  72. IN OUT PDISPATCHER_CONTEXT DispatcherContext
  73. )
  74. /*++
  75. Routine Description:
  76. This function walks up the list of SEB's associated with the specified
  77. procedure and calls except filters and finally handlers as necessary.
  78. It is called in two different contexts:
  79. (i) by the exception dispatcher after an exception is raised
  80. (ii) by the unwinder during an unwind operation
  81. In the first case, is searches the SEB list for except filters to evaluate.
  82. In the second case, it searches for finally handlers to execute.
  83. Arguments:
  84. ExceptionRecord - Supplies a pointer to an exception record.
  85. EstablisherFrame - Supplies a (virtual frame) pointer to the frame of the
  86. establisher function.
  87. ContextRecord - Supplies a pointer to a context record.
  88. DispatcherContext - Supplies a pointer to the exception dispatcher or
  89. unwind dispatcher context.
  90. Return Value:
  91. If the exception is handled by one of the exception filter routines, then
  92. there is no return from this routine and RtlUnwind is called. Otherwise,
  93. an exception disposition value of continue execution or continue search is
  94. returned.
  95. Notes:
  96. In context (i) there are 3 possibilities:
  97. (a) If an exception filter returns a value greater that 0 (meaning
  98. that the associated handler should be invoked) there is no
  99. return from this function. RtlUnwind is called to unwind the
  100. stack to the exception handler corresponding to that filter.
  101. (b) If an exception filter returns a value less than 0 (meaning
  102. that the exception should be dismissed), this routine returns
  103. value ExceptionContinueExecution.
  104. (c) If every filter returns value 0 (meaning that the search for a
  105. handler should continue elsewhere), this function returns
  106. ExceptionContinueSearch.
  107. In context (ii) there are 2 possibilities:
  108. (d) If no branches are detected out of finally handlers, this
  109. function returns ExceptionContinueSearch.
  110. (e) If a branch is detected out of a finally handler, there is no
  111. return from this routine. RtlUnwind is called to unwind to the
  112. branch target (and cancel the current unwind).
  113. There may be long jumps out of both except filters and finally handlers
  114. in which case this routine will be peeled off the stack without returning.
  115. --*/
  116. {
  117. ULONG ContinuationAddress;
  118. EXCEPTION_FILTER ExceptionFilter;
  119. PVOID ExceptionHandler;
  120. EXCEPTION_POINTERS ExceptionPointers;
  121. LONG FilterValue;
  122. ULONG RealFramePointer;
  123. PSEH_BLOCK Seb;
  124. PSEH_CONTEXT SehContext;
  125. PSEH_BLOCK TargetSeb;
  126. TERMINATION_HANDLER TerminationHandler;
  127. //
  128. // Get the address of the SEH context which is at some negative offset
  129. // from the virtual frame pointer. For GEM, the handler data field of
  130. // the function entry contains that offset. The current SEB pointer and
  131. // the RFP (static link) are obtained from the SEH context.
  132. //
  133. SehContext = (PSEH_CONTEXT)((ULONG)EstablisherFrame +
  134. (LONG)DispatcherContext->FunctionEntry->HandlerData);
  135. RealFramePointer = SehContext->RealFramePointer;
  136. //
  137. // If this is a dispatching context, walk up the list of SEBs evaluating
  138. // except filters.
  139. //
  140. if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) {
  141. //
  142. // Set up the ExceptionPointers structure that is used by except
  143. // filters to obtain data for the GetExceptionInformation intrinsic
  144. // function. Copy the current SEB pointer into a local variable
  145. // because the real SEB pointer is only modified in unwind contexts.
  146. //
  147. ExceptionPointers.ExceptionRecord = ExceptionRecord;
  148. ExceptionPointers.ContextRecord = ContextRecord;
  149. for (Seb = SehContext->CurrentSeb; Seb != NULL; Seb = Seb->ParentSeb) {
  150. if (IS_EXCEPT(Seb)) {
  151. //
  152. // This is an except filter. Get the addresses of the filter
  153. // and exception handler from the SEB, then call the except
  154. // filter.
  155. //
  156. ExceptionFilter = (EXCEPTION_FILTER)Seb->HandlerAddress;
  157. ExceptionHandler = (PVOID)Seb->JumpTarget;
  158. FilterValue = __C_ExecuteExceptionFilter(&ExceptionPointers,
  159. ExceptionFilter,
  160. RealFramePointer);
  161. //
  162. // If the except filter < 0, dismiss the exception. If > 0,
  163. // store the exception code on the stack for the except
  164. // handler, modify the given ExceptionRecord so that finally
  165. // handlers will be called properly during the unwind, then
  166. // unwind down to the except handler. If = 0, resume the
  167. // search for except filters.
  168. //
  169. if (FilterValue < 0) {
  170. return ExceptionContinueExecution;
  171. } else if (FilterValue > 0) {
  172. SehContext->ExceptionCode = ExceptionRecord->ExceptionCode;
  173. MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord,
  174. Seb->ParentSeb);
  175. RtlUnwind2(EstablisherFrame,
  176. ExceptionHandler,
  177. ExceptionRecord,
  178. 0,
  179. ContextRecord);
  180. }
  181. }
  182. }
  183. } else if (!IS_TARGET_UNWIND(ExceptionRecord->ExceptionFlags)) {
  184. //
  185. // This is an unwind but is not the target frame. Since the function
  186. // is being terminated, finally handlers for all try bodies that are
  187. // presently in scope must be executed. Walk up the SEB list all the
  188. // way to the top executing finally handlers. This corresponds to
  189. // exiting all try bodies that are presently in scope.
  190. //
  191. while (SehContext->CurrentSeb != NULL) {
  192. //
  193. // Get the address of the SEB and then update the SEH context.
  194. //
  195. Seb = SehContext->CurrentSeb;
  196. SehContext->CurrentSeb = Seb->ParentSeb;
  197. if (IS_FINALLY(Seb)) {
  198. //
  199. // This is a finally handler. Get the address of the handler
  200. // from the SEB and call the finally handler.
  201. //
  202. TerminationHandler = (TERMINATION_HANDLER)Seb->HandlerAddress;
  203. ContinuationAddress =
  204. __C_ExecuteTerminationHandler(TRUE,
  205. TerminationHandler,
  206. RealFramePointer);
  207. //
  208. // If the finally handler returns a non-zero result, there
  209. // was a branch out of the handler (to that address) and this
  210. // routine should unwind to that target.
  211. //
  212. if (ContinuationAddress != 0) {
  213. MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord,
  214. SehContext->CurrentSeb);
  215. RtlUnwind(EstablisherFrame,
  216. (PVOID)ContinuationAddress,
  217. ExceptionRecord,
  218. 0);
  219. }
  220. }
  221. }
  222. } else {
  223. //
  224. // This is the target frame of an unwind. Since the target may be
  225. // in a different try scope than the one defined by the current SEB
  226. // pointer, finally handlers between the two scopes must execute.
  227. // Walk up the SEB list from the current SEB to the target SEB and
  228. // execute all finally handlers encountered.
  229. //
  230. TargetSeb = (PSEH_BLOCK)ExceptionRecord->ExceptionInformation[0];
  231. ContinuationAddress = _OtsLocalFinallyUnwind(SehContext,
  232. TargetSeb,
  233. (PVOID)RealFramePointer);
  234. if (ContinuationAddress != 0) {
  235. //
  236. // A non-zero result indicates there was a branch out of a
  237. // finally handler that was being executed during the unwind.
  238. // This routine should unwind to that address.
  239. //
  240. MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord,
  241. SehContext->CurrentSeb);
  242. RtlUnwind(EstablisherFrame,
  243. (PVOID)ContinuationAddress,
  244. ExceptionRecord,
  245. 0);
  246. }
  247. }
  248. //
  249. // Continue search for exception or termination handlers.
  250. //
  251. return ExceptionContinueSearch;
  252. }
  253. ULONG
  254. _OtsLocalFinallyUnwind (
  255. IN PSEH_CONTEXT SehContext,
  256. IN PSEH_BLOCK TargetSeb,
  257. IN PVOID RealFramePointer
  258. )
  259. /*++
  260. Routine Description:
  261. This function walks up the SEB tree of the current procedure from the
  262. current SEB to the target SEB and executes all the finally handlers it
  263. encounters.
  264. Calls to this function are inserted into user code by the compiler when
  265. there are branches out of guarded regions that may require finally
  266. handlers to execute.
  267. This function is also called from _OtsCSpecificHandler when the target
  268. frame is reached during an unwind operation. There may be finally handlers
  269. that should execute before resuming execution at the unwind target.
  270. Arguments:
  271. SehContext - Supplies the address of the SEH context structure which is
  272. located in the stack frame.
  273. TargetSeb - Supplies the address of the SEB corresponding to the branch
  274. target address.
  275. RealFramePointer - Supplies the (real frame) pointer of the establisher
  276. frame, which is the current stack frame. This is used to set up the
  277. static link if a finally handler is invoked.
  278. Return Value:
  279. If a branch out of a finally handler is detected, the function value is
  280. the address of the branch target. Otherwise, the function value is zero.
  281. --*/
  282. {
  283. ULONG ContinuationAddress;
  284. BOOLEAN Nested;
  285. PSEH_BLOCK Seb;
  286. TERMINATION_HANDLER TerminationHandler;
  287. //
  288. // If the SEB pointers are the same, no finally handlers need to execute.
  289. // The branch is to a target location in the same guarded scope.
  290. //
  291. if (SehContext->CurrentSeb == TargetSeb) {
  292. return 0;
  293. }
  294. //
  295. // If the current SEB scope is not nested within the target SEB scope, no
  296. // finally handlers need to execute. Reset the current SEB pointer to the
  297. // target SEB pointer and return.
  298. //
  299. Nested = FALSE;
  300. Seb = SehContext->CurrentSeb;
  301. while (Seb != NULL) {
  302. Seb = Seb->ParentSeb;
  303. if (Seb == TargetSeb) {
  304. Nested = TRUE;
  305. break;
  306. }
  307. }
  308. if (Nested == FALSE) {
  309. SehContext->CurrentSeb = TargetSeb;
  310. return 0;
  311. }
  312. //
  313. // Walk up the list of SEB blocks executing finally handlers. If a branch
  314. // out of a finally is encountered along the way, return the target
  315. // address, otherwise return 0.
  316. //
  317. while (SehContext->CurrentSeb != TargetSeb) {
  318. //
  319. // Get the address of the SEB and then update the SEH context.
  320. //
  321. Seb = SehContext->CurrentSeb;
  322. SehContext->CurrentSeb = Seb->ParentSeb;
  323. if (IS_FINALLY(Seb)) {
  324. TerminationHandler = (TERMINATION_HANDLER)Seb->HandlerAddress;
  325. ContinuationAddress =
  326. __C_ExecuteTerminationHandler(TRUE,
  327. TerminationHandler,
  328. (ULONG)RealFramePointer);
  329. if (ContinuationAddress != 0) {
  330. return ContinuationAddress;
  331. }
  332. }
  333. }
  334. return 0;
  335. }