NT4/private/ole32/stg/docfile/debug.cxx
2020-09-30 17:12:29 +02:00

774 lines
19 KiB
C++

//+--------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992
//
// File: debug.cxx
//
// Contents: Debugging routines
//
// History: 07-Mar-92 DrewB Created
//
//---------------------------------------------------------------
#include <dfhead.cxx>
#pragma hdrstop
#if DBG == 1
#include <w4wchar.h>
#include <stdarg.h>
#include <dfdeb.hxx>
#include <logfile.hxx>
#include <df32.hxx>
//+-------------------------------------------------------------
//
// Function: DfDebug, public
//
// Synopsis: Sets debugging level
//
//---------------------------------------------------------------
DECLARE_INFOLEVEL(ol);
#define LOGFILENAME L"logfile.txt"
static CGlobalFileStream *_pgfstLogFiles = NULL;
WCHAR gwcsLogFile[] = LOGFILENAME;
STDAPI_(void) DfDebug(ULONG ulLevel, ULONG ulMSFLevel)
{
#if DBG == 1
olInfoLevel = ulLevel;
SetInfoLevel(ulMSFLevel);
_SetWin4InfoLevel(ulLevel | ulMSFLevel);
olDebugOut((DEB_ITRACE, "\n-- DfDebug(0x%lX, 0x%lX)\n",
ulLevel, ulMSFLevel));
#endif
}
// NT and Cairo
#ifdef WIN32
#if 0
// Throw Win32 error information
#define THROW_LAST_ERROR() THROW_SC(LAST_SCODE)
//+---------------------------------------------------------------------------
//
// Class: CDfGlobalMemory (dgm)
//
// Purpose: Create a fixed size chunk of globally shared memory
//
// Interface: See below
//
// History: 06-May-93 DrewB Created
//
// Notes: The init function is only called once when the shared
// memory is first created.
//
// The end function is only called once when the last
// reference to the global memory is released
//
// The reference count is added onto the global allocation
// and kept at offset zero so the address returned to
// client code is offset by sizeof(LONG)
//
//----------------------------------------------------------------------------
typedef void (*DfGlobalMemoryFn)(void *);
class CDfGlobalMemory
{
public:
CDfGlobalMemory(TCHAR const *ptcsName,
DWORD cbSize,
DfGlobalMemoryFn pfnInit,
DfGlobalMemoryFn pfnEnd);
~CDfGlobalMemory(void);
inline void *GetAddress(void) const;
private:
inline LONG *RefCount(void);
HANDLE _hMapping;
void *_pvMemory;
DfGlobalMemoryFn _pfnEnd;
};
//+---------------------------------------------------------------------------
//
// Member: CDfGlobalMemory::GetAddress, public
//
// Synopsis: Returns the address of the shared memory
//
// History: 06-May-93 DrewB Created
//
//----------------------------------------------------------------------------
inline void *CDfGlobalMemory::GetAddress(void) const
{
return (void *)((LONG *)_pvMemory+1);
}
//+---------------------------------------------------------------------------
//
// Member: CDfGlobalMemory::RefCount, private
//
// Synopsis: Returns a pointer to the reference count
//
// History: 07-May-93 DrewB Created
//
//----------------------------------------------------------------------------
inline LONG *CDfGlobalMemory::RefCount(void)
{
return (LONG *)_pvMemory;
}
//+---------------------------------------------------------------------------
//
// Member: CDfGlobalMemory::CDfGlobalMemory, public
//
// Synopsis: Creates a chunk of global memory
//
// Arguments: [ptcsName] - Name for sharing
// [cbSize] - Size of chunk
// [pfnInit] - Initialization function or NULL
// [pfnEnd] - Shutdown function or NULL
//
// History: 06-May-93 DrewB Created
//
// Notes: Allowed to throw on failure; this is debug only code
//
//----------------------------------------------------------------------------
CDfGlobalMemory::CDfGlobalMemory(TCHAR const *ptcsName,
DWORD cbSize,
DfGlobalMemoryFn pfnInit,
DfGlobalMemoryFn pfnEnd)
{
BOOL fOpened;
#if WIN32 == 100 || WIN32 > 200
CGlobalSecurity gs;
SCODE sc;
if (FAILED(sc = gs.Init()))
THROW_SC(sc);
_hMapping = CreateFileMapping((HANDLE)0xFFFFFFFF, gs, PAGE_READWRITE,
0, cbSize+sizeof(LONG), (TCHAR *)ptcsName);
#else
_hMapping = CreateFileMapping((HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE,
0, cbSize+sizeof(LONG), (TCHAR *)ptcsName);
#endif
if (_hMapping == NULL)
THROW_LAST_ERROR();
fOpened = GetLastError() == ERROR_ALREADY_EXISTS;
_pvMemory = MapViewOfFile(_hMapping, FILE_MAP_ALL_ACCESS,
0, 0, 0);
if (_pvMemory == NULL)
{
CloseHandle(_hMapping);
THROW_LAST_ERROR();
}
if (pfnInit && !fOpened)
{
*(RefCount()) = 0;
pfnInit(GetAddress());
}
_pfnEnd = pfnEnd;
InterlockedIncrement(RefCount());
}
//+---------------------------------------------------------------------------
//
// Member: CDfGlobalMemory::~CDfGlobalMemory, public
//
// Synopsis: Releases resources for shared memory
//
// History: 06-May-93 DrewB Created
//
//----------------------------------------------------------------------------
CDfGlobalMemory::~CDfGlobalMemory(void)
{
if (InterlockedDecrement(RefCount()) == 0 && _pfnEnd)
_pfnEnd(GetAddress());
UnmapViewOfFile(_pvMemory);
CloseHandle(_hMapping);
}
#endif //0
#endif // WIN32
// Resource limits
static LONG lResourceLimits[CDBRESOURCES] =
{
0x7fffffff, // DBR_MEMORY
0x7fffffff, // DBR_XSCOMMITS
0x0, // DBR_FAILCOUNT
0x0, // DBR_FAILLIMIT
0x0, // DBRQ_MEMORY_ALLOCATED
0x0, // DBRI_ALLOC_LIST
0x0, // DBRI_LOGFILE_LIST
0x0 // DBRF_LOGGING
};
#define CBRESOURCES sizeof(lResourceLimits)
#if 0
static CStaticDfMutex _sdmtxResources(TSTR("DfResourceMutex"));
static void ResInit(void *pvMemory)
{
// Initialize limits
memcpy(pvMemory, lResourceLimits, CBRESOURCES);
}
static CDfGlobalMemory _dgmResourceLimits(TSTR("DfResourceMemory"),
CBRESOURCES,
ResInit,
NULL);
#define RESLIMIT(n) \
(*((LONG *)_dgmResourceLimits.GetAddress()+(n)))
#define TAKEMTX \
olVerSucc(_sdmtxResources.Take(INFINITE))
#define RELEASEMTX \
_sdmtxResources.Release();
#else
#define RESLIMIT(n) lResourceLimits[n]
#define TAKEMTX
#define RELEASEMTX
#endif
//+---------------------------------------------------------------------------
//
// Function: DfSetResLimit, public
//
// Synopsis: Sets a resource limit
//
// History: 24-Nov-92 DrewB Created
//
//----------------------------------------------------------------------------
STDAPI_(void) DfSetResLimit(UINT iRes, LONG lLimit)
{
TAKEMTX;
RESLIMIT(iRes) = lLimit;
RELEASEMTX;
}
//+---------------------------------------------------------------------------
//
// Function: DfGetResLimit, public
//
// Synopsis: Gets a resource limit
//
// History: 24-Nov-92 DrewB Created
//
//----------------------------------------------------------------------------
STDAPI_(LONG) DfGetResLimit(UINT iRes)
{
// Doesn't need serialization
return RESLIMIT(iRes);
}
//+---------------------------------------------------------------------------
//
// Function: HaveResource, private
//
// Synopsis: Checks to see if a resource limit is exceeded
// and consumes resource if not
//
// History: 24-Nov-92 DrewB Created
//
//----------------------------------------------------------------------------
BOOL HaveResource(UINT iRes, LONG lRequest)
{
if (RESLIMIT(iRes) >= lRequest)
{
TAKEMTX;
RESLIMIT(iRes) -= lRequest;
RELEASEMTX;
return TRUE;
}
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Function: ModifyResLimit, private
//
// Synopsis: Adds to a resource limit
//
// History: 24-Nov-92 DrewB Created
//
//----------------------------------------------------------------------------
LONG ModifyResLimit(UINT iRes, LONG lChange)
{
LONG l;
TAKEMTX;
RESLIMIT(iRes) += lChange;
l = RESLIMIT(iRes);
RELEASEMTX;
return l;
}
//+-------------------------------------------------------------------------
//
// Function: SimulateFailure
//
// Synopsis: Check for simulated failure
//
// Effects: Tracks failure count
//
// Arguments: [failure] -- failure type
//
// Returns: TRUE if call should fail, FALSE if call should succeed
//
// Modifies: RESLIMIT(DBR_FAILCOUNT)
//
// Algorithm: Increment failure count, fail if count has succeeded
// limit
//
// History: 21-Jan-93 AlexT Created
//
//--------------------------------------------------------------------------
BOOL SimulateFailure(DBFAILURE failure)
{
LONG l;
BOOL fFail;
// We don't special case failure types, yet.
TAKEMTX;
RESLIMIT(DBR_FAILCOUNT)++;
l = RESLIMIT(DBR_FAILLIMIT);
fFail = RESLIMIT(DBR_FAILCOUNT) >= l;
RELEASEMTX;
if (l == 0)
{
// We're not simulating any failures; just tracking them
return(FALSE);
}
return fFail;
}
//+--------------------------------------------------------------
//
// Class: CChecksumBlock (cb)
//
// Purpose: Holds a memory block that is being checksummed
//
// Interface: See below
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
class CChecksumBlock
{
public:
CChecksumBlock(char *pszName,
void *pvAddr,
ULONG cBytes,
DWORD dwFlags,
CChecksumBlock *pcbNext,
CChecksumBlock *pcbPrev);
~CChecksumBlock(void);
char *_pszName;
void *_pvAddr;
ULONG _cBytes;
DWORD _dwFlags;
CChecksumBlock *_pcbNext, *_pcbPrev;
ULONG _ulChecksum;
};
// Global list of checksummed blocks
static CChecksumBlock *pcbChkBlocks = NULL;
//+--------------------------------------------------------------
//
// Member: CChecksumBlock::CChecksumBlock, private
//
// Synopsis: Ctor
//
// Arguments: [pszName] - Block name
// [pvAddr] - Starting addr
// [cBytes] - Length
// [dwFlags] - Type flags
// [pcbNext] - Next checksum block
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
CChecksumBlock::CChecksumBlock(char *pszName,
void *pvAddr,
ULONG cBytes,
DWORD dwFlags,
CChecksumBlock *pcbNext,
CChecksumBlock *pcbPrev)
{
ULONG i;
char *pc;
olVerify(_pszName = new char[strlen(pszName)+1]);
strcpy(_pszName, pszName);
_pvAddr = pvAddr;
_cBytes = cBytes;
_dwFlags = dwFlags;
_pcbNext = pcbNext;
if (pcbNext)
pcbNext->_pcbPrev = this;
_pcbPrev = pcbPrev;
if (pcbPrev)
pcbPrev->_pcbNext = this;
_ulChecksum = 0;
pc = (char *)pvAddr;
for (i = 0; i<cBytes; i++)
_ulChecksum += *pc++;
}
//+--------------------------------------------------------------
//
// Member: CChecksumBlock::~CChecksumBlock, private
//
// Synopsis: Dtor
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
CChecksumBlock::~CChecksumBlock(void)
{
delete _pszName;
}
//+--------------------------------------------------------------
//
// Function: DbgChkBlocks, private
//
// Synopsis: Verify checksums on all current blocks
//
// Arguments: [dwFlags] - Types of blocks to check
// [pszFile] - File check was called from
// [iLine] - Line in file
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
void DbgChkBlocks(DWORD dwFlags, char *pszFile, int iLine)
{
CChecksumBlock *pcb;
for (pcb = pcbChkBlocks; pcb; pcb = pcb->_pcbNext)
if (pcb->_dwFlags & dwFlags)
{
ULONG i, ulSum = 0;
char *pc;
for (pc = (char *)pcb->_pvAddr, i = 0; i<pcb->_cBytes; i++)
ulSum += *pc++;
if (ulSum != pcb->_ulChecksum)
olDebugOut((DEB_ERROR, "* Bad checksum %s:%d '%s' %p:%lu *\n",
pszFile, iLine, pcb->_pszName,
pcb->_pvAddr, pcb->_cBytes));
else if (dwFlags & DBG_VERBOSE)
olDebugOut((DEB_ERROR, "* Checksum passed %s:%d"
" '%s' %p:%lu *\n",
pszFile, iLine, pcb->_pszName,
pcb->_pvAddr, pcb->_cBytes));
}
}
//+--------------------------------------------------------------
//
// Function: DbgAddChkBlock, private
//
// Synopsis: Adds a checksum block
//
// Arguments: [pszName] - Name of block
// [pvAddr] - Starting addr
// [cBytes] - Length
// [dwFlags] - Type flags
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
void DbgAddChkBlock(char *pszName,
void *pvAddr,
ULONG cBytes,
DWORD dwFlags)
{
CChecksumBlock *pcb;
olVerify(pcb = new CChecksumBlock(pszName, pvAddr, cBytes,
dwFlags, pcbChkBlocks, NULL));
pcbChkBlocks = pcb;
}
//+--------------------------------------------------------------
//
// Function: DbgFreeChkBlock, private
//
// Synopsis: Removes a block from the list
//
// Arguments: [pvAddr] - Block's check address
//
// History: 10-Apr-92 DrewB Created
//
//---------------------------------------------------------------
void DbgFreeChkBlock(void *pvAddr)
{
CChecksumBlock *pcb;
for (pcb = pcbChkBlocks; pcb; pcb = pcb->_pcbNext)
if (pcb->_pvAddr == pvAddr)
{
if (pcb->_pcbPrev)
pcb->_pcbPrev->_pcbNext = pcb->_pcbNext;
else
pcbChkBlocks = pcb->_pcbNext;
if (pcb->_pcbNext)
pcb->_pcbNext->_pcbPrev = pcb->_pcbPrev;
delete pcb;
return;
}
}
//+--------------------------------------------------------------
//
// Function: DbgFreeChkBlocks, private
//
// Synopsis: Frees all checksum blocks
//
// History: 08-Apr-92 DrewB Created
//
//---------------------------------------------------------------
void DbgFreeChkBlocks(void)
{
CChecksumBlock *pcb;
while (pcbChkBlocks)
{
pcb = pcbChkBlocks->_pcbNext;
delete pcbChkBlocks;
pcbChkBlocks = pcb;
}
}
inline CGlobalFileStream *GetGlobalFileStream()
{
return((CGlobalFileStream *)DfGetResLimit(DBRI_LOGFILE_LIST));
}
inline void SetGlobalFileStream(CGlobalFileStream *pgfst)
{
DfSetResLimit(DBRI_LOGFILE_LIST, (LONG) pgfst);
}
#ifdef MULTIHEAP
static CGlobalFileStream *g_pDebugLogGlobalFileStream = NULL;
static CFileStream *g_pDebugLogFileStream = NULL;
#endif
SCODE GetLogFile(CFileStream **pfs)
#ifdef MULTIHEAP
{
// Do not use shared memory to write log files
SCODE sc = S_OK;
if (GetGlobalFileStream() == NULL)
{
g_pDebugLogGlobalFileStream = ::new CGlobalFileStream
(NULL, 0, LOGFILEDFFLAGS, LOGFILESTARTFLAGS);
SetGlobalFileStream (g_pDebugLogGlobalFileStream);
g_pDebugLogFileStream = ::new CFileStream (NULL);
}
g_pDebugLogFileStream->InitFromGlobal(GetGlobalFileStream());
*pfs = g_pDebugLogFileStream;
return sc;
}
#else
{
SCODE sc = S_OK;
CFileStream *pfsLoop = NULL;
*pfs = NULL;
if (GetGlobalFileStream() == NULL)
{
IMalloc *pMalloc;
#ifdef WIN32
olHChk(DfCreateSharedAllocator(&pMalloc));
#else
olHChk(CoGetMalloc(MEMCTX_SHARED, &pMalloc));
#endif
SetGlobalFileStream(new (pMalloc) CGlobalFileStream(pMalloc,
0, LOGFILEDFFLAGS,
LOGFILESTARTFLAGS));
pMalloc->Release();
}
if (GetGlobalFileStream() != NULL)
{
pfsLoop = GetGlobalFileStream()->Find(GetCurrentContextId());
if (pfsLoop == NULL)
{
IMalloc *pMalloc;
#ifdef WIN32
olHChk(DfCreateSharedAllocator(&pMalloc));
#else
olHChk(CoGetMalloc(MEMCTX_SHARED, &pMalloc));
#endif
pfsLoop = new (pMalloc) CFileStream(pMalloc);
pMalloc->Release();
if (pfsLoop != NULL)
pfsLoop->InitFromGlobal(GetGlobalFileStream());
}
}
EH_Err:
*pfs = pfsLoop;
return sc;
}
#endif // MULIHEAP
SCODE _FreeLogFile(void)
{
#ifdef MULTIHEAP
if (GetGlobalFileStream())
{
g_pDebugLogFileStream->RemoveFromGlobal();
memset (g_pDebugLogGlobalFileStream, 0, sizeof(CContextList));
SetGlobalFileStream (NULL);
::delete g_pDebugLogFileStream;
::delete g_pDebugLogGlobalFileStream;
}
return S_OK;
#else
CFileStream *pfsLoop = NULL;
if (GetGlobalFileStream())
pfsLoop = GetGlobalFileStream()->Find(GetCurrentContextId());
if (pfsLoop != NULL)
{
pfsLoop->vRelease();
GetGlobalFileStream()->Release();
SetGlobalFileStream(NULL);
return S_OK;
}
return STG_E_UNKNOWN;
#endif
}
long cLogNestings = 0;
void OutputLogfileMessage(char const *format, ...)
{
int length;
char achPreFormat[] = "PID[%lx] TID[%lx] ";
char achBuffer[256];
ULONG cbWritten;
CFileStream *pfs = NULL;
va_list arglist;
STATSTG stat;
if (cLogNestings > 0)
return;
TAKEMTX;
cLogNestings++;
va_start(arglist, format);
GetLogFile(&pfs);
if (NULL != pfs)
{
pfs->Init(gwcsLogFile);
pfs->Stat(&stat, STATFLAG_NONAME);
if (DfGetResLimit(DBRF_LOGGING) & DFLOG_PIDTID)
{
// Prepare prefix string
length = wsprintfA(achBuffer, "PID[%8lx] TID[%8lx] ",
GetCurrentProcessId(), GetCurrentThreadId());
// length does not include NULL terminator
pfs->WriteAt(stat.cbSize, achBuffer, length, &cbWritten);
stat.cbSize.LowPart += cbWritten;
}
// Write caller data to logfile
#if WIN32 == 300
wsprintfA(achBuffer, format, arglist);
#else
w4vsprintf(achBuffer, format, arglist);
#endif
length = strlen(achBuffer);
for (int i = 0; i < length; i++)
{
if (((achBuffer[i] < 32) || (achBuffer[i] > 127)) &&
(achBuffer[i] != '\n') && (achBuffer[i] != '\t'))
{
achBuffer[i] = '.';
}
}
pfs->WriteAt(stat.cbSize, achBuffer, length, &cbWritten);
}
cLogNestings--;
RELEASEMTX;
}
#endif // DBG == 1