1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS sysem libraries 4 * PURPOSE: Vectored Exception Handling 5 * FILE: lib/rtl/vectoreh.c 6 * PROGRAMERS: Thomas Weidenmueller 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <rtl.h> 12 13 #define NDEBUG 14 #include <debug.h> 15 16 RTL_CRITICAL_SECTION RtlpVectoredHandlerLock; 17 LIST_ENTRY RtlpVectoredExceptionList, RtlpVectoredContinueList; 18 19 typedef struct _RTL_VECTORED_HANDLER_ENTRY 20 { 21 LIST_ENTRY ListEntry; 22 PVECTORED_EXCEPTION_HANDLER VectoredHandler; 23 ULONG Refs; 24 } RTL_VECTORED_HANDLER_ENTRY, *PRTL_VECTORED_HANDLER_ENTRY; 25 26 /* FUNCTIONS ***************************************************************/ 27 28 VOID 29 NTAPI 30 RtlpInitializeVectoredExceptionHandling(VOID) 31 { 32 /* Initialize our two lists and the common lock */ 33 RtlInitializeCriticalSection(&RtlpVectoredHandlerLock); 34 InitializeListHead(&RtlpVectoredExceptionList); 35 InitializeListHead(&RtlpVectoredContinueList); 36 } 37 38 BOOLEAN 39 NTAPI 40 RtlpCallVectoredHandlers(IN PEXCEPTION_RECORD ExceptionRecord, 41 IN PCONTEXT Context, 42 IN PLIST_ENTRY VectoredHandlerList) 43 { 44 PLIST_ENTRY CurrentEntry; 45 PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler; 46 PVECTORED_EXCEPTION_HANDLER VectoredHandler; 47 EXCEPTION_POINTERS ExceptionInfo; 48 BOOLEAN HandlerRemoved; 49 LONG HandlerReturn; 50 51 /* 52 * Initialize these in case there are no entries, 53 * or if no one handled the exception 54 */ 55 HandlerRemoved = FALSE; 56 HandlerReturn = EXCEPTION_CONTINUE_SEARCH; 57 58 /* Set up the data to pass to the handler */ 59 ExceptionInfo.ExceptionRecord = ExceptionRecord; 60 ExceptionInfo.ContextRecord = Context; 61 62 /* Grab the lock */ 63 RtlEnterCriticalSection(&RtlpVectoredHandlerLock); 64 65 /* Loop entries */ 66 CurrentEntry = VectoredHandlerList->Flink; 67 while (CurrentEntry != VectoredHandlerList) 68 { 69 /* Get the struct */ 70 VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry, 71 RTL_VECTORED_HANDLER_ENTRY, 72 ListEntry); 73 74 /* Reference it so it doesn't go away while we are using it */ 75 VectoredExceptionHandler->Refs++; 76 77 /* Drop the lock before calling the handler */ 78 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); 79 80 /* 81 * Get the function pointer, decoding it so we will crash 82 * if malicious code has altered it. That is, if something has 83 * set VectoredHandler to a non-encoded pointer 84 */ 85 VectoredHandler = RtlDecodePointer(VectoredExceptionHandler->VectoredHandler); 86 87 /* Call the handler */ 88 HandlerReturn = VectoredHandler(&ExceptionInfo); 89 90 /* Handler called -- grab the lock to dereference */ 91 RtlEnterCriticalSection(&RtlpVectoredHandlerLock); 92 93 /* Dereference and see if it got deleted */ 94 VectoredExceptionHandler->Refs--; 95 if (VectoredExceptionHandler->Refs == 0) 96 { 97 /* It did -- do we have to free it now? */ 98 if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) 99 { 100 /* We don't, just remove it from the list and break out */ 101 RemoveEntryList(&VectoredExceptionHandler->ListEntry); 102 HandlerRemoved = TRUE; 103 break; 104 } 105 106 /* 107 * Get the next entry before freeing, 108 * and remove the current one from the list 109 */ 110 CurrentEntry = VectoredExceptionHandler->ListEntry.Flink; 111 RemoveEntryList(&VectoredExceptionHandler->ListEntry); 112 113 /* Free the entry outside of the lock, then reacquire it */ 114 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); 115 RtlFreeHeap(RtlGetProcessHeap(), 116 0, 117 VectoredExceptionHandler); 118 RtlEnterCriticalSection(&RtlpVectoredHandlerLock); 119 } 120 else 121 { 122 /* No delete -- should we continue execution? */ 123 if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) 124 { 125 /* Break out */ 126 break; 127 } 128 else 129 { 130 /* Continue searching the list */ 131 CurrentEntry = CurrentEntry->Flink; 132 } 133 } 134 } 135 136 /* Let go of the lock now */ 137 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); 138 139 /* Anything to free? */ 140 if (HandlerRemoved) 141 { 142 /* Get rid of it */ 143 RtlFreeHeap(RtlGetProcessHeap(), 144 0, 145 VectoredExceptionHandler); 146 } 147 148 /* Return whether to continue execution (ignored for continue handlers) */ 149 return (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) ? TRUE : FALSE; 150 } 151 152 PVOID 153 NTAPI 154 RtlpAddVectoredHandler(IN ULONG FirstHandler, 155 IN PVECTORED_EXCEPTION_HANDLER VectoredHandler, 156 IN PLIST_ENTRY VectoredHandlerList) 157 { 158 PRTL_VECTORED_HANDLER_ENTRY VectoredHandlerEntry; 159 160 /* Allocate our structure */ 161 VectoredHandlerEntry = RtlAllocateHeap(RtlGetProcessHeap(), 162 0, 163 sizeof(RTL_VECTORED_HANDLER_ENTRY)); 164 if (!VectoredHandlerEntry) return NULL; 165 166 /* Set it up, encoding the pointer for security */ 167 VectoredHandlerEntry->VectoredHandler = RtlEncodePointer(VectoredHandler); 168 VectoredHandlerEntry->Refs = 1; 169 170 /* Lock the list before modifying it */ 171 RtlEnterCriticalSection(&RtlpVectoredHandlerLock); 172 173 /* 174 * While holding the list lock, insert the handler 175 * at beginning or end of list according to caller. 176 */ 177 if (FirstHandler) 178 { 179 InsertHeadList(VectoredHandlerList, 180 &VectoredHandlerEntry->ListEntry); 181 } 182 else 183 { 184 InsertTailList(VectoredHandlerList, 185 &VectoredHandlerEntry->ListEntry); 186 } 187 188 /* Done with the list, unlock it */ 189 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); 190 191 /* Return pointer to the structure as the handle */ 192 return VectoredHandlerEntry; 193 } 194 195 ULONG 196 NTAPI 197 RtlpRemoveVectoredHandler(IN PVOID VectoredHandlerHandle, 198 IN PLIST_ENTRY VectoredHandlerList) 199 { 200 PLIST_ENTRY CurrentEntry; 201 PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler; 202 BOOLEAN HandlerRemoved; 203 BOOLEAN HandlerFound; 204 205 /* Initialize these in case we don't find anything */ 206 HandlerRemoved = FALSE; 207 HandlerFound = FALSE; 208 209 /* Acquire list lock */ 210 RtlEnterCriticalSection(&RtlpVectoredHandlerLock); 211 212 /* Loop the list */ 213 CurrentEntry = VectoredHandlerList->Flink; 214 while (CurrentEntry != VectoredHandlerList) 215 { 216 /* Get the struct */ 217 VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry, 218 RTL_VECTORED_HANDLER_ENTRY, 219 ListEntry); 220 221 /* Does it match? */ 222 if (VectoredExceptionHandler == VectoredHandlerHandle) 223 { 224 /* 225 * Great, this means it is a valid entry. 226 * However, it may be in use by the exception 227 * dispatcher, so we have a ref count to respect. 228 * If we can't remove it now then it will be done 229 * right after it is not in use anymore. 230 * 231 * Caller is supposed to keep track of if it has deleted the 232 * entry and should not call us twice for the same entry. 233 * We could maybe throw in some kind of ASSERT to detect this 234 * if this was to become a problem. 235 */ 236 VectoredExceptionHandler->Refs--; 237 if (VectoredExceptionHandler->Refs == 0) 238 { 239 /* Not in use, ok to remove and free */ 240 RemoveEntryList(&VectoredExceptionHandler->ListEntry); 241 HandlerRemoved = TRUE; 242 } 243 244 /* Found what we are looking for, stop searching */ 245 HandlerFound = TRUE; 246 break; 247 } 248 else 249 { 250 /* Get the next entry */ 251 CurrentEntry = CurrentEntry->Flink; 252 } 253 } 254 255 /* Done with the list, let go of the lock */ 256 RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); 257 258 /* Can we free what we found? */ 259 if (HandlerRemoved) 260 { 261 /* Do it */ 262 RtlFreeHeap(RtlGetProcessHeap(), 263 0, 264 VectoredExceptionHandler); 265 } 266 267 /* Return whether we found it */ 268 return (ULONG)HandlerFound; 269 } 270 271 BOOLEAN 272 NTAPI 273 RtlCallVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord, 274 IN PCONTEXT Context) 275 { 276 /* Call the shared routine */ 277 return RtlpCallVectoredHandlers(ExceptionRecord, 278 Context, 279 &RtlpVectoredExceptionList); 280 } 281 282 VOID 283 NTAPI 284 RtlCallVectoredContinueHandlers(IN PEXCEPTION_RECORD ExceptionRecord, 285 IN PCONTEXT Context) 286 { 287 /* 288 * Call the shared routine (ignoring result, 289 * execution always continues at this point) 290 */ 291 (VOID)RtlpCallVectoredHandlers(ExceptionRecord, 292 Context, 293 &RtlpVectoredContinueList); 294 } 295 296 DECLSPEC_HOTPATCH 297 PVOID 298 NTAPI 299 RtlAddVectoredExceptionHandler(IN ULONG FirstHandler, 300 IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) 301 { 302 /* Call the shared routine */ 303 return RtlpAddVectoredHandler(FirstHandler, 304 VectoredHandler, 305 &RtlpVectoredExceptionList); 306 } 307 308 DECLSPEC_HOTPATCH 309 PVOID 310 NTAPI 311 RtlAddVectoredContinueHandler(IN ULONG FirstHandler, 312 IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) 313 { 314 /* Call the shared routine */ 315 return RtlpAddVectoredHandler(FirstHandler, 316 VectoredHandler, 317 &RtlpVectoredContinueList); 318 } 319 320 //DECLSPEC_HOTPATCH 321 ULONG 322 NTAPI 323 RtlRemoveVectoredExceptionHandler(IN PVOID VectoredHandlerHandle) 324 { 325 /* Call the shared routine */ 326 return RtlpRemoveVectoredHandler(VectoredHandlerHandle, 327 &RtlpVectoredExceptionList); 328 } 329 330 //DECLSPEC_HOTPATCH 331 ULONG 332 NTAPI 333 RtlRemoveVectoredContinueHandler(IN PVOID VectoredHandlerHandle) 334 { 335 /* Call the shared routine */ 336 return RtlpRemoveVectoredHandler(VectoredHandlerHandle, 337 &RtlpVectoredContinueList); 338 } 339 340 /* EOF */ 341