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 %u 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 %p\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;
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 /* Return the exception code */
137 _SEH2_YIELD(return _SEH2_GetExceptionCode());
141 /* Initialize the wait event */
142 KeInitializeEvent(&GetSetContext
.Event
, NotificationEvent
, FALSE
);
144 /* Set the flags and previous mode */
145 GetSetContext
.Context
.ContextFlags
= Flags
;
146 GetSetContext
.Mode
= PreviousMode
;
148 /* Check if we're running in the same thread */
149 if (Thread
== PsGetCurrentThread())
151 /* Setup APC parameters manually */
152 GetSetContext
.Apc
.SystemArgument1
= NULL
;
153 GetSetContext
.Apc
.SystemArgument2
= Thread
;
155 /* Enter a guarded region to simulate APC_LEVEL */
156 KeEnterGuardedRegion();
158 /* Manually call the APC */
159 PspGetOrSetContextKernelRoutine(&GetSetContext
.Apc
,
162 &GetSetContext
.Apc
.SystemArgument1
,
163 &GetSetContext
.Apc
.SystemArgument2
);
165 /* Leave the guarded region */
166 KeLeaveGuardedRegion();
169 Status
= STATUS_SUCCESS
;
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 /* Get the exception code */
208 Status
= _SEH2_GetExceptionCode();
221 PsSetContextThread(IN PETHREAD Thread
,
222 IN OUT PCONTEXT ThreadContext
,
223 IN KPROCESSOR_MODE PreviousMode
)
225 GET_SET_CTX_CONTEXT GetSetContext
;
226 ULONG Size
= 0, Flags
= 0;
232 /* Set default length */
233 Size
= sizeof(CONTEXT
);
236 Flags
= ProbeForReadUlong(&ThreadContext
->ContextFlags
);
239 /* Check if the caller wanted extended registers */
240 if ((Flags
& CONTEXT_EXTENDED_REGISTERS
) !=
241 CONTEXT_EXTENDED_REGISTERS
)
243 /* Cut them out of the size */
244 Size
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
248 /* Check if we came from user mode */
249 if (PreviousMode
!= KernelMode
)
251 /* Probe the context */
252 ProbeForRead(ThreadContext
, Size
, sizeof(ULONG
));
255 /* Copy the context */
256 RtlCopyMemory(&GetSetContext
.Context
, ThreadContext
, Size
);
258 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
260 /* Return the exception code */
261 _SEH2_YIELD(return _SEH2_GetExceptionCode());
265 /* Initialize the wait event */
266 KeInitializeEvent(&GetSetContext
.Event
, NotificationEvent
, FALSE
);
268 /* Set the flags and previous mode */
269 GetSetContext
.Context
.ContextFlags
= Flags
;
270 GetSetContext
.Mode
= PreviousMode
;
272 /* Check if we're running in the same thread */
273 if (Thread
== PsGetCurrentThread())
275 /* Setup APC parameters manually */
276 GetSetContext
.Apc
.SystemArgument1
= UlongToPtr(1);
277 GetSetContext
.Apc
.SystemArgument2
= Thread
;
279 /* Enter a guarded region to simulate APC_LEVEL */
280 KeEnterGuardedRegion();
282 /* Manually call the APC */
283 PspGetOrSetContextKernelRoutine(&GetSetContext
.Apc
,
286 &GetSetContext
.Apc
.SystemArgument1
,
287 &GetSetContext
.Apc
.SystemArgument2
);
289 /* Leave the guarded region */
290 KeLeaveGuardedRegion();
293 Status
= STATUS_SUCCESS
;
297 /* Initialize the APC */
298 KeInitializeApc(&GetSetContext
.Apc
,
300 OriginalApcEnvironment
,
301 PspGetOrSetContextKernelRoutine
,
307 /* Queue it as a Get APC */
308 if (!KeInsertQueueApc(&GetSetContext
.Apc
, UlongToPtr(1), Thread
, 2))
310 /* It was already queued, so fail */
311 Status
= STATUS_UNSUCCESSFUL
;
315 /* Wait for the APC to complete */
316 Status
= KeWaitForSingleObject(&GetSetContext
.Event
,
330 NtGetContextThread(IN HANDLE ThreadHandle
,
331 IN OUT PCONTEXT ThreadContext
)
335 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
338 /* Get the Thread Object */
339 Status
= ObReferenceObjectByHandle(ThreadHandle
,
346 if (!NT_SUCCESS(Status
)) return Status
;
348 /* Make sure it's not a system thread */
349 if (Thread
->SystemThread
)
352 Status
= STATUS_INVALID_HANDLE
;
356 /* Call the kernel API */
357 Status
= PsGetContextThread(Thread
, ThreadContext
, PreviousMode
);
360 /* Dereference it and return */
361 ObDereferenceObject(Thread
);
367 NtSetContextThread(IN HANDLE ThreadHandle
,
368 IN PCONTEXT ThreadContext
)
372 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
375 /* Get the Thread Object */
376 Status
= ObReferenceObjectByHandle(ThreadHandle
,
383 if (!NT_SUCCESS(Status
)) return Status
;
385 /* Make sure it's not a system thread */
386 if (Thread
->SystemThread
)
389 Status
= STATUS_INVALID_HANDLE
;
393 /* Call the kernel API */
394 Status
= PsSetContextThread(Thread
, ThreadContext
, PreviousMode
);
397 /* Dereference it and return */
398 ObDereferenceObject(Thread
);