1373 lines
29 KiB
C
1373 lines
29 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1995-2001 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
debug.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Domain Name System (DNS) Library
|
|||
|
|
|||
|
Debug routines.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jim Gilroy (jamesg) January 31, 1995
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "local.h"
|
|||
|
|
|||
|
|
|||
|
#define DNSDBG_CONTEXT_SWITCH_LOGGING 1
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Debug globals
|
|||
|
//
|
|||
|
|
|||
|
DNS_DEBUG_INFO g_DnsDbgInfo = { 0 };
|
|||
|
|
|||
|
PDNS_DEBUG_INFO g_pDbgInfo = &g_DnsDbgInfo;
|
|||
|
|
|||
|
// Redirected
|
|||
|
|
|||
|
BOOL g_DbgRedirected = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Debug flag -- exposed as pointer in dnslib.h
|
|||
|
//
|
|||
|
// By default use DnsDebugFlag, but actual debug printing is
|
|||
|
// switched by *pDnsDebugFlag, which caller may point at local
|
|||
|
// flag if desired.
|
|||
|
//
|
|||
|
|
|||
|
PDWORD pDnsDebugFlag = (PDWORD)&g_DnsDbgInfo;
|
|||
|
|
|||
|
//
|
|||
|
// Note that in all functions below, we use the universal
|
|||
|
// check IS_DNSDBG_ON(), which is defined for debug AND retail.
|
|||
|
// Do NOT use any of the debug macros, as we want the code to
|
|||
|
// work equally well in retail versions of dnsapi.dll, so that
|
|||
|
// debug versions of calling modules can use these functions.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Print buffer sizes
|
|||
|
// - small default stack buffer
|
|||
|
// - large buffer on heap to handle any print
|
|||
|
//
|
|||
|
// NOTE: MUST have stack buffer of sufficient size to
|
|||
|
// handle any message we print on memory allocation
|
|||
|
// failure; otherwise we get into the obvious loop
|
|||
|
// of alloc failure causing print, which causes attempted
|
|||
|
// alloc and another print
|
|||
|
//
|
|||
|
|
|||
|
#define DNS_STACK_PRINT_BUFFER_LENGTH (0x300) // 768 covers 99%
|
|||
|
#define DNS_HEAP_PRINT_BUFFER_LENGTH (0x4000) // 16K will cover anything
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Public debug routines
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
Dns_Assert(
|
|||
|
IN LPSTR pszFile,
|
|||
|
IN INT LineNo,
|
|||
|
IN LPSTR pszExpr
|
|||
|
)
|
|||
|
{
|
|||
|
DnsDbg_Printf(
|
|||
|
"ASSERTION FAILED: %s\n"
|
|||
|
" %s, line %d\n",
|
|||
|
pszExpr,
|
|||
|
pszFile,
|
|||
|
LineNo );
|
|||
|
|
|||
|
DnsDbg_Flush();
|
|||
|
|
|||
|
// always print to debugger, even if debugger print flag not set
|
|||
|
|
|||
|
if ( ! IS_DNSDBG_ON( DEBUGGER ) )
|
|||
|
{
|
|||
|
DnsDbg_PrintfToDebugger(
|
|||
|
"ASSERTION FAILED: %s\n"
|
|||
|
" %s, line %d\n",
|
|||
|
pszExpr,
|
|||
|
pszFile,
|
|||
|
LineNo );
|
|||
|
}
|
|||
|
|
|||
|
if ( IS_DNSDBG_ON( BREAKPOINTS ) )
|
|||
|
{
|
|||
|
DebugBreak();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DnsDbg_Printf( "Skipping DNS_ASSERT, debug flag = %lx\n", *pDnsDebugFlag );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#if 0
|
|||
|
typedef struct _DnsDebugInit
|
|||
|
{
|
|||
|
DWORD Flag;
|
|||
|
PSTR pszFlagFile;
|
|||
|
PDWORD pDebugFlag;
|
|||
|
PSTR pszLogFile;
|
|||
|
DWORD WrapSize;
|
|||
|
BOOL fUseGlobalFile;
|
|||
|
BOOL fUseGlobalFlag;
|
|||
|
BOOL fSetGlobals;
|
|||
|
}
|
|||
|
DNS_DEBUG_INIT, *PDNS_DEBUG_INIT;
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
Dns_StartDebugEx(
|
|||
|
IN DWORD DebugFlag,
|
|||
|
IN PSTR pszFlagFile,
|
|||
|
IN OUT PDWORD pDebugFlag,
|
|||
|
IN PSTR pszLogFile,
|
|||
|
IN DWORD WrapSize,
|
|||
|
IN BOOL fUseGlobalFile,
|
|||
|
IN BOOL fUseGlobalFlag,
|
|||
|
IN BOOL fSetGlobals
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize debugging.
|
|||
|
Only current task is to read and set debug flags.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
includes:
|
|||
|
dwFlag -- debug flags
|
|||
|
pszFlagFile -- name of file containing debug flags
|
|||
|
pdwFlag -- ptr to DWORD to receive debug flags
|
|||
|
pszLogFile -- log file name
|
|||
|
dwWrapSize -- log file wrap size
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HANDLE hfile;
|
|||
|
DWORD freadFlag = FALSE;
|
|||
|
BOOL fretry = FALSE;
|
|||
|
CHAR prevName[ MAX_PATH+10 ];
|
|||
|
DWORD debugFlag;
|
|||
|
|
|||
|
PDNS_DEBUG_INFO pinfoGlobal = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// use external flag?
|
|||
|
// - save ptr to it
|
|||
|
//
|
|||
|
// allow use of external flag so callers -- eg. DNS server --
|
|||
|
// can easily manipulate flag during run time and still keep
|
|||
|
// their checking macros simple
|
|||
|
//
|
|||
|
|
|||
|
if ( pDebugFlag )
|
|||
|
{
|
|||
|
pDnsDebugFlag = pDebugFlag;
|
|||
|
g_DnsDbgInfo.Flag = *pDnsDebugFlag;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// get piggyback info
|
|||
|
//
|
|||
|
|
|||
|
if ( fUseGlobalFlag || fUseGlobalFile )
|
|||
|
{
|
|||
|
pinfoGlobal = DnsApiSetDebugGlobals( NULL );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// skip debug flag setup if piggybacking
|
|||
|
// - use the existing flag value
|
|||
|
// - but not safe to grab pointer which
|
|||
|
// may go away on dll unload
|
|||
|
//
|
|||
|
// DCR: safe way to use existing flags?
|
|||
|
// DCR: need to be able to get "last" debug flag set
|
|||
|
// without blowing up
|
|||
|
//
|
|||
|
|
|||
|
if ( fUseGlobalFlag &&
|
|||
|
pinfoGlobal &&
|
|||
|
pinfoGlobal->hFile )
|
|||
|
{
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// setup debug flag
|
|||
|
//
|
|||
|
|
|||
|
debugFlag = DebugFlag;
|
|||
|
if ( debugFlag )
|
|||
|
{
|
|||
|
freadFlag = TRUE;
|
|||
|
}
|
|||
|
else if ( pszFlagFile )
|
|||
|
{
|
|||
|
// read debug flag in file
|
|||
|
|
|||
|
hfile = CreateFile(
|
|||
|
pszFlagFile,
|
|||
|
GENERIC_READ,
|
|||
|
FILE_SHARE_READ,
|
|||
|
NULL,
|
|||
|
OPEN_EXISTING,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
if ( hfile == (HANDLE)INVALID_HANDLE_VALUE )
|
|||
|
{
|
|||
|
// if file specified and not found, then quit if explicit value
|
|||
|
// not given
|
|||
|
|
|||
|
if ( debugFlag == 0 )
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DWORD bytesRead;
|
|||
|
CHAR buffer[100];
|
|||
|
|
|||
|
RtlZeroMemory( buffer, sizeof(buffer) );
|
|||
|
|
|||
|
if ( ReadFile( hfile, buffer, 100, &bytesRead, NULL ) )
|
|||
|
{
|
|||
|
buffer[bytesRead] = '\0';
|
|||
|
debugFlag = strtoul( buffer, NULL, 16 );
|
|||
|
freadFlag = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DnsDbg_Printf( "read file failed: %ld\n", GetLastError( ) );
|
|||
|
if ( debugFlag == 0 )
|
|||
|
{
|
|||
|
CloseHandle( hfile );
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
CloseHandle( hfile );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// save any flag read
|
|||
|
// - reset global (internal or external) to it
|
|||
|
//
|
|||
|
|
|||
|
if ( freadFlag )
|
|||
|
{
|
|||
|
g_DnsDbgInfo.Flag = debugFlag;
|
|||
|
*pDnsDebugFlag = debugFlag;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// skip debug file open if piggybacking
|
|||
|
//
|
|||
|
// two levels
|
|||
|
// - only using file
|
|||
|
// - using file and debug flags
|
|||
|
|
|||
|
if ( fUseGlobalFile &&
|
|||
|
pinfoGlobal &&
|
|||
|
pinfoGlobal->hFile )
|
|||
|
{
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// open debug logfile
|
|||
|
//
|
|||
|
|
|||
|
fretry = 0;
|
|||
|
|
|||
|
while ( pszLogFile )
|
|||
|
{
|
|||
|
PCHAR pnameBuf = g_DnsDbgInfo.FileName;
|
|||
|
|
|||
|
// heap may not be initialized, copy filename to static buffer
|
|||
|
//
|
|||
|
// note: if we fail on first pass we try again but open directly
|
|||
|
// at file system root; given simply filename, applications
|
|||
|
// run from system32 and services (resolver) will attempt open
|
|||
|
// in system32 and some (resolver) do not by default have
|
|||
|
// permissions to create files there
|
|||
|
|
|||
|
if ( fretry == 0 )
|
|||
|
{
|
|||
|
strncpy( pnameBuf, pszLogFile, MAX_PATH );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pnameBuf[0] = '\\';
|
|||
|
strncpy( pnameBuf+1, pszLogFile, MAX_PATH-1 );
|
|||
|
}
|
|||
|
pnameBuf[MAX_PATH] = 0;
|
|||
|
|
|||
|
#if 0
|
|||
|
// jeff changes -- don't have time to fix up now
|
|||
|
// file wrapping should handle this sort of thing
|
|||
|
|
|||
|
//
|
|||
|
// Save off the current copy as ".prev"
|
|||
|
//
|
|||
|
|
|||
|
strcpy( prevName, DnsDebugFileName );
|
|||
|
strcat( prevName, ".prev" );
|
|||
|
|
|||
|
MoveFileEx(
|
|||
|
DnsDebugFileName,
|
|||
|
prevName,
|
|||
|
MOVEFILE_REPLACE_EXISTING );
|
|||
|
|
|||
|
DnsDebugFileHandle = CreateFile(
|
|||
|
DnsDebugFileName,
|
|||
|
GENERIC_READ | GENERIC_WRITE,
|
|||
|
FILE_SHARE_READ,
|
|||
|
NULL,
|
|||
|
CREATE_ALWAYS,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
#endif
|
|||
|
hfile = CreateFile(
|
|||
|
pnameBuf,
|
|||
|
GENERIC_READ | GENERIC_WRITE,
|
|||
|
FILE_SHARE_READ,
|
|||
|
NULL,
|
|||
|
CREATE_ALWAYS,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ( !hfile && !fretry )
|
|||
|
{
|
|||
|
fretry++;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
g_DnsDbgInfo.hFile = hfile;
|
|||
|
g_DnsDbgInfo.FileWrapSize = WrapSize;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// initialize console
|
|||
|
//
|
|||
|
|
|||
|
if ( IS_DNSDBG_ON( CONSOLE ) )
|
|||
|
{
|
|||
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|||
|
COORD coord;
|
|||
|
|
|||
|
AllocConsole();
|
|||
|
GetConsoleScreenBufferInfo(
|
|||
|
GetStdHandle(STD_OUTPUT_HANDLE),
|
|||
|
&csbi
|
|||
|
);
|
|||
|
coord.X = (SHORT)(csbi.srWindow.Right - csbi.srWindow.Left + 1);
|
|||
|
coord.Y = (SHORT)((csbi.srWindow.Bottom - csbi.srWindow.Top + 1) * 20);
|
|||
|
SetConsoleScreenBufferSize(
|
|||
|
GetStdHandle(STD_OUTPUT_HANDLE),
|
|||
|
coord
|
|||
|
);
|
|||
|
|
|||
|
g_DnsDbgInfo.fConsole = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// set "global" debug file info
|
|||
|
//
|
|||
|
// dnsapi.dll serves as storage for common dns client
|
|||
|
// debug file if that is desired; this lets applications
|
|||
|
// push all dns debug output into a single file
|
|||
|
//
|
|||
|
// currently push both file and debug flag value
|
|||
|
// note, we don't push debug file ptr as don't know
|
|||
|
// whose memory becomes invalid first
|
|||
|
//
|
|||
|
|
|||
|
if ( fSetGlobals && g_DnsDbgInfo.hFile )
|
|||
|
{
|
|||
|
DnsApiSetDebugGlobals(
|
|||
|
&g_DnsDbgInfo // set our info as global
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
Done:
|
|||
|
|
|||
|
//
|
|||
|
// use "global" (dnsapi.dll) debugging
|
|||
|
// - copy in our info if no existing info
|
|||
|
// - set to use global info blob
|
|||
|
//
|
|||
|
// two levels
|
|||
|
// - only using file
|
|||
|
// - using file and debug flags
|
|||
|
|
|||
|
if ( fUseGlobalFile &&
|
|||
|
pinfoGlobal )
|
|||
|
{
|
|||
|
// copy in our new info if no global info exists
|
|||
|
|
|||
|
if ( !pinfoGlobal->hFile &&
|
|||
|
g_DnsDbgInfo.hFile )
|
|||
|
{
|
|||
|
DnsApiSetDebugGlobals( &g_DnsDbgInfo );
|
|||
|
}
|
|||
|
|
|||
|
// point at global info
|
|||
|
|
|||
|
g_pDbgInfo = pinfoGlobal;
|
|||
|
g_DbgRedirected = TRUE;
|
|||
|
|
|||
|
if ( fUseGlobalFlag )
|
|||
|
{
|
|||
|
pDnsDebugFlag = (PDWORD) pinfoGlobal;
|
|||
|
}
|
|||
|
|
|||
|
// avoid double cleanup
|
|||
|
// - clear the handle in your modules blob
|
|||
|
|
|||
|
g_DnsDbgInfo.hFile = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// use print locking for debug locking
|
|||
|
//
|
|||
|
|
|||
|
DnsPrint_InitLocking( NULL );
|
|||
|
|
|||
|
DNSDBG( ANY, (
|
|||
|
"Initialized debugging:\n"
|
|||
|
"\tpDbgInfo %p\n"
|
|||
|
"\t&DnsDbgInfo %p\n"
|
|||
|
"\tfile (param) %s\n"
|
|||
|
"\thFile %p\n"
|
|||
|
"\tpDbgInfo->Flag %08x\n"
|
|||
|
"\tpDnsDebugFlag %p\n"
|
|||
|
"\t*pDnsDebugFlag %08x\n"
|
|||
|
"DnsLib compiled on %s at %s\n",
|
|||
|
g_pDbgInfo,
|
|||
|
&g_DnsDbgInfo,
|
|||
|
pszLogFile,
|
|||
|
g_pDbgInfo->hFile,
|
|||
|
g_pDbgInfo->Flag,
|
|||
|
pDnsDebugFlag,
|
|||
|
*pDnsDebugFlag,
|
|||
|
__DATE__,
|
|||
|
__TIME__ ));
|
|||
|
|
|||
|
} // Dns_StartDebug
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#if 0
|
|||
|
VOID
|
|||
|
Dns_StartDebugEx(
|
|||
|
IN DWORD dwFlag,
|
|||
|
IN PSTR pszFlagFile,
|
|||
|
IN OUT PDWORD pdwFlag,
|
|||
|
IN PSTR pszLogFile,
|
|||
|
IN DWORD dwWrapSize,
|
|||
|
IN BOOL fUseGlobalFile,
|
|||
|
IN BOOL fUseGlobalFlag,
|
|||
|
IN BOOL fSetGlobals
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize debugging.
|
|||
|
Only current task is to read and set debug flags.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
dwFlag -- debug flags
|
|||
|
pszFlagFile -- name of file containing debug flags
|
|||
|
pdwFlag -- ptr to DWORD to receive debug flags
|
|||
|
pszLogFile -- log file name
|
|||
|
dwWrapSize -- log file wrap size
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DNS_DEBUG_INIT info;
|
|||
|
|
|||
|
RtlZeroMemory
|
|||
|
&info,
|
|||
|
sizeof(info) );
|
|||
|
|
|||
|
info.pszFlagFile = pszFlagFile;
|
|||
|
info.DebugFlags = dwFlag;
|
|||
|
info.pDebugFlags = pdwFlag;
|
|||
|
info.pszLogFile = pszLogFile;
|
|||
|
info.dwWrapSize = dwWrapSize;
|
|||
|
|
|||
|
info.fUseGlobalFile = fUseGlobalFile;
|
|||
|
info.fUseGlobalFlag = fUseGlobalFlag;
|
|||
|
info.fSetGlobals = fSetGlobals;
|
|||
|
|
|||
|
privateStartDebug( &info );
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
Dns_StartDebug(
|
|||
|
IN DWORD dwFlag,
|
|||
|
IN PSTR pszFlagFile,
|
|||
|
IN OUT PDWORD pdwFlag,
|
|||
|
IN PSTR pszLogFile,
|
|||
|
IN DWORD dwWrapSize
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize debugging.
|
|||
|
Only current task is to read and set debug flags.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
dwFlag -- debug flags
|
|||
|
pszFlagFile -- name of file containing debug flags
|
|||
|
pdwFlag -- ptr to DWORD to receive debug flags
|
|||
|
pszLogFile -- log file name
|
|||
|
dwWrapSize -- log file wrap size
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
Dns_StartDebugEx(
|
|||
|
dwFlag,
|
|||
|
pszFlagFile,
|
|||
|
pdwFlag,
|
|||
|
pszLogFile,
|
|||
|
dwWrapSize,
|
|||
|
FALSE,
|
|||
|
FALSE,
|
|||
|
FALSE );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
Dns_EndDebug(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Terminate DNS debugging for shutdown.
|
|||
|
|
|||
|
Close debug file.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
// close file
|
|||
|
// - but only your dnslib instance
|
|||
|
// - shared global file is closed by dnsapi
|
|||
|
|
|||
|
if ( g_DnsDbgInfo.hFile )
|
|||
|
{
|
|||
|
CloseHandle( g_DnsDbgInfo.hFile );
|
|||
|
g_DnsDbgInfo.hFile = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PDNS_DEBUG_INFO
|
|||
|
Dns_SetDebugGlobals(
|
|||
|
IN OUT PDNS_DEBUG_INFO pInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Exposure of debug globals.
|
|||
|
|
|||
|
The purpose of this is to allow dnsapi.dll to use it's globals
|
|||
|
to allow common debug file. I'm using one routine for both
|
|||
|
get and set to mimize the interfaces.
|
|||
|
|
|||
|
Note however, that this is NOT the routine that routines in
|
|||
|
this module use to get cross-module debugging. They MUST call
|
|||
|
the actual dnsapi.dll routine so that they are attaching
|
|||
|
to the dnsapi's dnslib debugging globls not the ones with the
|
|||
|
dnslib statically linked into their module.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pInfo -- local info to use as global info
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Ptr to global info
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
//
|
|||
|
// verify valid info coming in
|
|||
|
// - must have file handle
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Implementation note:
|
|||
|
//
|
|||
|
// There are several issues to deal with when doing this
|
|||
|
// - multiple redirection
|
|||
|
// getting everyone to point at same blob
|
|||
|
// solutions:
|
|||
|
// - either double pointer (they read dnsapi.dll
|
|||
|
// pointer
|
|||
|
// - copy into dnsapi.dll the info
|
|||
|
// - locking
|
|||
|
// - broad scale print of structs
|
|||
|
// - cleanup
|
|||
|
// - no double close of handle
|
|||
|
// - memory sections disappearing while some dll
|
|||
|
// or exe still printing
|
|||
|
//
|
|||
|
// Approachs:
|
|||
|
// 1) redirect blob pointer
|
|||
|
// blob could expand to include actual print locks
|
|||
|
// 2) copy info into single blob
|
|||
|
// 3) expose debug routines
|
|||
|
//
|
|||
|
//
|
|||
|
// Perhaps best approach might be to expose the dnsapi.dll
|
|||
|
// printing
|
|||
|
// - solves locking (at detail level), doesn't prevent breakup
|
|||
|
// of high level printing unless it also redirected
|
|||
|
// - can be done at the private level after parsing to va_arg
|
|||
|
// - solves all the cleanup
|
|||
|
// - they can be dumb stubs in non-debug binary, and dnslib
|
|||
|
// routines can default to self if can't call dnsapi.dll
|
|||
|
// routines
|
|||
|
//
|
|||
|
// Then redirection is simply
|
|||
|
// - yes i use it -- redirection on each use
|
|||
|
// - i want my file (and params) to BE used
|
|||
|
//
|
|||
|
|
|||
|
#if 1
|
|||
|
//
|
|||
|
// copy over "i-want-to-be-global" callers context
|
|||
|
//
|
|||
|
// note: we're in dnsapi.dll here and should always be
|
|||
|
// pointed at our own context -- we can change that
|
|||
|
// later if desired
|
|||
|
//
|
|||
|
// note
|
|||
|
// - lock during copy to be safe
|
|||
|
// - don't leak existing handle
|
|||
|
// - protect global handle from double close
|
|||
|
//
|
|||
|
|
|||
|
if ( pInfo )
|
|||
|
{
|
|||
|
DnsPrint_Lock();
|
|||
|
|
|||
|
DNS_ASSERT( g_pDbgInfo == &g_DnsDbgInfo );
|
|||
|
|
|||
|
if ( pInfo->hFile )
|
|||
|
{
|
|||
|
HANDLE htemp = g_pDbgInfo->hFile;
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
& g_DnsDbgInfo,
|
|||
|
pInfo,
|
|||
|
sizeof(*pInfo) );
|
|||
|
|
|||
|
g_pDbgInfo = &g_DnsDbgInfo;
|
|||
|
pDnsDebugFlag = (PDWORD)&g_DnsDbgInfo;
|
|||
|
|
|||
|
CloseHandle( htemp );
|
|||
|
}
|
|||
|
DnsPrint_Unlock();
|
|||
|
}
|
|||
|
#else
|
|||
|
|
|||
|
//
|
|||
|
// point dnsapi.dll debugging global at this context
|
|||
|
// which becomes "global"
|
|||
|
// note: essential this is last writer wins, but this
|
|||
|
// should be fine for our purpuse (dnsup and resolver)
|
|||
|
// as these processes init the debug after the
|
|||
|
// dll loads
|
|||
|
//
|
|||
|
// problem with this approach is that folks redirected
|
|||
|
// onto dnsapi.dll do not get new info when it is
|
|||
|
// redirected (into dnsup)
|
|||
|
|
|||
|
if ( pInfo && pInfo->hFile )
|
|||
|
{
|
|||
|
g_pDbgInfo = pInfo;
|
|||
|
pDnsDebugFlag = (PDWORD)pInfo;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
return g_pDbgInfo;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#if 0
|
|||
|
VOID
|
|||
|
privateSyncGlobalDebug(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Sync up with global debug.
|
|||
|
|
|||
|
Get dnslib debugging in line with "global" debugging if
|
|||
|
that is desired for this dnslib instance.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if ( !g_DbgRedirected )
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// sync with global values
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DnsDbg_WrapLogFile(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Wrap the log file.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
CHAR backupName[ MAX_PATH+10 ];
|
|||
|
|
|||
|
FlushFileBuffers( g_pDbgInfo->hFile );
|
|||
|
CloseHandle( g_pDbgInfo->hFile );
|
|||
|
|
|||
|
strcpy( backupName, g_pDbgInfo->FileName );
|
|||
|
|
|||
|
if ( g_pDbgInfo->FileWrapCount == 0 )
|
|||
|
{
|
|||
|
strcat( backupName, ".first" );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
strcat( backupName, ".last" );
|
|||
|
}
|
|||
|
MoveFileEx(
|
|||
|
g_pDbgInfo->FileName,
|
|||
|
backupName,
|
|||
|
MOVEFILE_REPLACE_EXISTING
|
|||
|
);
|
|||
|
|
|||
|
g_pDbgInfo->hFile = CreateFile(
|
|||
|
g_pDbgInfo->FileName,
|
|||
|
GENERIC_READ | GENERIC_WRITE,
|
|||
|
FILE_SHARE_READ,
|
|||
|
NULL,
|
|||
|
CREATE_ALWAYS,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
g_pDbgInfo->FileWrapCount++;
|
|||
|
g_pDbgInfo->FileCurrentSize = 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
privateDnsDebugPrint(
|
|||
|
IN PBYTE pOutputBuffer,
|
|||
|
IN BOOL fPrintContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Private DNS debug print that does actual print.
|
|||
|
|
|||
|
May print to any of
|
|||
|
- debugger
|
|||
|
- console window
|
|||
|
- debug log file
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pOutputBuffer -- bytes to print
|
|||
|
|
|||
|
fPrintContext
|
|||
|
- TRUE to print thread context
|
|||
|
- FALSE otherwise
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD length;
|
|||
|
BOOL ret;
|
|||
|
|
|||
|
//
|
|||
|
// DCR: nice to automatically shut down console print when debugging
|
|||
|
// it would be cool to be able to have all flags on, and detect
|
|||
|
// when in ntsd, so that we don't get duplicated output
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// lock print to keep atomic even during wrap
|
|||
|
// - note use Print lock, which exists even in retail builds
|
|||
|
// Dbg lock is defined away
|
|||
|
//
|
|||
|
|
|||
|
DnsPrint_Lock();
|
|||
|
|
|||
|
//
|
|||
|
// catch and timestamp thread context switches
|
|||
|
//
|
|||
|
|
|||
|
if ( fPrintContext )
|
|||
|
{
|
|||
|
DWORD threadId = GetCurrentThreadId();
|
|||
|
BOOL fcontextSwitch = (g_pDbgInfo->LastThreadId != threadId);
|
|||
|
SYSTEMTIME st;
|
|||
|
BOOL fdoPrint = FALSE;
|
|||
|
|
|||
|
// get time
|
|||
|
// - if have context switch
|
|||
|
// - or putting in debug timestamps
|
|||
|
//
|
|||
|
// DCR: maybe have global that set to put in timestamps and
|
|||
|
// can set interval
|
|||
|
//
|
|||
|
// DCR: lock safe timestamps
|
|||
|
// better would be "lock-safe" timestamps that are printed
|
|||
|
// only when take the print lock -- then they would never
|
|||
|
// interrupt the a multi-part print
|
|||
|
// one way might be to test recursive depth of print CS
|
|||
|
// otherwise must change to lock that includes this
|
|||
|
// code
|
|||
|
|
|||
|
if ( fcontextSwitch
|
|||
|
||
|
|||
|
(pDnsDebugFlag && (*pDnsDebugFlag & DNS_DBG_TIMESTAMP)) )
|
|||
|
{
|
|||
|
GetLocalTime( &st );
|
|||
|
|
|||
|
if ( g_pDbgInfo->LastSecond != st.wSecond )
|
|||
|
{
|
|||
|
fdoPrint = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( fcontextSwitch || fdoPrint )
|
|||
|
{
|
|||
|
CHAR printBuffer[ 200 ];
|
|||
|
DWORD length;
|
|||
|
|
|||
|
length = sprintf(
|
|||
|
printBuffer,
|
|||
|
fcontextSwitch ?
|
|||
|
"\n%02d:%02d:%02d:%03d DBG switch from thread %X to thread %X\n" :
|
|||
|
"%02d:%02d:%02d:%03d DBG tick\n",
|
|||
|
st.wHour,
|
|||
|
st.wMinute,
|
|||
|
st.wSecond,
|
|||
|
st.wMilliseconds,
|
|||
|
g_pDbgInfo->LastThreadId,
|
|||
|
threadId );
|
|||
|
|
|||
|
g_pDbgInfo->LastSecond = st.wSecond;
|
|||
|
g_pDbgInfo->LastThreadId = threadId;
|
|||
|
|
|||
|
// print context
|
|||
|
// - suppress context even through thread test
|
|||
|
// would break recursion
|
|||
|
|
|||
|
privateDnsDebugPrint(
|
|||
|
printBuffer,
|
|||
|
FALSE // suppress context
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// output -- to debugger, console, file
|
|||
|
//
|
|||
|
|
|||
|
if ( IS_DNSDBG_ON( DEBUGGER ) )
|
|||
|
{
|
|||
|
OutputDebugString( pOutputBuffer );
|
|||
|
}
|
|||
|
|
|||
|
if ( IS_DNSDBG_ON( CONSOLE ) )
|
|||
|
{
|
|||
|
if ( g_pDbgInfo->fConsole )
|
|||
|
{
|
|||
|
length = strlen( pOutputBuffer );
|
|||
|
|
|||
|
ret = WriteFile(
|
|||
|
GetStdHandle(STD_OUTPUT_HANDLE),
|
|||
|
(PVOID) pOutputBuffer,
|
|||
|
length,
|
|||
|
&length,
|
|||
|
NULL
|
|||
|
);
|
|||
|
#if 0
|
|||
|
if ( !ret )
|
|||
|
{
|
|||
|
DnsDbg_PrintfToDebugger(
|
|||
|
"DnsDbg_Printf: console WriteFile failed: %ld\n",
|
|||
|
GetLastError() );
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// write to debug log
|
|||
|
//
|
|||
|
|
|||
|
if ( IS_DNSDBG_ON( FILE ) )
|
|||
|
{
|
|||
|
if ( g_pDbgInfo->hFile != INVALID_HANDLE_VALUE )
|
|||
|
{
|
|||
|
length = strlen( pOutputBuffer );
|
|||
|
|
|||
|
ret = WriteFile(
|
|||
|
g_pDbgInfo->hFile,
|
|||
|
(PVOID) pOutputBuffer,
|
|||
|
length,
|
|||
|
&length,
|
|||
|
NULL
|
|||
|
);
|
|||
|
if ( !ret )
|
|||
|
{
|
|||
|
DnsDbg_PrintfToDebugger(
|
|||
|
"DnsDbg_Printf: file WriteFile failed: %ld\n",
|
|||
|
GetLastError() );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if wrapping debug log file
|
|||
|
// - move current log to backup file
|
|||
|
// <file>.first on first wrap
|
|||
|
// <file>.last on subsequent wraps
|
|||
|
// - reopen current file name
|
|||
|
//
|
|||
|
|
|||
|
g_pDbgInfo->FileCurrentSize += length;
|
|||
|
|
|||
|
if ( g_pDbgInfo->FileWrapSize &&
|
|||
|
g_pDbgInfo->FileWrapSize <= g_pDbgInfo->FileCurrentSize )
|
|||
|
{
|
|||
|
DnsDbg_WrapLogFile();
|
|||
|
}
|
|||
|
else if ( IS_DNSDBG_ON( FLUSH ) )
|
|||
|
{
|
|||
|
FlushFileBuffers( g_pDbgInfo->hFile );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
DnsPrint_Unlock();
|
|||
|
|
|||
|
} // privateDnsDebugPrint
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
privateFormatAndPrintBuffer(
|
|||
|
IN LPSTR Format,
|
|||
|
IN va_list ArgList
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Arguments to formatted buffer print.
|
|||
|
|
|||
|
This helper routine exists to avoid duplicating buffer
|
|||
|
overflow logic in DnsDbg_Printf() and DnsDbg_PrintRoutine()
|
|||
|
|
|||
|
The overflow logic is required because the default stack size
|
|||
|
has been chopped down in whistler making is easy to generate
|
|||
|
stack expansion exceptions under stress. And of course this
|
|||
|
means the stress guys send me these B.S. stress failures.
|
|||
|
|
|||
|
Solution is to put a small buffer on the stack for perf, then
|
|||
|
allocate a larger buffer if the print doesn't fit into the
|
|||
|
stack buffer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Format -- standard C format string
|
|||
|
|
|||
|
ArgList -- standard arg list
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
CHAR stackBuffer[ DNS_STACK_PRINT_BUFFER_LENGTH ];
|
|||
|
ULONG bufLength;
|
|||
|
DWORD lastError;
|
|||
|
INT count;
|
|||
|
PCHAR pprintBuffer;
|
|||
|
PCHAR pheapBuffer = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// save last error so any WriteFile() failures don't mess it up
|
|||
|
//
|
|||
|
|
|||
|
lastError = GetLastError();
|
|||
|
|
|||
|
//
|
|||
|
// write formatted print buffer
|
|||
|
//
|
|||
|
// - first try stack buffer
|
|||
|
// - if fails, try heap buffer
|
|||
|
// - use best, always NULL terminate
|
|||
|
//
|
|||
|
|
|||
|
bufLength = DNS_STACK_PRINT_BUFFER_LENGTH;
|
|||
|
pprintBuffer = stackBuffer;
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
count = _vsnprintf(
|
|||
|
pprintBuffer,
|
|||
|
bufLength-1,
|
|||
|
Format,
|
|||
|
ArgList );
|
|||
|
|
|||
|
pprintBuffer[ bufLength-1 ] = 0;
|
|||
|
|
|||
|
if ( count > 0 || pheapBuffer )
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// try again with heap buffer
|
|||
|
|
|||
|
pheapBuffer = ALLOCATE_HEAP( DNS_HEAP_PRINT_BUFFER_LENGTH );
|
|||
|
if ( !pheapBuffer )
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
pprintBuffer = pheapBuffer;
|
|||
|
bufLength = DNS_HEAP_PRINT_BUFFER_LENGTH;
|
|||
|
}
|
|||
|
while( 1 );
|
|||
|
|
|||
|
va_end( ArgList );
|
|||
|
|
|||
|
// do the real print
|
|||
|
|
|||
|
privateDnsDebugPrint( pprintBuffer, TRUE );
|
|||
|
|
|||
|
if ( pheapBuffer )
|
|||
|
{
|
|||
|
FREE_HEAP( pheapBuffer );
|
|||
|
}
|
|||
|
|
|||
|
// restore LastError() if changed
|
|||
|
|
|||
|
if ( lastError != GetLastError() )
|
|||
|
{
|
|||
|
SetLastError( lastError );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DnsDbg_Printf(
|
|||
|
IN LPSTR Format,
|
|||
|
...
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
DNS debug print with printf semantics.
|
|||
|
|
|||
|
May print to any of
|
|||
|
- debugger
|
|||
|
- console window
|
|||
|
- debug log file
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pContext -- dummny context to match signature of PRINT_ROUTINE function
|
|||
|
|
|||
|
Format -- standard C format string
|
|||
|
|
|||
|
... -- standard arg list
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
va_list arglist;
|
|||
|
|
|||
|
va_start( arglist, Format );
|
|||
|
|
|||
|
privateFormatAndPrintBuffer(
|
|||
|
Format,
|
|||
|
arglist );
|
|||
|
|
|||
|
#if 0
|
|||
|
va_list arglist;
|
|||
|
CHAR outputBuffer[ DNS_PRINT_BUFFER_LENGTH+1 ];
|
|||
|
|
|||
|
va_start( arglist, Format );
|
|||
|
|
|||
|
vsnprintf( outputBuffer, DNS_PRINT_BUFFER_LENGTH, Format, arglist );
|
|||
|
|
|||
|
va_end( arglist );
|
|||
|
|
|||
|
outputBuffer[ DNS_PRINT_BUFFER_LENGTH ] = 0;
|
|||
|
|
|||
|
privateDnsDebugPrint( outputBuffer, TRUE );
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DnsDbg_PrintRoutine(
|
|||
|
IN OUT PPRINT_CONTEXT pContext,
|
|||
|
IN LPSTR Format,
|
|||
|
...
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
DNS debug print with PRINT_ROUTINE semantics.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pContext -- dummny context to match signature of PRINT_ROUTINE function
|
|||
|
|
|||
|
Format -- standard C format string
|
|||
|
|
|||
|
... -- standard arg list
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
va_list arglist;
|
|||
|
|
|||
|
va_start( arglist, Format );
|
|||
|
|
|||
|
privateFormatAndPrintBuffer(
|
|||
|
Format,
|
|||
|
arglist );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DnsDbg_Flush(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Flushes DNS debug printing to disk.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
FlushFileBuffers( g_pDbgInfo->hFile );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DnsDbg_PrintfToDebugger(
|
|||
|
IN LPSTR Format,
|
|||
|
...
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Print to debugger. Win95 has no DbgPrint().
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Format -- standard C format string
|
|||
|
|
|||
|
... -- standard arg list
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
va_list arglist;
|
|||
|
CHAR outputBuffer[ DNS_STACK_PRINT_BUFFER_LENGTH ];
|
|||
|
ULONG length;
|
|||
|
BOOL ret;
|
|||
|
|
|||
|
va_start( arglist, Format );
|
|||
|
|
|||
|
_vsnprintf( outputBuffer, DNS_STACK_PRINT_BUFFER_LENGTH, Format, arglist );
|
|||
|
|
|||
|
va_end( arglist );
|
|||
|
|
|||
|
outputBuffer[ DNS_STACK_PRINT_BUFFER_LENGTH ] = 0;
|
|||
|
|
|||
|
OutputDebugString( outputBuffer );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Debug utilities
|
|||
|
//
|
|||
|
// Other debug routines are coded generically as print routines (print.c)
|
|||
|
// and are macroed to debug routines by choosing DnsDbg_Printf() as the
|
|||
|
// print function.
|
|||
|
//
|
|||
|
|
|||
|
#if DBG
|
|||
|
|
|||
|
VOID
|
|||
|
DnsDbg_CSEnter(
|
|||
|
IN PCRITICAL_SECTION pLock,
|
|||
|
IN LPSTR pszLockName,
|
|||
|
IN LPSTR pszFile,
|
|||
|
IN INT LineNo
|
|||
|
)
|
|||
|
{
|
|||
|
DnsDbg_Printf(
|
|||
|
"\nENTERING %s lock %p in %s, line %d.\n",
|
|||
|
pszLockName,
|
|||
|
pLock,
|
|||
|
pszFile,
|
|||
|
LineNo );
|
|||
|
EnterCriticalSection( pLock );
|
|||
|
DnsDbg_Printf(
|
|||
|
"\nHOLDING %s lock %p in %s, line %d.\n",
|
|||
|
pszLockName,
|
|||
|
pLock,
|
|||
|
pszFile,
|
|||
|
LineNo );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DnsDbg_CSLeave(
|
|||
|
IN PCRITICAL_SECTION pLock,
|
|||
|
IN LPSTR pszLockName,
|
|||
|
IN LPSTR pszFile,
|
|||
|
IN INT LineNo
|
|||
|
)
|
|||
|
{
|
|||
|
DnsDbg_Printf(
|
|||
|
"\nRELEASING %s lock %p in %s, line %d.\n",
|
|||
|
pszLockName,
|
|||
|
pLock,
|
|||
|
pszFile,
|
|||
|
LineNo );
|
|||
|
LeaveCriticalSection( pLock );
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// End of debug.c
|
|||
|
//
|