1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel 4 * FILE: ntoskrnl/kd/kdmain.c 5 * PURPOSE: Kernel Debugger Initialization 6 * 7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 8 */ 9 10 #include <ntoskrnl.h> 11 #define NDEBUG 12 #include <debug.h> 13 14 // 15 // Retrieves the ComponentId and Level for BREAKPOINT_PRINT 16 // and OutputString and OutputStringLength for BREAKPOINT_PROMPT. 17 // 18 #if defined(_X86_) 19 20 // 21 // EBX/EDI on x86 22 // 23 #define KdpGetParameterThree(Context) ((Context)->Ebx) 24 #define KdpGetParameterFour(Context) ((Context)->Edi) 25 26 #elif defined(_AMD64_) 27 28 // 29 // R8/R9 on AMD64 30 // 31 #define KdpGetParameterThree(Context) ((Context)->R8) 32 #define KdpGetParameterFour(Context) ((Context)->R9) 33 34 #elif defined(_ARM_) 35 36 // 37 // R3/R4 on ARM 38 // 39 #define KdpGetParameterThree(Context) ((Context)->R3) 40 #define KdpGetParameterFour(Context) ((Context)->R4) 41 42 #else 43 #error Unsupported Architecture 44 #endif 45 46 /* VARIABLES ***************************************************************/ 47 48 BOOLEAN KdDebuggerEnabled = FALSE; 49 BOOLEAN KdEnteredDebugger = FALSE; 50 BOOLEAN KdDebuggerNotPresent = TRUE; 51 BOOLEAN KdBreakAfterSymbolLoad = FALSE; 52 BOOLEAN KdPitchDebugger = TRUE; 53 BOOLEAN KdIgnoreUmExceptions = FALSE; 54 55 VOID NTAPI PspDumpThreads(BOOLEAN SystemThreads); 56 57 #if 0 58 ULONG Kd_DEFAULT_MASK = 1 << DPFLTR_ERROR_LEVEL; 59 #endif 60 61 /* PRIVATE FUNCTIONS *********************************************************/ 62 63 ULONG 64 NTAPI 65 KdpServiceDispatcher(ULONG Service, 66 PVOID Buffer1, 67 ULONG Buffer1Length, 68 KPROCESSOR_MODE PreviousMode) 69 { 70 ULONG Result = 0; 71 72 switch (Service) 73 { 74 case BREAKPOINT_PRINT: /* DbgPrint */ 75 { 76 /* Call KDBG */ 77 BOOLEAN Handled; 78 Result = KdpPrint(MAXULONG, 79 DPFLTR_INFO_LEVEL, 80 (PCHAR)Buffer1, 81 (USHORT)Buffer1Length, 82 PreviousMode, 83 NULL, // TrapFrame, 84 NULL, // ExceptionFrame, 85 &Handled); 86 break; 87 } 88 89 #if DBG 90 case ' soR': /* ROS-INTERNAL */ 91 { 92 switch ((ULONG_PTR)Buffer1) 93 { 94 case DumpAllThreads: 95 PspDumpThreads(TRUE); 96 break; 97 98 case DumpUserThreads: 99 PspDumpThreads(FALSE); 100 break; 101 102 case KdSpare3: 103 MmDumpArmPfnDatabase(FALSE); 104 break; 105 106 default: 107 break; 108 } 109 break; 110 } 111 112 #if defined(_M_IX86) && !defined(_WINKD_) // See ke/i386/traphdlr.c 113 /* Register a debug callback */ 114 case 'CsoR': 115 { 116 switch (Buffer1Length) 117 { 118 case ID_Win32PreServiceHook: 119 KeWin32PreServiceHook = Buffer1; 120 break; 121 122 case ID_Win32PostServiceHook: 123 KeWin32PostServiceHook = Buffer1; 124 break; 125 126 } 127 break; 128 } 129 #endif 130 131 /* Special case for stack frame dumps */ 132 case 'DsoR': 133 { 134 KeRosDumpStackFrames((PULONG_PTR)Buffer1, Buffer1Length); 135 break; 136 } 137 138 #if defined(KDBG) 139 /* Register KDBG CLI callback */ 140 case 'RbdK': 141 { 142 Result = KdbRegisterCliCallback(Buffer1, Buffer1Length); 143 break; 144 } 145 #endif /* KDBG */ 146 #endif /* DBG */ 147 default: 148 DPRINT1("Invalid debug service call!\n"); 149 HalDisplayString("Invalid debug service call!\r\n"); 150 break; 151 } 152 153 return Result; 154 } 155 156 BOOLEAN 157 NTAPI 158 KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame, 159 IN PKEXCEPTION_FRAME ExceptionFrame, 160 IN PEXCEPTION_RECORD ExceptionRecord, 161 IN PCONTEXT Context, 162 IN KPROCESSOR_MODE PreviousMode, 163 IN BOOLEAN SecondChance) 164 { 165 KD_CONTINUE_TYPE Return = kdHandleException; 166 ULONG ExceptionCommand = ExceptionRecord->ExceptionInformation[0]; 167 168 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */ 169 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) && 170 (ExceptionRecord->NumberParameters > 0) && 171 ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) || 172 (ExceptionCommand == BREAKPOINT_UNLOAD_SYMBOLS) || 173 (ExceptionCommand == BREAKPOINT_COMMAND_STRING) || 174 (ExceptionCommand == BREAKPOINT_PRINT) || 175 (ExceptionCommand == BREAKPOINT_PROMPT))) 176 { 177 /* Check if this is a debug print */ 178 if (ExceptionCommand == BREAKPOINT_PRINT) 179 { 180 /* Call KDBG */ 181 NTSTATUS ReturnStatus; 182 BOOLEAN Handled; 183 ReturnStatus = KdpPrint((ULONG)KdpGetParameterThree(Context), 184 (ULONG)KdpGetParameterFour(Context), 185 (PCHAR)ExceptionRecord->ExceptionInformation[1], 186 (USHORT)ExceptionRecord->ExceptionInformation[2], 187 PreviousMode, 188 TrapFrame, 189 ExceptionFrame, 190 &Handled); 191 192 /* Update the return value for the caller */ 193 KeSetContextReturnRegister(Context, ReturnStatus); 194 } 195 #ifdef KDBG 196 else if (ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) 197 { 198 PKD_SYMBOLS_INFO SymbolsInfo; 199 KD_SYMBOLS_INFO CapturedSymbolsInfo; 200 PLDR_DATA_TABLE_ENTRY LdrEntry; 201 202 SymbolsInfo = (PKD_SYMBOLS_INFO)ExceptionRecord->ExceptionInformation[2]; 203 if (PreviousMode != KernelMode) 204 { 205 _SEH2_TRY 206 { 207 ProbeForRead(SymbolsInfo, 208 sizeof(*SymbolsInfo), 209 1); 210 KdpMoveMemory(&CapturedSymbolsInfo, 211 SymbolsInfo, 212 sizeof(*SymbolsInfo)); 213 SymbolsInfo = &CapturedSymbolsInfo; 214 } 215 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 216 { 217 SymbolsInfo = NULL; 218 } 219 _SEH2_END; 220 } 221 222 if (SymbolsInfo != NULL) 223 { 224 /* Load symbols. Currently implemented only for KDBG! */ 225 if (KdbpSymFindModule(SymbolsInfo->BaseOfDll, NULL, -1, &LdrEntry)) 226 { 227 KdbSymProcessSymbols(LdrEntry); 228 } 229 } 230 } 231 else if (ExceptionCommand == BREAKPOINT_PROMPT) 232 { 233 /* Call KDBG */ 234 ULONG ReturnLength; 235 ReturnLength = KdpPrompt((PCHAR)ExceptionRecord->ExceptionInformation[1], 236 (USHORT)ExceptionRecord->ExceptionInformation[2], 237 (PCHAR)KdpGetParameterThree(Context), 238 (USHORT)KdpGetParameterFour(Context), 239 PreviousMode, 240 TrapFrame, 241 ExceptionFrame); 242 243 /* Update the return value for the caller */ 244 KeSetContextReturnRegister(Context, ReturnLength); 245 } 246 #endif 247 248 /* This we can handle: simply bump the Program Counter */ 249 KeSetContextPc(Context, KeGetContextPc(Context) + KD_BREAKPOINT_SIZE); 250 return TRUE; 251 } 252 253 #ifdef KDBG 254 /* Check if this is an assertion failure */ 255 if (ExceptionRecord->ExceptionCode == STATUS_ASSERTION_FAILURE) 256 { 257 /* Bump EIP to the instruction following the int 2C */ 258 Context->Eip += 2; 259 } 260 #endif 261 262 /* Get out of here if the Debugger isn't connected */ 263 if (KdDebuggerNotPresent) return FALSE; 264 265 #ifdef KDBG 266 /* Call KDBG if available */ 267 Return = KdbEnterDebuggerException(ExceptionRecord, 268 PreviousMode, 269 Context, 270 TrapFrame, 271 !SecondChance); 272 #else /* not KDBG */ 273 if (WrapperInitRoutine) 274 { 275 /* Call GDB */ 276 Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord, 277 Context, 278 TrapFrame); 279 } 280 281 /* We'll manually dump the stack for the user... */ 282 KeRosDumpStackFrames(NULL, 0); 283 #endif /* not KDBG */ 284 285 /* Debugger didn't handle it, please handle! */ 286 if (Return == kdHandleException) return FALSE; 287 288 /* Debugger handled it */ 289 return TRUE; 290 } 291 292 BOOLEAN 293 NTAPI 294 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord, 295 IN PCONTEXT Context, 296 IN KPROCESSOR_MODE PreviousMode) 297 { 298 /* KDBG has its own mechanism for ignoring user mode exceptions */ 299 return FALSE; 300 } 301 302 /* PUBLIC FUNCTIONS *********************************************************/ 303 304 VOID 305 NTAPI 306 KdUpdateDataBlock(VOID) 307 { 308 } 309 310 BOOLEAN 311 NTAPI 312 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame, 313 IN PKEXCEPTION_FRAME ExceptionFrame) 314 { 315 return FALSE; 316 } 317 318 VOID 319 NTAPI 320 KdExitDebugger(IN BOOLEAN Enable) 321 { 322 } 323 324 /* 325 * @implemented 326 */ 327 BOOLEAN 328 NTAPI 329 KdRefreshDebuggerNotPresent(VOID) 330 { 331 UNIMPLEMENTED; 332 333 /* Just return whatever was set previously -- FIXME! */ 334 return KdDebuggerNotPresent; 335 } 336 337 /* 338 * @implemented 339 */ 340 NTSTATUS 341 NTAPI 342 KdDisableDebugger(VOID) 343 { 344 KIRQL OldIrql; 345 346 /* Raise IRQL */ 347 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 348 349 /* TODO: Disable any breakpoints */ 350 351 /* Disable the Debugger */ 352 KdDebuggerEnabled = FALSE; 353 SharedUserData->KdDebuggerEnabled = FALSE; 354 355 /* Lower the IRQL */ 356 KeLowerIrql(OldIrql); 357 358 /* Return success */ 359 return STATUS_SUCCESS; 360 } 361 362 NTSTATUS 363 NTAPI 364 KdEnableDebuggerWithLock(IN BOOLEAN NeedLock) 365 { 366 return STATUS_ACCESS_DENIED; 367 } 368 369 /* 370 * @implemented 371 */ 372 NTSTATUS 373 NTAPI 374 KdEnableDebugger(VOID) 375 { 376 KIRQL OldIrql; 377 378 /* Raise IRQL */ 379 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 380 381 /* TODO: Re-enable any breakpoints */ 382 383 /* Enable the Debugger */ 384 KdDebuggerEnabled = TRUE; 385 SharedUserData->KdDebuggerEnabled = TRUE; 386 387 /* Lower the IRQL */ 388 KeLowerIrql(OldIrql); 389 390 /* Return success */ 391 return STATUS_SUCCESS; 392 } 393 394 /* 395 * @implemented 396 */ 397 BOOLEAN 398 NTAPI 399 KdPollBreakIn(VOID) 400 { 401 return FALSE; 402 } 403 404 /* 405 * @unimplemented 406 */ 407 NTSTATUS 408 NTAPI 409 KdPowerTransition(ULONG PowerState) 410 { 411 UNIMPLEMENTED; 412 return STATUS_NOT_IMPLEMENTED; 413 } 414 415 /* 416 * @unimplemented 417 */ 418 NTSTATUS 419 NTAPI 420 KdChangeOption(IN KD_OPTION Option, 421 IN ULONG InBufferLength OPTIONAL, 422 IN PVOID InBuffer, 423 IN ULONG OutBufferLength OPTIONAL, 424 OUT PVOID OutBuffer, 425 OUT PULONG OutBufferRequiredLength OPTIONAL) 426 { 427 UNIMPLEMENTED; 428 return STATUS_NOT_IMPLEMENTED; 429 } 430 431 /* 432 * @unimplemented 433 */ 434 NTSTATUS 435 NTAPI 436 KdSystemDebugControl(IN SYSDBG_COMMAND Command, 437 IN PVOID InputBuffer, 438 IN ULONG InputBufferLength, 439 OUT PVOID OutputBuffer, 440 IN ULONG OutputBufferLength, 441 IN OUT PULONG ReturnLength, 442 IN KPROCESSOR_MODE PreviousMode) 443 { 444 /* HACK */ 445 return KdpServiceDispatcher(Command, 446 InputBuffer, 447 InputBufferLength, 448 PreviousMode); 449 } 450 451 PKDEBUG_ROUTINE KiDebugRoutine = KdpEnterDebuggerException; 452 453 /* EOF */ 454