Windows2000/private/windows/shell/dskquota/common/debug.cpp
2020-09-30 17:12:32 +02:00

434 lines
10 KiB
C++

/* File: debug.cpp
Description: Provides debugging macros to support tracing, debugger print
statements, error message debugger output and assertions.
I'm sure you're saying "why ANOTHER debugger output implementation".
There are many around but I haven't found one that is as flexible and
consistent as I would like. This library suports the concept of
both functional "masks" and detail "levels" to control the quantity
of debugger output.
Masks let you control debugger output based on program function. For
instance, if you tag a DBGPRINT statement with the mask DM_XYZ, it
will only be activated if the global variable DebugParams::PrintMask
has the DM_XYZ bit set.
Levels let you control debugger output based on a level of desired
detail. Sometimes you just want to see the basic functions happening
but other times, you need to see everything that's going on. This
leveling allows you to specify at which level a macro is enabled.
The library is designed to be activated with the DBG macro.
If DBG is not defined as 1, there is no trace of this code in your
product.
Revision History:
Date Description Programmer
-------- ----------- ----------
01/19/98 Replaced with version from CSC cache viewer. BrianAu
*/
#include "pch.h"
#pragma hdrstop
#if DBG
// Defaults for the DebugParams members.
// By default, tracing and printing should be silent (no output).
// The default mask values of 0 ensure this.
// Also, printing and tracing are not verbose by default.
// Note that errors and asserts are always active when DBG is defined as 1.
// Errors and asserts are also always verbose.
LPCTSTR DebugParams::m_pszModule = TEXT("");
UINT DebugParams::TraceLevel = 0;
UINT DebugParams::PrintLevel = 0;
bool DebugParams::TraceVerbose = false;
bool DebugParams::PrintVerbose = false;
bool DebugParams::TraceOnExit = true;
ULONGLONG DebugParams::TraceMask = 0;
ULONGLONG DebugParams::PrintMask = 0;
// Static default values for DebugPrint and DebugTrace classes.
const ULONGLONG DebugPrint::DEFMASK = (ULONGLONG)-1;
const UINT DebugPrint::DEFLEVEL = 0;
const ULONGLONG DebugTrace::DEFMASK = (ULONGLONG)-1;
const UINT DebugTrace::DEFLEVEL = 0;
LPCTSTR
DebugParams::SetModule(
LPCTSTR pszModule
)
{
LPCTSTR pszModulePrev = m_pszModule;
m_pszModule = pszModule;
return pszModulePrev;
}
void
DebugParams::SetDebugMask(
ULONGLONG llMask
)
{
TraceMask = PrintMask = llMask;
}
void
DebugParams::SetDebugLevel(
UINT uLevel
)
{
TraceLevel = PrintLevel = uLevel;
}
void
DebugParams::SetDebugVerbose(
bool bVerbose
)
{
TraceVerbose = PrintVerbose = bVerbose;
}
void
DebugParams::SetTraceOnExit(
bool bTrace
)
{
TraceOnExit = bTrace;
}
void *
DebugParams::GetItemPtr(
DebugParams::Item item,
DebugParams::Type type
)
{
// Assertions are active for all levels, any program function (mask = -1)
// and are always verbose.
static bool bAssertVerbose = true;
static UINT uAssertLevel = 0;
static ULONGLONG llAssertMask = DM_ALL;
// This array just eliminates the need for a lot of code when setting
// or reading the various global DebugParam members.
static void *rgpMember[eTypeMax][eItemMax] = { { &TraceMask, &TraceLevel, &TraceVerbose },
{ &PrintMask, &PrintLevel, &PrintVerbose },
{ &llAssertMask, &uAssertLevel, &bAssertVerbose }
};
return rgpMember[type][item];
}
ULONGLONG
DebugParams::SetMask(
ULONGLONG llMask,
DebugParams::Type type
)
{
ULONGLONG *pllMask = (ULONGLONG *)GetItemPtr(DebugParams::eMask, type);
ULONGLONG llMaskPrev = *pllMask;
*pllMask = llMask;
return llMaskPrev;
}
UINT
DebugParams::SetLevel(
UINT uLevel,
DebugParams::Type type
)
{
UINT *puLevel = (UINT *)GetItemPtr(DebugParams::eLevel, type);
UINT uLevelPrev = *puLevel;
*puLevel = uLevel;
return uLevelPrev;
}
bool
DebugParams::SetVerbose(
bool bVerbose,
DebugParams::Type type
)
{
bool *pbVerbose = (bool *)GetItemPtr(DebugParams::eVerbose, type);
bool bVerbosePrev = *pbVerbose;
*pbVerbose = bVerbose;
return bVerbosePrev;
}
DebugTrace::DebugTrace(
LPCTSTR pszFile,
INT iLineNo
) : m_pszFile(pszFile),
m_iLineNo(iLineNo),
m_llMask(0),
m_uLevel(0)
{
// Do nothing.
}
void
DebugTrace::Enter(
ULONGLONG llMask,
UINT uLevel,
LPCTSTR pszBlockName
) const
{
DebugPrint(DebugParams::eTrace, m_pszFile, m_iLineNo).Print(m_llMask = llMask, m_uLevel = uLevel, TEXT("++ ENTER %s"), m_pszBlockName = pszBlockName);
}
void
DebugTrace::Enter(
ULONGLONG llMask,
UINT uLevel,
LPCTSTR pszBlockName,
LPCTSTR pszFmt,
...
) const
{
va_list args;
va_start(args, pszFmt);
TCHAR szMsg[1024];
wvsprintf(szMsg, pszFmt, args);
va_end(args);
DebugPrint(DebugParams::eTrace, m_pszFile, m_iLineNo).Print(m_llMask = llMask, m_uLevel = uLevel, TEXT("++ ENTER %s: %s"), m_pszBlockName = pszBlockName, szMsg);
}
void
DebugTrace::Enter(
LPCTSTR pszBlockName
) const
{
Enter(DebugTrace::DEFMASK, DebugTrace::DEFLEVEL, pszBlockName);
}
void
DebugTrace::Enter(
LPCTSTR pszBlockName,
LPCTSTR pszFmt,
...
) const
{
va_list args;
va_start(args, pszFmt);
TCHAR szMsg[1024];
wvsprintf(szMsg, pszFmt, args);
va_end(args);
DebugPrint(DebugParams::eTrace, m_pszFile, m_iLineNo).Print(m_llMask = DebugTrace::DEFMASK, m_uLevel = DebugTrace::DEFLEVEL, TEXT("++ ENTER %s: %s"), m_pszBlockName = pszBlockName, szMsg);
}
DebugTrace::~DebugTrace(void)
{
if (DebugParams::TraceOnExit)
DebugPrint(DebugParams::eTrace, m_pszFile, m_iLineNo).Print(m_llMask, m_uLevel, TEXT("-- LEAVE %s"), m_pszBlockName);
}
DebugPrint::DebugPrint(
DebugParams::Type type,
LPCTSTR pszFile,
INT iLineNo
) : m_pszFile(pszFile),
m_iLineNo(iLineNo),
m_type(type)
{
// Do nothing.
}
void
DebugPrint::Print(
LPCTSTR pszFmt,
...
) const
{
va_list args;
va_start(args, pszFmt);
Print(DebugPrint::DEFMASK, DebugPrint::DEFLEVEL, pszFmt, args);
va_end(args);
}
void
DebugPrint::Print(
ULONGLONG llMask,
UINT uLevel,
LPCTSTR pszFmt,
...
) const
{
va_list args;
va_start(args, pszFmt);
Print(llMask, uLevel, pszFmt, args);
va_end(args);
}
// Determine if there are any corresponding bits set in two ULONGLONG
// values. Can't just do a simple bitwise AND operation because the compiler
// truncates the operands to integer size.
bool
DebugPrint::AnyBitSet(
ULONGLONG llMask,
ULONGLONG llTest
)
{
ULARGE_INTEGER ulMask, ulTest;
ulMask.QuadPart = llMask;
ulTest.QuadPart = llTest;
return (ulMask.LowPart & ulTest.LowPart) || (ulMask.HighPart & ulTest.HighPart);
}
// Internal [private] print function.
// All other print functions end up here.
void
DebugPrint::Print(
ULONGLONG llMask,
UINT uLevel,
LPCTSTR pszFmt,
va_list args
) const
{
// Crude check to make sure we haven't overflowed the text buffer.
// It's 1K so I don't expect it. But if we do, it needs to be
// announced somehow so either the buffer can be enlarged or the
// message text reduced. I can't use DBGASSERT because that will
// cause recursion.
#define CHECKOVERFLOW \
if (pszWrite >= (pszEnd - 3)) {\
OutputDebugString(TEXT("Buffer overflow in DebugPrint::Print, File:")TEXT(__FILE__)TEXT(" Line:")TEXT("#__LINE__")); \
DebugBreak(); }
// Retrieve the global DebugParam members for the "type" being printed.
// i.e. ePrint, eAssert or eTrace.
ULONGLONG *pllMask = (ULONGLONG *)DebugParams::GetItemPtr(DebugParams::eMask, m_type);
UINT *puLevel = (UINT *)DebugParams::GetItemPtr(DebugParams::eLevel, m_type);
bool *pbVerbose = (bool *)DebugParams::GetItemPtr(DebugParams::eVerbose, m_type);
if ((uLevel <= *puLevel) && AnyBitSet(llMask, *pllMask))
{
// The statement is both "mask" and "level" enabled.
// Generate debugger output.
TCHAR szText[1024];
LPTSTR pszWrite = szText;
LPCTSTR pszEnd = pszWrite + ARRAYSIZE(szText);
// Each message has "[<module>:<thread>]" prefix.
pszWrite += wsprintf(pszWrite,
TEXT("[%s:%d] "),
DebugParams::m_pszModule,
GetCurrentThreadId());
CHECKOVERFLOW;
// Append the message text (formatted).
pszWrite += wvsprintf(pszWrite, pszFmt, args);
CHECKOVERFLOW;
if (*pbVerbose)
{
// Verbose output is desired. Add the filename/line number pair
// indented on the next line.
pszWrite += wsprintf(pszWrite, TEXT("\n\r\t+->File: %s, Line: %d"), m_pszFile, m_iLineNo);
}
CHECKOVERFLOW;
// Append a CRLF.
lstrcpy(pszWrite, TEXT("\n\r"));
OutputDebugString(szText);
}
}
DebugError::DebugError(
LPCTSTR pszFile,
INT iLineNo
) : DebugPrint(DebugParams::ePrint, pszFile, iLineNo)
{
// Do nothing.
}
void
DebugError::Error(
LPCTSTR pszFmt,
...
) const
{
va_list args;
va_start(args, pszFmt);
ULONGLONG llMaskSaved = DebugParams::PrintMask;
UINT uLevelSaved = DebugParams::PrintLevel;
DebugParams::PrintMask = (ULONGLONG)-1;
DebugParams::PrintLevel = 99999;
Print((ULONGLONG)-1, 0, pszFmt, args);
DebugParams::PrintLevel = uLevelSaved;
DebugParams::PrintMask = llMaskSaved;
va_end(args);
}
DebugAssert::DebugAssert(
LPCTSTR pszFile,
INT iLineNo,
LPCTSTR pszTest
)
{
DebugPrint PrintThis(DebugParams::eAssert, pszFile, iLineNo);
ULONGLONG llMaskSaved = DebugParams::PrintMask;
UINT uLevelSaved = DebugParams::PrintLevel;
DebugParams::PrintMask = (ULONGLONG)-1;
DebugParams::PrintLevel = 99999;
PrintThis.Print((ULONGLONG)-1, 0, pszTest);
DebugParams::PrintLevel = uLevelSaved;
DebugParams::PrintMask = llMaskSaved;
DebugBreak();
}
#endif // DBG