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
)
64 PULONG Esp
= (PULONG
)Thread
->Tcb
.KernelStack
;
65 PULONG Ebp
= (PULONG
)Esp
[4];
68 DbgPrint("Ebp %p\n", Ebp
);
71 while(Ebp
!= 0 && Ebp
>= (PULONG
)Thread
->Tcb
.StackLimit
)
73 /* Print what's on the stack */
74 DbgPrint("%.8X %.8X%s", Ebp
[0], Ebp
[1], (i
% 8) == 7 ? "\n" : " ");
79 /* Print a new line if there's nothing */
80 if((i
% 8) != 0) DbgPrint("\n");
82 DbgPrint("FIXME: Backtrace skipped on non-x86\n");
86 /* Move to the next Thread */
87 CurrentThread
= CurrentThread
->Flink
;
91 /* Move to the next Process */
92 CurrentProcess
= CurrentProcess
->Flink
;
97 /* PUBLIC FUNCTIONS **********************************************************/
104 PsGetContextThread(IN PETHREAD Thread
,
105 IN OUT PCONTEXT ThreadContext
,
106 IN KPROCESSOR_MODE PreviousMode
)
108 GET_SET_CTX_CONTEXT GetSetContext
;
109 ULONG Size
= 0, Flags
= 0;
115 /* Set default ength */
116 Size
= sizeof(CONTEXT
);
119 Flags
= ProbeForReadUlong(&ThreadContext
->ContextFlags
);
122 /* Check if the caller wanted extended registers */
123 if ((Flags
& CONTEXT_EXTENDED_REGISTERS
) !=
124 CONTEXT_EXTENDED_REGISTERS
)
126 /* Cut them out of the size */
127 Size
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
131 /* Check if we came from user mode */
132 if (PreviousMode
!= KernelMode
)
134 /* Probe the context */
135 ProbeForWrite(ThreadContext
, Size
, sizeof(ULONG
));
138 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
140 /* Return the exception code */
141 _SEH2_YIELD(return _SEH2_GetExceptionCode());
145 /* Initialize the wait event */
146 KeInitializeEvent(&GetSetContext
.Event
, NotificationEvent
, FALSE
);
148 /* Set the flags and previous mode */
149 GetSetContext
.Context
.ContextFlags
= Flags
;
150 GetSetContext
.Mode
= PreviousMode
;
152 /* Check if we're running in the same thread */
153 if (Thread
== PsGetCurrentThread())
155 /* Setup APC parameters manually */
156 GetSetContext
.Apc
.SystemArgument1
= NULL
;
157 GetSetContext
.Apc
.SystemArgument2
= Thread
;
159 /* Enter a guarded region to simulate APC_LEVEL */
160 KeEnterGuardedRegion();
162 /* Manually call the APC */
163 PspGetOrSetContextKernelRoutine(&GetSetContext
.Apc
,
166 &GetSetContext
.Apc
.SystemArgument1
,
167 &GetSetContext
.Apc
.SystemArgument2
);
169 /* Leave the guarded region */
170 KeLeaveGuardedRegion();
173 Status
= STATUS_SUCCESS
;
177 /* Initialize the APC */
178 KeInitializeApc(&GetSetContext
.Apc
,
180 OriginalApcEnvironment
,
181 PspGetOrSetContextKernelRoutine
,
187 /* Queue it as a Get APC */
188 if (!KeInsertQueueApc(&GetSetContext
.Apc
, NULL
, Thread
, 2))
190 /* It was already queued, so fail */
191 Status
= STATUS_UNSUCCESSFUL
;
195 /* Wait for the APC to complete */
196 Status
= KeWaitForSingleObject(&GetSetContext
.Event
,
206 /* Copy the context */
207 RtlCopyMemory(ThreadContext
, &GetSetContext
.Context
, Size
);
209 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
211 /* Get the exception code */
212 Status
= _SEH2_GetExceptionCode();
225 PsSetContextThread(IN PETHREAD Thread
,
226 IN OUT PCONTEXT ThreadContext
,
227 IN KPROCESSOR_MODE PreviousMode
)
229 GET_SET_CTX_CONTEXT GetSetContext
;
230 ULONG Size
= 0, Flags
= 0;
236 /* Set default length */
237 Size
= sizeof(CONTEXT
);
240 Flags
= ProbeForReadUlong(&ThreadContext
->ContextFlags
);
243 /* Check if the caller wanted extended registers */
244 if ((Flags
& CONTEXT_EXTENDED_REGISTERS
) !=
245 CONTEXT_EXTENDED_REGISTERS
)
247 /* Cut them out of the size */
248 Size
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
252 /* Check if we came from user mode */
253 if (PreviousMode
!= KernelMode
)
255 /* Probe the context */
256 ProbeForRead(ThreadContext
, Size
, sizeof(ULONG
));
259 /* Copy the context */
260 RtlCopyMemory(&GetSetContext
.Context
, ThreadContext
, Size
);
262 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
264 /* Return the exception code */
265 _SEH2_YIELD(return _SEH2_GetExceptionCode());
269 /* Initialize the wait event */
270 KeInitializeEvent(&GetSetContext
.Event
, NotificationEvent
, FALSE
);
272 /* Set the flags and previous mode */
273 GetSetContext
.Context
.ContextFlags
= Flags
;
274 GetSetContext
.Mode
= PreviousMode
;
276 /* Check if we're running in the same thread */
277 if (Thread
== PsGetCurrentThread())
279 /* Setup APC parameters manually */
280 GetSetContext
.Apc
.SystemArgument1
= UlongToPtr(1);
281 GetSetContext
.Apc
.SystemArgument2
= Thread
;
283 /* Enter a guarded region to simulate APC_LEVEL */
284 KeEnterGuardedRegion();
286 /* Manually call the APC */
287 PspGetOrSetContextKernelRoutine(&GetSetContext
.Apc
,
290 &GetSetContext
.Apc
.SystemArgument1
,
291 &GetSetContext
.Apc
.SystemArgument2
);
293 /* Leave the guarded region */
294 KeLeaveGuardedRegion();
297 Status
= STATUS_SUCCESS
;
301 /* Initialize the APC */
302 KeInitializeApc(&GetSetContext
.Apc
,
304 OriginalApcEnvironment
,
305 PspGetOrSetContextKernelRoutine
,
311 /* Queue it as a Get APC */
312 if (!KeInsertQueueApc(&GetSetContext
.Apc
, UlongToPtr(1), Thread
, 2))
314 /* It was already queued, so fail */
315 Status
= STATUS_UNSUCCESSFUL
;
319 /* Wait for the APC to complete */
320 Status
= KeWaitForSingleObject(&GetSetContext
.Event
,
334 NtGetContextThread(IN HANDLE ThreadHandle
,
335 IN OUT PCONTEXT ThreadContext
)
339 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
342 /* Get the Thread Object */
343 Status
= ObReferenceObjectByHandle(ThreadHandle
,
350 if (!NT_SUCCESS(Status
)) return Status
;
352 /* Make sure it's not a system thread */
353 if (Thread
->SystemThread
)
356 Status
= STATUS_INVALID_HANDLE
;
360 /* Call the kernel API */
361 Status
= PsGetContextThread(Thread
, ThreadContext
, PreviousMode
);
364 /* Dereference it and return */
365 ObDereferenceObject(Thread
);
371 NtSetContextThread(IN HANDLE ThreadHandle
,
372 IN PCONTEXT ThreadContext
)
376 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
379 /* Get the Thread Object */
380 Status
= ObReferenceObjectByHandle(ThreadHandle
,
387 if (!NT_SUCCESS(Status
)) return Status
;
389 /* Make sure it's not a system thread */
390 if (Thread
->SystemThread
)
393 Status
= STATUS_INVALID_HANDLE
;
397 /* Call the kernel API */
398 Status
= PsSetContextThread(Thread
, ThreadContext
, PreviousMode
);
401 /* Dereference it and return */
402 ObDereferenceObject(Thread
);