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)
10 /* INCLUDES ****************************************************************/
16 /* PRIVATE FUNCTIONS *********************************************************/
21 PspDumpThreads(BOOLEAN IncludeSystem
)
23 PLIST_ENTRY CurrentThread
, CurrentProcess
;
28 /* Loop all Active Processes */
29 CurrentProcess
= PsActiveProcessHead
.Flink
;
30 while(CurrentProcess
!= &PsActiveProcessHead
)
33 Process
= CONTAINING_RECORD(CurrentProcess
, EPROCESS
, ActiveProcessLinks
);
35 /* Skip the Initial Process if requested */
36 if((Process
!= PsInitialSystemProcess
) ||
37 (Process
== PsInitialSystemProcess
&& IncludeSystem
))
39 /* Loop all its threads */
40 CurrentThread
= Process
->ThreadListHead
.Flink
;
41 while(CurrentThread
!= &Process
->ThreadListHead
)
45 Thread
= CONTAINING_RECORD(CurrentThread
, ETHREAD
, ThreadListEntry
);
49 DbgPrint("State %d Affinity %08x Priority %d PID.TID %d.%d Name %.8s Stack: \n",
53 Thread
->Cid
.UniqueProcess
,
54 Thread
->Cid
.UniqueThread
,
55 Thread
->ThreadsProcess
->ImageFileName
);
57 /* Make sure it's not running */
58 if(Thread
->Tcb
.State
== Ready
||
59 Thread
->Tcb
.State
== Standby
||
60 Thread
->Tcb
.State
== Waiting
)
63 PULONG Esp
= (PULONG
)Thread
->Tcb
.KernelStack
;
64 PULONG Ebp
= (PULONG
)Esp
[4];
67 DbgPrint("Ebp 0x%.8X\n", Ebp
);
70 while(Ebp
!= 0 && Ebp
>= (PULONG
)Thread
->Tcb
.StackLimit
)
72 /* Print what's on the stack */
73 DbgPrint("%.8X %.8X%s", Ebp
[0], Ebp
[1], (i
% 8) == 7 ? "\n" : " ");
78 /* Print a new line if there's nothing */
79 if((i
% 8) != 0) DbgPrint("\n");
82 /* Move to the next Thread */
83 CurrentThread
= CurrentThread
->Flink
;
87 /* Move to the next Process */
88 CurrentProcess
= CurrentProcess
->Flink
;
93 /* PUBLIC FUNCTIONS **********************************************************/
100 PsGetContextThread(IN PETHREAD Thread
,
101 IN OUT PCONTEXT ThreadContext
,
102 IN KPROCESSOR_MODE PreviousMode
)
104 GET_SET_CTX_CONTEXT GetSetContext
;
105 ULONG Size
= 0, Flags
= 0;
106 NTSTATUS Status
= STATUS_SUCCESS
;
111 /* Set default ength */
112 Size
= sizeof(CONTEXT
);
115 Flags
= ProbeForReadUlong(&ThreadContext
->ContextFlags
);
118 /* Check if the caller wanted extended registers */
119 if ((Flags
& CONTEXT_EXTENDED_REGISTERS
) !=
120 CONTEXT_EXTENDED_REGISTERS
)
122 /* Cut them out of the size */
123 Size
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
127 /* Check if we came from user mode */
128 if (PreviousMode
!= KernelMode
)
130 /* Probe the context */
131 ProbeForWrite(ThreadContext
, Size
, sizeof(ULONG
));
134 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
136 /* Get exception code */
137 Status
= _SEH2_GetExceptionCode();
141 /* Check if we got success */
142 if (!NT_SUCCESS(Status
)) return Status
;
144 /* Initialize the wait event */
145 KeInitializeEvent(&GetSetContext
.Event
, NotificationEvent
, FALSE
);
147 /* Set the flags and previous mode */
148 GetSetContext
.Context
.ContextFlags
= Flags
;
149 GetSetContext
.Mode
= PreviousMode
;
151 /* Check if we're running in the same thread */
152 if (Thread
== PsGetCurrentThread())
154 /* Setup APC parameters manually */
155 GetSetContext
.Apc
.SystemArgument1
= NULL
;
156 GetSetContext
.Apc
.SystemArgument2
= Thread
;
158 /* Enter a guarded region to simulate APC_LEVEL */
159 KeEnterGuardedRegion();
161 /* Manually call the APC */
162 PspGetOrSetContextKernelRoutine(&GetSetContext
.Apc
,
165 &GetSetContext
.Apc
.SystemArgument1
,
166 &GetSetContext
.Apc
.SystemArgument2
);
168 /* Leave the guarded region */
169 KeLeaveGuardedRegion();
173 /* Initialize the APC */
174 KeInitializeApc(&GetSetContext
.Apc
,
176 OriginalApcEnvironment
,
177 PspGetOrSetContextKernelRoutine
,
183 /* Queue it as a Get APC */
184 if (!KeInsertQueueApc(&GetSetContext
.Apc
, NULL
, Thread
, 2))
186 /* It was already queued, so fail */
187 Status
= STATUS_UNSUCCESSFUL
;
191 /* Wait for the APC to complete */
192 Status
= KeWaitForSingleObject(&GetSetContext
.Event
,
202 /* Copy the context */
203 RtlCopyMemory(ThreadContext
, &GetSetContext
.Context
, Size
);
205 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
207 Status
= _SEH2_GetExceptionCode();
220 PsSetContextThread(IN PETHREAD Thread
,
221 IN OUT PCONTEXT ThreadContext
,
222 IN KPROCESSOR_MODE PreviousMode
)
224 GET_SET_CTX_CONTEXT GetSetContext
;
225 ULONG Size
= 0, Flags
= 0;
226 NTSTATUS Status
= STATUS_SUCCESS
;
231 /* Set default length */
232 Size
= sizeof(CONTEXT
);
235 Flags
= ProbeForReadUlong(&ThreadContext
->ContextFlags
);
238 /* Check if the caller wanted extended registers */
239 if ((Flags
& CONTEXT_EXTENDED_REGISTERS
) !=
240 CONTEXT_EXTENDED_REGISTERS
)
242 /* Cut them out of the size */
243 Size
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
247 /* Check if we came from user mode */
248 if (PreviousMode
!= KernelMode
)
250 /* Probe the context */
251 ProbeForRead(ThreadContext
, Size
, sizeof(ULONG
));
254 /* Copy the context */
255 RtlCopyMemory(&GetSetContext
.Context
, ThreadContext
, Size
);
257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
259 /* Get exception code */
260 Status
= _SEH2_GetExceptionCode();
264 /* Check if we got success */
265 if (!NT_SUCCESS(Status
)) return Status
;
267 /* Initialize the wait event */
268 KeInitializeEvent(&GetSetContext
.Event
, NotificationEvent
, FALSE
);
270 /* Set the flags and previous mode */
271 GetSetContext
.Context
.ContextFlags
= Flags
;
272 GetSetContext
.Mode
= PreviousMode
;
274 /* Check if we're running in the same thread */
275 if (Thread
== PsGetCurrentThread())
277 /* Setup APC parameters manually */
278 GetSetContext
.Apc
.SystemArgument1
= UlongToPtr(1);
279 GetSetContext
.Apc
.SystemArgument2
= Thread
;
281 /* Enter a guarded region to simulate APC_LEVEL */
282 KeEnterGuardedRegion();
284 /* Manually call the APC */
285 PspGetOrSetContextKernelRoutine(&GetSetContext
.Apc
,
288 &GetSetContext
.Apc
.SystemArgument1
,
289 &GetSetContext
.Apc
.SystemArgument2
);
291 /* Leave the guarded region */
292 KeLeaveGuardedRegion();
296 /* Initialize the APC */
297 KeInitializeApc(&GetSetContext
.Apc
,
299 OriginalApcEnvironment
,
300 PspGetOrSetContextKernelRoutine
,
306 /* Queue it as a Get APC */
307 if (!KeInsertQueueApc(&GetSetContext
.Apc
, UlongToPtr(1), Thread
, 2))
309 /* It was already queued, so fail */
310 Status
= STATUS_UNSUCCESSFUL
;
314 /* Wait for the APC to complete */
315 Status
= KeWaitForSingleObject(&GetSetContext
.Event
,
329 NtGetContextThread(IN HANDLE ThreadHandle
,
330 IN OUT PCONTEXT ThreadContext
)
334 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
337 /* Get the Thread Object */
338 Status
= ObReferenceObjectByHandle(ThreadHandle
,
345 if (!NT_SUCCESS(Status
)) return Status
;
347 /* Make sure it's not a system thread */
348 if (Thread
->SystemThread
)
351 Status
= STATUS_INVALID_HANDLE
;
355 /* Call the kernel API */
356 Status
= PsGetContextThread(Thread
, ThreadContext
, PreviousMode
);
359 /* Dereference it and return */
360 ObDereferenceObject(Thread
);
366 NtSetContextThread(IN HANDLE ThreadHandle
,
367 IN PCONTEXT ThreadContext
)
371 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
374 /* Get the Thread Object */
375 Status
= ObReferenceObjectByHandle(ThreadHandle
,
382 if (!NT_SUCCESS(Status
)) return Status
;
384 /* Make sure it's not a system thread */
385 if (Thread
->SystemThread
)
388 Status
= STATUS_INVALID_HANDLE
;
392 /* Call the kernel API */
393 Status
= PsSetContextThread(Thread
, ThreadContext
, PreviousMode
);
396 /* Dereference it and return */
397 ObDereferenceObject(Thread
);