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 #endif /* not KDBG */ 281 282 /* Debugger didn't handle it, please handle! */ 283 if (Return == kdHandleException) return FALSE; 284 285 /* Debugger handled it */ 286 return TRUE; 287 } 288 289 BOOLEAN 290 NTAPI 291 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord, 292 IN PCONTEXT Context, 293 IN KPROCESSOR_MODE PreviousMode) 294 { 295 /* KDBG has its own mechanism for ignoring user mode exceptions */ 296 return FALSE; 297 } 298 299 /* PUBLIC FUNCTIONS *********************************************************/ 300 301 VOID 302 NTAPI 303 KdUpdateDataBlock(VOID) 304 { 305 } 306 307 BOOLEAN 308 NTAPI 309 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame, 310 IN PKEXCEPTION_FRAME ExceptionFrame) 311 { 312 return FALSE; 313 } 314 315 VOID 316 NTAPI 317 KdExitDebugger(IN BOOLEAN Enable) 318 { 319 } 320 321 /* 322 * @implemented 323 */ 324 BOOLEAN 325 NTAPI 326 KdRefreshDebuggerNotPresent(VOID) 327 { 328 UNIMPLEMENTED; 329 330 /* Just return whatever was set previously -- FIXME! */ 331 return KdDebuggerNotPresent; 332 } 333 334 /* 335 * @implemented 336 */ 337 NTSTATUS 338 NTAPI 339 KdDisableDebugger(VOID) 340 { 341 KIRQL OldIrql; 342 343 /* Raise IRQL */ 344 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 345 346 /* TODO: Disable any breakpoints */ 347 348 /* Disable the Debugger */ 349 KdDebuggerEnabled = FALSE; 350 SharedUserData->KdDebuggerEnabled = FALSE; 351 352 /* Lower the IRQL */ 353 KeLowerIrql(OldIrql); 354 355 /* Return success */ 356 return STATUS_SUCCESS; 357 } 358 359 NTSTATUS 360 NTAPI 361 KdEnableDebuggerWithLock(IN BOOLEAN NeedLock) 362 { 363 return STATUS_ACCESS_DENIED; 364 } 365 366 /* 367 * @implemented 368 */ 369 NTSTATUS 370 NTAPI 371 KdEnableDebugger(VOID) 372 { 373 KIRQL OldIrql; 374 375 /* Raise IRQL */ 376 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 377 378 /* TODO: Re-enable any breakpoints */ 379 380 /* Enable the Debugger */ 381 KdDebuggerEnabled = TRUE; 382 SharedUserData->KdDebuggerEnabled = TRUE; 383 384 /* Lower the IRQL */ 385 KeLowerIrql(OldIrql); 386 387 /* Return success */ 388 return STATUS_SUCCESS; 389 } 390 391 /* 392 * @implemented 393 */ 394 BOOLEAN 395 NTAPI 396 KdPollBreakIn(VOID) 397 { 398 return FALSE; 399 } 400 401 /* 402 * @unimplemented 403 */ 404 NTSTATUS 405 NTAPI 406 KdPowerTransition(ULONG PowerState) 407 { 408 UNIMPLEMENTED; 409 return STATUS_NOT_IMPLEMENTED; 410 } 411 412 /* 413 * @unimplemented 414 */ 415 NTSTATUS 416 NTAPI 417 KdChangeOption(IN KD_OPTION Option, 418 IN ULONG InBufferLength OPTIONAL, 419 IN PVOID InBuffer, 420 IN ULONG OutBufferLength OPTIONAL, 421 OUT PVOID OutBuffer, 422 OUT PULONG OutBufferRequiredLength OPTIONAL) 423 { 424 UNIMPLEMENTED; 425 return STATUS_NOT_IMPLEMENTED; 426 } 427 428 /* 429 * @unimplemented 430 */ 431 NTSTATUS 432 NTAPI 433 KdSystemDebugControl(IN SYSDBG_COMMAND Command, 434 IN PVOID InputBuffer, 435 IN ULONG InputBufferLength, 436 OUT PVOID OutputBuffer, 437 IN ULONG OutputBufferLength, 438 IN OUT PULONG ReturnLength, 439 IN KPROCESSOR_MODE PreviousMode) 440 { 441 /* HACK */ 442 return KdpServiceDispatcher(Command, 443 InputBuffer, 444 InputBufferLength, 445 PreviousMode); 446 } 447 448 PKDEBUG_ROUTINE KiDebugRoutine = KdpEnterDebuggerException; 449 450 /* EOF */ 451