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.

210 lines
5.8 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. vectxcpt.c
  5. Abstract:
  6. This module implements call out functionality needed to
  7. implement vectored exception handlers
  8. Author:
  9. Mark Lucovsky (markl) 14-Feb-2000
  10. Revision History:
  11. --*/
  12. #include <ntos.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <ldrp.h>
  16. typedef struct _VECTXCPT_CALLOUT_ENTRY {
  17. LIST_ENTRY Links;
  18. PVECTORED_EXCEPTION_HANDLER VectoredHandler;
  19. } VECTXCPT_CALLOUT_ENTRY, *PVECTXCPT_CALLOUT_ENTRY;
  20. BOOLEAN
  21. RtlCallVectoredExceptionHandlers(
  22. IN PEXCEPTION_RECORD ExceptionRecord,
  23. IN PCONTEXT ContextRecord
  24. )
  25. /*++
  26. Routine Description:
  27. This function is called by the user-mode exception dispatcher trampoline
  28. logic prior to performing a frame based exception handler search.
  29. It's purpose is call any registered vectored exception handlers. If any one
  30. of the registered handlers tells this function to continue execution, exception
  31. handler searching is terminated and the passed in context is restored.
  32. If none of the vectored handlers returns this indication, frame based handling
  33. resumes.
  34. Arguments:
  35. ExceptionInfo - Supplies the address of an EXCEPTION_POINTERS structures
  36. that defines the current exception.
  37. Return Value:
  38. EXCEPTION_CONTINUE_EXECUTION - A vectored handler would like execution to continue
  39. without searching for frame based exception handlers
  40. EXCEPTION_CONTINUE_SEARCH - None of the vectored handlers have "handled" the
  41. exception, so frame based handlers should be searched
  42. --*/
  43. {
  44. PLIST_ENTRY Next;
  45. PVECTXCPT_CALLOUT_ENTRY CalloutEntry;
  46. LONG ReturnValue;
  47. EXCEPTION_POINTERS ExceptionInfo;
  48. if (IsListEmpty (&RtlpCalloutEntryList)) {
  49. return FALSE;
  50. }
  51. ExceptionInfo.ExceptionRecord = ExceptionRecord;
  52. ExceptionInfo.ContextRecord = ContextRecord;
  53. RtlEnterCriticalSection(&RtlpCalloutEntryLock);
  54. Next = RtlpCalloutEntryList.Flink;
  55. while ( Next != &RtlpCalloutEntryList) {
  56. //
  57. // Call all of the vectored handlers
  58. // The first one that returns EXCEPTION_CONTINUE_EXECUTION is assumed to
  59. // have "handled" the exception.
  60. //
  61. CalloutEntry = (PVECTXCPT_CALLOUT_ENTRY)(CONTAINING_RECORD(Next,VECTXCPT_CALLOUT_ENTRY,Links));
  62. ReturnValue = (CalloutEntry->VectoredHandler)(&ExceptionInfo);
  63. if (ReturnValue == EXCEPTION_CONTINUE_EXECUTION) {
  64. RtlLeaveCriticalSection(&RtlpCalloutEntryLock);
  65. return TRUE;
  66. }
  67. Next = Next->Flink;
  68. }
  69. RtlLeaveCriticalSection(&RtlpCalloutEntryLock);
  70. return FALSE;
  71. }
  72. PVOID
  73. RtlAddVectoredExceptionHandler(
  74. IN ULONG FirstHandler,
  75. IN PVECTORED_EXCEPTION_HANDLER VectoredHandler
  76. )
  77. /*++
  78. Routine Description:
  79. This function is used to register a vectored exception handler. The caller
  80. can request that this be the first handler, or the last handler called by
  81. using the FirstHandler argument.
  82. If this API is used and that VectoredHandler points to a DLL, and that DLL unloads,
  83. the unload does not invalidate the registration of the handler. This is considered a
  84. programming error.
  85. Arguments:
  86. FirstHandler - If non-zero, specifies that the VectoredHandler should be the
  87. first handler called. This of course changes when a subsequent call is
  88. made by other code in the process that also requests to be the FirstHandler. If zero,
  89. the vectored handler is added as the last handler to be called.
  90. VectoredHandler - Supplies the address of the handler to call.
  91. Return Value:
  92. NULL - The operation failed. No further error status is available.
  93. Non-Null - The operation was successful. This value may be used in a subsequent call
  94. to RtlRemoveVectoredExceptionHandler.
  95. --*/
  96. {
  97. PVECTXCPT_CALLOUT_ENTRY CalloutEntry;
  98. LONG ReturnValue;
  99. CalloutEntry = RtlAllocateHeap(RtlProcessHeap(),0,sizeof(*CalloutEntry));
  100. if (CalloutEntry) {
  101. CalloutEntry->VectoredHandler = VectoredHandler;
  102. RtlEnterCriticalSection(&RtlpCalloutEntryLock);
  103. if (FirstHandler) {
  104. InsertHeadList(&RtlpCalloutEntryList,&CalloutEntry->Links);
  105. } else {
  106. InsertTailList(&RtlpCalloutEntryList,&CalloutEntry->Links);
  107. }
  108. RtlLeaveCriticalSection(&RtlpCalloutEntryLock);
  109. }
  110. return CalloutEntry;
  111. }
  112. ULONG
  113. RtlRemoveVectoredExceptionHandler(
  114. IN PVOID VectoredHandlerHandle
  115. )
  116. /*++
  117. Routine Description:
  118. This function is used to un-register a vectored exception handler.
  119. Arguments:
  120. VectoredHandlerHandle - Specifies a vectored handler previsouly registerd using
  121. RtlAddVectoredExceptionHandler.
  122. Return Value:
  123. Non-Zero - The operation was successful. The vectored handler associated with the
  124. specified VectoredHandlerHandle will not be called.
  125. Zero - The operation failed. The specified VecoteredHandlerHandle does not match
  126. a handler previously added with RtlAddVectoredExceptionHandler.
  127. --*/
  128. {
  129. PLIST_ENTRY Next;
  130. PVECTXCPT_CALLOUT_ENTRY CalloutEntry;
  131. LONG ReturnValue;
  132. BOOLEAN FoundOne = FALSE;
  133. RtlEnterCriticalSection(&RtlpCalloutEntryLock);
  134. Next = RtlpCalloutEntryList.Flink;
  135. while ( Next != &RtlpCalloutEntryList) {
  136. CalloutEntry = (PVECTXCPT_CALLOUT_ENTRY)(CONTAINING_RECORD(Next,VECTXCPT_CALLOUT_ENTRY,Links));
  137. if (CalloutEntry == VectoredHandlerHandle) {
  138. RemoveEntryList(&CalloutEntry->Links);
  139. FoundOne = TRUE;
  140. break;
  141. }
  142. Next = Next->Flink;
  143. }
  144. RtlLeaveCriticalSection(&RtlpCalloutEntryLock);
  145. if (FoundOne) {
  146. RtlFreeHeap(RtlProcessHeap(),0,CalloutEntry);
  147. }
  148. return FoundOne ? 1 : 0;
  149. }