[SHELL32] SHChangeNotify: Use tree for CDirectoryList (#6784)
[reactos.git] / ntoskrnl / ke / except.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ke/except.c
5 * PURPOSE: Platform independent exception handling
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Alex Ionescu (alex.ionescu@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* FUNCTIONS *****************************************************************/
17
18 VOID
19 NTAPI
20 KiContinuePreviousModeUser(IN PCONTEXT Context,
21 IN PKEXCEPTION_FRAME ExceptionFrame,
22 IN PKTRAP_FRAME TrapFrame)
23 {
24 CONTEXT LocalContext;
25
26 /* We'll have to make a copy and probe it */
27 ProbeForRead(Context, sizeof(CONTEXT), sizeof(ULONG));
28 RtlCopyMemory(&LocalContext, Context, sizeof(CONTEXT));
29 Context = &LocalContext;
30
31 #ifdef _M_AMD64
32 KiSetTrapContext(TrapFrame, &LocalContext, UserMode);
33 #else
34 /* Convert the context into Exception/Trap Frames */
35 KeContextToTrapFrame(&LocalContext,
36 ExceptionFrame,
37 TrapFrame,
38 LocalContext.ContextFlags,
39 UserMode);
40 #endif
41 }
42
43 NTSTATUS
44 NTAPI
45 KiContinue(IN PCONTEXT Context,
46 IN PKEXCEPTION_FRAME ExceptionFrame,
47 IN PKTRAP_FRAME TrapFrame)
48 {
49 NTSTATUS Status = STATUS_SUCCESS;
50 KIRQL OldIrql = APC_LEVEL;
51 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
52
53 /* Raise to APC_LEVEL, only if needed */
54 if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
55
56 /* Set up SEH to validate the context */
57 _SEH2_TRY
58 {
59 /* Check the previous mode */
60 if (PreviousMode != KernelMode)
61 {
62 /* Validate from user-mode */
63 KiContinuePreviousModeUser(Context,
64 ExceptionFrame,
65 TrapFrame);
66 }
67 else
68 {
69 #ifdef _M_AMD64
70 KiSetTrapContext(TrapFrame, Context, KernelMode);
71 #else
72 /* Convert the context into Exception/Trap Frames */
73 KeContextToTrapFrame(Context,
74 ExceptionFrame,
75 TrapFrame,
76 Context->ContextFlags,
77 KernelMode);
78 #endif
79 }
80 }
81 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
82 {
83 /* Save the exception code */
84 Status = _SEH2_GetExceptionCode();
85 }
86 _SEH2_END;
87
88 /* Lower the IRQL if needed */
89 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
90
91 /* Return status */
92 return Status;
93 }
94
95 NTSTATUS
96 NTAPI
97 KiRaiseException(IN PEXCEPTION_RECORD ExceptionRecord,
98 IN PCONTEXT Context,
99 IN PKEXCEPTION_FRAME ExceptionFrame,
100 IN PKTRAP_FRAME TrapFrame,
101 IN BOOLEAN SearchFrames)
102 {
103 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
104 CONTEXT LocalContext;
105 EXCEPTION_RECORD LocalExceptionRecord;
106 ULONG ParameterCount, Size;
107
108 /* Check if we need to probe */
109 if (PreviousMode != KernelMode)
110 {
111 /* Set up SEH */
112 _SEH2_TRY
113 {
114 /* Probe the context */
115 ProbeForRead(Context, sizeof(CONTEXT), sizeof(ULONG));
116
117 /* Probe the Exception Record */
118 ProbeForRead(ExceptionRecord,
119 FIELD_OFFSET(EXCEPTION_RECORD, NumberParameters) +
120 sizeof(ULONG),
121 sizeof(ULONG));
122
123 /* Validate the maximum parameters */
124 if ((ParameterCount = ExceptionRecord->NumberParameters) >
125 EXCEPTION_MAXIMUM_PARAMETERS)
126 {
127 /* Too large */
128 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
129 }
130
131 /* Probe the entire parameters now*/
132 Size = (sizeof(EXCEPTION_RECORD) -
133 ((EXCEPTION_MAXIMUM_PARAMETERS - ParameterCount) * sizeof(ULONG)));
134 ProbeForRead(ExceptionRecord, Size, sizeof(ULONG));
135
136 /* Now make copies in the stack */
137 RtlCopyMemory(&LocalContext, Context, sizeof(CONTEXT));
138 RtlCopyMemory(&LocalExceptionRecord, ExceptionRecord, Size);
139 Context = &LocalContext;
140 ExceptionRecord = &LocalExceptionRecord;
141
142 /* Update the parameter count */
143 ExceptionRecord->NumberParameters = ParameterCount;
144 }
145 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
146 {
147 /* Don't fail silently */
148 DPRINT1("KiRaiseException: Failed to Probe\n");
149
150 /* Return the exception code */
151 _SEH2_YIELD(return _SEH2_GetExceptionCode());
152 }
153 _SEH2_END;
154 }
155
156 /* Convert the context record */
157 KeContextToTrapFrame(Context,
158 ExceptionFrame,
159 TrapFrame,
160 Context->ContextFlags,
161 PreviousMode);
162
163 /* Dispatch the exception */
164 ExceptionRecord->ExceptionCode &= ~KI_EXCEPTION_INTERNAL;
165 KiDispatchException(ExceptionRecord,
166 ExceptionFrame,
167 TrapFrame,
168 PreviousMode,
169 SearchFrames);
170
171 /* We are done */
172 return STATUS_SUCCESS;
173 }
174
175 /* SYSTEM CALLS ***************************************************************/
176
177 NTSTATUS
178 NTAPI
179 NtRaiseException(IN PEXCEPTION_RECORD ExceptionRecord,
180 IN PCONTEXT Context,
181 IN BOOLEAN FirstChance)
182 {
183 NTSTATUS Status;
184 PKTHREAD Thread;
185 PKTRAP_FRAME TrapFrame;
186
187 /* Get trap frame and link previous one*/
188 Thread = KeGetCurrentThread();
189 TrapFrame = Thread->TrapFrame;
190 Thread->TrapFrame = KiGetLinkedTrapFrame(TrapFrame);
191
192 /* Set exception list */
193 #ifdef _M_IX86
194 KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList;
195 #endif
196
197 /* Raise the exception */
198 Status = KiRaiseException(ExceptionRecord,
199 Context,
200 NULL,
201 TrapFrame,
202 FirstChance);
203 if (NT_SUCCESS(Status))
204 {
205 /* It was handled, so exit restoring all state */
206 KiServiceExit2(TrapFrame);
207 }
208 else
209 {
210 /* Exit with error */
211 KiServiceExit(TrapFrame, Status);
212 }
213
214 /* We don't actually make it here */
215 return Status;
216 }
217
218 NTSTATUS
219 NTAPI
220 NtContinue(IN PCONTEXT Context,
221 IN BOOLEAN TestAlert)
222 {
223 PKTHREAD Thread;
224 NTSTATUS Status;
225 PKTRAP_FRAME TrapFrame;
226
227 /* Get trap frame and link previous one*/
228 Thread = KeGetCurrentThread();
229 TrapFrame = Thread->TrapFrame;
230 Thread->TrapFrame = KiGetLinkedTrapFrame(TrapFrame);
231
232 /* Continue from this point on */
233 Status = KiContinue(Context, NULL, TrapFrame);
234 if (NT_SUCCESS(Status))
235 {
236 /* Check if alert was requested */
237 if (TestAlert) KeTestAlertThread(Thread->PreviousMode);
238
239 /* Exit to new trap frame */
240 KiServiceExit2(TrapFrame);
241 }
242 else
243 {
244 /* Exit with an error */
245 KiServiceExit(TrapFrame, Status);
246 }
247
248 /* We don't actually make it here */
249 return Status;
250 }
251
252 /* EOF */