Big merge: thanks alex and greatlord. Not a complete merge but most
[reactos.git] / reactos / ntoskrnl / ps / debug.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/debug.c
5 * PURPOSE: Process Manager: Debugging Support (Set/Get Context)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller (w3seek@reactos.org)
8 */
9
10 /* INCLUDES ****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* GLOBALS *****************************************************************/
17
18 /* Thread "Set/Get Context" Context Structure */
19 typedef struct _GET_SET_CTX_CONTEXT
20 {
21 KAPC Apc;
22 KEVENT Event;
23 KPROCESSOR_MODE Mode;
24 CONTEXT Context;
25 } GET_SET_CTX_CONTEXT, *PGET_SET_CTX_CONTEXT;
26
27 /* PRIVATE FUNCTIONS *********************************************************/
28
29 #ifdef DBG
30 VOID
31 NTAPI
32 PspDumpThreads(BOOLEAN IncludeSystem)
33 {
34 PLIST_ENTRY CurrentThread, CurrentProcess;
35 PEPROCESS Process;
36 PETHREAD Thread;
37 ULONG nThreads = 0;
38
39 /* Loop all Active Processes */
40 CurrentProcess = PsActiveProcessHead.Flink;
41 while(CurrentProcess != &PsActiveProcessHead)
42 {
43 /* Get the process */
44 Process = CONTAINING_RECORD(CurrentProcess, EPROCESS, ActiveProcessLinks);
45
46 /* Skip the Initial Process if requested */
47 if((Process != PsInitialSystemProcess) ||
48 (Process == PsInitialSystemProcess && IncludeSystem))
49 {
50 /* Loop all its threads */
51 CurrentThread = Process->ThreadListHead.Flink;
52 while(CurrentThread != &Process->ThreadListHead)
53 {
54
55 /* Get teh Thread */
56 Thread = CONTAINING_RECORD(CurrentThread, ETHREAD, ThreadListEntry);
57 nThreads++;
58
59 /* Print the Info */
60 DbgPrint("State %d Affinity %08x Priority %d PID.TID %d.%d Name %.8s Stack: \n",
61 Thread->Tcb.State,
62 Thread->Tcb.Affinity,
63 Thread->Tcb.Priority,
64 Thread->Cid.UniqueProcess,
65 Thread->Cid.UniqueThread,
66 Thread->ThreadsProcess->ImageFileName);
67
68 /* Make sure it's not running */
69 if(Thread->Tcb.State == Ready ||
70 Thread->Tcb.State == Standby ||
71 Thread->Tcb.State == Waiting)
72 {
73 ULONG i = 0;
74 PULONG Esp = (PULONG)Thread->Tcb.KernelStack;
75 PULONG Ebp = (PULONG)Esp[4];
76
77 /* Print EBP */
78 DbgPrint("Ebp 0x%.8X\n", Ebp);
79
80 /* Walk it */
81 while(Ebp != 0 && Ebp >= (PULONG)Thread->Tcb.StackLimit)
82 {
83 /* Print what's on the stack */
84 DbgPrint("%.8X %.8X%s", Ebp[0], Ebp[1], (i % 8) == 7 ? "\n" : " ");
85 Ebp = (PULONG)Ebp[0];
86 i++;
87 }
88
89 /* Print a new line if there's nothing */
90 if((i % 8) != 0) DbgPrint("\n");
91 }
92 }
93
94 /* Move to the next Thread */
95 CurrentThread = CurrentThread->Flink;
96 }
97
98 /* Move to the next Process */
99 CurrentProcess = CurrentProcess->Flink;
100 }
101 }
102 #endif
103
104 VOID
105 NTAPI
106 PspGetOrSetContextKernelRoutine(IN PKAPC Apc,
107 IN OUT PKNORMAL_ROUTINE* NormalRoutine,
108 IN OUT PVOID* NormalContext,
109 IN OUT PVOID* SystemArgument1,
110 IN OUT PVOID* SystemArgument2)
111 {
112 PGET_SET_CTX_CONTEXT GetSetContext;
113 PKEVENT Event;
114 PCONTEXT Context;
115 PKTHREAD Thread;
116 KPROCESSOR_MODE Mode;
117 #ifdef _M_IX86
118 PKTRAP_FRAME TrapFrame;
119 #endif
120 PAGED_CODE();
121
122 /* Get the Context Structure */
123 GetSetContext = CONTAINING_RECORD(Apc, GET_SET_CTX_CONTEXT, Apc);
124 Context = &GetSetContext->Context;
125 Event = &GetSetContext->Event;
126 Mode = GetSetContext->Mode;
127 Thread = Apc->SystemArgument2;
128
129 #ifdef _M_IX86
130 if (TrapFrame->SegCs == KGDT_R0_CODE && Mode != KernelMode)
131 /* Get the trap frame */
132 TrapFrame = (PKTRAP_FRAME)((ULONG_PTR)KeGetCurrentThread()->InitialStack -
133 sizeof (FX_SAVE_AREA) - sizeof (KTRAP_FRAME));
134
135 /* Sanity check */
136 ASSERT(((TrapFrame->SegCs & MODE_MASK) != KernelMode) ||
137 (TrapFrame->EFlags & EFLAGS_V86_MASK));
138
139 /* Check if it's a set or get */
140 if (SystemArgument1)
141 {
142 /* Get the Context */
143 KeTrapFrameToContext(TrapFrame, NULL, Context);
144 }
145 else
146 {
147 /* Set the Context */
148 KeContextToTrapFrame(Context,
149 NULL,
150 TrapFrame,
151 Context->ContextFlags,
152 Mode);
153 }
154 #endif
155
156 /* Notify the Native API that we are done */
157 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
158 }
159
160 /* PUBLIC FUNCTIONS **********************************************************/
161
162 /*
163 * @implemented
164 */
165 NTSTATUS
166 NTAPI
167 PsGetContextThread(IN PETHREAD Thread,
168 IN OUT PCONTEXT ThreadContext,
169 IN KPROCESSOR_MODE PreviousMode)
170 {
171 GET_SET_CTX_CONTEXT GetSetContext;
172 ULONG Size = 0, Flags = 0;
173 NTSTATUS Status = STATUS_SUCCESS;
174
175 /* Enter SEH */
176 _SEH_TRY
177 {
178 /* Set default ength */
179 Size = sizeof(CONTEXT);
180
181 /* Read the flags */
182 ProbeForReadUlong(&ThreadContext->ContextFlags);
183 Flags = ThreadContext->ContextFlags;
184
185 /* Check if the caller wanted extended registers */
186 if ((Flags & CONTEXT_EXTENDED_REGISTERS) !=
187 CONTEXT_EXTENDED_REGISTERS)
188 {
189 /* Cut them out of the size */
190 Size = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
191 }
192
193 /* Check if we came from user mode */
194 if (PreviousMode != KernelMode)
195 {
196 /* Probe the context */
197 ProbeForWrite(ThreadContext, Size, sizeof(ULONG));
198 }
199 }
200 _SEH_HANDLE
201 {
202 /* Get exception code */
203 Status = _SEH_GetExceptionCode();
204 }
205 _SEH_END;
206
207 /* Check if we got success */
208 if (!NT_SUCCESS(Status)) return Status;
209
210 /* Initialize the wait event */
211 KeInitializeEvent(&GetSetContext.Event, NotificationEvent, FALSE);
212
213 /* Set the flags and previous mode */
214 GetSetContext.Context.ContextFlags = Flags;
215 GetSetContext.Mode = PreviousMode;
216
217 /* Check if we're running in the same thread */
218 if (Thread == PsGetCurrentThread())
219 {
220 /* Setup APC parameters manually */
221 GetSetContext.Apc.SystemArgument1 = NULL;
222 GetSetContext.Apc.SystemArgument2 = Thread;
223
224 /* Enter a guarded region to simulate APC_LEVEL */
225 KeEnterGuardedRegion();
226
227 /* Manually call the APC */
228 PspGetOrSetContextKernelRoutine(&GetSetContext.Apc,
229 NULL,
230 NULL,
231 &GetSetContext.Apc.SystemArgument1,
232 &GetSetContext.Apc.SystemArgument2);
233
234 /* Leave the guarded region */
235 KeLeaveGuardedRegion();
236 }
237 else
238 {
239 /* Initialize the APC */
240 KeInitializeApc(&GetSetContext.Apc,
241 &Thread->Tcb,
242 OriginalApcEnvironment,
243 PspGetOrSetContextKernelRoutine,
244 NULL,
245 NULL,
246 KernelMode,
247 NULL);
248
249 /* Queue it as a Get APC */
250 if (!KeInsertQueueApc(&GetSetContext.Apc, NULL, Thread, 2))
251 {
252 /* It was already queued, so fail */
253 Status = STATUS_UNSUCCESSFUL;
254 }
255 else
256 {
257 /* Wait for the APC to complete */
258 Status = KeWaitForSingleObject(&GetSetContext.Event,
259 0,
260 KernelMode,
261 FALSE,
262 NULL);
263 }
264
265 /* Copy the context */
266 RtlMoveMemory(ThreadContext, &GetSetContext.Context, Size);
267 }
268
269 /* Return status */
270 return Status;
271 }
272
273 /*
274 * @implemented
275 */
276 NTSTATUS
277 NTAPI
278 PsSetContextThread(IN PETHREAD Thread,
279 IN OUT PCONTEXT ThreadContext,
280 IN KPROCESSOR_MODE PreviousMode)
281 {
282 GET_SET_CTX_CONTEXT GetSetContext;
283 ULONG Size = 0, Flags = 0;
284 NTSTATUS Status = STATUS_SUCCESS;
285
286 /* Enter SEH */
287 _SEH_TRY
288 {
289 /* Set default length */
290 Size = sizeof(CONTEXT);
291
292 /* Read the flags */
293 ProbeForReadUlong(&ThreadContext->ContextFlags);
294 Flags = ThreadContext->ContextFlags;
295
296 /* Check if the caller wanted extended registers */
297 if ((Flags & CONTEXT_EXTENDED_REGISTERS) !=
298 CONTEXT_EXTENDED_REGISTERS)
299 {
300 /* Cut them out of the size */
301 Size = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
302 }
303
304 /* Check if we came from user mode */
305 if (PreviousMode != KernelMode)
306 {
307 /* Probe the context */
308 ProbeForRead(ThreadContext, Size, sizeof(ULONG));
309 }
310
311 /* Copy the context */
312 RtlMoveMemory(&GetSetContext.Context, ThreadContext, Size);
313 }
314 _SEH_HANDLE
315 {
316 /* Get exception code */
317 Status = _SEH_GetExceptionCode();
318 }
319 _SEH_END;
320
321 /* Check if we got success */
322 if (!NT_SUCCESS(Status)) return Status;
323
324 /* Initialize the wait event */
325 KeInitializeEvent(&GetSetContext.Event, NotificationEvent, FALSE);
326
327 /* Set the flags and previous mode */
328 GetSetContext.Context.ContextFlags = Flags;
329 GetSetContext.Mode = PreviousMode;
330
331 /* Check if we're running in the same thread */
332 if (Thread == PsGetCurrentThread())
333 {
334 /* Setup APC parameters manually */
335 GetSetContext.Apc.SystemArgument1 = UlongToPtr(1);
336 GetSetContext.Apc.SystemArgument2 = Thread;
337
338 /* Enter a guarded region to simulate APC_LEVEL */
339 KeEnterGuardedRegion();
340
341 /* Manually call the APC */
342 PspGetOrSetContextKernelRoutine(&GetSetContext.Apc,
343 NULL,
344 NULL,
345 &GetSetContext.Apc.SystemArgument1,
346 &GetSetContext.Apc.SystemArgument2);
347
348 /* Leave the guarded region */
349 KeLeaveGuardedRegion();
350 }
351 else
352 {
353 /* Initialize the APC */
354 KeInitializeApc(&GetSetContext.Apc,
355 &Thread->Tcb,
356 OriginalApcEnvironment,
357 PspGetOrSetContextKernelRoutine,
358 NULL,
359 NULL,
360 KernelMode,
361 NULL);
362
363 /* Queue it as a Get APC */
364 if (!KeInsertQueueApc(&GetSetContext.Apc, UlongToPtr(1), Thread, 2))
365 {
366 /* It was already queued, so fail */
367 Status = STATUS_UNSUCCESSFUL;
368 }
369 else
370 {
371 /* Wait for the APC to complete */
372 Status = KeWaitForSingleObject(&GetSetContext.Event,
373 0,
374 KernelMode,
375 FALSE,
376 NULL);
377 }
378 }
379
380 /* Return status */
381 return Status;
382 }
383
384 NTSTATUS
385 NTAPI
386 NtGetContextThread(IN HANDLE ThreadHandle,
387 IN OUT PCONTEXT ThreadContext)
388 {
389 PETHREAD Thread;
390 NTSTATUS Status;
391 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
392 PAGED_CODE();
393
394 /* Get the Thread Object */
395 Status = ObReferenceObjectByHandle(ThreadHandle,
396 THREAD_GET_CONTEXT,
397 PsThreadType,
398 PreviousMode,
399 (PVOID*)&Thread,
400 NULL);
401
402 /* Make sure it's not a system thread */
403 if (Thread->SystemThread)
404 {
405 /* Fail */
406 Status = STATUS_INVALID_HANDLE;
407 }
408 else
409 {
410 /* Call the kernel API */
411 Status = PsGetContextThread(Thread, ThreadContext, PreviousMode);
412 }
413
414 /* Dereference it and return */
415 ObDereferenceObject(Thread);
416 return Status;
417 }
418
419 NTSTATUS
420 NTAPI
421 NtSetContextThread(IN HANDLE ThreadHandle,
422 IN PCONTEXT ThreadContext)
423 {
424 PETHREAD Thread;
425 NTSTATUS Status;
426 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
427 PAGED_CODE();
428
429 /* Get the Thread Object */
430 Status = ObReferenceObjectByHandle(ThreadHandle,
431 THREAD_SET_CONTEXT,
432 PsThreadType,
433 PreviousMode,
434 (PVOID*)&Thread,
435 NULL);
436
437 /* Make sure it's not a system thread */
438 if (Thread->SystemThread)
439 {
440 /* Fail */
441 Status = STATUS_INVALID_HANDLE;
442 }
443 else
444 {
445 /* Call the kernel API */
446 Status = PsSetContextThread(Thread, ThreadContext, PreviousMode);
447 }
448
449 /* Dereference it and return */
450 ObDereferenceObject(Thread);
451 return Status;
452 }
453
454 /* EOF */