ReactOS  0.4.15-dev-1171-gab82533
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  */
21 VOID
22 NTAPI
23 RtlGetCallersAddress(OUT PVOID *CallersAddress,
24  OUT PVOID *CallersCaller)
25 {
26  USHORT FrameCount;
27  PVOID BackTrace[2];
28  PULONG BackTraceHash = NULL;
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  */
65 BOOLEAN
66 NTAPI
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 */
81  RtlCallVectoredContinueHandlers(ExceptionRecord, Context);
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 */
171  RtlCallVectoredContinueHandlers(ExceptionRecord, Context);
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  */
228 VOID
229 NTAPI
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 */
307  ExceptionRecord2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
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 */
347  Disposition = RtlpExecuteHandlerForUnwind(ExceptionRecord,
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 */
#define STATUS_INVALID_UNWIND_TARGET
Definition: ntstatus.h:278
#define CONTEXT_CONTROL
Definition: nt_native.h:1369
#define IN
Definition: typedefs.h:39
struct _EXCEPTION_REGISTRATION_RECORD * Next
Definition: compat.h:474
#define TRUE
Definition: types.h:120
#define STATUS_BAD_STACK
Definition: ntstatus.h:277
NTSYSAPI NTSTATUS NTAPI ZwRaiseException(_In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PCONTEXT Context, _In_ BOOLEAN SearchFrames)
#define EXCEPTION_NONCONTINUABLE
Definition: rtltypes.h:154
#define EXCEPTION_UNWINDING
Definition: rtltypes.h:155
NTSYSAPI VOID NTAPI RtlRaiseException(_In_ PEXCEPTION_RECORD ExceptionRecord)
#define CONTEXT_SEGMENTS
Definition: nt_native.h:1371
_In_ ACCESS_MASK _In_ POBJECT_ATTRIBUTES _Reserved_ ULONG _In_opt_ PUNICODE_STRING _In_ ULONG _Out_opt_ PULONG Disposition
Definition: cmfuncs.h:50
PEXCEPTION_ROUTINE Handler
Definition: compat.h:475
PVOID ExceptionAddress
Definition: compat.h:211
EXCEPTION_DISPOSITION NTAPI RtlpExecuteHandlerForUnwind(PEXCEPTION_RECORD ExceptionRecord, PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, PCONTEXT Context, PVOID DispatcherContext, PEXCEPTION_ROUTINE ExceptionHandler)
uint32_t ULONG_PTR
Definition: typedefs.h:65
NTSYSAPI NTSTATUS NTAPI ZwContinue(_In_ PCONTEXT Context, _In_ BOOLEAN TestAlert)
DWORD ExceptionCode
Definition: compat.h:208
VOID NTAPI RtlpSetExceptionList(PEXCEPTION_REGISTRATION_RECORD NewExceptionList)
UINT32 void void ** ReturnValue
Definition: acevents.h:214
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
#define STATUS_INVALID_DISPOSITION
Definition: ntstatus.h:275
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT _In_ PVOID DispatcherContext
Definition: ntbasedef.h:655
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define EXCEPTION_STACK_INVALID
Definition: rtltypes.h:157
ULONG ContextFlags
Definition: nt_native.h:1426
VOID NTAPI RtlpCaptureContext(OUT PCONTEXT ContextRecord)
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:190
BOOLEAN NTAPI RtlCallVectoredExceptionHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PCONTEXT Context)
Definition: libsupp.c:810
VOID NTAPI RtlGetCallersAddress(_Out_ PVOID *CallersAddress, _Out_ PVOID *CallersCaller)
Definition: except.c:22
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define EXCEPTION_EXIT_UNWIND
Definition: rtltypes.h:156
#define STATUS_NONCONTINUABLE_EXCEPTION
Definition: ntstatus.h:274
PEXCEPTION_REGISTRATION_RECORD NTAPI RtlpGetExceptionList(VOID)
VOID NTAPI RtlpGetStackLimits(PULONG_PTR StackBase, PULONG_PTR StackLimit)
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: compat.h:210
#define EXCEPTION_NESTED_CALL
Definition: rtltypes.h:158
#define EXCEPTION_CHAIN_END
Definition: rtltypes.h:63
unsigned short USHORT
Definition: pedump.c:61
unsigned int * PULONG
Definition: retypes.h:1
#define STATUS_UNWIND
Definition: ntstatus.h:276
void * _ReturnAddress(void)
#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)
VOID NTAPI RtlUnwind(_In_opt_ PVOID TargetFrame, _In_opt_ PVOID TargetIp, _In_opt_ PEXCEPTION_RECORD ExceptionRecord, _In_ PVOID ReturnValue)
Definition: except.c:47
struct tagContext Context
Definition: acpixf.h:1034
VOID NTAPI RtlCallVectoredContinueHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PCONTEXT Context)
Definition: libsupp.c:819
unsigned int ULONG
Definition: retypes.h:1
VOID NTAPI RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN PVOID ContextData, IN ULONG Size)
Definition: libsupp.c:201
enum _EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION
#define ULONG_PTR
Definition: config.h:101
DWORD ExceptionFlags
Definition: compat.h:209
#define CONTEXT_INTEGER
Definition: nt_native.h:1370
BOOLEAN NTAPI RtlDispatchException(_In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PCONTEXT Context)
Definition: except.c:34
DWORD NumberParameters
Definition: compat.h:212
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68