2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/debug.c
5 * PURPOSE: Thread managment
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
12 /* INCLUDES ****************************************************************/
16 #include <internal/debug.h>
18 /* GLOBALS *****************************************************************/
20 /* Thread "Set/Get Context" Context Structure */
21 typedef struct _GET_SET_CTX_CONTEXT
{
27 } GET_SET_CTX_CONTEXT
, *PGET_SET_CTX_CONTEXT
;
30 /* FUNCTIONS ***************************************************************/
33 * FUNCTION: This routine is called by an APC sent by NtGetContextThread to
34 * copy the context of a thread into a buffer.
38 PspGetOrSetContextKernelRoutine(PKAPC Apc
,
39 PKNORMAL_ROUTINE
* NormalRoutine
,
41 PVOID
* SystemArgument1
,
42 PVOID
* SystemArgument2
)
44 PGET_SET_CTX_CONTEXT GetSetContext
;
48 PKTRAP_FRAME TrapFrame
;
50 TrapFrame
= (PKTRAP_FRAME
)((ULONG_PTR
)KeGetCurrentThread()->InitialStack
-
51 sizeof (FX_SAVE_AREA
) - sizeof (KTRAP_FRAME
));
53 /* Get the Context Structure */
54 GetSetContext
= CONTAINING_RECORD(Apc
, GET_SET_CTX_CONTEXT
, Apc
);
55 Context
= &GetSetContext
->Context
;
56 Event
= &GetSetContext
->Event
;
57 Mode
= GetSetContext
->Mode
;
59 if (TrapFrame
->Cs
== KGDT_R0_CODE
&& Mode
!= KernelMode
)
61 GetSetContext
->Status
= STATUS_ACCESS_DENIED
;
65 /* Check if it's a set or get */
66 if (*SystemArgument1
) {
68 KeTrapFrameToContext(TrapFrame
, NULL
, Context
);
71 KeContextToTrapFrame(Context
, NULL
, TrapFrame
, Mode
);
73 GetSetContext
->Status
= STATUS_SUCCESS
;
76 /* Notify the Native API that we are done */
77 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
82 NtGetContextThread(IN HANDLE ThreadHandle
,
83 IN OUT PCONTEXT ThreadContext
)
86 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
87 GET_SET_CTX_CONTEXT GetSetContext
;
88 NTSTATUS Status
= STATUS_SUCCESS
;
89 PCONTEXT SafeThreadContext
= NULL
;
93 /* Check the buffer to be OK */
94 if(PreviousMode
!= KernelMode
) {
98 ProbeForWrite(ThreadContext
,
101 GetSetContext
.Context
= *ThreadContext
;
102 SafeThreadContext
= &GetSetContext
.Context
;
106 Status
= _SEH_GetExceptionCode();
110 if(!NT_SUCCESS(Status
)) return Status
;
112 SafeThreadContext
= ThreadContext
;
115 /* Get the Thread Object */
116 Status
= ObReferenceObjectByHandle(ThreadHandle
,
124 if(NT_SUCCESS(Status
)) {
126 /* Check if we're running in the same thread */
127 if(Thread
== PsGetCurrentThread()) {
129 * I don't know if trying to get your own context makes much
130 * sense but we can handle it more efficently.
132 KeTrapFrameToContext(Thread
->Tcb
.TrapFrame
, NULL
, SafeThreadContext
);
136 /* Copy context into GetSetContext if not already done */
137 if(PreviousMode
== KernelMode
) {
138 GetSetContext
.Context
= *ThreadContext
;
139 SafeThreadContext
= &GetSetContext
.Context
;
142 /* Use an APC... Initialize the Event */
143 KeInitializeEvent(&GetSetContext
.Event
,
147 /* Set the previous mode */
148 GetSetContext
.Mode
= PreviousMode
;
150 /* Initialize the APC */
151 KeInitializeApc(&GetSetContext
.Apc
,
153 OriginalApcEnvironment
,
154 PspGetOrSetContextKernelRoutine
,
160 /* Queue it as a Get APC */
161 if (!KeInsertQueueApc(&GetSetContext
.Apc
,
166 Status
= STATUS_THREAD_IS_TERMINATING
;
170 /* Wait for the APC to complete */
171 Status
= KeWaitForSingleObject(&GetSetContext
.Event
,
176 if (NT_SUCCESS(Status
))
177 Status
= GetSetContext
.Status
;
181 /* Dereference the thread */
182 ObDereferenceObject(Thread
);
184 /* Check for success and return the Context */
185 if(NT_SUCCESS(Status
) && SafeThreadContext
!= ThreadContext
) {
188 *ThreadContext
= GetSetContext
.Context
;
192 Status
= _SEH_GetExceptionCode();
204 NtSetContextThread(IN HANDLE ThreadHandle
,
205 IN PCONTEXT ThreadContext
)
208 GET_SET_CTX_CONTEXT GetSetContext
;
209 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
210 NTSTATUS Status
= STATUS_SUCCESS
;
214 /* Check the buffer to be OK */
215 if(PreviousMode
!= KernelMode
) {
219 ProbeForRead(ThreadContext
,
223 GetSetContext
.Context
= *ThreadContext
;
224 ThreadContext
= &GetSetContext
.Context
;
228 Status
= _SEH_GetExceptionCode();
231 if(!NT_SUCCESS(Status
)) return Status
;
234 /* Get the Thread Object */
235 Status
= ObReferenceObjectByHandle(ThreadHandle
,
243 if(NT_SUCCESS(Status
)) {
245 /* Check if we're running in the same thread */
246 if(Thread
== PsGetCurrentThread()) {
249 * I don't know if trying to set your own context makes much
250 * sense but we can handle it more efficently.
252 KeContextToTrapFrame(ThreadContext
, NULL
, Thread
->Tcb
.TrapFrame
, PreviousMode
);
256 /* Copy context into GetSetContext if not already done */
257 if(PreviousMode
== KernelMode
)
258 GetSetContext
.Context
= *ThreadContext
;
260 /* Use an APC... Initialize the Event */
261 KeInitializeEvent(&GetSetContext
.Event
,
265 /* Set the previous mode */
266 GetSetContext
.Mode
= PreviousMode
;
268 /* Initialize the APC */
269 KeInitializeApc(&GetSetContext
.Apc
,
271 OriginalApcEnvironment
,
272 PspGetOrSetContextKernelRoutine
,
278 /* Queue it as a Get APC */
279 if (!KeInsertQueueApc(&GetSetContext
.Apc
,
284 Status
= STATUS_THREAD_IS_TERMINATING
;
288 /* Wait for the APC to complete */
289 Status
= KeWaitForSingleObject(&GetSetContext
.Event
,
294 if (NT_SUCCESS(Status
))
295 Status
= GetSetContext
.Status
;
299 /* Dereference the thread */
300 ObDereferenceObject(Thread
);
310 PspDumpThreads(BOOLEAN IncludeSystem
)
312 PLIST_ENTRY CurrentThread
, CurrentProcess
;
317 /* Loop all Active Processes */
318 CurrentProcess
= PsActiveProcessHead
.Flink
;
319 while(CurrentProcess
!= &PsActiveProcessHead
)
321 /* Get the process */
322 Process
= CONTAINING_RECORD(CurrentProcess
, EPROCESS
, ActiveProcessLinks
);
324 /* Skip the Initial Process if requested */
325 if((Process
!= PsInitialSystemProcess
) ||
326 (Process
== PsInitialSystemProcess
&& IncludeSystem
))
328 /* Loop all its threads */
329 CurrentThread
= Process
->ThreadListHead
.Flink
;
330 while(CurrentThread
!= &Process
->ThreadListHead
)
334 Thread
= CONTAINING_RECORD(CurrentThread
, ETHREAD
, ThreadListEntry
);
338 DbgPrint("State %d Affinity %08x Priority %d PID.TID %d.%d Name %.8s Stack: \n",
340 Thread
->Tcb
.Affinity
,
341 Thread
->Tcb
.Priority
,
342 Thread
->Cid
.UniqueProcess
,
343 Thread
->Cid
.UniqueThread
,
344 Thread
->ThreadsProcess
->ImageFileName
);
346 /* Make sure it's not running */
347 if(Thread
->Tcb
.State
== Ready
||
348 Thread
->Tcb
.State
== Standby
||
349 Thread
->Tcb
.State
== Waiting
)
352 PULONG Esp
= (PULONG
)Thread
->Tcb
.KernelStack
;
353 PULONG Ebp
= (PULONG
)Esp
[4];
356 DbgPrint("Ebp 0x%.8X\n", Ebp
);
359 while(Ebp
!= 0 && Ebp
>= (PULONG
)Thread
->Tcb
.StackLimit
)
361 /* Print what's on the stack */
362 DbgPrint("%.8X %.8X%s", Ebp
[0], Ebp
[1], (i
% 8) == 7 ? "\n" : " ");
363 Ebp
= (PULONG
)Ebp
[0];
367 /* Print a new line if there's nothing */
368 if((i
% 8) != 0) DbgPrint("\n");
372 /* Move to the next Thread */
373 CurrentThread
= CurrentThread
->Flink
;
376 /* Move to the next Process */
377 CurrentProcess
= CurrentProcess
->Flink
;