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(IN PVOID Context) 53 { 54 PEPROCESS ProcessToAttach, ProcessToKill; 55 ULONG_PTR PageInAddress; 56 PEPROCESS Process; 57 KAPC_STATE ApcState; 58 59 UNREFERENCED_PARAMETER(Context); 60 61 /* Be sure we were started in an initialized state */ 62 ASSERTMSG("ExpDebuggerWorker being entered in non-initialized state!\n", 63 ExpDebuggerWork == WinKdWorkerInitialized); 64 if (ExpDebuggerWork != WinKdWorkerInitialized) 65 { 66 /* An error happened, so get a chance to restart proper */ 67 ExpDebuggerWork = WinKdWorkerReady; 68 return; 69 } 70 71 /* Get the processes to be attached or killed, and the address to page in */ 72 ProcessToAttach = ExpDebuggerProcessAttach; 73 ProcessToKill = ExpDebuggerProcessKill; 74 PageInAddress = ExpDebuggerPageIn; 75 76 /* Reset the state machine to its ready state */ 77 ExpDebuggerProcessAttach = NULL; 78 ExpDebuggerProcessKill = NULL; 79 ExpDebuggerPageIn = (ULONG_PTR)NULL; 80 ExpDebuggerWork = WinKdWorkerReady; 81 82 /* Default to the current process if we don't find the process to be attached or killed */ 83 Process = NULL; 84 85 /* Check if we need to attach or kill some process */ 86 if (ProcessToAttach != NULL || ProcessToKill != NULL) 87 { 88 /* Find the process in the list */ 89 Process = PsGetNextProcess(Process); 90 while (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 /* Get the next process */ 109 Process = PsGetNextProcess(Process); 110 } 111 112 /* We either have found a process, or we default to the current process */ 113 } 114 115 /* If we have an address to page in... */ 116 if (PageInAddress) 117 { 118 /* ... try to do it by attempting to read at this address */ 119 _SEH2_TRY 120 { 121 ProbeForReadUchar(PageInAddress); 122 } 123 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 124 { 125 DPRINT1("Failed to page in address 0x%p, Status 0x%08lx\n", PageInAddress, _SEH2_GetExceptionCode()); 126 } 127 _SEH2_END; 128 } 129 130 /* Break into the process (or the current one if Process == NULL) */ 131 DbgBreakPointWithStatus(DBG_STATUS_WORKER); 132 133 /* If we are attached to a process, not the current one... */ 134 if (Process) 135 { 136 /* ... we can detach from the process */ 137 KeUnstackDetachProcess(&ApcState); 138 /* Dereference the process which was referenced for us by PsGetNextProcess */ 139 ObDereferenceObject(Process); 140 } 141 } 142 143 /*++ 144 * @name NtSystemDebugControl 145 * @implemented 146 * 147 * Perform various queries to debugger. 148 * This API is subject to test-case creation to further evaluate its 149 * abilities (if needed to at all) 150 * 151 * See: http://www.osronline.com/showthread.cfm?link=93915 152 * http://void.ru/files/Ntexapi.h 153 * http://www.codeguru.com/code/legacy/system/ntexapi.zip 154 * http://www.securityfocus.com/bid/9694 155 * 156 * @param ControlCode 157 * Description of the parameter. Wrapped to more lines on ~70th 158 * column. 159 * 160 * @param InputBuffer 161 * FILLME 162 * 163 * @param InputBufferLength 164 * FILLME 165 * 166 * @param OutputBuffer 167 * FILLME 168 * 169 * @param OutputBufferLength 170 * FILLME 171 * 172 * @param ReturnLength 173 * FILLME 174 * 175 * @return STATUS_SUCCESS in case of success, proper error code otherwise 176 * 177 * @remarks None 178 * 179 *--*/ 180 NTSTATUS 181 NTAPI 182 NtSystemDebugControl(SYSDBG_COMMAND ControlCode, 183 PVOID InputBuffer, 184 ULONG InputBufferLength, 185 PVOID OutputBuffer, 186 ULONG OutputBufferLength, 187 PULONG ReturnLength) 188 { 189 switch (ControlCode) 190 { 191 case SysDbgQueryModuleInformation: 192 case SysDbgQueryTraceInformation: 193 case SysDbgSetTracepoint: 194 case SysDbgSetSpecialCall: 195 case SysDbgClearSpecialCalls: 196 case SysDbgQuerySpecialCalls: 197 case SysDbgQueryVersion: 198 case SysDbgReadVirtual: 199 case SysDbgWriteVirtual: 200 case SysDbgReadPhysical: 201 case SysDbgWritePhysical: 202 case SysDbgReadControlSpace: 203 case SysDbgWriteControlSpace: 204 case SysDbgReadIoSpace: 205 case SysDbgWriteIoSpace: 206 case SysDbgReadMsr: 207 case SysDbgWriteMsr: 208 case SysDbgReadBusData: 209 case SysDbgWriteBusData: 210 case SysDbgCheckLowMemory: 211 case SysDbgGetTriageDump: 212 return STATUS_NOT_IMPLEMENTED; 213 case SysDbgBreakPoint: 214 case SysDbgEnableKernelDebugger: 215 case SysDbgDisableKernelDebugger: 216 case SysDbgGetAutoKdEnable: 217 case SysDbgSetAutoKdEnable: 218 case SysDbgGetPrintBufferSize: 219 case SysDbgSetPrintBufferSize: 220 case SysDbgGetKdUmExceptionEnable: 221 case SysDbgSetKdUmExceptionEnable: 222 case SysDbgGetKdBlockEnable: 223 case SysDbgSetKdBlockEnable: 224 return KdSystemDebugControl( 225 ControlCode, 226 InputBuffer, InputBufferLength, 227 OutputBuffer, OutputBufferLength, 228 ReturnLength, KeGetPreviousMode()); 229 default: 230 return STATUS_INVALID_INFO_CLASS; 231 } 232 } 233