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