ReactOS 0.4.15-dev-8419-g7f0e8a3
except.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Run-Time Library
4 * PURPOSE: User-mode exception support for IA-32
5 * FILE: lib/rtl/i386/except.c
6 * PROGRAMERS: Alex Ionescu (alex@relsoft.net)
7 * Casper S. Hornstrup (chorns@users.sourceforge.net)
8 */
9
10/* INCLUDES *****************************************************************/
11
12#include <rtl.h>
13#define NDEBUG
14#include <debug.h>
15
16/* PUBLIC FUNCTIONS **********************************************************/
17
18/*
19 * @implemented
20 */
21VOID
24 OUT PVOID *CallersCaller)
25{
26 USHORT FrameCount;
27 PVOID BackTrace[2];
29
30 /* Get the tow back trace address */
31 FrameCount = RtlCaptureStackBackTrace(2, 2, &BackTrace[0],BackTraceHash);
32
33 /* Only if user want it */
34 if (CallersAddress != NULL)
35 {
36 /* only when first frames exist */
37 if (FrameCount >= 1)
38 {
39 *CallersAddress = BackTrace[0];
40 }
41 else
42 {
43 *CallersAddress = NULL;
44 }
45 }
46
47 /* Only if user want it */
48 if (CallersCaller != NULL)
49 {
50 /* only when second frames exist */
51 if (FrameCount >= 2)
52 {
53 *CallersCaller = BackTrace[1];
54 }
55 else
56 {
57 *CallersCaller = NULL;
58 }
59 }
60}
61
62/*
63 * @implemented
64 */
69{
70 PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, NestedFrame = NULL;
72 EXCEPTION_RECORD ExceptionRecord2;
74 ULONG_PTR StackLow, StackHigh;
75 ULONG_PTR RegistrationFrameEnd;
76
77 /* Perform vectored exception handling for user mode */
78 if (RtlCallVectoredExceptionHandlers(ExceptionRecord, Context))
79 {
80 /* Exception handled, now call vectored continue handlers */
82
83 /* Continue execution */
84 return TRUE;
85 }
86
87 /* Get the current stack limits and registration frame */
88 RtlpGetStackLimits(&StackLow, &StackHigh);
89 RegistrationFrame = RtlpGetExceptionList();
90
91 /* Now loop every frame */
92 while (RegistrationFrame != EXCEPTION_CHAIN_END)
93 {
94 /* Registration chain entries are never NULL */
95 ASSERT(RegistrationFrame != NULL);
96
97 /* Find out where it ends */
98 RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame +
100
101 /* Make sure the registration frame is located within the stack */
102 if ((RegistrationFrameEnd > StackHigh) ||
103 ((ULONG_PTR)RegistrationFrame < StackLow) ||
104 ((ULONG_PTR)RegistrationFrame & 0x3))
105 {
106 /* Check if this happened in the DPC Stack */
107 if (RtlpHandleDpcStackException(RegistrationFrame,
108 RegistrationFrameEnd,
109 &StackLow,
110 &StackHigh))
111 {
112 /* Use DPC Stack Limits and restart */
113 continue;
114 }
115
116 /* Set invalid stack and bail out */
117 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
118 return FALSE;
119 }
120
121 //
122 // TODO: Implement and call here RtlIsValidHandler(RegistrationFrame->Handler)
123 // for supporting SafeSEH functionality, see the following articles:
124 // https://www.optiv.com/blog/old-meets-new-microsoft-windows-safeseh-incompatibility
125 // https://msrc-blog.microsoft.com/2012/01/10/more-information-on-the-impact-of-ms12-001/
126 //
127
128 /* Check if logging is enabled */
129 RtlpCheckLogException(ExceptionRecord,
130 Context,
131 RegistrationFrame,
132 sizeof(*RegistrationFrame));
133
134 /* Call the handler */
135 Disposition = RtlpExecuteHandlerForException(ExceptionRecord,
136 RegistrationFrame,
137 Context,
139 RegistrationFrame->Handler);
140
141 /* Check if this is a nested frame */
142 if (RegistrationFrame == NestedFrame)
143 {
144 /* Mask out the flag and the nested frame */
145 ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL;
146 NestedFrame = NULL;
147 }
148
149 /* Handle the dispositions */
150 switch (Disposition)
151 {
152 /* Continue execution */
154 {
155 /* Check if it was non-continuable */
156 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
157 {
158 /* Set up the exception record */
159 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
160 ExceptionRecord2.ExceptionCode =
162 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
163 ExceptionRecord2.NumberParameters = 0;
164
165 /* Raise the exception */
166 RtlRaiseException(&ExceptionRecord2);
167 }
168 else
169 {
170 /* In user mode, call any registered vectored continue handlers */
172
173 /* Execution continues */
174 return TRUE;
175 }
176 }
177
178 /* Continue searching */
180 if (ExceptionRecord->ExceptionFlags & EXCEPTION_STACK_INVALID)
181 {
182 /* We have an invalid stack, bail out */
183 return FALSE;
184 }
185 break;
186
187 /* Nested exception */
189 {
190 /* Turn the nested flag on */
191 ExceptionRecord->ExceptionFlags |= EXCEPTION_NESTED_CALL;
192
193 /* Update the current nested frame */
194 if (DispatcherContext.RegistrationPointer > NestedFrame)
195 {
196 /* Get the frame from the dispatcher context */
197 NestedFrame = DispatcherContext.RegistrationPointer;
198 }
199 break;
200 }
201
202 /* Anything else */
203 default:
204 {
205 /* Set up the exception record */
206 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
207 ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
208 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
209 ExceptionRecord2.NumberParameters = 0;
210
211 /* Raise the exception */
212 RtlRaiseException(&ExceptionRecord2);
213 break;
214 }
215 }
216
217 /* Go to the next frame */
218 RegistrationFrame = RegistrationFrame->Next;
219 }
220
221 /* Unhandled, bail out */
222 return FALSE;
223}
224
225/*
226 * @implemented
227 */
228VOID
229NTAPI
231 IN PVOID TargetIp OPTIONAL,
232 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
234{
235 PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, OldFrame;
237 EXCEPTION_RECORD ExceptionRecord2, ExceptionRecord3;
239 ULONG_PTR StackLow, StackHigh;
240 ULONG_PTR RegistrationFrameEnd;
241 CONTEXT LocalContext;
243
244 /* Get the current stack limits */
245 RtlpGetStackLimits(&StackLow, &StackHigh);
246
247 /* Check if we don't have an exception record */
248 if (!ExceptionRecord)
249 {
250 /* Overwrite the argument */
251 ExceptionRecord = &ExceptionRecord3;
252
253 /* Setup a local one */
254 ExceptionRecord3.ExceptionFlags = 0;
255 ExceptionRecord3.ExceptionCode = STATUS_UNWIND;
256 ExceptionRecord3.ExceptionRecord = NULL;
257 ExceptionRecord3.ExceptionAddress = _ReturnAddress();
258 ExceptionRecord3.NumberParameters = 0;
259 }
260
261 /* Check if we have a frame */
262 if (TargetFrame)
263 {
264 /* Set it as unwinding */
265 ExceptionRecord->ExceptionFlags |= EXCEPTION_UNWINDING;
266 }
267 else
268 {
269 /* Set the Exit Unwind flag as well */
270 ExceptionRecord->ExceptionFlags |= (EXCEPTION_UNWINDING |
272 }
273
274 /* Now capture the context */
275 Context = &LocalContext;
276 LocalContext.ContextFlags = CONTEXT_INTEGER |
280
281 /* Pop the current arguments off */
282 Context->Esp += sizeof(TargetFrame) +
283 sizeof(TargetIp) +
284 sizeof(ExceptionRecord) +
285 sizeof(ReturnValue);
286
287 /* Set the new value for EAX */
288 Context->Eax = (ULONG)ReturnValue;
289
290 /* Get the current frame */
291 RegistrationFrame = RtlpGetExceptionList();
292
293 /* Now loop every frame */
294 while (RegistrationFrame != EXCEPTION_CHAIN_END)
295 {
296 /* Registration chain entries are never NULL */
297 ASSERT(RegistrationFrame != NULL);
298
299 /* If this is the target */
300 if (RegistrationFrame == TargetFrame) ZwContinue(Context, FALSE);
301
302 /* Check if the frame is too low */
303 if ((TargetFrame) &&
304 ((ULONG_PTR)TargetFrame < (ULONG_PTR)RegistrationFrame))
305 {
306 /* Create an invalid unwind exception */
308 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
309 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
310 ExceptionRecord2.NumberParameters = 0;
311
312 /* Raise the exception */
313 RtlRaiseException(&ExceptionRecord2);
314 }
315
316 /* Find out where it ends */
317 RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame +
319
320 /* Make sure the registration frame is located within the stack */
321 if ((RegistrationFrameEnd > StackHigh) ||
322 ((ULONG_PTR)RegistrationFrame < StackLow) ||
323 ((ULONG_PTR)RegistrationFrame & 0x3))
324 {
325 /* Check if this happened in the DPC Stack */
326 if (RtlpHandleDpcStackException(RegistrationFrame,
327 RegistrationFrameEnd,
328 &StackLow,
329 &StackHigh))
330 {
331 /* Use DPC Stack Limits and restart */
332 continue;
333 }
334
335 /* Create an invalid stack exception */
336 ExceptionRecord2.ExceptionCode = STATUS_BAD_STACK;
337 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
338 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
339 ExceptionRecord2.NumberParameters = 0;
340
341 /* Raise the exception */
342 RtlRaiseException(&ExceptionRecord2);
343 }
344 else
345 {
346 /* Call the handler */
348 RegistrationFrame,
349 Context,
351 RegistrationFrame->Handler);
352
353 switch(Disposition)
354 {
355 /* Continue searching */
357 break;
358
359 /* Collision */
361 {
362 /* Get the original frame */
363 RegistrationFrame = DispatcherContext.RegistrationPointer;
364 break;
365 }
366
367 /* Anything else */
368 default:
369 {
370 /* Set up the exception record */
371 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
372 ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
373 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
374 ExceptionRecord2.NumberParameters = 0;
375
376 /* Raise the exception */
377 RtlRaiseException(&ExceptionRecord2);
378 break;
379 }
380 }
381
382 /* Go to the next frame */
383 OldFrame = RegistrationFrame;
384 RegistrationFrame = RegistrationFrame->Next;
385
386 /* Remove this handler */
387 RtlpSetExceptionList(OldFrame);
388 }
389 }
390
391 /* Check if we reached the end */
392 if (TargetFrame == EXCEPTION_CHAIN_END)
393 {
394 /* Unwind completed, so we don't exit */
396 }
397 else
398 {
399 /* This is an exit_unwind or the frame wasn't present in the list */
400 ZwRaiseException(ExceptionRecord, Context, FALSE);
401 }
402}
403
404/* EOF */
unsigned char BOOLEAN
UINT32 void void ** ReturnValue
Definition: acevents.h:216
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
VOID NTAPI RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN PVOID ContextData, IN ULONG Size)
Definition: libsupp.c:203
BOOLEAN NTAPI RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, IN ULONG_PTR RegistrationFrameEnd, IN OUT PULONG_PTR StackLow, IN OUT PULONG_PTR StackHigh)
Definition: libsupp.c:192
VOID NTAPI RtlpGetStackLimits(OUT PULONG_PTR LowLimit, OUT PULONG_PTR HighLimit)
Definition: libsupp.c:337
@ ExceptionContinueSearch
Definition: compat.h:91
@ ExceptionCollidedUnwind
Definition: compat.h:93
@ ExceptionNestedException
Definition: compat.h:92
@ ExceptionContinueExecution
Definition: compat.h:90
enum _EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION
#define ULONG_PTR
Definition: config.h:101
_In_ ULONG _Out_opt_ PULONG BackTraceHash
#define _ReturnAddress()
Definition: intrin_arm.h:35
#define ASSERT(a)
Definition: mode.c:44
_In_ ACCESS_MASK _In_ POBJECT_ATTRIBUTES _Reserved_ ULONG _In_opt_ PUNICODE_STRING _In_ ULONG _Out_opt_ PULONG Disposition
Definition: cmfuncs.h:56
NTSYSAPI NTSTATUS NTAPI ZwContinue(_In_ PCONTEXT Context, _In_ BOOLEAN TestAlert)
NTSYSAPI NTSTATUS NTAPI ZwRaiseException(_In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PCONTEXT Context, _In_ BOOLEAN SearchFrames)
NTSYSAPI BOOLEAN NTAPI RtlDispatchException(_In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PCONTEXT Context)
Definition: except.c:43
NTSYSAPI VOID NTAPI RtlRaiseException(_In_ PEXCEPTION_RECORD ExceptionRecord)
#define EXCEPTION_CHAIN_END
Definition: rtltypes.h:63
#define CONTEXT_CONTROL
Definition: nt_native.h:1369
#define CONTEXT_INTEGER
Definition: nt_native.h:1370
#define CONTEXT_SEGMENTS
Definition: nt_native.h:1371
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT _In_ PVOID DispatcherContext
Definition: ntbasedef.h:655
VOID NTAPI RtlCallVectoredContinueHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PCONTEXT Context)
Definition: libsupp.c:822
BOOLEAN NTAPI RtlCallVectoredExceptionHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PCONTEXT Context)
Definition: libsupp.c:813
#define STATUS_INVALID_DISPOSITION
Definition: ntstatus.h:275
#define STATUS_UNWIND
Definition: ntstatus.h:276
#define STATUS_NONCONTINUABLE_EXCEPTION
Definition: ntstatus.h:274
#define STATUS_INVALID_UNWIND_TARGET
Definition: ntstatus.h:278
#define STATUS_BAD_STACK
Definition: ntstatus.h:277
unsigned short USHORT
Definition: pedump.c:61
VOID NTAPI RtlpCaptureContext(OUT PCONTEXT ContextRecord)
EXCEPTION_DISPOSITION NTAPI RtlpExecuteHandlerForUnwind(PEXCEPTION_RECORD ExceptionRecord, PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, PCONTEXT Context, PVOID DispatcherContext, PEXCEPTION_ROUTINE ExceptionHandler)
VOID NTAPI RtlUnwind(_In_opt_ PVOID TargetFrame, _In_opt_ PVOID TargetIp, _In_opt_ PEXCEPTION_RECORD ExceptionRecord, _In_ PVOID ReturnValue)
Definition: except.c:47
VOID NTAPI RtlGetCallersAddress(_Out_ PVOID *CallersAddress, _Out_ PVOID *CallersCaller)
Definition: except.c:22
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
ULONG ContextFlags
Definition: nt_native.h:1426
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: compat.h:210
DWORD ExceptionCode
Definition: compat.h:208
DWORD NumberParameters
Definition: compat.h:212
DWORD ExceptionFlags
Definition: compat.h:209
PVOID ExceptionAddress
Definition: compat.h:211
struct _EXCEPTION_REGISTRATION_RECORD * Next
Definition: compat.h:726
#define EXCEPTION_NONCONTINUABLE
Definition: stubs.h:23
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
NTSYSAPI USHORT NTAPI RtlCaptureStackBackTrace(_In_ ULONG FramesToSkip, _In_ ULONG FramesToCapture, _Out_writes_to_(FramesToCapture, return) PVOID *BackTrace, _Out_opt_ PULONG BackTraceHash)
#define EXCEPTION_EXIT_UNWIND
Definition: rtltypes.h:156
#define EXCEPTION_NESTED_CALL
Definition: rtltypes.h:158
#define EXCEPTION_STACK_INVALID
Definition: rtltypes.h:157
#define EXCEPTION_UNWINDING
Definition: rtltypes.h:155