branch update for HEAD-2003021201
[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
48 #define NDEBUG
49 #include <internal/debug.h>
50
51 /* FUNCTIONS ***************************************************************/
52
53 VOID
54 KeContextToTrapFrame(PCONTEXT Context,
55                      PKTRAP_FRAME TrapFrame)
56 {
57    if (Context->ContextFlags & CONTEXT_CONTROL)
58      {
59         TrapFrame->Esp = Context->Esp;
60         TrapFrame->Ss = Context->SegSs;
61         TrapFrame->Cs = Context->SegCs;
62         TrapFrame->Eip = Context->Eip;
63         TrapFrame->Eflags = Context->EFlags;    
64         TrapFrame->Ebp = Context->Ebp;
65      }
66    if (Context->ContextFlags & CONTEXT_INTEGER)
67      {
68         TrapFrame->Eax = Context->Eax;
69         TrapFrame->Ebx = Context->Ebx;
70         TrapFrame->Ecx = Context->Ecx;
71         /*
72          * Edx is used in the TrapFrame to hold the old trap frame pointer
73          * so we don't want to overwrite it here
74          */
75 /*      TrapFrame->Edx = Context->Edx; */
76         TrapFrame->Esi = Context->Esi;
77         TrapFrame->Edi = Context->Edi;
78      }
79    if (Context->ContextFlags & CONTEXT_SEGMENTS)
80      {
81         TrapFrame->Ds = Context->SegDs;
82         TrapFrame->Es = Context->SegEs;
83         TrapFrame->Fs = Context->SegFs;
84         TrapFrame->Gs = Context->SegGs;
85      }
86    if (Context->ContextFlags & CONTEXT_FLOATING_POINT)
87      {
88         /*
89          * Not handled
90          */
91      }
92    if (Context->ContextFlags & CONTEXT_DEBUG_REGISTERS)
93      {
94         /*
95          * Not handled
96          */
97      }
98 }
99
100 VOID
101 KeTrapFrameToContext(PKTRAP_FRAME TrapFrame,
102                      PCONTEXT Context)
103 {
104    if (Context->ContextFlags & CONTEXT_CONTROL)
105      {
106         Context->SegSs = TrapFrame->Ss;
107         Context->Esp = TrapFrame->Esp;
108         Context->SegCs = TrapFrame->Cs;
109         Context->Eip = TrapFrame->Eip;
110         Context->EFlags = TrapFrame->Eflags;
111         Context->Ebp = TrapFrame->Ebp;
112      }
113    if (Context->ContextFlags & CONTEXT_INTEGER)
114      {
115         Context->Eax = TrapFrame->Eax;
116         Context->Ebx = TrapFrame->Ebx;
117         Context->Ecx = TrapFrame->Ecx;
118         /*
119          * NOTE: In the trap frame which is built on entry to a system
120          * call TrapFrame->Edx will actually hold the address of the
121          * previous TrapFrame. I don't believe leaking this information
122          * has security implications. Also EDX holds the address of the
123          * arguments to the system call in progress so it isn't of much
124          * interest to the debugger.
125          */
126         Context->Edx = TrapFrame->Edx;
127         Context->Esi = TrapFrame->Esi;
128         Context->Edi = TrapFrame->Edi;
129      }
130    if (Context->ContextFlags & CONTEXT_SEGMENTS)
131      {
132         Context->SegDs = TrapFrame->Ds;
133         Context->SegEs = TrapFrame->Es;
134         Context->SegFs = TrapFrame->Fs;
135         Context->SegGs = TrapFrame->Gs;
136      }
137    if (Context->ContextFlags & CONTEXT_DEBUG_REGISTERS)
138      {
139         /*
140          * FIXME: Implement this case
141          */     
142      }
143    if (Context->ContextFlags & CONTEXT_FLOATING_POINT)
144      {
145         /*
146          * FIXME: Implement this case
147          */
148      }
149 #if 0
150    if (Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS)
151      {
152         /*
153          * FIXME: Investigate this
154          */
155      }
156 #endif
157 }
158
159 VOID STDCALL
160 KeGetContextRundownRoutine(PKAPC Apc)
161 {
162    PKEVENT Event;
163    PNTSTATUS Status;
164    
165    Event = (PKEVENT)Apc->SystemArgument1;
166    Status = (PNTSTATUS)Apc->SystemArgument2;
167    (*Status) = STATUS_THREAD_IS_TERMINATING;
168    KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
169 }
170
171 VOID STDCALL
172 KeGetContextKernelRoutine(PKAPC Apc,
173                           PKNORMAL_ROUTINE* NormalRoutine,
174                           PVOID* NormalContext,
175                           PVOID* SystemArgument1,
176                           PVOID* SystemArgument2)
177 /*
178  * FUNCTION: This routine is called by an APC sent by NtGetContextThread to
179  * copy the context of a thread into a buffer.
180  */
181 {
182    PKEVENT Event;
183    PCONTEXT Context;
184    PNTSTATUS Status;
185    
186    Context = (PCONTEXT)(*NormalContext);
187    Event = (PKEVENT)(*SystemArgument1);
188    Status = (PNTSTATUS)(*SystemArgument2);
189    
190    KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, Context);
191    
192    *Status = STATUS_SUCCESS;
193    KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
194 }
195
196 NTSTATUS STDCALL
197 NtGetContextThread(IN HANDLE ThreadHandle,
198                    OUT PCONTEXT Context)
199 {
200    PETHREAD Thread;
201    NTSTATUS Status;
202    
203    Status = ObReferenceObjectByHandle(ThreadHandle,
204                                       THREAD_GET_CONTEXT,
205                                       PsThreadType,
206                                       UserMode,
207                                       (PVOID*)&Thread,
208                                       NULL);
209    if (!NT_SUCCESS(Status))
210      {
211         return(Status);
212      }
213    if (Thread == PsGetCurrentThread())
214      {
215         /*
216          * I don't know if trying to get your own context makes much
217          * sense but we can handle it more efficently.
218          */
219         
220         KeTrapFrameToContext(Thread->Tcb.TrapFrame, Context);
221         ObDereferenceObject(Thread);
222         return(STATUS_SUCCESS);
223      }
224    else
225      {
226         KAPC Apc;
227         KEVENT Event;
228         NTSTATUS AStatus;
229         CONTEXT KContext;
230         
231         KContext.ContextFlags = Context->ContextFlags;
232         KeInitializeEvent(&Event,
233                           NotificationEvent,
234                           FALSE);       
235         AStatus = STATUS_SUCCESS;
236         
237         KeInitializeApc(&Apc,
238                         &Thread->Tcb,
239                         0,
240                         KeGetContextKernelRoutine,
241                         KeGetContextRundownRoutine,
242                         NULL,
243                         KernelMode,
244                         (PVOID)&KContext);
245         KeInsertQueueApc(&Apc,
246                          (PVOID)&Event,
247                          (PVOID)&AStatus,
248                          0);
249         Status = KeWaitForSingleObject(&Event,
250                                        0,
251                                        UserMode,
252                                        FALSE,
253                                        NULL);
254         if (!NT_SUCCESS(Status))
255           {
256              return(Status);
257           }
258         if (!NT_SUCCESS(AStatus))
259           {
260              return(AStatus);
261           }
262         memcpy(Context, &KContext, sizeof(CONTEXT));
263         ObDereferenceObject(Thread);
264         return(STATUS_SUCCESS);
265      }
266 }
267
268 NTSTATUS STDCALL
269 NtSetContextThread(IN HANDLE ThreadHandle,
270                    IN PCONTEXT Context)
271 {
272    UNIMPLEMENTED;
273 }
274
275 /* EOF */