385 lines
11 KiB
C
385 lines
11 KiB
C
|
//------------------------------------------------------------*
|
||
|
// File name: DEBUG.C
|
||
|
//
|
||
|
// Description: Debug helper code for System control panel
|
||
|
// applet
|
||
|
//
|
||
|
//
|
||
|
// Microsoft Confidential
|
||
|
// Copyright (c) Microsoft Corporation 1992-1996
|
||
|
// All rights reserved
|
||
|
//
|
||
|
// History
|
||
|
// 10-Nov-1996 JonPa Created it.
|
||
|
//
|
||
|
//------------------------------------------------------------*
|
||
|
#include <windows.h>
|
||
|
#include "debug.h"
|
||
|
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
// Constants
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
|
||
|
#ifdef DBG_CODE
|
||
|
|
||
|
#define CCH_LABEL (sizeof(DWORD) * 2) // 64 BITS == 8 ANSI chars
|
||
|
|
||
|
#define CB_TAG sizeof(DWORD)
|
||
|
#define DW_TAG ((DWORD)(0x434C4143)) // 'CALC'
|
||
|
|
||
|
#define DW_TAG2 ((DWORD)(0x444F4F47)) // 'GOOD'
|
||
|
|
||
|
#define CH_FILL '*'
|
||
|
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
// Structures and Types
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
|
||
|
//
|
||
|
// NOTE!!!!
|
||
|
//
|
||
|
// The HOBJHDR structure MUST be a multiple of 8 bytes (64bits) in len!
|
||
|
// otherwise this code will *FAULT* on ALPHA machines!
|
||
|
//
|
||
|
|
||
|
typedef struct HHO *PHHO;
|
||
|
|
||
|
struct HHO {
|
||
|
PHHO phhoNext;
|
||
|
PHHO phhoPrev;
|
||
|
CHAR szFile[CCH_LABEL];
|
||
|
DWORD iLine;
|
||
|
DWORD cBytesData;
|
||
|
DWORD dwTmp;
|
||
|
DWORD dwTag2;
|
||
|
};
|
||
|
|
||
|
typedef struct HHO HOBJHDR;
|
||
|
|
||
|
typedef struct {
|
||
|
LPVOID pvPtr;
|
||
|
CHAR szFile[CCH_LABEL];
|
||
|
DWORD iLine;
|
||
|
CHAR szFreedBy[CCH_LABEL];
|
||
|
DWORD iLineFreed;
|
||
|
} FREELOGREC, *PFREELOGREC;
|
||
|
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
// Global variables
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
|
||
|
//
|
||
|
// Root of memory chain
|
||
|
|
||
|
HOBJHDR ghhoRoot = { &ghhoRoot, &ghhoRoot, { 'R', 'O', 'O', 'T' }, 0, sizeof(ghhoRoot) };
|
||
|
|
||
|
|
||
|
//
|
||
|
// Buffer used for OutputDebugString formatting (See DbgPrintf and DbgStopX)
|
||
|
|
||
|
TCHAR szDbgOutBuffer[1024];
|
||
|
|
||
|
//
|
||
|
// Buffer used for logging
|
||
|
|
||
|
#define CFLR_MAX 1024
|
||
|
FREELOGREC aflrFreeLog[CFLR_MAX];
|
||
|
PFREELOGREC g_pflrUnused = NULL;
|
||
|
|
||
|
#define NextFreeLogRec( pflr ) ((pflr >= &aflrFreeLog[CFLR_MAX-1]) ? aflrFreeLog : pflr+1)
|
||
|
#define PrevFreeLogRec( pflr ) ((pflr <= aflrFreeLog) ? &aflrFreeLog[CFLR_MAX-1] : pflr-1)
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
//
|
||
|
// void DbgPrintf( LPTSTR szFmt, ... )
|
||
|
//
|
||
|
// Formatted version of OutputDebugString
|
||
|
//
|
||
|
// Parameters: Same as printf()
|
||
|
//
|
||
|
// History:
|
||
|
// 18-Jan-1996 JonPa Wrote it
|
||
|
//---------------------------------------------------------------
|
||
|
void DbgPrintf( LPTSTR szFmt, ... ) {
|
||
|
va_list marker;
|
||
|
|
||
|
va_start( marker, szFmt );
|
||
|
|
||
|
wvsprintf( szDbgOutBuffer, szFmt, marker );
|
||
|
OutputDebugString( szDbgOutBuffer );
|
||
|
|
||
|
va_end( marker );
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
//
|
||
|
// void DbgStopX(LPSTR mszFile, int iLine, LPTSTR szText )
|
||
|
//
|
||
|
// Print a string (with location id) and then break
|
||
|
//
|
||
|
// Parameters:
|
||
|
// mszFile ANSI filename (__FILE__)
|
||
|
// iLine line number (__LINE__)
|
||
|
// szText Text string to send to debug port
|
||
|
//
|
||
|
// History:
|
||
|
// 18-Jan-1996 JonPa Wrote it
|
||
|
//---------------------------------------------------------------
|
||
|
void DbgStopX(LPSTR mszFile, int iLine, LPTSTR szText ) {
|
||
|
int cch;
|
||
|
|
||
|
wsprintf( szDbgOutBuffer, TEXT("RATPAK (%hs %d) : %s\n"), mszFile, iLine, szText );
|
||
|
|
||
|
OutputDebugString(szDbgOutBuffer);
|
||
|
|
||
|
DebugBreak();
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
//
|
||
|
// void MemAllocWorker(LPSTR szFile, int iLine, UINT uFlags, UINT cBytes)
|
||
|
//
|
||
|
// Debug replacement for LocalAlloc
|
||
|
//
|
||
|
// Parameters:
|
||
|
// mszFile ANSI filename (__FILE__)
|
||
|
// iLine line number (__LINE__)
|
||
|
// uFlags same as LocalAlloc
|
||
|
// cBytes same as LocalAlloc
|
||
|
//
|
||
|
// History:
|
||
|
// 18-Jan-1996 JonPa Wrote it
|
||
|
//---------------------------------------------------------------
|
||
|
HLOCAL MemAllocWorker(LPSTR szFile, int iLine, UINT uFlags, UINT cBytes) {
|
||
|
PHHO phhoNew;
|
||
|
HLOCAL hMem;
|
||
|
LPSTR psz;
|
||
|
UINT i, cBytesAlloc;
|
||
|
|
||
|
cBytesAlloc = cBytes;
|
||
|
|
||
|
//
|
||
|
// If fixed alloc...
|
||
|
//
|
||
|
if ((uFlags & (LMEM_MOVEABLE | LMEM_DISCARDABLE)) != 0) {
|
||
|
DBGSTOPX( szFile, iLine, "Attempting to allocate movable memory... Returning NULL");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
cBytesAlloc = cBytes + sizeof(HOBJHDR);
|
||
|
|
||
|
// DWORD align Tag
|
||
|
cBytesAlloc = ((cBytesAlloc + 3) & ~3);
|
||
|
cBytesAlloc += CB_TAG;
|
||
|
|
||
|
|
||
|
hMem = LocalAlloc( uFlags, cBytesAlloc );
|
||
|
|
||
|
//
|
||
|
// If a valid pointer, and it is a fixed pointer...
|
||
|
//
|
||
|
phhoNew = (PHHO)hMem;
|
||
|
|
||
|
if (hMem != NULL) {
|
||
|
|
||
|
|
||
|
phhoNew->phhoNext = ghhoRoot.phhoNext;
|
||
|
ghhoRoot.phhoNext = phhoNew;
|
||
|
phhoNew->phhoNext->phhoPrev = phhoNew;
|
||
|
phhoNew->phhoPrev = &ghhoRoot;
|
||
|
|
||
|
phhoNew->dwTag2 = DW_TAG2;
|
||
|
|
||
|
for( psz = szFile; *psz != '\0'; psz++ );
|
||
|
|
||
|
for( ; psz != szFile && *psz != ':' && *psz != '/' && *psz != '\\'; psz--);
|
||
|
if (*psz == ':' || *psz == '/' || *psz == '\\')
|
||
|
psz++;
|
||
|
|
||
|
for( i = 0; i < CCH_LABEL; i++ ) {
|
||
|
phhoNew->szFile[i] = *psz;
|
||
|
if (*psz) {
|
||
|
psz++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
phhoNew->iLine = iLine;
|
||
|
|
||
|
phhoNew->cBytesData = cBytes;
|
||
|
|
||
|
phhoNew += 1; // point phhoNew to 1st byte after structure
|
||
|
|
||
|
// round up to nearest DWORD
|
||
|
{ LPBYTE pb = (LPBYTE)phhoNew + cBytes;
|
||
|
|
||
|
cBytesAlloc -= CB_TAG;
|
||
|
cBytes += sizeof(HOBJHDR);
|
||
|
|
||
|
while( cBytes < cBytesAlloc ) {
|
||
|
*pb++ = CH_FILL;
|
||
|
cBytes++;
|
||
|
}
|
||
|
|
||
|
*((LPDWORD)pb) = DW_TAG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (HLOCAL)phhoNew;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
//
|
||
|
// void MemFreeWorker( LPSTR szFile, int iLine, HLOCAL hMem )
|
||
|
//
|
||
|
// Debug replacement for LocalFree
|
||
|
//
|
||
|
// Parameters:
|
||
|
// mszFile ANSI filename (__FILE__)
|
||
|
// iLine line number (__LINE__)
|
||
|
// hMem same as LocalAlloc
|
||
|
//
|
||
|
// History:
|
||
|
// 18-Jan-1996 JonPa Wrote it
|
||
|
//---------------------------------------------------------------
|
||
|
HLOCAL MemFreeWorker( LPSTR szFile, int iLine, HLOCAL hMem ) {
|
||
|
PHHO phhoMem;
|
||
|
UINT uFlags;
|
||
|
UINT cBytes, cBytesAlloc;
|
||
|
LPSTR psz;
|
||
|
INT i;
|
||
|
|
||
|
|
||
|
if (g_pflrUnused == NULL) {
|
||
|
ZeroMemory( aflrFreeLog, sizeof(aflrFreeLog) );
|
||
|
g_pflrUnused = aflrFreeLog;
|
||
|
}
|
||
|
|
||
|
if (hMem == NULL) {
|
||
|
DBGSTOPX( szFile, iLine, "Freeing NULL handle!");
|
||
|
return LocalFree(hMem);
|
||
|
}
|
||
|
|
||
|
phhoMem = (PHHO)hMem - 1;
|
||
|
|
||
|
if (phhoMem->dwTag2 != DW_TAG2) {
|
||
|
PFREELOGREC pflr;
|
||
|
//
|
||
|
// Our tag has been stompped on, see if we have already freed this object
|
||
|
//
|
||
|
for( pflr = PrevFreeLogRec(g_pflrUnused); pflr != g_pflrUnused; pflr = PrevFreeLogRec(pflr) ) {
|
||
|
if (pflr->pvPtr == phhoMem) {
|
||
|
DBGPRINTF((TEXT("RATPAK: Object may have already been freed by %.8hs line %d\n(that obj was allocated by %.8hs line %d)\n"),
|
||
|
pflr->szFreedBy, pflr->iLineFreed, pflr->szFile, pflr->iLine));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DBGPRINTF((TEXT("RATPAK: Trashed memory object (0x%X%08X) was allocated in %.8hs line %d (%d bytes)\n"), (DWORD)(((DWORDLONG)hMem) >> 32), PtrToUlong(hMem), phhoMem->szFile, phhoMem->iLine, phhoMem->cBytesData));
|
||
|
DBGSTOPX( szFile, iLine, "Either heap object trashed or not allocated object");
|
||
|
}
|
||
|
|
||
|
cBytes = phhoMem->cBytesData;
|
||
|
|
||
|
#if 0
|
||
|
if (cBytes < 0) {
|
||
|
// Not our object?
|
||
|
DBGSTOPX( szFile, iLine, "Either heap object trashed or not allocated object");
|
||
|
return LocalFree(hMem);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
cBytes += sizeof(HOBJHDR);
|
||
|
|
||
|
// DWORD align
|
||
|
cBytesAlloc = (cBytes + 3) & ~3;
|
||
|
|
||
|
{ LPBYTE pb = (LPBYTE)(phhoMem);
|
||
|
pb += cBytes;
|
||
|
while( cBytes < cBytesAlloc ) {
|
||
|
if (*pb++ != CH_FILL) {
|
||
|
DBGPRINTF((TEXT("RATPAK: Trashed memory object (0x%08X) was allocated in %.8hs line %d (%d bytes)\n"),
|
||
|
hMem, phhoMem->szFile, phhoMem->iLine, phhoMem->cBytesData));
|
||
|
DBGSTOPX( szFile, iLine, "End of structure overwritten");
|
||
|
}
|
||
|
cBytes++;
|
||
|
}
|
||
|
|
||
|
if (*((LPDWORD)pb) != DW_TAG) {
|
||
|
DBGPRINTF((TEXT("RATPAK: Memory object (0x%08X) was not allocated!\n"), hMem));
|
||
|
DBGSTOPX( szFile, iLine, "Freeing structure that was not allocated!");
|
||
|
|
||
|
// Not our structure
|
||
|
return LocalFree(hMem);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Our structure, check header
|
||
|
if (phhoMem->phhoNext->phhoPrev != phhoMem || phhoMem->phhoPrev->phhoNext != phhoMem ) {
|
||
|
DBGPRINTF((TEXT("RATPAK: Orphaned memory object (0x%08X) was allocated in %.8hs line %d (%d bytes)\n"),
|
||
|
hMem, phhoMem->szFile, phhoMem->iLine, phhoMem->cBytesData));
|
||
|
DBGSTOPX( szFile, iLine, "Attempting to free orphaned memory object");
|
||
|
}
|
||
|
|
||
|
phhoMem->phhoPrev->phhoNext = phhoMem->phhoNext;
|
||
|
phhoMem->phhoNext->phhoPrev = phhoMem->phhoPrev;
|
||
|
|
||
|
//
|
||
|
// Log this free, incase we try and free it twice
|
||
|
//
|
||
|
|
||
|
// Mark as freed
|
||
|
phhoMem->dwTag2 = 0;
|
||
|
|
||
|
// Remember who alloc'ed obj
|
||
|
g_pflrUnused->pvPtr = phhoMem;
|
||
|
CopyMemory( g_pflrUnused->szFile, phhoMem->szFile, sizeof(g_pflrUnused->szFile) );
|
||
|
g_pflrUnused->iLine = phhoMem->iLine;
|
||
|
|
||
|
// Remember who freed the obj
|
||
|
for( psz = szFile; *psz != '\0'; psz++ );
|
||
|
|
||
|
for( ; psz != szFile && *psz != ':' && *psz != '/' && *psz != '\\'; psz--);
|
||
|
if (*psz == ':' || *psz == '/' || *psz == '\\')
|
||
|
psz++;
|
||
|
|
||
|
for( i = 0; i < CCH_LABEL; i++ ) {
|
||
|
g_pflrUnused->szFreedBy[i] = *psz;
|
||
|
if (*psz) {
|
||
|
psz++;
|
||
|
}
|
||
|
}
|
||
|
g_pflrUnused->iLineFreed = iLine;
|
||
|
|
||
|
// Point roaming ptr to next record and mark as unused
|
||
|
g_pflrUnused = NextFreeLogRec(g_pflrUnused);
|
||
|
ZeroMemory( g_pflrUnused, sizeof(*g_pflrUnused) );
|
||
|
|
||
|
return LocalFree(phhoMem);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------
|
||
|
//
|
||
|
// void MemExitCheckWorker() {
|
||
|
//
|
||
|
// Debug replacement for LocalFree
|
||
|
//
|
||
|
// Parameters:
|
||
|
// mszFile ANSI filename (__FILE__)
|
||
|
// iLine line number (__LINE__)
|
||
|
// hMem same as LocalAlloc
|
||
|
//
|
||
|
// History:
|
||
|
// 18-Jan-1996 JonPa Wrote it
|
||
|
//---------------------------------------------------------------
|
||
|
void MemExitCheckWorker( void ) {
|
||
|
PHHO phho;
|
||
|
|
||
|
for( phho = ghhoRoot.phhoNext; phho != &ghhoRoot; phho = phho->phhoNext ) {
|
||
|
DBGPRINTF((TEXT("RATPAK: Exiting with out freeing object (Header=0x%08X) allocated in %.8hs line %d (%d bytes)\n"),
|
||
|
phho, phho->szFile, phho->iLine, phho->cBytesData));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif // DBG_CODE
|