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