You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
614 lines
16 KiB
614 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 2000-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
print.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the common code to filter and print debug
|
|
messages.
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 12-Jan-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "kdp.h"
|
|
#pragma hdrstop
|
|
#include <malloc.h>
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGEKD, KdpPrint)
|
|
#pragma alloc_text(PAGEKD, KdpPrompt)
|
|
#pragma alloc_text(PAGEKD, KdpSymbol)
|
|
#pragma alloc_text(PAGEKD, KdpCommandString)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
extern PWD_HANDLER ExpWdHandler;
|
|
extern PVOID ExpWdHandlerContext;
|
|
|
|
#if 0
|
|
ULONG gLdrHits;
|
|
#endif
|
|
|
|
NTSTATUS
|
|
KdpPrint(
|
|
IN ULONG ComponentId,
|
|
IN ULONG Level,
|
|
IN PCHAR Message,
|
|
IN USHORT Length,
|
|
IN KPROCESSOR_MODE PreviousMode,
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
|
OUT PBOOLEAN Completion
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function filters debug print requests, probes and saves user mode
|
|
message buffers on the stack, logs the print message, and prints the
|
|
message on the debug terminal if apprpriate.
|
|
|
|
Arguments:
|
|
|
|
ComponentId - Supplies the component id of the component that issued
|
|
the debug print.
|
|
|
|
Level - Supplies the debug filer level number or mask.
|
|
|
|
Message - Supplies a pointer to the output message.
|
|
|
|
Length - Supplies the length of the output message.
|
|
|
|
PreviousMode - Supplies the previous processor mode.
|
|
|
|
TrapFrame - Supplies a pointer to a trap frame.
|
|
|
|
ExceptionFrame - Supplies a pointer to a exception.
|
|
|
|
Completion - Supplies a pointer to the variable that receives the
|
|
debug print completion status.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Is returned if the debug print is filtered or is
|
|
successfully printed.
|
|
|
|
STATUS_BREAKPOINT - Is returned if ...
|
|
|
|
STATUS_DEVICE_NOT_CONNECTED - Is returned if the kernel debugger is
|
|
not enabled and the debug print message was not filtered.
|
|
|
|
STATUS_ACCESS_VIOLATION - Is returned if an access violation occurs
|
|
while attempting to copy a user mode buffer to the kernel stack.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PCHAR Buffer;
|
|
BOOLEAN Enable;
|
|
ULONG Mask;
|
|
STRING Output;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// If the the component id if out of range or output is enabled for the
|
|
// specified filter level, then attempt to print the output. Otherwise,
|
|
// immediately return success.
|
|
//
|
|
|
|
*Completion = FALSE;
|
|
if (Level > 31) {
|
|
Mask = Level;
|
|
|
|
} else {
|
|
Mask = 1 << Level;
|
|
}
|
|
|
|
if (((Mask & Kd_WIN2000_Mask) == 0) &&
|
|
(ComponentId < KdComponentTableSize) &&
|
|
((Mask & *KdComponentTable[ComponentId]) == 0)) {
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Limit the message length to 512 bytes.
|
|
//
|
|
|
|
if (Length > 512) {
|
|
Length = 512;
|
|
}
|
|
|
|
//
|
|
// If the previous mode is user, then probe and capture the
|
|
// message buffer on the stack.
|
|
//
|
|
|
|
if (PreviousMode != KernelMode) {
|
|
try {
|
|
ProbeForRead(Message, Length, sizeof(UCHAR));
|
|
Buffer = alloca(512);
|
|
KdpQuickMoveMemory(Buffer, Message, Length);
|
|
Message = Buffer;
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
return STATUS_ACCESS_VIOLATION;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Log debug output in circular buffer and print output
|
|
// if debugger is enabled.
|
|
//
|
|
|
|
Output.Buffer = Message;
|
|
Output.Length = Length;
|
|
KdLogDbgPrint(&Output);
|
|
if (KdDebuggerNotPresent == FALSE) {
|
|
Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
|
|
if (KdpPrintString(&Output)) {
|
|
Status = STATUS_BREAKPOINT;
|
|
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
KdExitDebugger(Enable);
|
|
|
|
} else {
|
|
Status = STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
}
|
|
|
|
*Completion = TRUE;
|
|
return Status;
|
|
}
|
|
|
|
USHORT
|
|
KdpPrompt(
|
|
IN PCHAR Message,
|
|
IN USHORT MessageLength,
|
|
IN OUT PCHAR Reply,
|
|
IN USHORT ReplyLength,
|
|
IN KPROCESSOR_MODE PreviousMode,
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function filters debug print requests, probes and saves user mode
|
|
message buffers on the stack, logs the print message, and prints the
|
|
message on the debug terminal if apprpriate.
|
|
|
|
Arguments:
|
|
|
|
Message - Supplies a pointer to the output message.
|
|
|
|
MessageLength - Supplies the length of the output message.
|
|
|
|
Reply - Supplies a pointer to the input buffer.
|
|
|
|
ReplyLength - Supplies the length of the output message.
|
|
|
|
PreviousMode - Supplies the previous processor mode.
|
|
|
|
TrapFrame - Supplies a pointer to a trap frame.
|
|
|
|
ExceptionFrame - Supplies a pointer to a exception.
|
|
|
|
Return Value:
|
|
|
|
The length of the input message is returned as the function value.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PCHAR Buffer;
|
|
BOOLEAN Enable;
|
|
STRING Input;
|
|
STRING Output;
|
|
|
|
//
|
|
// Limit the output and input message length to 512 bytes.
|
|
//
|
|
|
|
if (MessageLength > 512) {
|
|
MessageLength = 512;
|
|
}
|
|
|
|
if (ReplyLength > 512) {
|
|
ReplyLength = 512;
|
|
}
|
|
|
|
//
|
|
// If the previous mode is user, then probe and capture the
|
|
// message buffer on the stack.
|
|
//
|
|
|
|
if (PreviousMode != KernelMode) {
|
|
try {
|
|
ProbeForRead(Message, MessageLength, sizeof(UCHAR));
|
|
Buffer = alloca(512);
|
|
KdpQuickMoveMemory(Buffer, Message, MessageLength);
|
|
Message = Buffer;
|
|
ProbeForWrite(Reply, ReplyLength, sizeof(UCHAR));
|
|
Buffer = alloca(512);
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
return 0;
|
|
}
|
|
|
|
} else {
|
|
Buffer = Reply;
|
|
}
|
|
|
|
Input.Buffer = Buffer;
|
|
Input.Length = 0;
|
|
Input.MaximumLength = ReplyLength;
|
|
Output.Buffer = Message;
|
|
Output.Length = MessageLength;
|
|
|
|
//
|
|
// Log debug output in circular buffer and print the prompt message.
|
|
//
|
|
|
|
KdLogDbgPrint(&Output);
|
|
Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
|
|
do {
|
|
} while (KdpPromptString(&Output, &Input) == TRUE);
|
|
|
|
KdExitDebugger(Enable);
|
|
|
|
//
|
|
// If the previous mode was user, then copy the prompt input to the
|
|
// reply buffer.
|
|
//
|
|
|
|
if (PreviousMode == UserMode) {
|
|
try {
|
|
KdpQuickMoveMemory(Reply, Input.Buffer, Input.Length);
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
}
|
|
}
|
|
|
|
return Input.Length;
|
|
}
|
|
|
|
BOOLEAN
|
|
KdpReport(
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
|
IN PEXCEPTION_RECORD ExceptionRecord,
|
|
IN PCONTEXT ContextRecord,
|
|
IN KPROCESSOR_MODE PreviousMode,
|
|
IN BOOLEAN SecondChance
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reports an exception to the host kernel debugger.
|
|
|
|
Arguments:
|
|
|
|
TrapFrame - Supplies a pointer to a trap frame that describes the
|
|
trap.
|
|
|
|
ExceptionFrame - Supplies a pointer to a exception frame that describes
|
|
the exception.
|
|
|
|
ExceptionRecord - Supplies a pointer to an exception record that
|
|
describes the exception.
|
|
|
|
ContextRecord - Supplies the context at the time of the exception.
|
|
|
|
SecondChance - Supplies a boolean value that determines whether this is
|
|
the second chance (TRUE) that the exception has been raised.
|
|
|
|
Return Value:
|
|
|
|
The disposition of whether the exception was handled (TRUE) or not is
|
|
returned as the function value.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BOOLEAN Completion;
|
|
BOOLEAN Enable;
|
|
PKPRCB Prcb;
|
|
|
|
UNREFERENCED_PARAMETER (PreviousMode);
|
|
|
|
//
|
|
// If the exception code is a breakpoint or single step, or stop
|
|
// on exeception is set, or this is the second change to handle
|
|
// the exception, then attempt to enter the kernel debugger.
|
|
//
|
|
|
|
if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) ||
|
|
#if defined(_WIN64)
|
|
(ExceptionRecord->ExceptionCode == STATUS_WX86_BREAKPOINT) ||
|
|
#endif
|
|
(ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP) ||
|
|
((NtGlobalFlag & FLG_STOP_ON_EXCEPTION) != 0) ||
|
|
(SecondChance != FALSE)) {
|
|
|
|
//
|
|
// If this is the first chance to handle the exception and the
|
|
// exception code is either a port disconnected or success code,
|
|
// then do not enter the kernel debugger.
|
|
//
|
|
|
|
if ((SecondChance == FALSE) &&
|
|
#if defined(_WIN64)
|
|
(ExceptionRecord->ExceptionCode != STATUS_WX86_BREAKPOINT) &&
|
|
#endif
|
|
((ExceptionRecord->ExceptionCode == STATUS_PORT_DISCONNECTED) ||
|
|
(NT_SUCCESS(ExceptionRecord->ExceptionCode)))) {
|
|
|
|
//
|
|
// This exception should not be reported to the kernel debugger.
|
|
//
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Debugging help:
|
|
//
|
|
// For user mode breakpoints going to the kernel debugger,
|
|
// try to get the user mode module list and image headers
|
|
// paged in before we call the debugger. Walk the list twice
|
|
// in case paging in some modules pages out some
|
|
// previously paged in data.
|
|
//
|
|
#if 0
|
|
if (PreviousMode == UserMode)
|
|
{
|
|
PPEB Peb = PsGetCurrentProcess()->Peb;
|
|
PPEB_LDR_DATA Ldr;
|
|
PLIST_ENTRY LdrHead, LdrNext;
|
|
PLDR_DATA_TABLE_ENTRY LdrEntry;
|
|
UCHAR DataHeader;
|
|
ULONG i,j;
|
|
|
|
try {
|
|
|
|
Ldr = Peb->Ldr;
|
|
|
|
LdrHead = &Ldr->InLoadOrderModuleList;
|
|
|
|
ProbeForRead (LdrHead, sizeof (LIST_ENTRY), sizeof (UCHAR));
|
|
|
|
for (j=0; j<2; j++) {
|
|
|
|
for (LdrNext = LdrHead->Flink, i = 0;
|
|
LdrNext != LdrHead && i < 500;
|
|
LdrNext = LdrNext->Flink, i++) {
|
|
|
|
// BUGBUG
|
|
gLdrHits++;
|
|
|
|
LdrEntry = CONTAINING_RECORD (LdrNext, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
|
|
ProbeForRead (LdrEntry, sizeof (LDR_DATA_TABLE_ENTRY), sizeof (UCHAR));
|
|
|
|
DataHeader = ProbeAndReadUchar((PUCHAR)LdrEntry->DllBase);
|
|
}
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
}
|
|
}
|
|
#endif
|
|
//
|
|
// Report state change to the host kernel debugger.
|
|
//
|
|
|
|
Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
|
|
|
|
Prcb = KeGetCurrentPrcb();
|
|
KiSaveProcessorControlState(&Prcb->ProcessorState);
|
|
KdpQuickMoveMemory((PCHAR)&Prcb->ProcessorState.ContextFrame,
|
|
(PCHAR)ContextRecord,
|
|
sizeof(CONTEXT));
|
|
|
|
if (ExpWdHandler != NULL) {
|
|
ExpWdHandler( WdActionStopTimer, ExpWdHandlerContext, NULL, TRUE );
|
|
}
|
|
|
|
Completion =
|
|
KdpReportExceptionStateChange(ExceptionRecord,
|
|
&Prcb->ProcessorState.ContextFrame,
|
|
SecondChance);
|
|
|
|
KdpQuickMoveMemory((PCHAR)ContextRecord,
|
|
(PCHAR)&Prcb->ProcessorState.ContextFrame,
|
|
sizeof(CONTEXT));
|
|
|
|
KiRestoreProcessorControlState(&Prcb->ProcessorState);
|
|
|
|
if (ExpWdHandler != NULL) {
|
|
ExpWdHandler( WdActionStartTimer, ExpWdHandlerContext, NULL, TRUE );
|
|
}
|
|
|
|
KdExitDebugger(Enable);
|
|
|
|
KdpControlCPressed = FALSE;
|
|
return Completion;
|
|
|
|
} else {
|
|
|
|
//
|
|
// This exception should not be reported to the kernel debugger.
|
|
//
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
KdpSymbol(
|
|
IN PSTRING String,
|
|
IN PKD_SYMBOLS_INFO Symbol,
|
|
IN BOOLEAN Unload,
|
|
IN KPROCESSOR_MODE PreviousMode,
|
|
IN PCONTEXT ContextRecord,
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function loads or unloads debug symbols.
|
|
|
|
Arguments:
|
|
|
|
String - Supplies a pointer to a string descriptor.
|
|
|
|
Symbol - Supplies a pointer to the symbol information.
|
|
|
|
Unload - Supplies a boolean value that determines whether the symbols
|
|
are being unloaded (TRUE) or loaded (FALSE).
|
|
|
|
PreviousMode - Supplies the previous processor mode.
|
|
|
|
ContextRecord - Supplies a pointer to a context record.
|
|
|
|
TrapFrame - Supplies a pointer to a trap frame.
|
|
|
|
ExceptionFrame - Supplies a pointer to a exception.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BOOLEAN Enable;
|
|
PKPRCB Prcb;
|
|
|
|
//
|
|
// If the previous mode is kernel and the kernel debugger is present,
|
|
// then load or unload symbols.
|
|
//
|
|
|
|
if ((PreviousMode == KernelMode) &&
|
|
(KdDebuggerNotPresent == FALSE)) {
|
|
|
|
//
|
|
// Save and restore the processor context in case the
|
|
// kernel debugger has been configured to stop on dll
|
|
// loads.
|
|
//
|
|
|
|
Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
|
|
|
|
Prcb = KeGetCurrentPrcb();
|
|
KiSaveProcessorControlState(&Prcb->ProcessorState);
|
|
KdpQuickMoveMemory((PCHAR)&Prcb->ProcessorState.ContextFrame,
|
|
(PCHAR)ContextRecord,
|
|
sizeof(CONTEXT));
|
|
|
|
KdpReportLoadSymbolsStateChange(String,
|
|
Symbol,
|
|
Unload,
|
|
&Prcb->ProcessorState.ContextFrame);
|
|
KdpQuickMoveMemory((PCHAR)ContextRecord,
|
|
(PCHAR)&Prcb->ProcessorState.ContextFrame,
|
|
sizeof(CONTEXT));
|
|
|
|
KiRestoreProcessorControlState(&Prcb->ProcessorState);
|
|
KdExitDebugger(Enable);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
KdpCommandString(
|
|
IN PSTRING Name,
|
|
IN PSTRING Command,
|
|
IN KPROCESSOR_MODE PreviousMode,
|
|
IN PCONTEXT ContextRecord,
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reports an exception to the host kernel debugger.
|
|
|
|
Arguments:
|
|
|
|
Name - Identification of the originator of the command.
|
|
|
|
Command - Command string.
|
|
|
|
PreviousMode - Supplies the previous processor mode.
|
|
|
|
ContextRecord - Supplies a pointer to a context record.
|
|
|
|
TrapFrame - Supplies a pointer to a trap frame that describes the
|
|
trap.
|
|
|
|
ExceptionFrame - Supplies a pointer to a exception frame that describes
|
|
the exception.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Report state change to the host kernel debugger.
|
|
//
|
|
|
|
if ((PreviousMode == KernelMode) &&
|
|
(KdDebuggerNotPresent == FALSE)) {
|
|
|
|
BOOLEAN Enable;
|
|
PKPRCB Prcb;
|
|
|
|
Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
|
|
|
|
Prcb = KeGetCurrentPrcb();
|
|
KiSaveProcessorControlState(&Prcb->ProcessorState);
|
|
KdpQuickMoveMemory((PCHAR)&Prcb->ProcessorState.ContextFrame,
|
|
(PCHAR)ContextRecord,
|
|
sizeof(CONTEXT));
|
|
|
|
KdpReportCommandStringStateChange(Name, Command,
|
|
&Prcb->ProcessorState.ContextFrame);
|
|
|
|
KdpQuickMoveMemory((PCHAR)ContextRecord,
|
|
(PCHAR)&Prcb->ProcessorState.ContextFrame,
|
|
sizeof(CONTEXT));
|
|
|
|
KiRestoreProcessorControlState(&Prcb->ProcessorState);
|
|
KdExitDebugger(Enable);
|
|
}
|
|
}
|