415 lines
10 KiB
C++
415 lines
10 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1997.
|
||
|
//
|
||
|
// File: D E B U G X . C P P
|
||
|
//
|
||
|
// Contents: Implementation of debug support routines.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// Author: danielwe 16 Feb 1997
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.h>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#ifdef DBG
|
||
|
|
||
|
#include "ncdebug.h"
|
||
|
#include "ncdefine.h"
|
||
|
|
||
|
static int nAssertLevel = 0;
|
||
|
static PFNASSERTHOOK pfnAssertHook = DefAssertSzFn;
|
||
|
|
||
|
#define MAX_ASSERT_TEXT_SIZE 4096
|
||
|
//
|
||
|
// We can only do memory tracking if we've included crtdbg.h and
|
||
|
// _DEBUG is defined.
|
||
|
//
|
||
|
#if defined(_INC_CRTDBG) && defined(_DEBUG)
|
||
|
struct DBG_SHARED_MEM
|
||
|
{
|
||
|
_CrtMemState crtState;
|
||
|
DWORD cRef;
|
||
|
};
|
||
|
|
||
|
DBG_SHARED_MEM * g_pMem = NULL;
|
||
|
HANDLE g_hMap = NULL;
|
||
|
|
||
|
static const WCHAR c_szSharedMem[] = L"DBG_NetCfgSharedMemory";
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: InitDbgState
|
||
|
//
|
||
|
// Purpose: Initializes the memory leak detection code.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns: Nothing.
|
||
|
//
|
||
|
// Author: danielwe 13 May 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
VOID InitDbgState()
|
||
|
{
|
||
|
g_hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
|
||
|
0, sizeof(DBG_SHARED_MEM), c_szSharedMem);
|
||
|
if (g_hMap)
|
||
|
{
|
||
|
LPVOID pvMem;
|
||
|
BOOL fExisted = (GetLastError() == ERROR_ALREADY_EXISTS);
|
||
|
|
||
|
pvMem = MapViewOfFile(g_hMap, FILE_MAP_WRITE, 0, 0, 0);
|
||
|
g_pMem = reinterpret_cast<DBG_SHARED_MEM *>(pvMem);
|
||
|
|
||
|
if (!fExisted)
|
||
|
{
|
||
|
// First time creating the file mapping. Initialize things.
|
||
|
|
||
|
g_pMem->cRef = 0;
|
||
|
|
||
|
// start looking for leaks now
|
||
|
_CrtMemCheckpoint(&g_pMem->crtState);
|
||
|
}
|
||
|
|
||
|
g_pMem->cRef++;
|
||
|
TraceTag(ttidDefault, "DBGMEM: Init Refcount on shared mem is now %d",
|
||
|
g_pMem->cRef);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UnInitDbgState
|
||
|
//
|
||
|
// Purpose: Uninitializes the memory leak detection code.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns: Nothing.
|
||
|
//
|
||
|
// Author: danielwe 13 May 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
VOID UnInitDbgState()
|
||
|
{
|
||
|
if (g_pMem)
|
||
|
{
|
||
|
g_pMem->cRef--;
|
||
|
TraceTag(ttidDefault, "DBGMEM: Uninit Refcount on shared mem is now %d",
|
||
|
g_pMem->cRef);
|
||
|
|
||
|
if (!g_pMem->cRef)
|
||
|
{
|
||
|
// manually force dump of leaks when refcount goes to 0
|
||
|
_CrtMemDumpAllObjectsSince(&g_pMem->crtState);
|
||
|
}
|
||
|
|
||
|
UnmapViewOfFile(reinterpret_cast<LPVOID>(g_pMem));
|
||
|
CloseHandle(g_hMap);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
BOOL WINAPI FInAssert(VOID)
|
||
|
{
|
||
|
return nAssertLevel > 0;
|
||
|
}
|
||
|
|
||
|
VOID WINAPIV AssertFmt(BOOL fExp, PCSTR pszaFile, int nLine, PCSTR pszaFmt, ...)
|
||
|
{
|
||
|
CHAR rgch[MAX_ASSERT_TEXT_SIZE];
|
||
|
|
||
|
if (!fExp)
|
||
|
{
|
||
|
va_list valMarker;
|
||
|
|
||
|
va_start(valMarker, pszaFmt);
|
||
|
wvsprintfA(rgch, pszaFmt, valMarker);
|
||
|
va_end(valMarker);
|
||
|
|
||
|
AssertSzFn(rgch, pszaFile, nLine);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID WINAPI AssertSzFn(PCSTR pszaMsg, PCSTR pszaFile, INT nLine)
|
||
|
{
|
||
|
CHAR rgch[MAX_ASSERT_TEXT_SIZE];
|
||
|
|
||
|
++nAssertLevel;
|
||
|
|
||
|
if (pszaFile)
|
||
|
{
|
||
|
if (pszaMsg)
|
||
|
{
|
||
|
wsprintfA(rgch, "Net Config Assert Failure:\r\n File %s, line %d:\r\n %s\r\n",
|
||
|
pszaFile, nLine, pszaMsg);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wsprintfA(rgch, "Net Config Assert Failure:\r\n File %s, line %d.\r\n",
|
||
|
pszaFile, nLine);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pszaMsg)
|
||
|
{
|
||
|
wsprintfA(rgch, "Net Config Assert Failure:\r\n:\r\n %s\r\n",
|
||
|
pszaMsg);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wsprintfA(rgch, "Net Config Assert Failure\r\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
OutputDebugStringA(rgch);
|
||
|
|
||
|
if (pfnAssertHook)
|
||
|
{
|
||
|
(*pfnAssertHook)(pszaMsg, pszaFile, nLine);
|
||
|
}
|
||
|
|
||
|
--nAssertLevel;
|
||
|
}
|
||
|
|
||
|
VOID WINAPI AssertSzFn(PCSTR pszaMsg, PCSTR pszaFile, INT nLine, PCSTR pszaFunc)
|
||
|
{
|
||
|
CHAR rgch[MAX_ASSERT_TEXT_SIZE];
|
||
|
|
||
|
++nAssertLevel;
|
||
|
|
||
|
if (pszaFile)
|
||
|
{
|
||
|
if (pszaMsg)
|
||
|
{
|
||
|
wsprintfA(rgch, "Net Config Assert Failure:\r\n File %s, line %d, Func: %s:\r\n %s\r\n",
|
||
|
pszaFile, nLine, pszaFunc, pszaMsg );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wsprintfA(rgch, "Net Config Assert Failure:\r\n File %s, line %d, Func: %s:.\r\n",
|
||
|
pszaFile, nLine, pszaFunc ) ;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pszaMsg)
|
||
|
{
|
||
|
wsprintfA(rgch, "Net Config Assert Failure:\r\n:\r\n %s\r\n",
|
||
|
pszaMsg);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wsprintfA(rgch, "Net Config Assert Failure\r\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
OutputDebugStringA(rgch);
|
||
|
|
||
|
if (pfnAssertHook)
|
||
|
{
|
||
|
(*pfnAssertHook)(pszaMsg, pszaFile, nLine);
|
||
|
}
|
||
|
|
||
|
--nAssertLevel;
|
||
|
}
|
||
|
|
||
|
VOID WINAPI AssertSzFnWithDbgPrompt(BOOL fPromptIgnore, PCSTR pszaMsg, PCSTR pszaFile, INT nLine, PCSTR pszaFunc)
|
||
|
{
|
||
|
CHAR rgch[MAX_ASSERT_TEXT_SIZE];
|
||
|
|
||
|
DWORD dwProcId = GetCurrentProcessId();
|
||
|
if (fPromptIgnore)
|
||
|
{
|
||
|
wsprintfA(rgch, "%s.\r\nPlease attach a kernel mode debugger, or (if you have local access to symbols) a user mode debugger to process id %d (decimal) and hit IGNORE to debug the problem\r\nE.g. use ntsd -Gg -p %d, (or ntsd -d -Gg -p %d) and then hit IGNORE.", pszaMsg, dwProcId, dwProcId, dwProcId);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wsprintfA(rgch, "%s.\r\nPlease attach a user mode debugger to process id %d (decimal) and hit RETRY to debug the problem\r\nE.g. use ntsd -Gg -p %d, (or ntsd -d -Gg -p %d) and then hit RETRY.", pszaMsg, dwProcId, dwProcId, dwProcId);
|
||
|
}
|
||
|
AssertSzFn(rgch, pszaFile, nLine, pszaFunc);
|
||
|
};
|
||
|
|
||
|
VOID CALLBACK DefAssertSzFn(PCSTR pszaMsg, PCSTR pszaFile, INT nLine)
|
||
|
{
|
||
|
CHAR rgch[2048];
|
||
|
INT nID;
|
||
|
int cch;
|
||
|
PSTR pch;
|
||
|
BOOL fNYIWarning = FALSE;
|
||
|
CHAR szaNYI[] = "NYI:";
|
||
|
|
||
|
if (pszaFile)
|
||
|
{
|
||
|
wsprintfA(rgch, "File %s, line %d\r\n\r\n", pszaFile, nLine);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rgch[0] = 0;
|
||
|
}
|
||
|
|
||
|
if (pszaMsg)
|
||
|
{
|
||
|
// Check to see if this is an NYI alert. If so, then we'll want
|
||
|
// to use a different MessageBox title
|
||
|
if (strncmp(pszaMsg, szaNYI, strlen(szaNYI)) == 0)
|
||
|
{
|
||
|
fNYIWarning = TRUE;
|
||
|
}
|
||
|
|
||
|
lstrcatA(rgch, pszaMsg);
|
||
|
}
|
||
|
|
||
|
|
||
|
cch = lstrlenA(rgch);
|
||
|
pch = &rgch[cch];
|
||
|
|
||
|
if (cch < celems(rgch))
|
||
|
{
|
||
|
lstrcpynA(pch, "\n\nPress Abort to crash, Retry to debug, or Ignore to ignore."
|
||
|
"\nHold down Shift to copy the assert text to the "
|
||
|
"clipboard before the action is taken.", celems(rgch) - cch - 1);
|
||
|
}
|
||
|
|
||
|
MessageBeep(MB_ICONHAND);
|
||
|
|
||
|
nID = MessageBoxA(NULL, rgch,
|
||
|
fNYIWarning ? "Net Config -- Not Yet Implemented" : "Net Config Assert Failure",
|
||
|
MB_ABORTRETRYIGNORE | MB_DEFBUTTON3 | MB_ICONHAND |
|
||
|
MB_SETFOREGROUND | MB_TASKMODAL | MB_SERVICE_NOTIFICATION);
|
||
|
|
||
|
if (nID == IDRETRY)
|
||
|
{
|
||
|
DebugBreak();
|
||
|
}
|
||
|
|
||
|
// if cancelling, force a hard exit w/ a GP-fault so that Dr. Watson
|
||
|
// generates a nice stack trace log.
|
||
|
if (nID == IDABORT)
|
||
|
{
|
||
|
*(BYTE *) 0 = 1; // write to address 0 causes GP-fault
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID WINAPI SetAssertFn(PFNASSERTHOOK pfn)
|
||
|
{
|
||
|
pfnAssertHook = pfn;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
// To be called during DLL_PROCESS_DETACH for a DLL which implements COM
|
||
|
// objects or hands out references to objects which can be tracked.
|
||
|
// Call this function with the name of the DLL (so that it can be traced
|
||
|
// to the debugger) and the lock count of the DLL. If the lock count is
|
||
|
// non-zero, it means the DLL is being unloaded prematurley. When this
|
||
|
// condition is detected, a message is printed to the debugger and a
|
||
|
// DebugBreak will be invoked if the debug flag dfidBreakOnPrematureDllUnload
|
||
|
// is set.
|
||
|
//
|
||
|
// Assumptions:
|
||
|
// Trace and debugging features have not been uninitialized.
|
||
|
//
|
||
|
//
|
||
|
VOID
|
||
|
DbgCheckPrematureDllUnload (
|
||
|
PCSTR pszaDllName,
|
||
|
UINT ModuleLockCount)
|
||
|
{
|
||
|
if (0 != ModuleLockCount)
|
||
|
{
|
||
|
TraceTag(ttidNetcfgBase, "ModuleLockCount == %d. "
|
||
|
"%s is being unloaded with clients still holding references!",
|
||
|
ModuleLockCount,
|
||
|
pszaDllName);
|
||
|
|
||
|
if (FIsDebugFlagSet(dfidBreakOnPrematureDllUnload))
|
||
|
{
|
||
|
DebugBreak ();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif //! DBG
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: InitializeDebugging
|
||
|
//
|
||
|
// Purpose: Called by every DLL or EXE to initialize the debugging
|
||
|
// objects (Trace and DebugFlag tables)
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 23 Sep 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
NOTHROW void InitializeDebugging()
|
||
|
{
|
||
|
// For debug builds or if we have retail tracing enabled we need to
|
||
|
// include the tracing code.
|
||
|
// Ignore the error return, since we don't return it here anyway.
|
||
|
//
|
||
|
#ifdef ENABLETRACE
|
||
|
(void) HrInitTracing();
|
||
|
#endif
|
||
|
|
||
|
#if defined(DBG) && defined(_INC_CRTDBG) && defined(_DEBUG)
|
||
|
if (FIsDebugFlagSet (dfidDumpLeaks))
|
||
|
{
|
||
|
InitDbgState();
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UnInitializeDebugging
|
||
|
//
|
||
|
// Purpose: Uninitialize the debugging objects (Tracing and DbgFlags)
|
||
|
//
|
||
|
// Arguments:
|
||
|
// (none)
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: jeffspr 23 Sep 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
NOTHROW void UnInitializeDebugging()
|
||
|
{
|
||
|
// For debug builds or if we have retail tracing enabled we will have
|
||
|
// included the tracing code. We now need to uninitialize it.
|
||
|
// Ignore the error return, since we don't return it here anyway.
|
||
|
//
|
||
|
#ifdef ENABLETRACE
|
||
|
|
||
|
(void) HrUnInitTracing();
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#if defined(DBG) && defined(_INC_CRTDBG) && defined(_DEBUG)
|
||
|
if (FIsDebugFlagSet (dfidDumpLeaks))
|
||
|
{
|
||
|
UnInitDbgState();
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|