########################################################################
# John Robbins - Jan '99 Microsoft Systems Journal Bugslayer Column
########################################################################
########################################################################
# This is a sample sources file you can use as a template. This
# template includes the extra defines to take advantage of the new
# targets in DDKCommon.inc
#
########################################################################
#
# To use this sample, DDKCOMMON.INC will need to be in one of the
# directories specified in your INCLUDE environment variable.
#
########################################################################
# Helpful hint from the BUILD.EXE documentation:
# There should be no blank spaces between a BUILD keyword and the equal
# sign. For example, the following line is invalid:
#
# SOURCES = file.c
#
# while the following line is valid:
#
# SOURCES= file.c
#
########################################################################
# The first section is nothing but mandatory items.
########################################################################
########################################################################
# The TARGETNAME. This is the name of the item being built (without the
# extension). This is mandatory.
TARGETNAME=
########################################################################
# The path where all binaries are built. This is just the initial part.
# BUILD.EXE will put them into the $(TARGETPATH)\$(CPU)\$(DDKBUILDENV)
# Directory.
TARGETPATH=
########################################################################
# The type of item that is being built. This is mandatory.
# Value Meaning
# DYNLINK - A DLL.
# DRIVER - A kernel device driver.
# EXPORT_DRIVER - A kernel device driver with exports.
# PROGRAM - A windows executable.
# PROGLIB - A windows library.
# MINPORT - A miniport driver.
# GDI_DRIVER - A video driver.
# LIBRARY - A library (?)
TARGETTYPE=
########################################################################
# All the source files in this project. This is mandatory.
SOURCES=
########################################################################
# The items below this line are not mandatory, but they are certainly
# helpful!
########################################################################
########################################################################
# If you can, always use precompiled headers to speed up your builds.
# The first macro is the name of the precompiled header. If you are
# using .CPP/.CXX extensions, the second is needed as well.
#PRECOMPILED_INCLUDE=PCH.h
#PRECOMPILED_CXX=1
########################################################################
# The include directories for your project.
#INCLUDES=..\Include;$(INCLUDE)
########################################################################
# Set defines particular to the driver.
#C_DEFINES=$(C_DEFINES)
########################################################################
# Turn on PDB file generation. This seems to only work for checked
# builds as *FULL* source PDB files are not generated for free builds.
USE_PDB=1
# These are the flags that get *FULL* debugging information turned on
# for free builds. While the BUILD.EXE documentation implies that you
# should not process conditional syntax for its "keywords" but this
# seems to work fine. I do not know if it will work in the future.
!if "$(DDKBUILDENV)"=="free"
NTDEBUGTYPE=windbg
NTDEBUG=ntsdnodbg
LINKER_NOREF=1
!endif
########################################################################
# Set the warning levels to maximum.
ALPHA_WARNING_LEVEL=/W4
I386_WARNING_LEVEL=/W4
########################################################################
# Set the linker to produce a map file. A must have in emergency
# situations.
LINKER_FLAGS=$(LINKER_FLAGS) -MAP -MAPINFO:EXPORTS -MAPINFO:LINES
########################################################################
# If you need to link against some libs that you have, you can specify
# them here.
#TARGETLIBS=$(TARGETPATH)\*\$(DDKBUILDENV)\Track.lib
########################################################################
# User Mode program settings.
# The type, console or windows.
#UMTYPE=console
#UMTYPE=windows
# The base address. For EXE's, this needs to be 0x400000.
#UMBASE=0x400000
# Use MSVCRT.DLL instead of the NT CRT DLL. Always use this when doing
# console programs.
#USE_MSVCRT=1
########################################################################
# This puts all checked build .OBJ files into the .\objd directory
# to keep the free and checked apart. The final binaries still got to
# the free and checked output directories.
CHECKED_ALT_DIR=1
########################################################################
# Things to be built after the initial scan by BUILD.EXE. Always put
# MakeDirs first so the DDKHelper DDKCOMMON.MAK gets pulled in and the
# output directories get made.
NTTARGETFILE0=MakeDirs
########################################################################
# If you want to automatically create the .DBG file for your driver, you
# can uncomment the following macro lines. You need to set the
# CHECKED_DBGDIRS and FREE_DBGDIR to your check and free symbols
# directories, respectively. If you want to set the base address for
# your driver, you can use the DEVBASE macro. If you don't set it, the
# default is 0x10000.
#DEVBASE=0x10000
#CHECKED_DBGDIR=e:\Checked\Symbols
#FREE_DBGDIR=e:\WinNT\Symbols
#NTTARGETFILES=CreateDBG
Figure 2 Better BUILD_DEFAULT Settings
-F = When displaying errors/warnings to stdout, print the full path
-w = Shows warnings on screen
-e = Generates BUILD.LOG, BUILD.WRN, and BUILD.ERR files
-b = Displays full error message text
Figure 3 DrvDiagnostics.h
/*----------------------------------------------------------------------
John Robbins - Jan '99 Microsoft Systems Journal Bugslayer Column
------------------------------------------------------------------------
VERY useful driver diagnostic routines.
----------------------------------------------------------------------*/
#ifndef _DRVDIAGNOSTICS_H
#define _DRVDIAGNOSTICS_H
#if DBG !=0
#ifndef _DEBUG
#define _DEBUG
#endif
#endif
////////////////////////////////////////////////////////////////////////
// The usual trace macros.
#ifdef _DEBUG
// The trace macros that work in C and C++.
#define TRACE0(x) DbgPrint ( x )
#define TRACE1(x,y) DbgPrint ( x , y )
#define TRACE2(x,y,z) DbgPrint ( x , y , z )
#define TRACE3(x,y,z,a) DbgPrint ( x , y , z , a )
// A VERIFY macro.
#define VERIFY(x) ASSERT(x)
// The C++ specific trace statements.
#ifdef __cplusplus
#define TRACE DbgPrint
#endif // __cplusplus
#ifdef __cplusplus
// The C++ BreakIfKdPresent function.
inline void BreakIfKdPresent ( void )
{
// Wind through the IAT and grab the real value.
PULONG * pData = (PULONG*)(&KdDebuggerEnabled) ;
if ( 1 == **pData )
{
DbgBreakPoint ( ) ;
}
} ;
#else
// The C BreakIfKdPresent macro.
#define BreakIfKdPresent() \
{ \
PULONG * pData = (PULONG*)(&KdDebuggerEnabled) ; \
if ( 1 == **pData ) \
{ \
DbgBreakPoint ( ) ; \
} \
}
#endif
// The C/C++ ASSERTIRQL define. This checks that the IRQL is equal to
// that specified. If it is not, then the assert fires.
#define ASSERTIRQL(x) \
ASSERTMSG ( "KeGetCurrentIrql ( ) == "#x , \
KeGetCurrentIrql ( ) == x ) ;
// For consistency....
#define ASSERTIRQL_EQ(x) ASSERTIRQL ( x )
// Is the IRQL less than x?
#define ASSERTIRQL_LT(x) \
ASSERTMSG ( "KeGetCurrentIrql ( ) < "#x , \
KeGetCurrentIrql ( )< x ) ;
// Is the IRQL less than or equal to x?
#define ASSERTIRQL_LE(x) \
ASSERTMSG ( "KeGetCurrentIrql ( ) <= "#x , \
KeGetCurrentIrql ( ) <= x ) ;
// Is the IRQL greater than or equal to x?
#define ASSERTIRQL_GE(x) \
ASSERTMSG ( "KeGetCurrentIrql ( ) >= "#x , \
KeGetCurrentIrql ( ) >= x ) ;
// Is the IRQL greater than x?
#define ASSERTIRQL_GT(x) \
ASSERTMSG ( "KeGetCurrentIrql ( ) > "#x , \
KeGetCurrentIrql ( ) > x ) ;
// Is the IRQL not equal to x?
#define ASSERTIRQL_NE(x) \
ASSERTMSG ( "KeGetCurrentIrql ( ) != "#x , \
KeGetCurrentIrql ( ) != x ) ;
#else // _DEBUG is not defined.
#define TRACE0(x)
#define TRACE1(x,y)
#define TRACE2(x,y,z)
#define TRACE3(x,y,z,a)
#define BreakIfKdPresent()
#define ASSERTIRQL(x)
#define ASSERTIRQL_EQ(x)
#define ASSERTIRQL_LE(x)
#define ASSERTIRQL_GE(x)
#define ASSERTIRQL_GT(x)
#define ASSERTIRQL_NE(x)
#define VERIFY(x) x
#ifdef __cplusplus
inline void _cdecl FakeDbgPrint ( PCH , ... ) { }
#define TRACE 1 ? (void)0 : ::FakeDbgPrint
#endif // __cplusplus
#endif // _DEBUG
#endif // _DRVDIAGNOSTICS_H
Figure 4 Track Functions
Track Type |
Function |
Memory |
ExAllocatePool |
ExAllocatePoolWithTag |
|
ExAllocatePoolWithQuota |
|
ExAllocatePoolWithQuotaTag |
|
ExFreePool |
|
MmAllocateContiguousMemory |
|
MmAllocateNonCachedMemory |
|
MmFreeContiguousMemory |
|
MmFreeNonCachedMemory |
|
General Resource |
IoCreateDevice |
IoDeleteDevice |
|
RtlAnsiStringToUnicodeString |
|
RtlFreeUnicodeString |
|
RtlUnicodeStringToAnsiString |
|
RtlFreeAnsiString |
|
MmMapIoSpace |
|
MmUnmapIoSpace |
IoAllocateMdl |
IoBuildPartialMdl |
|
IoFreeMdl |
|
MmMapLockedPages |
|
MmUnmapLockedPages |
|
Handle |
ZwClose |
IoCreateNotificationEvent |
|
IoCreateSynchronizationEvent |
|
ZwCreateDirectoryObject |
|
ZwCreateFile |
|
ZwOpenKey |
|
ZwOpenSection |
Figure 5 Track_MmMapIoSpace and Track_MmUnmapIoSpace
PVOID Track_MmMapIoSpace ( IN PHYSICAL_ADDRESS PhysicalAddress,
IN ULONG NumberOfBytes,
IN MEMORY_CACHING_TYPE CacheType,
char * szFile,
ULONG uLine )
{
// Make the call no matter what.
PVOID pRet = MmMapIoSpace ( PhysicalAddress ,
NumberOfBytes ,
CacheType ) ;
if ( ( TRUE == InternalInitialized ( ) ) &&
( NULL != pRet ) )
{
// Add away.
InternalAddSimpleAlloction ( TRACKCLASS_GENERALRESOURCES ,
eMmMapIoSpace ,
(ULONG)pRet ,
szFile ,
uLine ) ;
g_GeneralResourcesStats.ulTotalCalls++ ;
}
return ( pRet ) ;
}
VOID Track_MmUnmapIoSpace ( IN PVOID BaseAddress,
IN ULONG NumberOfBytes,
char * szFile,
ULONG uLine )
{
if ( FALSE == InternalInitialized ( ) )
{
MmUnmapIoSpace ( BaseAddress , NumberOfBytes ) ;
return ;
}
ASSERT ( TRUE == MmIsAddressValid ( BaseAddress ) ) ;
// Grab the spinlock so the information can removed from the list.
KIRQL kOldIrql ;
// A boolean that tells me if I can MmUnmapIoSpace.
BOOLEAN bCallFunction = TRUE ;
__try
{
__try
{
InternalAcquireSpinLock ( &kOldIrql ) ;
PTRACKALLOCATION pTemp =
FindGeneralResourcesRecord ( eMmUnmapIoSpace ,
(ULONG)BaseAddress ,
szFile ,
uLine ) ;
if ( NULL != pTemp )
{
// Is this from the matching allocator?
if ( eMmMapIoSpace != pTemp->sID )
{
// Got a little problem.
TRACE ( k_TRACK_ERROR ) ;
TRACE ( "The object created in %s, line %d "
"cannot be deleted with "
"MmUnmapIoSpace.\n" ,
pTemp->szSource ,
pTemp->lLine ) ;
TRACE ( k_TRACK_ERROR ) ;
ASSERTMSG ( "Invalid delete" , FALSE ) ;
bCallFunction = FALSE ;
}
else
{
bCallFunction = TRUE ;
InternalRemoveAllocation ( pTemp ) ;
}
}
else
{
bCallFunction = FALSE ;
}
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
ASSERTMSG ( "Track_MmUnmapIoSpace had an access "
"violation!\n" ,
FALSE ) ;
}
}
__finally
{
// Always release the spinlock and drop the IRQL so that I can
// call MmUnmapIoSpace.
InternalReleaseSpinLock ( kOldIrql ) ;
if ( TRUE == bCallFunction )
{
MmUnmapIoSpace ( BaseAddress , NumberOfBytes ) ;
}
}
}