Source code of Windows XP (NT5)
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

/*++
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 */