update for HEAD-2003091401
[reactos.git] / 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$
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         /*
73          * Edx is used in the TrapFrame to hold the old trap frame pointer
74          * so we don't want to overwrite it here
75          */
76 /*      TrapFrame->Edx = Context->Edx; */
77         TrapFrame->Esi = Context->Esi;
78         TrapFrame->Edi = Context->Edi;
79      }
80    if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
81      {
82         TrapFrame->Ds = Context->SegDs;
83         TrapFrame->Es = Context->SegEs;
84         TrapFrame->Fs = Context->SegFs;
85         TrapFrame->Gs = Context->SegGs;
86      }
87    if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
88      {
89         /*
90          * Not handled
91          */
92      }
93    if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
94      {
95         /*
96          * Not handled
97          */
98      }
99 }
100
101 VOID
102 KeTrapFrameToContext(PKTRAP_FRAME TrapFrame,
103                      PCONTEXT Context)
104 {
105    if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
106      {
107         Context->SegSs = TrapFrame->Ss;
108         Context->Esp = TrapFrame->Esp;
109         Context->SegCs = TrapFrame->Cs;
110         Context->Eip = TrapFrame->Eip;
111         Context->EFlags = TrapFrame->Eflags;
112         Context->Ebp = TrapFrame->Ebp;
113      }
114    if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
115      {
116         Context->Eax = TrapFrame->Eax;
117         Context->Ebx = TrapFrame->Ebx;
118         Context->Ecx = TrapFrame->Ecx;
119         /*
120          * NOTE: In the trap frame which is built on entry to a system
121          * call TrapFrame->Edx will actually hold the address of the
122          * previous TrapFrame. I don't believe leaking this information
123          * has security implications. Also EDX holds the address of the
124          * arguments to the system call in progress so it isn't of much
125          * interest to the debugger.
126          */
127         Context->Edx = TrapFrame->Edx;
128         Context->Esi = TrapFrame->Esi;
129         Context->Edi = TrapFrame->Edi;
130      }
131    if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
132      {
133         Context->SegDs = TrapFrame->Ds;
134         Context->SegEs = TrapFrame->Es;
135         Context->SegFs = TrapFrame->Fs;
136         Context->SegGs = TrapFrame->Gs;
137      }
138    if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
139      {
140         /*
141          * FIXME: Implement this case
142          */     
143      }
144    if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
145      {
146         /*
147          * FIXME: Implement this case
148          */
149      }
150 #if 0
151    if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
152      {
153         /*
154          * FIXME: Investigate this
155          */
156      }
157 #endif
158 }
159
160 VOID STDCALL
161 KeGetSetContextRundownRoutine(PKAPC Apc)
162 {
163   PKEVENT Event;
164   PNTSTATUS Status;
165
166   Event = (PKEVENT)Apc->SystemArgument1;   
167   Status = (PNTSTATUS)Apc->SystemArgument2;
168   (*Status) = STATUS_THREAD_IS_TERMINATING;
169   KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
170 }
171
172 VOID STDCALL
173 KeGetContextKernelRoutine(PKAPC Apc,
174                           PKNORMAL_ROUTINE* NormalRoutine,
175                           PVOID* NormalContext,
176                           PVOID* SystemArgument1,
177                           PVOID* SystemArgument2)
178 /*
179  * FUNCTION: This routine is called by an APC sent by NtGetContextThread to
180  * copy the context of a thread into a buffer.
181  */
182 {
183   PKEVENT Event;
184   PCONTEXT Context;
185   PNTSTATUS Status;
186    
187   Context = (PCONTEXT)(*NormalContext);
188   Event = (PKEVENT)(*SystemArgument1);
189   Status = (PNTSTATUS)(*SystemArgument2);
190    
191   KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, Context);
192    
193   *Status = STATUS_SUCCESS;
194   KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
195 }
196
197 NTSTATUS STDCALL
198 NtGetContextThread(IN HANDLE ThreadHandle,
199                    OUT PCONTEXT UnsafeContext)
200 {
201   PETHREAD Thread;
202   NTSTATUS Status;
203   CONTEXT Context;
204   KAPC Apc;
205   KEVENT Event;
206   NTSTATUS AStatus;
207
208   Status = MmCopyFromCaller(&Context, UnsafeContext, sizeof(CONTEXT));
209   if (! NT_SUCCESS(Status))
210     {
211       return Status;
212     }
213   Status = ObReferenceObjectByHandle(ThreadHandle,
214                                      THREAD_GET_CONTEXT,
215                                      PsThreadType,
216                                      UserMode,
217                                      (PVOID*)&Thread,
218                                      NULL);
219   if (! NT_SUCCESS(Status))
220     {
221       return Status;
222     }
223   if (Thread == PsGetCurrentThread())
224     {
225       /*
226        * I don't know if trying to get your own context makes much
227        * sense but we can handle it more efficently.
228        */
229         
230       KeTrapFrameToContext(Thread->Tcb.TrapFrame, &Context);
231       Status = STATUS_SUCCESS;
232     }
233   else
234     {
235       KeInitializeEvent(&Event,
236                         NotificationEvent,
237                         FALSE); 
238       AStatus = STATUS_SUCCESS;
239         
240       KeInitializeApc(&Apc,
241                       &Thread->Tcb,
242                       OriginalApcEnvironment,
243                       KeGetContextKernelRoutine,
244                       KeGetSetContextRundownRoutine,
245                       NULL,
246                       KernelMode,
247                       (PVOID)&Context);
248       if (!KeInsertQueueApc(&Apc,
249                             (PVOID)&Event,
250                             (PVOID)&AStatus,
251                             IO_NO_INCREMENT))
252         {
253           Status = STATUS_THREAD_IS_TERMINATING;
254         }
255       else
256         {
257           Status = KeWaitForSingleObject(&Event,
258                                          0,
259                                          UserMode,
260                                          FALSE,
261                                          NULL);
262           if (NT_SUCCESS(Status) && !NT_SUCCESS(AStatus))
263             {
264               Status = AStatus;
265             }
266         }
267     }
268   if (NT_SUCCESS(Status))
269     {
270       Status = MmCopyToCaller(UnsafeContext, &Context, sizeof(Context));
271     }
272
273   ObDereferenceObject(Thread);
274   return Status;
275 }
276
277 VOID STDCALL
278 KeSetContextKernelRoutine(PKAPC Apc,
279                           PKNORMAL_ROUTINE* NormalRoutine,
280                           PVOID* NormalContext,
281                           PVOID* SystemArgument1,
282                           PVOID* SystemArgument2)
283 /*
284  * FUNCTION: This routine is called by an APC sent by NtSetContextThread to
285  * set the context of a thread from a buffer.
286  */
287 {
288   PKEVENT Event;
289   PCONTEXT Context;
290   PNTSTATUS Status;
291    
292   Context = (PCONTEXT)(*NormalContext);
293   Event = (PKEVENT)(*SystemArgument1);
294   Status = (PNTSTATUS)(*SystemArgument2);
295    
296   KeContextToTrapFrame(Context, KeGetCurrentThread()->TrapFrame);
297    
298   *Status = STATUS_SUCCESS;
299   KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
300 }
301
302 NTSTATUS STDCALL
303 NtSetContextThread(IN HANDLE ThreadHandle,
304                    IN PCONTEXT UnsafeContext)
305 {
306   PETHREAD Thread;
307   NTSTATUS Status;
308   KAPC Apc;
309   KEVENT Event;
310   NTSTATUS AStatus;
311   CONTEXT Context;
312
313   Status = MmCopyFromCaller(&Context, UnsafeContext, sizeof(CONTEXT));
314   if (! NT_SUCCESS(Status))
315     {
316       return Status;
317     }
318   Status = ObReferenceObjectByHandle(ThreadHandle,
319                                      THREAD_SET_CONTEXT,
320                                      PsThreadType,
321                                      UserMode,
322                                      (PVOID*)&Thread,
323                                      NULL);
324   if (!NT_SUCCESS(Status))
325     {
326       return Status;
327     }
328
329   if (Thread == PsGetCurrentThread())
330     {
331       /*
332        * I don't know if trying to set your own context makes much
333        * sense but we can handle it more efficently.
334        */
335         
336       KeContextToTrapFrame(&Context, Thread->Tcb.TrapFrame);
337       Status = STATUS_SUCCESS;
338     }
339   else
340     {
341       KeInitializeEvent(&Event,
342                         NotificationEvent,
343                         FALSE); 
344       AStatus = STATUS_SUCCESS;
345         
346       KeInitializeApc(&Apc,
347                       &Thread->Tcb,
348                       OriginalApcEnvironment,
349                       KeSetContextKernelRoutine,
350                       KeGetSetContextRundownRoutine,
351                       NULL,
352                       KernelMode,
353                       (PVOID)&Context);
354       if (!KeInsertQueueApc(&Apc,
355                             (PVOID)&Event,
356                             (PVOID)&AStatus,
357                             IO_NO_INCREMENT))
358         {
359           Status = STATUS_THREAD_IS_TERMINATING;
360         }
361       else
362         {
363           Status = KeWaitForSingleObject(&Event,
364                                          0,
365                                          UserMode,
366                                          FALSE,
367                                      NULL);
368           if (NT_SUCCESS(Status) && !NT_SUCCESS(AStatus))
369             {
370               Status = AStatus;
371             }
372         }
373     }
374
375   ObDereferenceObject(Thread);
376   return Status;
377 }
378
379 /* EOF */