48077e79565c55fd766fe97b5e06849428bc08a6
[reactos.git] / reactos / ntoskrnl / ps / debug.c
1 /*
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)
8 */
9
10 /* INCLUDES ****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* PRIVATE FUNCTIONS *********************************************************/
17
18 #ifdef DBG
19 VOID
20 NTAPI
21 PspDumpThreads(BOOLEAN IncludeSystem)
22 {
23 PLIST_ENTRY CurrentThread, CurrentProcess;
24 PEPROCESS Process;
25 PETHREAD Thread;
26 ULONG nThreads = 0;
27
28 /* Loop all Active Processes */
29 CurrentProcess = PsActiveProcessHead.Flink;
30 while(CurrentProcess != &PsActiveProcessHead)
31 {
32 /* Get the process */
33 Process = CONTAINING_RECORD(CurrentProcess, EPROCESS, ActiveProcessLinks);
34
35 /* Skip the Initial Process if requested */
36 if((Process != PsInitialSystemProcess) ||
37 (Process == PsInitialSystemProcess && IncludeSystem))
38 {
39 /* Loop all its threads */
40 CurrentThread = Process->ThreadListHead.Flink;
41 while(CurrentThread != &Process->ThreadListHead)
42 {
43
44 /* Get teh Thread */
45 Thread = CONTAINING_RECORD(CurrentThread, ETHREAD, ThreadListEntry);
46 nThreads++;
47
48 /* Print the Info */
49 DbgPrint("State %d Affinity %08x Priority %d PID.TID %d.%d Name %.8s Stack: \n",
50 Thread->Tcb.State,
51 Thread->Tcb.Affinity,
52 Thread->Tcb.Priority,
53 Thread->Cid.UniqueProcess,
54 Thread->Cid.UniqueThread,
55 Thread->ThreadsProcess->ImageFileName);
56
57 /* Make sure it's not running */
58 if(Thread->Tcb.State == Ready ||
59 Thread->Tcb.State == Standby ||
60 Thread->Tcb.State == Waiting)
61 {
62 ULONG i = 0;
63 PULONG Esp = (PULONG)Thread->Tcb.KernelStack;
64 PULONG Ebp = (PULONG)Esp[4];
65
66 /* Print EBP */
67 DbgPrint("Ebp 0x%.8X\n", Ebp);
68
69 /* Walk it */
70 while(Ebp != 0 && Ebp >= (PULONG)Thread->Tcb.StackLimit)
71 {
72 /* Print what's on the stack */
73 DbgPrint("%.8X %.8X%s", Ebp[0], Ebp[1], (i % 8) == 7 ? "\n" : " ");
74 Ebp = (PULONG)Ebp[0];
75 i++;
76 }
77
78 /* Print a new line if there's nothing */
79 if((i % 8) != 0) DbgPrint("\n");
80 }
81
82 /* Move to the next Thread */
83 CurrentThread = CurrentThread->Flink;
84 }
85 }
86
87 /* Move to the next Process */
88 CurrentProcess = CurrentProcess->Flink;
89 }
90 }
91 #endif
92
93 /* PUBLIC FUNCTIONS **********************************************************/
94
95 /*
96 * @implemented
97 */
98 NTSTATUS
99 NTAPI
100 PsGetContextThread(IN PETHREAD Thread,
101 IN OUT PCONTEXT ThreadContext,
102 IN KPROCESSOR_MODE PreviousMode)
103 {
104 GET_SET_CTX_CONTEXT GetSetContext;
105 ULONG Size = 0, Flags = 0;
106 NTSTATUS Status = STATUS_SUCCESS;
107
108 /* Enter SEH */
109 _SEH2_TRY
110 {
111 /* Set default ength */
112 Size = sizeof(CONTEXT);
113
114 /* Read the flags */
115 Flags = ProbeForReadUlong(&ThreadContext->ContextFlags);
116
117 #ifdef _M_IX86
118 /* Check if the caller wanted extended registers */
119 if ((Flags & CONTEXT_EXTENDED_REGISTERS) !=
120 CONTEXT_EXTENDED_REGISTERS)
121 {
122 /* Cut them out of the size */
123 Size = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
124 }
125 #endif
126
127 /* Check if we came from user mode */
128 if (PreviousMode != KernelMode)
129 {
130 /* Probe the context */
131 ProbeForWrite(ThreadContext, Size, sizeof(ULONG));
132 }
133 }
134 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
135 {
136 /* Get exception code */
137 Status = _SEH2_GetExceptionCode();
138 }
139 _SEH2_END;
140
141 /* Check if we got success */
142 if (!NT_SUCCESS(Status)) return Status;
143
144 /* Initialize the wait event */
145 KeInitializeEvent(&GetSetContext.Event, NotificationEvent, FALSE);
146
147 /* Set the flags and previous mode */
148 GetSetContext.Context.ContextFlags = Flags;
149 GetSetContext.Mode = PreviousMode;
150
151 /* Check if we're running in the same thread */
152 if (Thread == PsGetCurrentThread())
153 {
154 /* Setup APC parameters manually */
155 GetSetContext.Apc.SystemArgument1 = NULL;
156 GetSetContext.Apc.SystemArgument2 = Thread;
157
158 /* Enter a guarded region to simulate APC_LEVEL */
159 KeEnterGuardedRegion();
160
161 /* Manually call the APC */
162 PspGetOrSetContextKernelRoutine(&GetSetContext.Apc,
163 NULL,
164 NULL,
165 &GetSetContext.Apc.SystemArgument1,
166 &GetSetContext.Apc.SystemArgument2);
167
168 /* Leave the guarded region */
169 KeLeaveGuardedRegion();
170 }
171 else
172 {
173 /* Initialize the APC */
174 KeInitializeApc(&GetSetContext.Apc,
175 &Thread->Tcb,
176 OriginalApcEnvironment,
177 PspGetOrSetContextKernelRoutine,
178 NULL,
179 NULL,
180 KernelMode,
181 NULL);
182
183 /* Queue it as a Get APC */
184 if (!KeInsertQueueApc(&GetSetContext.Apc, NULL, Thread, 2))
185 {
186 /* It was already queued, so fail */
187 Status = STATUS_UNSUCCESSFUL;
188 }
189 else
190 {
191 /* Wait for the APC to complete */
192 Status = KeWaitForSingleObject(&GetSetContext.Event,
193 0,
194 KernelMode,
195 FALSE,
196 NULL);
197 }
198 }
199
200 _SEH2_TRY
201 {
202 /* Copy the context */
203 RtlCopyMemory(ThreadContext, &GetSetContext.Context, Size);
204 }
205 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
206 {
207 Status = _SEH2_GetExceptionCode();
208 }
209 _SEH2_END;
210
211 /* Return status */
212 return Status;
213 }
214
215 /*
216 * @implemented
217 */
218 NTSTATUS
219 NTAPI
220 PsSetContextThread(IN PETHREAD Thread,
221 IN OUT PCONTEXT ThreadContext,
222 IN KPROCESSOR_MODE PreviousMode)
223 {
224 GET_SET_CTX_CONTEXT GetSetContext;
225 ULONG Size = 0, Flags = 0;
226 NTSTATUS Status = STATUS_SUCCESS;
227
228 /* Enter SEH */
229 _SEH2_TRY
230 {
231 /* Set default length */
232 Size = sizeof(CONTEXT);
233
234 /* Read the flags */
235 Flags = ProbeForReadUlong(&ThreadContext->ContextFlags);
236
237 #ifdef _M_IX86
238 /* Check if the caller wanted extended registers */
239 if ((Flags & CONTEXT_EXTENDED_REGISTERS) !=
240 CONTEXT_EXTENDED_REGISTERS)
241 {
242 /* Cut them out of the size */
243 Size = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
244 }
245 #endif
246
247 /* Check if we came from user mode */
248 if (PreviousMode != KernelMode)
249 {
250 /* Probe the context */
251 ProbeForRead(ThreadContext, Size, sizeof(ULONG));
252 }
253
254 /* Copy the context */
255 RtlCopyMemory(&GetSetContext.Context, ThreadContext, Size);
256 }
257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
258 {
259 /* Get exception code */
260 Status = _SEH2_GetExceptionCode();
261 }
262 _SEH2_END;
263
264 /* Check if we got success */
265 if (!NT_SUCCESS(Status)) return Status;
266
267 /* Initialize the wait event */
268 KeInitializeEvent(&GetSetContext.Event, NotificationEvent, FALSE);
269
270 /* Set the flags and previous mode */
271 GetSetContext.Context.ContextFlags = Flags;
272 GetSetContext.Mode = PreviousMode;
273
274 /* Check if we're running in the same thread */
275 if (Thread == PsGetCurrentThread())
276 {
277 /* Setup APC parameters manually */
278 GetSetContext.Apc.SystemArgument1 = UlongToPtr(1);
279 GetSetContext.Apc.SystemArgument2 = Thread;
280
281 /* Enter a guarded region to simulate APC_LEVEL */
282 KeEnterGuardedRegion();
283
284 /* Manually call the APC */
285 PspGetOrSetContextKernelRoutine(&GetSetContext.Apc,
286 NULL,
287 NULL,
288 &GetSetContext.Apc.SystemArgument1,
289 &GetSetContext.Apc.SystemArgument2);
290
291 /* Leave the guarded region */
292 KeLeaveGuardedRegion();
293 }
294 else
295 {
296 /* Initialize the APC */
297 KeInitializeApc(&GetSetContext.Apc,
298 &Thread->Tcb,
299 OriginalApcEnvironment,
300 PspGetOrSetContextKernelRoutine,
301 NULL,
302 NULL,
303 KernelMode,
304 NULL);
305
306 /* Queue it as a Get APC */
307 if (!KeInsertQueueApc(&GetSetContext.Apc, UlongToPtr(1), Thread, 2))
308 {
309 /* It was already queued, so fail */
310 Status = STATUS_UNSUCCESSFUL;
311 }
312 else
313 {
314 /* Wait for the APC to complete */
315 Status = KeWaitForSingleObject(&GetSetContext.Event,
316 0,
317 KernelMode,
318 FALSE,
319 NULL);
320 }
321 }
322
323 /* Return status */
324 return Status;
325 }
326
327 NTSTATUS
328 NTAPI
329 NtGetContextThread(IN HANDLE ThreadHandle,
330 IN OUT PCONTEXT ThreadContext)
331 {
332 PETHREAD Thread;
333 NTSTATUS Status;
334 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
335 PAGED_CODE();
336
337 /* Get the Thread Object */
338 Status = ObReferenceObjectByHandle(ThreadHandle,
339 THREAD_GET_CONTEXT,
340 PsThreadType,
341 PreviousMode,
342 (PVOID*)&Thread,
343 NULL);
344
345 if (!NT_SUCCESS(Status)) return Status;
346
347 /* Make sure it's not a system thread */
348 if (Thread->SystemThread)
349 {
350 /* Fail */
351 Status = STATUS_INVALID_HANDLE;
352 }
353 else
354 {
355 /* Call the kernel API */
356 Status = PsGetContextThread(Thread, ThreadContext, PreviousMode);
357 }
358
359 /* Dereference it and return */
360 ObDereferenceObject(Thread);
361 return Status;
362 }
363
364 NTSTATUS
365 NTAPI
366 NtSetContextThread(IN HANDLE ThreadHandle,
367 IN PCONTEXT ThreadContext)
368 {
369 PETHREAD Thread;
370 NTSTATUS Status;
371 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
372 PAGED_CODE();
373
374 /* Get the Thread Object */
375 Status = ObReferenceObjectByHandle(ThreadHandle,
376 THREAD_SET_CONTEXT,
377 PsThreadType,
378 PreviousMode,
379 (PVOID*)&Thread,
380 NULL);
381
382 if (!NT_SUCCESS(Status)) return Status;
383
384 /* Make sure it's not a system thread */
385 if (Thread->SystemThread)
386 {
387 /* Fail */
388 Status = STATUS_INVALID_HANDLE;
389 }
390 else
391 {
392 /* Call the kernel API */
393 Status = PsSetContextThread(Thread, ThreadContext, PreviousMode);
394 }
395
396 /* Dereference it and return */
397 ObDereferenceObject(Thread);
398 return Status;
399 }
400
401 /* EOF */