NtRaiseException fixed to not clobber EAX any more, and both NtContinue and NtRaiseEx...
[reactos.git] / reactos / ntoskrnl / ps / debug.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2000, 1999, 1998 David Welch <welch@cwcom.net>,
4 * Philip Susi <phreak@iag.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 /* $Id: debug.c,v 1.12 2004/07/02 01:36:25 royce Exp $
21 *
22 * PROJECT: ReactOS kernel
23 * FILE: ntoskrnl/ps/debug.c
24 * PURPOSE: Thread managment
25 * PROGRAMMER: David Welch (welch@mcmail.com)
26 * REVISION HISTORY:
27 * 23/06/98: Created
28 * 12/10/99: Phillip Susi: Thread priorities, and APC work
29 */
30
31 /*
32 * NOTE:
33 *
34 * All of the routines that manipulate the thread queue synchronize on
35 * a single spinlock
36 *
37 */
38
39 /* INCLUDES ****************************************************************/
40
41 #include <ddk/ntddk.h>
42 #include <internal/ke.h>
43 #include <internal/ob.h>
44 #include <string.h>
45 #include <internal/ps.h>
46 #include <internal/ob.h>
47 #include <internal/safe.h>
48
49 #define NDEBUG
50 #include <internal/debug.h>
51
52 /* FUNCTIONS ***************************************************************/
53
54 VOID
55 KeContextToTrapFrame(PCONTEXT Context,
56 PKTRAP_FRAME TrapFrame)
57 {
58 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
59 {
60 TrapFrame->Esp = Context->Esp;
61 TrapFrame->Ss = Context->SegSs;
62 TrapFrame->Cs = Context->SegCs;
63 TrapFrame->Eip = Context->Eip;
64 TrapFrame->Eflags = Context->EFlags;
65 TrapFrame->Ebp = Context->Ebp;
66 }
67 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
68 {
69 TrapFrame->Eax = Context->Eax;
70 TrapFrame->Ebx = Context->Ebx;
71 TrapFrame->Ecx = Context->Ecx;
72 TrapFrame->Edx = Context->Edx;
73 TrapFrame->Esi = Context->Esi;
74 TrapFrame->Edi = Context->Edi;
75 }
76 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
77 {
78 TrapFrame->Ds = Context->SegDs;
79 TrapFrame->Es = Context->SegEs;
80 TrapFrame->Fs = Context->SegFs;
81 TrapFrame->Gs = Context->SegGs;
82 }
83 if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
84 {
85 /*
86 * Not handled
87 */
88 }
89 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
90 {
91 /*
92 * Not handled
93 */
94 }
95 }
96
97 VOID
98 KeTrapFrameToContext(PKTRAP_FRAME TrapFrame,
99 PCONTEXT Context)
100 {
101 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
102 {
103 Context->SegSs = TrapFrame->Ss;
104 Context->Esp = TrapFrame->Esp;
105 Context->SegCs = TrapFrame->Cs;
106 Context->Eip = TrapFrame->Eip;
107 Context->EFlags = TrapFrame->Eflags;
108 Context->Ebp = TrapFrame->Ebp;
109 }
110 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
111 {
112 Context->Eax = TrapFrame->Eax;
113 Context->Ebx = TrapFrame->Ebx;
114 Context->Ecx = TrapFrame->Ecx;
115 /*
116 * NOTE: In the trap frame which is built on entry to a system
117 * call TrapFrame->Edx will actually hold the address of the
118 * previous TrapFrame. I don't believe leaking this information
119 * has security implications. Also EDX holds the address of the
120 * arguments to the system call in progress so it isn't of much
121 * interest to the debugger.
122 */
123 Context->Edx = TrapFrame->Edx;
124 Context->Esi = TrapFrame->Esi;
125 Context->Edi = TrapFrame->Edi;
126 }
127 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
128 {
129 Context->SegDs = TrapFrame->Ds;
130 Context->SegEs = TrapFrame->Es;
131 Context->SegFs = TrapFrame->Fs;
132 Context->SegGs = TrapFrame->Gs;
133 }
134 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
135 {
136 /*
137 * FIXME: Implement this case
138 */
139 }
140 if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
141 {
142 /*
143 * FIXME: Implement this case
144 */
145 }
146 #if 0
147 if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
148 {
149 /*
150 * FIXME: Investigate this
151 */
152 }
153 #endif
154 }
155
156 VOID STDCALL
157 KeGetSetContextRundownRoutine(PKAPC Apc)
158 {
159 PKEVENT Event;
160 PNTSTATUS Status;
161
162 Event = (PKEVENT)Apc->SystemArgument1;
163 Status = (PNTSTATUS)Apc->SystemArgument2;
164 (*Status) = STATUS_THREAD_IS_TERMINATING;
165 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
166 }
167
168 VOID STDCALL
169 KeGetContextKernelRoutine(PKAPC Apc,
170 PKNORMAL_ROUTINE* NormalRoutine,
171 PVOID* NormalContext,
172 PVOID* SystemArgument1,
173 PVOID* SystemArgument2)
174 /*
175 * FUNCTION: This routine is called by an APC sent by NtGetContextThread to
176 * copy the context of a thread into a buffer.
177 */
178 {
179 PKEVENT Event;
180 PCONTEXT Context;
181 PNTSTATUS Status;
182
183 Context = (PCONTEXT)(*NormalContext);
184 Event = (PKEVENT)(*SystemArgument1);
185 Status = (PNTSTATUS)(*SystemArgument2);
186
187 KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, Context);
188
189 *Status = STATUS_SUCCESS;
190 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
191 }
192
193 NTSTATUS STDCALL
194 NtGetContextThread(IN HANDLE ThreadHandle,
195 OUT PCONTEXT UnsafeContext)
196 {
197 PETHREAD Thread;
198 NTSTATUS Status;
199 CONTEXT Context;
200 KAPC Apc;
201 KEVENT Event;
202 NTSTATUS AStatus;
203
204 Status = MmCopyFromCaller(&Context, UnsafeContext, sizeof(CONTEXT));
205 if (! NT_SUCCESS(Status))
206 {
207 return Status;
208 }
209 Status = ObReferenceObjectByHandle(ThreadHandle,
210 THREAD_GET_CONTEXT,
211 PsThreadType,
212 UserMode,
213 (PVOID*)&Thread,
214 NULL);
215 if (! NT_SUCCESS(Status))
216 {
217 return Status;
218 }
219 if (Thread == PsGetCurrentThread())
220 {
221 /*
222 * I don't know if trying to get your own context makes much
223 * sense but we can handle it more efficently.
224 */
225
226 KeTrapFrameToContext(Thread->Tcb.TrapFrame, &Context);
227 Status = STATUS_SUCCESS;
228 }
229 else
230 {
231 KeInitializeEvent(&Event,
232 NotificationEvent,
233 FALSE);
234 AStatus = STATUS_SUCCESS;
235
236 KeInitializeApc(&Apc,
237 &Thread->Tcb,
238 OriginalApcEnvironment,
239 KeGetContextKernelRoutine,
240 KeGetSetContextRundownRoutine,
241 NULL,
242 KernelMode,
243 (PVOID)&Context);
244 if (!KeInsertQueueApc(&Apc,
245 (PVOID)&Event,
246 (PVOID)&AStatus,
247 IO_NO_INCREMENT))
248 {
249 Status = STATUS_THREAD_IS_TERMINATING;
250 }
251 else
252 {
253 Status = KeWaitForSingleObject(&Event,
254 0,
255 UserMode,
256 FALSE,
257 NULL);
258 if (NT_SUCCESS(Status) && !NT_SUCCESS(AStatus))
259 {
260 Status = AStatus;
261 }
262 }
263 }
264 if (NT_SUCCESS(Status))
265 {
266 Status = MmCopyToCaller(UnsafeContext, &Context, sizeof(Context));
267 }
268
269 ObDereferenceObject(Thread);
270 return Status;
271 }
272
273 VOID STDCALL
274 KeSetContextKernelRoutine(PKAPC Apc,
275 PKNORMAL_ROUTINE* NormalRoutine,
276 PVOID* NormalContext,
277 PVOID* SystemArgument1,
278 PVOID* SystemArgument2)
279 /*
280 * FUNCTION: This routine is called by an APC sent by NtSetContextThread to
281 * set the context of a thread from a buffer.
282 */
283 {
284 PKEVENT Event;
285 PCONTEXT Context;
286 PNTSTATUS Status;
287
288 Context = (PCONTEXT)(*NormalContext);
289 Event = (PKEVENT)(*SystemArgument1);
290 Status = (PNTSTATUS)(*SystemArgument2);
291
292 KeContextToTrapFrame(Context, KeGetCurrentThread()->TrapFrame);
293
294 *Status = STATUS_SUCCESS;
295 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
296 }
297
298 NTSTATUS STDCALL
299 NtSetContextThread(IN HANDLE ThreadHandle,
300 IN PCONTEXT UnsafeContext)
301 {
302 PETHREAD Thread;
303 NTSTATUS Status;
304 KAPC Apc;
305 KEVENT Event;
306 NTSTATUS AStatus;
307 CONTEXT Context;
308
309 Status = MmCopyFromCaller(&Context, UnsafeContext, sizeof(CONTEXT));
310 if (! NT_SUCCESS(Status))
311 {
312 return Status;
313 }
314 Status = ObReferenceObjectByHandle(ThreadHandle,
315 THREAD_SET_CONTEXT,
316 PsThreadType,
317 UserMode,
318 (PVOID*)&Thread,
319 NULL);
320 if (!NT_SUCCESS(Status))
321 {
322 return Status;
323 }
324
325 if (Thread == PsGetCurrentThread())
326 {
327 /*
328 * I don't know if trying to set your own context makes much
329 * sense but we can handle it more efficently.
330 */
331
332 KeContextToTrapFrame(&Context, Thread->Tcb.TrapFrame);
333 Status = STATUS_SUCCESS;
334 }
335 else
336 {
337 KeInitializeEvent(&Event,
338 NotificationEvent,
339 FALSE);
340 AStatus = STATUS_SUCCESS;
341
342 KeInitializeApc(&Apc,
343 &Thread->Tcb,
344 OriginalApcEnvironment,
345 KeSetContextKernelRoutine,
346 KeGetSetContextRundownRoutine,
347 NULL,
348 KernelMode,
349 (PVOID)&Context);
350 if (!KeInsertQueueApc(&Apc,
351 (PVOID)&Event,
352 (PVOID)&AStatus,
353 IO_NO_INCREMENT))
354 {
355 Status = STATUS_THREAD_IS_TERMINATING;
356 }
357 else
358 {
359 Status = KeWaitForSingleObject(&Event,
360 0,
361 UserMode,
362 FALSE,
363 NULL);
364 if (NT_SUCCESS(Status) && !NT_SUCCESS(AStatus))
365 {
366 Status = AStatus;
367 }
368 }
369 }
370
371 ObDereferenceObject(Thread);
372 return Status;
373 }
374
375 /* EOF */