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 ****************************************************************/
14 #include <internal/debug.h>
16 /* GLOBALS *****************************************************************/
18 /* Thread "Set/Get Context" Context Structure */
19 typedef struct _GET_SET_CTX_CONTEXT
25 } GET_SET_CTX_CONTEXT
, *PGET_SET_CTX_CONTEXT
;
27 /* PRIVATE FUNCTIONS *********************************************************/
32 PspDumpThreads(BOOLEAN IncludeSystem
)
34 PLIST_ENTRY CurrentThread
, CurrentProcess
;
39 /* Loop all Active Processes */
40 CurrentProcess
= PsActiveProcessHead
.Flink
;
41 while(CurrentProcess
!= &PsActiveProcessHead
)
44 Process
= CONTAINING_RECORD(CurrentProcess
, EPROCESS
, ActiveProcessLinks
);
46 /* Skip the Initial Process if requested */
47 if((Process
!= PsInitialSystemProcess
) ||
48 (Process
== PsInitialSystemProcess
&& IncludeSystem
))
50 /* Loop all its threads */
51 CurrentThread
= Process
->ThreadListHead
.Flink
;
52 while(CurrentThread
!= &Process
->ThreadListHead
)
56 Thread
= CONTAINING_RECORD(CurrentThread
, ETHREAD
, ThreadListEntry
);
60 DbgPrint("State %d Affinity %08x Priority %d PID.TID %d.%d Name %.8s Stack: \n",
64 Thread
->Cid
.UniqueProcess
,
65 Thread
->Cid
.UniqueThread
,
66 Thread
->ThreadsProcess
->ImageFileName
);
68 /* Make sure it's not running */
69 if(Thread
->Tcb
.State
== Ready
||
70 Thread
->Tcb
.State
== Standby
||
71 Thread
->Tcb
.State
== Waiting
)
74 PULONG Esp
= (PULONG
)Thread
->Tcb
.KernelStack
;
75 PULONG Ebp
= (PULONG
)Esp
[4];
78 DbgPrint("Ebp 0x%.8X\n", Ebp
);
81 while(Ebp
!= 0 && Ebp
>= (PULONG
)Thread
->Tcb
.StackLimit
)
83 /* Print what's on the stack */
84 DbgPrint("%.8X %.8X%s", Ebp
[0], Ebp
[1], (i
% 8) == 7 ? "\n" : " ");
89 /* Print a new line if there's nothing */
90 if((i
% 8) != 0) DbgPrint("\n");
94 /* Move to the next Thread */
95 CurrentThread
= CurrentThread
->Flink
;
98 /* Move to the next Process */
99 CurrentProcess
= CurrentProcess
->Flink
;
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
)
112 PGET_SET_CTX_CONTEXT GetSetContext
;
116 KPROCESSOR_MODE Mode
;
118 PKTRAP_FRAME TrapFrame
;
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
;
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
));
136 ASSERT(((TrapFrame
->SegCs
& MODE_MASK
) != KernelMode
) ||
137 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
));
139 /* Check if it's a set or get */
142 /* Get the Context */
143 KeTrapFrameToContext(TrapFrame
, NULL
, Context
);
147 /* Set the Context */
148 KeContextToTrapFrame(Context
,
151 Context
->ContextFlags
,
156 /* Notify the Native API that we are done */
157 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
160 /* PUBLIC FUNCTIONS **********************************************************/
167 PsGetContextThread(IN PETHREAD Thread
,
168 IN OUT PCONTEXT ThreadContext
,
169 IN KPROCESSOR_MODE PreviousMode
)
171 GET_SET_CTX_CONTEXT GetSetContext
;
172 ULONG Size
= 0, Flags
= 0;
173 NTSTATUS Status
= STATUS_SUCCESS
;
178 /* Set default ength */
179 Size
= sizeof(CONTEXT
);
182 ProbeForReadUlong(&ThreadContext
->ContextFlags
);
183 Flags
= ThreadContext
->ContextFlags
;
185 /* Check if the caller wanted extended registers */
186 if ((Flags
& CONTEXT_EXTENDED_REGISTERS
) !=
187 CONTEXT_EXTENDED_REGISTERS
)
189 /* Cut them out of the size */
190 Size
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
193 /* Check if we came from user mode */
194 if (PreviousMode
!= KernelMode
)
196 /* Probe the context */
197 ProbeForWrite(ThreadContext
, Size
, sizeof(ULONG
));
202 /* Get exception code */
203 Status
= _SEH_GetExceptionCode();
207 /* Check if we got success */
208 if (!NT_SUCCESS(Status
)) return Status
;
210 /* Initialize the wait event */
211 KeInitializeEvent(&GetSetContext
.Event
, NotificationEvent
, FALSE
);
213 /* Set the flags and previous mode */
214 GetSetContext
.Context
.ContextFlags
= Flags
;
215 GetSetContext
.Mode
= PreviousMode
;
217 /* Check if we're running in the same thread */
218 if (Thread
== PsGetCurrentThread())
220 /* Setup APC parameters manually */
221 GetSetContext
.Apc
.SystemArgument1
= NULL
;
222 GetSetContext
.Apc
.SystemArgument2
= Thread
;
224 /* Enter a guarded region to simulate APC_LEVEL */
225 KeEnterGuardedRegion();
227 /* Manually call the APC */
228 PspGetOrSetContextKernelRoutine(&GetSetContext
.Apc
,
231 &GetSetContext
.Apc
.SystemArgument1
,
232 &GetSetContext
.Apc
.SystemArgument2
);
234 /* Leave the guarded region */
235 KeLeaveGuardedRegion();
239 /* Initialize the APC */
240 KeInitializeApc(&GetSetContext
.Apc
,
242 OriginalApcEnvironment
,
243 PspGetOrSetContextKernelRoutine
,
249 /* Queue it as a Get APC */
250 if (!KeInsertQueueApc(&GetSetContext
.Apc
, NULL
, Thread
, 2))
252 /* It was already queued, so fail */
253 Status
= STATUS_UNSUCCESSFUL
;
257 /* Wait for the APC to complete */
258 Status
= KeWaitForSingleObject(&GetSetContext
.Event
,
265 /* Copy the context */
266 RtlMoveMemory(ThreadContext
, &GetSetContext
.Context
, Size
);
278 PsSetContextThread(IN PETHREAD Thread
,
279 IN OUT PCONTEXT ThreadContext
,
280 IN KPROCESSOR_MODE PreviousMode
)
282 GET_SET_CTX_CONTEXT GetSetContext
;
283 ULONG Size
= 0, Flags
= 0;
284 NTSTATUS Status
= STATUS_SUCCESS
;
289 /* Set default length */
290 Size
= sizeof(CONTEXT
);
293 ProbeForReadUlong(&ThreadContext
->ContextFlags
);
294 Flags
= ThreadContext
->ContextFlags
;
296 /* Check if the caller wanted extended registers */
297 if ((Flags
& CONTEXT_EXTENDED_REGISTERS
) !=
298 CONTEXT_EXTENDED_REGISTERS
)
300 /* Cut them out of the size */
301 Size
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
304 /* Check if we came from user mode */
305 if (PreviousMode
!= KernelMode
)
307 /* Probe the context */
308 ProbeForRead(ThreadContext
, Size
, sizeof(ULONG
));
311 /* Copy the context */
312 RtlMoveMemory(&GetSetContext
.Context
, ThreadContext
, Size
);
316 /* Get exception code */
317 Status
= _SEH_GetExceptionCode();
321 /* Check if we got success */
322 if (!NT_SUCCESS(Status
)) return Status
;
324 /* Initialize the wait event */
325 KeInitializeEvent(&GetSetContext
.Event
, NotificationEvent
, FALSE
);
327 /* Set the flags and previous mode */
328 GetSetContext
.Context
.ContextFlags
= Flags
;
329 GetSetContext
.Mode
= PreviousMode
;
331 /* Check if we're running in the same thread */
332 if (Thread
== PsGetCurrentThread())
334 /* Setup APC parameters manually */
335 GetSetContext
.Apc
.SystemArgument1
= UlongToPtr(1);
336 GetSetContext
.Apc
.SystemArgument2
= Thread
;
338 /* Enter a guarded region to simulate APC_LEVEL */
339 KeEnterGuardedRegion();
341 /* Manually call the APC */
342 PspGetOrSetContextKernelRoutine(&GetSetContext
.Apc
,
345 &GetSetContext
.Apc
.SystemArgument1
,
346 &GetSetContext
.Apc
.SystemArgument2
);
348 /* Leave the guarded region */
349 KeLeaveGuardedRegion();
353 /* Initialize the APC */
354 KeInitializeApc(&GetSetContext
.Apc
,
356 OriginalApcEnvironment
,
357 PspGetOrSetContextKernelRoutine
,
363 /* Queue it as a Get APC */
364 if (!KeInsertQueueApc(&GetSetContext
.Apc
, UlongToPtr(1), Thread
, 2))
366 /* It was already queued, so fail */
367 Status
= STATUS_UNSUCCESSFUL
;
371 /* Wait for the APC to complete */
372 Status
= KeWaitForSingleObject(&GetSetContext
.Event
,
386 NtGetContextThread(IN HANDLE ThreadHandle
,
387 IN OUT PCONTEXT ThreadContext
)
391 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
394 /* Get the Thread Object */
395 Status
= ObReferenceObjectByHandle(ThreadHandle
,
402 /* Make sure it's not a system thread */
403 if (Thread
->SystemThread
)
406 Status
= STATUS_INVALID_HANDLE
;
410 /* Call the kernel API */
411 Status
= PsGetContextThread(Thread
, ThreadContext
, PreviousMode
);
414 /* Dereference it and return */
415 ObDereferenceObject(Thread
);
421 NtSetContextThread(IN HANDLE ThreadHandle
,
422 IN PCONTEXT ThreadContext
)
426 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
429 /* Get the Thread Object */
430 Status
= ObReferenceObjectByHandle(ThreadHandle
,
437 /* Make sure it's not a system thread */
438 if (Thread
->SystemThread
)
441 Status
= STATUS_INVALID_HANDLE
;
445 /* Call the kernel API */
446 Status
= PsSetContextThread(Thread
, ThreadContext
, PreviousMode
);
449 /* Dereference it and return */
450 ObDereferenceObject(Thread
);