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