xref: /reactos/ntoskrnl/ex/dbgctrl.c (revision a3019731)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/ex/dbgctrl.c
5  * PURPOSE:         System debug control
6  * PROGRAMMERS:     Alex Ionescu
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* DATA **********************************************************************/
16 
17 /*
18  * WinDBG Debugger Worker State Machine data
19  */
20 WORK_QUEUE_ITEM ExpDebuggerWorkItem;
21 /*
22  * The following global variables must be visible through all the kernel
23  * because WinDBG explicitely search for them inside our symbols.
24  */
25 WINKD_WORKER_STATE ExpDebuggerWork;
26 PEPROCESS ExpDebuggerProcessAttach;
27 PEPROCESS ExpDebuggerProcessKill;
28 ULONG_PTR ExpDebuggerPageIn;
29 
30 /* FUNCTIONS *****************************************************************/
31 
32 /*
33  * WinDBG Debugger Worker State Machine
34  *
35  * This functionality is used whenever WinDBG wants to attach or kill a user-mode
36  * process from within live kernel-mode session, and/or page-in an address region.
37  * It is implemented as a state machine: when it is in "Ready" state, WinDBG can
38  * initialize the data for the state machine, then switch its state to "Start".
39  * The worker thread balance manager detects this, switches the state to "Initialized"
40  * and queues a worker thread. As long as the state is not "Ready" again, WinDBG
41  * prevents from requeuing a new thread. When the thread is started, it captures
42  * all the data, then resets the machine state to "Ready", thus allowing WinDBG
43  * to requeue another worker thread.
44  *
45  * WinDBG commands:
46  *     .process /i <addr> (where <addr> is the address of the EPROCESS block for this process)
47  *     .kill <addr>       (       "                "                "                "       )
48  *     .pagein <addr>     (where <addr> is the address to page in)
49  */
50 VOID
51 NTAPI
52 ExpDebuggerWorker(
53     _In_ PVOID Context)
54 {
55     PEPROCESS ProcessToAttach, ProcessToKill;
56     ULONG_PTR PageInAddress;
57     PEPROCESS Process;
58     KAPC_STATE ApcState;
59 
60     UNREFERENCED_PARAMETER(Context);
61 
62     /* Be sure we were started in an initialized state */
63     ASSERTMSG("ExpDebuggerWorker being entered in non-initialized state!\n",
64               ExpDebuggerWork == WinKdWorkerInitialized);
65     if (ExpDebuggerWork != WinKdWorkerInitialized)
66     {
67         /* An error happened, so get a chance to restart proper */
68         ExpDebuggerWork = WinKdWorkerReady;
69         return;
70     }
71 
72     /* Get the processes to be attached or killed, and the address to page in */
73     ProcessToAttach = ExpDebuggerProcessAttach;
74     ProcessToKill   = ExpDebuggerProcessKill;
75     PageInAddress   = ExpDebuggerPageIn;
76 
77     /* Reset the state machine to its ready state */
78     ExpDebuggerProcessAttach = NULL;
79     ExpDebuggerProcessKill   = NULL;
80     ExpDebuggerPageIn = (ULONG_PTR)NULL;
81     ExpDebuggerWork = WinKdWorkerReady;
82 
83     /* Default to the current process if we don't find the process to be attached or killed */
84     Process = NULL;
85 
86     /* Check if we need to attach or kill some process */
87     if (ProcessToAttach || ProcessToKill)
88     {
89         /* Find the process in the list */
90         while ((Process = PsGetNextProcess(Process)))
91         {
92             /* Is this the process we want to attach to? */
93             if (Process == ProcessToAttach)
94             {
95                 /* Yes, attach ourselves to it */
96                 KeStackAttachProcess(&Process->Pcb, &ApcState);
97                 break;
98             }
99             /* Or is this the process we want to kill? */
100             else if (Process == ProcessToKill)
101             {
102                 /* Yes, kill and dereference it, then return */
103                 PsTerminateProcess(Process, DBG_TERMINATE_PROCESS);
104                 ObDereferenceObject(Process);
105                 return;
106             }
107         }
108 
109         if (!Process)
110         {
111             DbgPrintEx(DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL,
112                        "EX debug work: Unable to find process %p\n",
113                        ProcessToAttach ? ProcessToAttach : ProcessToKill);
114         }
115 
116         /* We either have found a process, or we default to the current one */
117     }
118 
119     /* If we have an address to page in... */
120     if (PageInAddress)
121     {
122         /* ... try to do it by attempting to read at this address */
123         _SEH2_TRY
124         {
125             ProbeForReadUchar(PageInAddress);
126         }
127         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
128         {
129             DbgPrintEx(DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL,
130                        "EX page in: Failed to page-in address 0x%p, Status 0x%08lx\n",
131                        PageInAddress, _SEH2_GetExceptionCode());
132         }
133         _SEH2_END;
134     }
135 
136     /* Break into the process (or the current one if Process == NULL) */
137     DbgBreakPointWithStatus(DBG_STATUS_WORKER);
138 
139     /* If we are attached to a process, not the current one... */
140     if (Process)
141     {
142         /* ... we can detach from the process */
143         KeUnstackDetachProcess(&ApcState);
144         /* Dereference the process referenced by PsGetNextProcess() */
145         ObDereferenceObject(Process);
146     }
147 }
148 
149 /*++
150  * @name NtSystemDebugControl
151  * @implemented
152  *
153  * Perform various queries to debugger.
154  * This API is subject to test-case creation to further evaluate its
155  * abilities (if needed to at all)
156  *
157  * See: http://www.osronline.com/showthread.cfm?link=93915
158  *      http://void.ru/files/Ntexapi.h
159  *      http://www.codeguru.com/code/legacy/system/ntexapi.zip
160  *      http://www.securityfocus.com/bid/9694
161  *
162  * @param ControlCode
163  *        Description of the parameter. Wrapped to more lines on ~70th
164  *        column.
165  *
166  * @param InputBuffer
167  *        FILLME
168  *
169  * @param InputBufferLength
170  *        FILLME
171  *
172  * @param OutputBuffer
173  *        FILLME
174  *
175  * @param OutputBufferLength
176  *        FILLME
177  *
178   * @param ReturnLength
179  *        FILLME
180  *
181  * @return STATUS_SUCCESS in case of success, proper error code otherwise
182  *
183  * @remarks None
184  *
185  *--*/
186 NTSTATUS
187 NTAPI
188 NtSystemDebugControl(SYSDBG_COMMAND ControlCode,
189                      PVOID InputBuffer,
190                      ULONG InputBufferLength,
191                      PVOID OutputBuffer,
192                      ULONG OutputBufferLength,
193                      PULONG ReturnLength)
194 {
195     switch (ControlCode)
196     {
197         case SysDbgQueryModuleInformation:
198         case SysDbgQueryTraceInformation:
199         case SysDbgSetTracepoint:
200         case SysDbgSetSpecialCall:
201         case SysDbgClearSpecialCalls:
202         case SysDbgQuerySpecialCalls:
203         case SysDbgQueryVersion:
204         case SysDbgReadVirtual:
205         case SysDbgWriteVirtual:
206         case SysDbgReadPhysical:
207         case SysDbgWritePhysical:
208         case SysDbgReadControlSpace:
209         case SysDbgWriteControlSpace:
210         case SysDbgReadIoSpace:
211         case SysDbgWriteIoSpace:
212         case SysDbgReadMsr:
213         case SysDbgWriteMsr:
214         case SysDbgReadBusData:
215         case SysDbgWriteBusData:
216         case SysDbgCheckLowMemory:
217         case SysDbgGetTriageDump:
218             return STATUS_NOT_IMPLEMENTED;
219         case SysDbgBreakPoint:
220         case SysDbgEnableKernelDebugger:
221         case SysDbgDisableKernelDebugger:
222         case SysDbgGetAutoKdEnable:
223         case SysDbgSetAutoKdEnable:
224         case SysDbgGetPrintBufferSize:
225         case SysDbgSetPrintBufferSize:
226         case SysDbgGetKdUmExceptionEnable:
227         case SysDbgSetKdUmExceptionEnable:
228         case SysDbgGetKdBlockEnable:
229         case SysDbgSetKdBlockEnable:
230             return KdSystemDebugControl(
231                 ControlCode,
232                 InputBuffer, InputBufferLength,
233                 OutputBuffer, OutputBufferLength,
234                 ReturnLength, KeGetPreviousMode());
235         default:
236             return STATUS_INVALID_INFO_CLASS;
237     }
238 }
239