a028cdb9a324b7eb7c0be1990c377eb667d6b996
[reactos.git] / reactos / ntoskrnl / ps / debug.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/debug.c
6 * PURPOSE: Thread managment
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 * Phillip Susi
10 */
11
12 /*
13 * NOTE:
14 *
15 * All of the routines that manipulate the thread queue synchronize on
16 * a single spinlock
17 *
18 */
19
20 /* INCLUDES ****************************************************************/
21
22 #include <ntoskrnl.h>
23 #define NDEBUG
24 #include <internal/debug.h>
25
26 /* FUNCTIONS ***************************************************************/
27
28 VOID
29 KeContextToTrapFrame(PCONTEXT Context,
30 PKTRAP_FRAME TrapFrame)
31 {
32 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
33 {
34 TrapFrame->Esp = Context->Esp;
35 TrapFrame->Ss = Context->SegSs;
36 TrapFrame->Cs = Context->SegCs;
37 TrapFrame->Eip = Context->Eip;
38 TrapFrame->Eflags = Context->EFlags;
39 TrapFrame->Ebp = Context->Ebp;
40 }
41 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
42 {
43 TrapFrame->Eax = Context->Eax;
44 TrapFrame->Ebx = Context->Ebx;
45 TrapFrame->Ecx = Context->Ecx;
46 TrapFrame->Edx = Context->Edx;
47 TrapFrame->Esi = Context->Esi;
48 TrapFrame->Edi = Context->Edi;
49 }
50 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
51 {
52 TrapFrame->Ds = Context->SegDs;
53 TrapFrame->Es = Context->SegEs;
54 TrapFrame->Fs = Context->SegFs;
55 TrapFrame->Gs = Context->SegGs;
56 }
57 if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
58 {
59 /*
60 * Not handled
61 *
62 * This should be handled separately I think.
63 * - blight
64 */
65 }
66 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
67 {
68 /*
69 * Not handled
70 */
71 }
72 }
73
74 VOID
75 KeTrapFrameToContext(PKTRAP_FRAME TrapFrame,
76 PCONTEXT Context)
77 {
78 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
79 {
80 Context->SegSs = TrapFrame->Ss;
81 Context->Esp = TrapFrame->Esp;
82 Context->SegCs = TrapFrame->Cs;
83 Context->Eip = TrapFrame->Eip;
84 Context->EFlags = TrapFrame->Eflags;
85 Context->Ebp = TrapFrame->Ebp;
86 }
87 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
88 {
89 Context->Eax = TrapFrame->Eax;
90 Context->Ebx = TrapFrame->Ebx;
91 Context->Ecx = TrapFrame->Ecx;
92 /*
93 * NOTE: In the trap frame which is built on entry to a system
94 * call TrapFrame->Edx will actually hold the address of the
95 * previous TrapFrame. I don't believe leaking this information
96 * has security implications. Also EDX holds the address of the
97 * arguments to the system call in progress so it isn't of much
98 * interest to the debugger.
99 */
100 Context->Edx = TrapFrame->Edx;
101 Context->Esi = TrapFrame->Esi;
102 Context->Edi = TrapFrame->Edi;
103 }
104 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
105 {
106 Context->SegDs = TrapFrame->Ds;
107 Context->SegEs = TrapFrame->Es;
108 Context->SegFs = TrapFrame->Fs;
109 Context->SegGs = TrapFrame->Gs;
110 }
111 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
112 {
113 /*
114 * FIXME: Implement this case
115 */
116 Context->ContextFlags &= (~CONTEXT_DEBUG_REGISTERS) | CONTEXT_i386;
117 }
118 if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
119 {
120 /*
121 * FIXME: Implement this case
122 *
123 * I think this should only be filled for FPU exceptions, otherwise I
124 * would not know where to get it from as it can be the current state
125 * of the FPU or already saved in the thread's FPU save area.
126 * -blight
127 */
128 Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
129 }
130 #if 0
131 if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
132 {
133 /*
134 * FIXME: Investigate this
135 *
136 * This is the XMM state (first 512 bytes of FXSAVE_FORMAT/FX_SAVE_AREA)
137 * This should only be filled in case of a SIMD exception I think, so
138 * this is not the right place (like for FPU the state could already be
139 * saved in the thread's FX_SAVE_AREA or still be in the CPU)
140 * -blight
141 */
142 Context->ContextFlags &= ~CONTEXT_EXTENDED_REGISTERS;
143 }
144 #endif
145 }
146
147 VOID STDCALL
148 KeGetSetContextRundownRoutine(PKAPC Apc)
149 {
150 PKEVENT Event;
151 PNTSTATUS Status;
152
153 Event = (PKEVENT)Apc->SystemArgument1;
154 Status = (PNTSTATUS)Apc->SystemArgument2;
155 (*Status) = STATUS_THREAD_IS_TERMINATING;
156 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
157 }
158
159 VOID STDCALL
160 KeGetContextKernelRoutine(PKAPC Apc,
161 PKNORMAL_ROUTINE* NormalRoutine,
162 PVOID* NormalContext,
163 PVOID* SystemArgument1,
164 PVOID* SystemArgument2)
165 /*
166 * FUNCTION: This routine is called by an APC sent by NtGetContextThread to
167 * copy the context of a thread into a buffer.
168 */
169 {
170 PKEVENT Event;
171 PCONTEXT Context;
172 PNTSTATUS Status;
173
174 Context = (PCONTEXT)(*NormalContext);
175 Event = (PKEVENT)(*SystemArgument1);
176 Status = (PNTSTATUS)(*SystemArgument2);
177
178 KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, Context);
179
180 *Status = STATUS_SUCCESS;
181 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
182 }
183
184 NTSTATUS STDCALL
185 NtGetContextThread(IN HANDLE ThreadHandle,
186 OUT PCONTEXT ThreadContext)
187 {
188 PETHREAD Thread;
189 CONTEXT Context;
190 KAPC Apc;
191 KEVENT Event;
192 KPROCESSOR_MODE PreviousMode;
193 NTSTATUS Status = STATUS_SUCCESS;
194
195 PAGED_CODE();
196
197 PreviousMode = ExGetPreviousMode();
198
199 if(PreviousMode != KernelMode)
200 {
201 _SEH_TRY
202 {
203 ProbeForWrite(ThreadContext,
204 sizeof(CONTEXT),
205 sizeof(ULONG));
206 }
207 _SEH_HANDLE
208 {
209 Status = _SEH_GetExceptionCode();
210 }
211 _SEH_END;
212
213 if(!NT_SUCCESS(Status))
214 {
215 return Status;
216 }
217 }
218
219 Status = ObReferenceObjectByHandle(ThreadHandle,
220 THREAD_GET_CONTEXT,
221 PsThreadType,
222 PreviousMode,
223 (PVOID*)&Thread,
224 NULL);
225 if(NT_SUCCESS(Status))
226 {
227 if(Thread == PsGetCurrentThread())
228 {
229 /*
230 * I don't know if trying to get your own context makes much
231 * sense but we can handle it more efficently.
232 */
233
234 KeTrapFrameToContext(Thread->Tcb.TrapFrame, &Context);
235 }
236 else
237 {
238 KeInitializeEvent(&Event,
239 NotificationEvent,
240 FALSE);
241
242 KeInitializeApc(&Apc,
243 &Thread->Tcb,
244 OriginalApcEnvironment,
245 KeGetContextKernelRoutine,
246 KeGetSetContextRundownRoutine,
247 NULL,
248 KernelMode,
249 (PVOID)&Context);
250 if (!KeInsertQueueApc(&Apc,
251 (PVOID)&Event,
252 (PVOID)&Status,
253 IO_NO_INCREMENT))
254 {
255 Status = STATUS_THREAD_IS_TERMINATING;
256 }
257 else
258 {
259 Status = KeWaitForSingleObject(&Event,
260 0,
261 KernelMode,
262 FALSE,
263 NULL);
264 }
265 }
266 ObDereferenceObject(Thread);
267
268 if(NT_SUCCESS(Status))
269 {
270 _SEH_TRY
271 {
272 *ThreadContext = Context;
273 }
274 _SEH_HANDLE
275 {
276 Status = _SEH_GetExceptionCode();
277 }
278 _SEH_END;
279 }
280 }
281
282 return Status;
283 }
284
285 VOID STDCALL
286 KeSetContextKernelRoutine(PKAPC Apc,
287 PKNORMAL_ROUTINE* NormalRoutine,
288 PVOID* NormalContext,
289 PVOID* SystemArgument1,
290 PVOID* SystemArgument2)
291 /*
292 * FUNCTION: This routine is called by an APC sent by NtSetContextThread to
293 * set the context of a thread from a buffer.
294 */
295 {
296 PKEVENT Event;
297 PCONTEXT Context;
298 PNTSTATUS Status;
299
300 Context = (PCONTEXT)(*NormalContext);
301 Event = (PKEVENT)(*SystemArgument1);
302 Status = (PNTSTATUS)(*SystemArgument2);
303
304 KeContextToTrapFrame(Context, KeGetCurrentThread()->TrapFrame);
305
306 *Status = STATUS_SUCCESS;
307 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
308 }
309
310 NTSTATUS STDCALL
311 NtSetContextThread(IN HANDLE ThreadHandle,
312 IN PCONTEXT ThreadContext)
313 {
314 PETHREAD Thread;
315 KAPC Apc;
316 KEVENT Event;
317 CONTEXT Context;
318 KPROCESSOR_MODE PreviousMode;
319 NTSTATUS Status = STATUS_SUCCESS;
320
321 PAGED_CODE();
322
323 PreviousMode = ExGetPreviousMode();
324
325 if(PreviousMode != KernelMode)
326 {
327 _SEH_TRY
328 {
329 ProbeForRead(ThreadContext,
330 sizeof(CONTEXT),
331 sizeof(ULONG));
332 Context = *ThreadContext;
333 ThreadContext = &Context;
334 }
335 _SEH_HANDLE
336 {
337 Status = _SEH_GetExceptionCode();
338 }
339 _SEH_END;
340
341 if(!NT_SUCCESS(Status))
342 {
343 return Status;
344 }
345 }
346
347 Status = ObReferenceObjectByHandle(ThreadHandle,
348 THREAD_SET_CONTEXT,
349 PsThreadType,
350 PreviousMode,
351 (PVOID*)&Thread,
352 NULL);
353 if(NT_SUCCESS(Status))
354 {
355 if (Thread == PsGetCurrentThread())
356 {
357 /*
358 * I don't know if trying to set your own context makes much
359 * sense but we can handle it more efficently.
360 */
361
362 KeContextToTrapFrame(&Context, Thread->Tcb.TrapFrame);
363 }
364 else
365 {
366 KeInitializeEvent(&Event,
367 NotificationEvent,
368 FALSE);
369
370 KeInitializeApc(&Apc,
371 &Thread->Tcb,
372 OriginalApcEnvironment,
373 KeSetContextKernelRoutine,
374 KeGetSetContextRundownRoutine,
375 NULL,
376 KernelMode,
377 (PVOID)&Context);
378 if (!KeInsertQueueApc(&Apc,
379 (PVOID)&Event,
380 (PVOID)&Status,
381 IO_NO_INCREMENT))
382 {
383 Status = STATUS_THREAD_IS_TERMINATING;
384 }
385 else
386 {
387 Status = KeWaitForSingleObject(&Event,
388 0,
389 KernelMode,
390 FALSE,
391 NULL);
392 }
393 }
394 ObDereferenceObject(Thread);
395 }
396
397 return Status;
398 }
399
400 /* EOF */