mirror of https://github.com/tongzx/nt5src
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.
552 lines
11 KiB
552 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
DBG.C
|
|
|
|
Abstract:
|
|
|
|
This module contains debug only code for DBCLASS driver
|
|
|
|
Author:
|
|
|
|
jdunn
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
|
|
Revision History:
|
|
|
|
11-5-96 : created
|
|
|
|
--*/
|
|
#include <wdm.h>
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
#include "dbci.h"
|
|
#include "dbclass.h"
|
|
#include "dbfilter.h"
|
|
|
|
|
|
#ifdef MAX_DEBUG
|
|
#define DEBUG_HEAP
|
|
#endif
|
|
|
|
typedef struct _HEAP_TAG_BUFFER {
|
|
ULONG Sig;
|
|
ULONG Length;
|
|
} HEAP_TAG_BUFFER, *PHEAP_TAG_BUFFER;
|
|
|
|
|
|
#if DBG
|
|
|
|
extern ULONG DBCLASS_Debug_Trace_Level;
|
|
|
|
#ifdef NTKERN_TRACE
|
|
ULONG DBCLASS_W98_Debug_Trace = 1;
|
|
#else
|
|
ULONG DBCLASS_W98_Debug_Trace = 0;
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
DBCLASS_GetClassGlobalDebugRegistryParameters(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[4];
|
|
PWCHAR usb = L"class\\dbc";
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Set up QueryTable to do the following:
|
|
//
|
|
|
|
// spew level
|
|
QueryTable[0].QueryRoutine = DBCLASS_GetConfigValue;
|
|
QueryTable[0].Flags = 0;
|
|
QueryTable[0].Name = DEBUG_LEVEL_KEY;
|
|
QueryTable[0].EntryContext = &DBCLASS_Debug_Trace_Level;
|
|
QueryTable[0].DefaultType = REG_DWORD;
|
|
QueryTable[0].DefaultData = &DBCLASS_Debug_Trace_Level;
|
|
QueryTable[0].DefaultLength = sizeof(DBCLASS_Debug_Trace_Level);
|
|
|
|
// ntkern trace buffer
|
|
QueryTable[1].QueryRoutine = DBCLASS_GetConfigValue;
|
|
QueryTable[1].Flags = 0;
|
|
QueryTable[1].Name = DEBUG_WIN9X_KEY;
|
|
QueryTable[1].EntryContext = &DBCLASS_W98_Debug_Trace;
|
|
QueryTable[1].DefaultType = REG_DWORD;
|
|
QueryTable[1].DefaultData = &DBCLASS_W98_Debug_Trace;
|
|
QueryTable[1].DefaultLength = sizeof(DBCLASS_W98_Debug_Trace);
|
|
|
|
// break on start
|
|
QueryTable[2].QueryRoutine = DBCLASS_GetConfigValue;
|
|
QueryTable[2].Flags = 0;
|
|
QueryTable[2].Name = DEBUG_BREAK_ON;
|
|
QueryTable[2].EntryContext = &DBCLASS_BreakOn;
|
|
QueryTable[2].DefaultType = REG_DWORD;
|
|
QueryTable[2].DefaultData = &DBCLASS_BreakOn;
|
|
QueryTable[2].DefaultLength = sizeof(DBCLASS_BreakOn);
|
|
|
|
//
|
|
// Stop
|
|
//
|
|
QueryTable[3].QueryRoutine = NULL;
|
|
QueryTable[3].Flags = 0;
|
|
QueryTable[3].Name = NULL;
|
|
|
|
ntStatus = RtlQueryRegistryValues(
|
|
RTL_REGISTRY_SERVICES,
|
|
usb,
|
|
QueryTable, // QueryTable
|
|
NULL, // Context
|
|
NULL); // Environment
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
DBCLASS_KdPrint((1, "'Debug Trace Level Set: (%d)\n", DBCLASS_Debug_Trace_Level));
|
|
|
|
if (DBCLASS_W98_Debug_Trace) {
|
|
DBCLASS_KdPrint((1, "'NTKERN Trace is ON\n"));
|
|
} else {
|
|
DBCLASS_KdPrint((1, "'NTKERN Trace is OFF\n"));
|
|
}
|
|
|
|
if (DBCLASS_BreakOn) {
|
|
DBCLASS_KdPrint((1, "'DEBUG BREAK is ON\n"));
|
|
}
|
|
|
|
|
|
|
|
if (DBCLASS_Debug_Trace_Level > 0) {
|
|
ULONG DBCLASS_Debug_Asserts = 1;
|
|
}
|
|
}
|
|
|
|
if ( STATUS_OBJECT_NAME_NOT_FOUND == ntStatus ) {
|
|
ntStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
DBCLASS_AssertBaysEmpty(
|
|
PDBC_CONTEXT DbcContext
|
|
)
|
|
{
|
|
USHORT bay;
|
|
|
|
for (bay=1; bay <=NUMBER_OF_BAYS(DbcContext); bay++) {
|
|
DBCLASS_ASSERT(
|
|
DbcContext->BayInformation[bay].DeviceFilterObject == NULL);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DBCLASS_Warning(
|
|
PVOID Context,
|
|
PUCHAR Message,
|
|
BOOLEAN DebugBreak
|
|
)
|
|
{
|
|
DbgPrint("DBCLASS: Warning *************************************************************\n");
|
|
DbgPrint("%s", Message);
|
|
DbgPrint("******************************************************************************\n");
|
|
|
|
if (DebugBreak) {
|
|
TRAP();
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DBCLASS_Assert(
|
|
IN PVOID FailedAssertion,
|
|
IN PVOID FileName,
|
|
IN ULONG LineNumber,
|
|
IN PCHAR Message
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Debug Assert function.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object
|
|
|
|
Irp - pointer to an I/O Request Packet
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
// this makes the compiler generate a ret
|
|
ULONG stop = 1;
|
|
|
|
assert_loop:
|
|
|
|
// just call the NT assert function and stop
|
|
// in the debugger.
|
|
RtlAssert( FailedAssertion, FileName, LineNumber, Message );
|
|
|
|
// loop here to prevent users from going past
|
|
// are assert before we can look at it
|
|
|
|
TRAP();
|
|
if (stop) {
|
|
goto assert_loop;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
ULONG
|
|
_cdecl
|
|
DBCLASS_KdPrintX(
|
|
ULONG l,
|
|
PCH Format,
|
|
...
|
|
)
|
|
{
|
|
va_list list;
|
|
int i;
|
|
int arg[6];
|
|
|
|
if (DBCLASS_Debug_Trace_Level >= l) {
|
|
if (l <= 1) {
|
|
// dump line to debugger
|
|
if (DBCLASS_W98_Debug_Trace) {
|
|
DbgPrint("DBCLASS.SYS: ");
|
|
*Format = ' ';
|
|
} else {
|
|
DbgPrint("'DBCLASS.SYS: ");
|
|
}
|
|
} else {
|
|
// dump line to NTKERN buffer
|
|
DbgPrint("'DBCLASS.SYS: ");
|
|
if (DBCLASS_W98_Debug_Trace) {
|
|
*Format = 0x27;
|
|
}
|
|
}
|
|
va_start(list, Format);
|
|
for (i=0; i<6; i++)
|
|
arg[i] = va_arg(list, int);
|
|
|
|
DbgPrint(Format, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
PVOID
|
|
DBCLASS_GetHeap(
|
|
IN POOL_TYPE PoolType,
|
|
IN ULONG NumberOfBytes,
|
|
IN ULONG Signature,
|
|
IN PLONG TotalAllocatedHeapSpace
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Debug routine, used to debug heap problems. We are using this since
|
|
most NT debug functions are not supported by NTKERN.
|
|
|
|
Arguments:
|
|
|
|
PoolType - pool type passed to ExAllocatePool
|
|
|
|
NumberOfBytes - number of bytes for item
|
|
|
|
Signature - four byte signature supplied by caller
|
|
|
|
TotalAllocatedHeapSpace - pointer to variable where client stores
|
|
the total accumulated heap space allocated.
|
|
|
|
Return Value:
|
|
|
|
pointer to allocated memory
|
|
|
|
--*/
|
|
{
|
|
PUCHAR p;
|
|
#ifdef DEBUG_HEAP
|
|
PHEAP_TAG_BUFFER tagBuffer;
|
|
|
|
// we call ExAllocatePoolWithTag but no tag will be added
|
|
// when running under NTKERN
|
|
|
|
p = (PUCHAR) ExAllocatePoolWithTag(PoolType,
|
|
NumberOfBytes + sizeof(HEAP_TAG_BUFFER)*2,
|
|
Signature);
|
|
|
|
if (p) {
|
|
tagBuffer = (PHEAP_TAG_BUFFER) p;
|
|
tagBuffer->Sig = Signature;
|
|
tagBuffer->Length = NumberOfBytes;
|
|
p += sizeof(HEAP_TAG_BUFFER);
|
|
*TotalAllocatedHeapSpace += NumberOfBytes;
|
|
|
|
tagBuffer = (PHEAP_TAG_BUFFER) (p + NumberOfBytes);
|
|
tagBuffer->Sig = Signature;
|
|
tagBuffer->Length = NumberOfBytes;
|
|
}
|
|
|
|
// LOGENTRY(LOG_MISC, (PUCHAR) &Signature, 0, 0, 0);
|
|
// LOGENTRY(LOG_MISC, 'GetH', p, NumberOfBytes, stk[1] & 0x00FFFFFF);
|
|
#else
|
|
p = (PUCHAR) ExAllocatePoolWithTag(PoolType,
|
|
NumberOfBytes,
|
|
Signature);
|
|
|
|
#endif /* DEBUG_HEAP */
|
|
return p;
|
|
}
|
|
|
|
VOID
|
|
DBCLASS_RetHeap(
|
|
IN PVOID P,
|
|
IN ULONG Signature,
|
|
IN PLONG TotalAllocatedHeapSpace
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Debug routine, used to debug heap problems. We are using this since
|
|
most NT debug functions are not supported by NTKERN.
|
|
|
|
Arguments:
|
|
|
|
P - pointer to free
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
#ifdef DEBUG_HEAP
|
|
PHEAP_TAG_BUFFER endTagBuffer;
|
|
PHEAP_TAG_BUFFER beginTagBuffer;
|
|
|
|
DBCLASS_ASSERT(P != 0);
|
|
|
|
beginTagBuffer = (PHEAP_TAG_BUFFER) ((PUCHAR)P - sizeof(HEAP_TAG_BUFFER));
|
|
endTagBuffer = (PHEAP_TAG_BUFFER) ((PUCHAR)P + beginTagBuffer->Length);
|
|
|
|
*TotalAllocatedHeapSpace -= beginTagBuffer->Length;
|
|
|
|
// LOGENTRY(LOG_MISC, (PUCHAR) &Signature, 0, 0, 0);
|
|
// LOGENTRY(LOG_MISC, 'RetH', P, tagBuffer->Length, stk[1] & 0x00FFFFFF);
|
|
|
|
DBCLASS_ASSERT(*TotalAllocatedHeapSpace >= 0);
|
|
DBCLASS_ASSERT(beginTagBuffer->Sig == Signature);
|
|
DBCLASS_ASSERT(endTagBuffer->Sig == Signature);
|
|
DBCLASS_ASSERT(endTagBuffer->Length == beginTagBuffer->Length);
|
|
|
|
// fill the buffer with bad data
|
|
RtlFillMemory(P, beginTagBuffer->Length, 0xff);
|
|
beginTagBuffer->Sig = DBCLASS_FREE_TAG;
|
|
|
|
// free the original block
|
|
ExFreePool(beginTagBuffer);
|
|
#else
|
|
ExFreePool(P);
|
|
#endif /* DEBUG_HEAP */
|
|
}
|
|
|
|
#endif /* DBG */
|
|
|
|
#ifdef DEBUG_LOG
|
|
|
|
KSPIN_LOCK LogSpinLock;
|
|
|
|
struct LOG_ENTRY {
|
|
ULONG le_sig; // Identifying string
|
|
ULONG le_info1; // entry specific info
|
|
ULONG le_info2; // entry specific info
|
|
ULONG le_info3; // entry specific info
|
|
}; /* USBD_LOG_ENTRY */
|
|
|
|
|
|
struct LOG_ENTRY *DbclassLStart = 0; // No log yet
|
|
struct LOG_ENTRY *DbclassLPtr;
|
|
struct LOG_ENTRY *DbclassLEnd;
|
|
#ifdef PROFILE
|
|
ULONG LogMask = LOG_PROFILE;
|
|
#else
|
|
ULONG LogMask = 0xFFFFFFFF;
|
|
#endif
|
|
|
|
VOID
|
|
DBCLASS_Debug_LogEntry(
|
|
IN ULONG Mask,
|
|
IN ULONG Sig,
|
|
IN ULONG Info1,
|
|
IN ULONG Info2,
|
|
IN ULONG Info3
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds an Entry to USBH log.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL irql;
|
|
|
|
typedef union _SIG {
|
|
struct {
|
|
UCHAR Byte0;
|
|
UCHAR Byte1;
|
|
UCHAR Byte2;
|
|
UCHAR Byte3;
|
|
} b;
|
|
ULONG l;
|
|
} SIG, *PSIG;
|
|
|
|
SIG sig, rsig;
|
|
|
|
if (DbclassLStart == 0) {
|
|
return;
|
|
}
|
|
|
|
if ((Mask & LogMask) == 0) {
|
|
return;
|
|
}
|
|
|
|
irql = KeGetCurrentIrql();
|
|
if (irql < DISPATCH_LEVEL) {
|
|
KeAcquireSpinLock(&LogSpinLock, &irql);
|
|
} else {
|
|
KeAcquireSpinLockAtDpcLevel(&LogSpinLock);
|
|
}
|
|
|
|
if (DbclassLPtr > DbclassLStart) {
|
|
DbclassLPtr -= 1; // Decrement to next entry
|
|
} else {
|
|
DbclassLPtr = DbclassLEnd;
|
|
}
|
|
|
|
if (irql < DISPATCH_LEVEL) {
|
|
KeReleaseSpinLock(&LogSpinLock, irql);
|
|
} else {
|
|
KeReleaseSpinLockFromDpcLevel(&LogSpinLock);
|
|
}
|
|
|
|
DBCLASS_ASSERT(DbclassLPtr >= DbclassLStart);
|
|
|
|
sig.l = Sig;
|
|
rsig.b.Byte0 = sig.b.Byte3;
|
|
rsig.b.Byte1 = sig.b.Byte2;
|
|
rsig.b.Byte2 = sig.b.Byte1;
|
|
rsig.b.Byte3 = sig.b.Byte0;
|
|
|
|
DbclassLPtr->le_sig = rsig.l;
|
|
DbclassLPtr->le_info1 = Info1;
|
|
DbclassLPtr->le_info2 = Info2;
|
|
DbclassLPtr->le_info3 = Info3;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
DBCLASS_LogInit(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Init the debug log - remember interesting information in a circular buffer
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
#ifdef MAX_DEBUG
|
|
ULONG logSize = 4096*6;
|
|
#else
|
|
ULONG logSize = 4096*3;
|
|
#endif
|
|
|
|
|
|
KeInitializeSpinLock(&LogSpinLock);
|
|
|
|
DbclassLStart = ExAllocatePoolWithTag(NonPagedPool,
|
|
logSize,
|
|
DBC_TAG);
|
|
|
|
if (DbclassLStart) {
|
|
DbclassLPtr = DbclassLStart;
|
|
|
|
// Point the end (and first entry) 1 entry from the end of the segment
|
|
DbclassLEnd = DbclassLStart + (logSize / sizeof(struct LOG_ENTRY)) - 1;
|
|
} else {
|
|
TRAP(); //no mem for log!
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
DBCLASS_LogFree(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Init the debug log - remember interesting information in a circular buffer
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
if (DbclassLStart) {
|
|
ExFreePool(DbclassLStart);
|
|
}
|
|
}
|
|
|
|
#endif /* DEBUG_LOG */
|
|
|
|
|