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