- Optimized the dispatcher lock. It is now gone on non-SMP systems and IRQL is raised...
[reactos.git] / reactos / ntoskrnl / ps / debug.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/debug.c
5 * PURPOSE: Thread managment
6 *
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
8 * Phillip Susi
9 */
10
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *****************************************************************/
19
20 /* Thread "Set/Get Context" Context Structure */
21 typedef struct _GET_SET_CTX_CONTEXT {
22 KAPC Apc;
23 KEVENT Event;
24 CONTEXT Context;
25 KPROCESSOR_MODE Mode;
26 NTSTATUS Status;
27 } GET_SET_CTX_CONTEXT, *PGET_SET_CTX_CONTEXT;
28
29
30 /* FUNCTIONS ***************************************************************/
31
32 /*
33 * FUNCTION: This routine is called by an APC sent by NtGetContextThread to
34 * copy the context of a thread into a buffer.
35 */
36 VOID
37 STDCALL
38 PspGetOrSetContextKernelRoutine(PKAPC Apc,
39 PKNORMAL_ROUTINE* NormalRoutine,
40 PVOID* NormalContext,
41 PVOID* SystemArgument1,
42 PVOID* SystemArgument2)
43 {
44 PGET_SET_CTX_CONTEXT GetSetContext;
45 PKEVENT Event;
46 PCONTEXT Context;
47 KPROCESSOR_MODE Mode;
48 PKTRAP_FRAME TrapFrame;
49
50 TrapFrame = (PKTRAP_FRAME)((ULONG_PTR)KeGetCurrentThread()->InitialStack -
51 sizeof (FX_SAVE_AREA) - sizeof (KTRAP_FRAME));
52
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;
58
59 if (TrapFrame->SegCs == KGDT_R0_CODE && Mode != KernelMode)
60 {
61 GetSetContext->Status = STATUS_ACCESS_DENIED;
62 }
63 else
64 {
65 /* Check if it's a set or get */
66 if (*SystemArgument1) {
67 /* Get the Context */
68 KeTrapFrameToContext(TrapFrame, NULL, Context);
69 } else {
70 /* Set the Context */
71 KeContextToTrapFrame(Context, NULL, TrapFrame, Mode);
72 }
73 GetSetContext->Status = STATUS_SUCCESS;
74 }
75
76 /* Notify the Native API that we are done */
77 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
78 }
79
80 NTSTATUS
81 STDCALL
82 NtGetContextThread(IN HANDLE ThreadHandle,
83 IN OUT PCONTEXT ThreadContext)
84 {
85 PETHREAD Thread;
86 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
87 GET_SET_CTX_CONTEXT GetSetContext;
88 NTSTATUS Status = STATUS_SUCCESS;
89 PCONTEXT SafeThreadContext = NULL;
90
91 PAGED_CODE();
92
93 /* Check the buffer to be OK */
94 if(PreviousMode != KernelMode) {
95
96 _SEH_TRY {
97
98 ProbeForWrite(ThreadContext,
99 sizeof(CONTEXT),
100 sizeof(ULONG));
101 GetSetContext.Context = *ThreadContext;
102 SafeThreadContext = &GetSetContext.Context;
103
104 } _SEH_HANDLE {
105
106 Status = _SEH_GetExceptionCode();
107
108 } _SEH_END;
109
110 if(!NT_SUCCESS(Status)) return Status;
111 } else {
112 SafeThreadContext = ThreadContext;
113 }
114
115 /* Get the Thread Object */
116 Status = ObReferenceObjectByHandle(ThreadHandle,
117 THREAD_GET_CONTEXT,
118 PsThreadType,
119 PreviousMode,
120 (PVOID*)&Thread,
121 NULL);
122
123 /* Check success */
124 if(NT_SUCCESS(Status)) {
125
126 /* Check if we're running in the same thread */
127 if(Thread == PsGetCurrentThread()) {
128 /*
129 * I don't know if trying to get your own context makes much
130 * sense but we can handle it more efficently.
131 */
132 KeTrapFrameToContext(Thread->Tcb.TrapFrame, NULL, SafeThreadContext);
133
134 } else {
135
136 /* Copy context into GetSetContext if not already done */
137 if(PreviousMode == KernelMode) {
138 GetSetContext.Context = *ThreadContext;
139 SafeThreadContext = &GetSetContext.Context;
140 }
141
142 /* Use an APC... Initialize the Event */
143 KeInitializeEvent(&GetSetContext.Event,
144 NotificationEvent,
145 FALSE);
146
147 /* Set the previous mode */
148 GetSetContext.Mode = PreviousMode;
149
150 /* Initialize the APC */
151 KeInitializeApc(&GetSetContext.Apc,
152 &Thread->Tcb,
153 OriginalApcEnvironment,
154 PspGetOrSetContextKernelRoutine,
155 NULL,
156 NULL,
157 KernelMode,
158 NULL);
159
160 /* Queue it as a Get APC */
161 if (!KeInsertQueueApc(&GetSetContext.Apc,
162 (PVOID)1,
163 NULL,
164 IO_NO_INCREMENT)) {
165
166 Status = STATUS_THREAD_IS_TERMINATING;
167
168 } else {
169
170 /* Wait for the APC to complete */
171 Status = KeWaitForSingleObject(&GetSetContext.Event,
172 0,
173 KernelMode,
174 FALSE,
175 NULL);
176 if (NT_SUCCESS(Status))
177 Status = GetSetContext.Status;
178 }
179 }
180
181 /* Dereference the thread */
182 ObDereferenceObject(Thread);
183
184 /* Check for success and return the Context */
185 if(NT_SUCCESS(Status) && SafeThreadContext != ThreadContext) {
186 _SEH_TRY {
187
188 *ThreadContext = GetSetContext.Context;
189
190 } _SEH_HANDLE {
191
192 Status = _SEH_GetExceptionCode();
193
194 } _SEH_END;
195 }
196 }
197
198 /* Return status */
199 return Status;
200 }
201
202 NTSTATUS
203 STDCALL
204 NtSetContextThread(IN HANDLE ThreadHandle,
205 IN PCONTEXT ThreadContext)
206 {
207 PETHREAD Thread;
208 GET_SET_CTX_CONTEXT GetSetContext;
209 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
210 NTSTATUS Status = STATUS_SUCCESS;
211
212 PAGED_CODE();
213
214 /* Check the buffer to be OK */
215 if(PreviousMode != KernelMode) {
216
217 _SEH_TRY {
218
219 ProbeForRead(ThreadContext,
220 sizeof(CONTEXT),
221 sizeof(ULONG));
222
223 GetSetContext.Context = *ThreadContext;
224 ThreadContext = &GetSetContext.Context;
225
226 } _SEH_HANDLE {
227
228 Status = _SEH_GetExceptionCode();
229 } _SEH_END;
230
231 if(!NT_SUCCESS(Status)) return Status;
232 }
233
234 /* Get the Thread Object */
235 Status = ObReferenceObjectByHandle(ThreadHandle,
236 THREAD_SET_CONTEXT,
237 PsThreadType,
238 PreviousMode,
239 (PVOID*)&Thread,
240 NULL);
241
242 /* Check success */
243 if(NT_SUCCESS(Status)) {
244
245 /* Check if we're running in the same thread */
246 if(Thread == PsGetCurrentThread()) {
247
248 /*
249 * I don't know if trying to set your own context makes much
250 * sense but we can handle it more efficently.
251 */
252 KeContextToTrapFrame(ThreadContext, NULL, Thread->Tcb.TrapFrame, PreviousMode);
253
254 } else {
255
256 /* Copy context into GetSetContext if not already done */
257 if(PreviousMode == KernelMode)
258 GetSetContext.Context = *ThreadContext;
259
260 /* Use an APC... Initialize the Event */
261 KeInitializeEvent(&GetSetContext.Event,
262 NotificationEvent,
263 FALSE);
264
265 /* Set the previous mode */
266 GetSetContext.Mode = PreviousMode;
267
268 /* Initialize the APC */
269 KeInitializeApc(&GetSetContext.Apc,
270 &Thread->Tcb,
271 OriginalApcEnvironment,
272 PspGetOrSetContextKernelRoutine,
273 NULL,
274 NULL,
275 KernelMode,
276 NULL);
277
278 /* Queue it as a Get APC */
279 if (!KeInsertQueueApc(&GetSetContext.Apc,
280 (PVOID)0,
281 NULL,
282 IO_NO_INCREMENT)) {
283
284 Status = STATUS_THREAD_IS_TERMINATING;
285
286 } else {
287
288 /* Wait for the APC to complete */
289 Status = KeWaitForSingleObject(&GetSetContext.Event,
290 0,
291 KernelMode,
292 FALSE,
293 NULL);
294 if (NT_SUCCESS(Status))
295 Status = GetSetContext.Status;
296 }
297 }
298
299 /* Dereference the thread */
300 ObDereferenceObject(Thread);
301 }
302
303 /* Return status */
304 return Status;
305 }
306
307 #ifdef DBG
308 VOID
309 STDCALL
310 PspDumpThreads(BOOLEAN IncludeSystem)
311 {
312 PLIST_ENTRY CurrentThread, CurrentProcess;
313 PEPROCESS Process;
314 PETHREAD Thread;
315 ULONG nThreads = 0;
316
317 /* Loop all Active Processes */
318 CurrentProcess = PsActiveProcessHead.Flink;
319 while(CurrentProcess != &PsActiveProcessHead)
320 {
321 /* Get the process */
322 Process = CONTAINING_RECORD(CurrentProcess, EPROCESS, ActiveProcessLinks);
323
324 /* Skip the Initial Process if requested */
325 if((Process != PsInitialSystemProcess) ||
326 (Process == PsInitialSystemProcess && IncludeSystem))
327 {
328 /* Loop all its threads */
329 CurrentThread = Process->ThreadListHead.Flink;
330 while(CurrentThread != &Process->ThreadListHead)
331 {
332
333 /* Get teh Thread */
334 Thread = CONTAINING_RECORD(CurrentThread, ETHREAD, ThreadListEntry);
335 nThreads++;
336
337 /* Print the Info */
338 DbgPrint("State %d Affinity %08x Priority %d PID.TID %d.%d Name %.8s Stack: \n",
339 Thread->Tcb.State,
340 Thread->Tcb.Affinity,
341 Thread->Tcb.Priority,
342 Thread->Cid.UniqueProcess,
343 Thread->Cid.UniqueThread,
344 Thread->ThreadsProcess->ImageFileName);
345
346 /* Make sure it's not running */
347 if(Thread->Tcb.State == Ready ||
348 Thread->Tcb.State == Standby ||
349 Thread->Tcb.State == Waiting)
350 {
351 ULONG i = 0;
352 PULONG Esp = (PULONG)Thread->Tcb.KernelStack;
353 PULONG Ebp = (PULONG)Esp[4];
354
355 /* Print EBP */
356 DbgPrint("Ebp 0x%.8X\n", Ebp);
357
358 /* Walk it */
359 while(Ebp != 0 && Ebp >= (PULONG)Thread->Tcb.StackLimit)
360 {
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];
364 i++;
365 }
366
367 /* Print a new line if there's nothing */
368 if((i % 8) != 0) DbgPrint("\n");
369 }
370 }
371
372 /* Move to the next Thread */
373 CurrentThread = CurrentThread->Flink;
374 }
375
376 /* Move to the next Process */
377 CurrentProcess = CurrentProcess->Flink;
378 }
379 }
380 #endif
381
382 /* EOF */