BOOLEAN NTAPI KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT Context, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN SecondChance) { KD_CONTINUE_TYPE Return = kdHandleException; ULONG ExceptionCommand = ExceptionRecord->ExceptionInformation[0]; /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */ if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) && (ExceptionRecord->NumberParameters > 0) && ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) || (ExceptionCommand == BREAKPOINT_UNLOAD_SYMBOLS) || (ExceptionCommand == BREAKPOINT_COMMAND_STRING) || (ExceptionCommand == BREAKPOINT_PRINT) || (ExceptionCommand == BREAKPOINT_PROMPT))) { /* Check if this is a debug print */ if (ExceptionCommand == BREAKPOINT_PRINT) { /* Print the string */ KdpServiceDispatcher(BREAKPOINT_PRINT, (PVOID)ExceptionRecord->ExceptionInformation[1], ExceptionRecord->ExceptionInformation[2]); /* Return success */ KeSetContextReturnRegister(Context, STATUS_SUCCESS); } #ifdef KDBG else if (ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) { PLDR_DATA_TABLE_ENTRY LdrEntry; /* Load symbols. Currently implemented only for KDBG! */ if(KdbpSymFindModule(((PKD_SYMBOLS_INFO)ExceptionRecord->ExceptionInformation[2])->BaseOfDll, NULL, -1, &LdrEntry)) KdbSymProcessSymbols(LdrEntry); } else if (ExceptionCommand == BREAKPOINT_PROMPT) { ULONG ReturnValue; LPSTR OutString; USHORT OutStringLength; /* Get the response string and length */ OutString = (LPSTR)Context->Ebx; OutStringLength = (USHORT)Context->Edi; /* Call KDBG */ ReturnValue = KdpPrompt((LPSTR)ExceptionRecord-> ExceptionInformation[1], (USHORT)ExceptionRecord-> ExceptionInformation[2], OutString, OutStringLength); /* Return the number of characters that we received */ Context->Eax = ReturnValue; } #endif /* This we can handle: simply bump the Program Counter */ KeSetContextPc(Context, KeGetContextPc(Context) + KD_BREAKPOINT_SIZE); return TRUE; } #ifdef KDBG /* Check if this is an assertion failure */ if (ExceptionRecord->ExceptionCode == STATUS_ASSERTION_FAILURE) { /* Bump EIP to the instruction following the int 2C */ Context->Eip += 2; } #endif /* Get out of here if the Debugger isn't connected */ if (KdDebuggerNotPresent) return FALSE; #ifdef KDBG /* Call KDBG if available */ Return = KdbEnterDebuggerException(ExceptionRecord, PreviousMode, Context, TrapFrame, !SecondChance); #else /* not KDBG */ if (WrapperInitRoutine) { /* Call GDB */ Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord, Context, TrapFrame); } #endif /* not KDBG */ /* Debugger didn't handle it, please handle! */ if (Return == kdHandleException) return FALSE; /* Debugger handled it */ return TRUE; }
BOOLEAN NTAPI KdpTrap(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN SecondChanceException) { BOOLEAN Unload = FALSE; ULONG_PTR ProgramCounter; BOOLEAN Handled; NTSTATUS ReturnStatus; USHORT ReturnLength; /* * Check if we got a STATUS_BREAKPOINT with a SubID for Print, Prompt or * Load/Unload symbols. Make sure it isn't a software breakpoints as those * are handled by KdpReport. */ if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) && (ExceptionRecord->ExceptionInformation[0] != BREAKPOINT_BREAK)) { /* Save Program Counter */ ProgramCounter = KeGetContextPc(ContextRecord); /* Check what kind of operation was requested from us */ switch (ExceptionRecord->ExceptionInformation[0]) { /* DbgPrint */ case BREAKPOINT_PRINT: /* Call the worker routine */ ReturnStatus = KdpPrint((ULONG)KdpGetParameterThree(ContextRecord), (ULONG)KdpGetParameterFour(ContextRecord), (LPSTR)ExceptionRecord-> ExceptionInformation[1], (USHORT)ExceptionRecord-> ExceptionInformation[2], PreviousMode, TrapFrame, ExceptionFrame, &Handled); /* Update the return value for the caller */ KeSetContextReturnRegister(ContextRecord, ReturnStatus); break; /* DbgPrompt */ case BREAKPOINT_PROMPT: /* Call the worker routine */ ReturnLength = KdpPrompt((LPSTR)ExceptionRecord-> ExceptionInformation[1], (USHORT)ExceptionRecord-> ExceptionInformation[2], (LPSTR)KdpGetParameterThree(ContextRecord), (USHORT)KdpGetParameterFour(ContextRecord), PreviousMode, TrapFrame, ExceptionFrame); Handled = TRUE; /* Update the return value for the caller */ KeSetContextReturnRegister(ContextRecord, ReturnLength); break; /* DbgUnLoadImageSymbols */ case BREAKPOINT_UNLOAD_SYMBOLS: /* Drop into the load case below, with the unload parameter */ Unload = TRUE; /* DbgLoadImageSymbols */ case BREAKPOINT_LOAD_SYMBOLS: /* Call the worker routine */ KdpSymbol((PSTRING)ExceptionRecord-> ExceptionInformation[1], (PKD_SYMBOLS_INFO)ExceptionRecord-> ExceptionInformation[2], Unload, PreviousMode, ContextRecord, TrapFrame, ExceptionFrame); Handled = TRUE; break; /* DbgCommandString */ case BREAKPOINT_COMMAND_STRING: /* Call the worker routine */ KdpCommandString((PSTRING)ExceptionRecord-> ExceptionInformation[1], (PSTRING)ExceptionRecord-> ExceptionInformation[2], PreviousMode, ContextRecord, TrapFrame, ExceptionFrame); Handled = TRUE; break; /* Anything else, do nothing */ default: /* Invalid debug service! Don't handle this! */ Handled = FALSE; break; } /* * If the PC was not updated, we'll increment it ourselves so execution * continues past the breakpoint. */ if (ProgramCounter == KeGetContextPc(ContextRecord)) { /* Update it */ KeSetContextPc(ContextRecord, ProgramCounter + KD_BREAKPOINT_SIZE); } } else { /* Call the worker routine */ Handled = KdpReport(TrapFrame, ExceptionFrame, ExceptionRecord, ContextRecord, PreviousMode, SecondChanceException); } /* Return TRUE or FALSE to caller */ return Handled; }