windows-nt/Source/XPSP1/NT/net/config/inc/trace.h

479 lines
16 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: T R A C E . H
//
// Contents: Class definition for CTracing
//
// Notes:
//
// Author: jeffspr 15 Apr 1997
//
//----------------------------------------------------------------------------
#pragma once
#include "tracetag.h"
#include "stlalgor.h"
#include "stldeque.h"
#include "stlmap.h"
// ISSUE: The customized STL that we have conflicts with the declarations pulled in
// from stdexcpt.h which gets included by typeinfo.h. This sucks!
// Hence we can't include typeinfo.h to get RTTI's type_info structure,
// so we have to declare type_info ourselves. This is a well documented
// structure inside MSDN though.
class type_info {
public:
_CRTIMP virtual ~type_info();
_CRTIMP int operator==(const type_info& rhs) const;
_CRTIMP int operator!=(const type_info& rhs) const;
_CRTIMP int before(const type_info& rhs) const;
_CRTIMP const char* name() const;
_CRTIMP const char* raw_name() const;
private:
void *_m_data;
char _m_d_name[1];
type_info(const type_info& rhs);
type_info& operator=(const type_info& rhs);
};
#define TAKEOWNERSHIP
#ifdef ENABLETRACE
// This is needed for TraceHr, since we can't use a macro (vargs), but we
// need to get the file and line from the source.
#define FAL __FILE__,__LINE__,__FUNCTION__
// The Trace Stack functions
#if defined (_IA64_)
#include <ia64reg.h>
extern "C" unsigned __int64 __getReg(int whichReg);
extern "C" void __setReg(int whichReg, __int64 value);
#pragma intrinsic(__getReg)
#pragma intrinsic(__setReg)
#define GetR32 __getReg(CV_IA64_IntR32)
#define GetR33 __getReg(CV_IA64_IntR33)
#define GetR34 __getReg(CV_IA64_IntR34)
#endif // defined(_IA64_)
extern "C" void* _ReturnAddress(void);
#pragma intrinsic(_ReturnAddress)
extern LPCRITICAL_SECTION g_csTracing;
class CTracingIndent;
class CTracingFuncCall
{
public:
#if defined (_X86_) || defined (_AMD64_)
CTracingFuncCall(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, const DWORD_PTR ReturnAddress, const DWORD_PTR dwFramePointer);
#elif defined (_IA64_)
CTracingFuncCall(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, const DWORD_PTR ReturnAddress, const __int64 Args1, const __int64 Args2, const __int64 Args3);
#else
CTracingFuncCall(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine);
#endif
CTracingFuncCall(const CTracingFuncCall& TracingFuncCall);
~CTracingFuncCall();
public:
LPSTR m_szFunctionName;
LPSTR m_szFunctionDName;
LPSTR m_szFile;
DWORD_PTR m_ReturnAddress;
#if defined (_X86_) || defined (_AMD64_)
DWORD m_arguments[3];
#elif defined (_IA64_ )
__int64 m_arguments[3];
#else
// ... add other processors here
#endif
DWORD m_dwFramePointer;
DWORD m_dwThreadId;
DWORD m_dwLine;
friend CTracingIndent;
};
class CTracingThreadInfo
{
public:
CTracingThreadInfo();
~CTracingThreadInfo();
public:
LPVOID m_pfnStack;
DWORD m_dwLevel;
DWORD m_dwThreadId;
friend CTracingIndent;
};
class CTracingIndent
{
LPSTR m_szFunctionDName;
DWORD m_dwFramePointer;
BOOL bFirstTrace;
public:
#if defined (_X86_) || defined (_AMD64_)
void AddTrace(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, LPCVOID pReturnAddress, const DWORD_PTR dwFramePointer);
#elif defined (_IA64_)
void AddTrace(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, LPCVOID pReturnAddress, const __int64 Args1, const __int64 Args2, const __int64 Args3);
#else
void AddTrace(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine);
#endif
void RemoveTrace(LPCSTR szFunctionDName, const DWORD dwFramePointer);
CTracingIndent();
~CTracingIndent();
static CTracingThreadInfo* GetThreadInfo();
static DWORD getspaces();
static void TraceStackFn(TRACETAGID TraceTagId);
static void TraceStackFn(IN OUT LPSTR szString, IN OUT LPDWORD pdwSize);
};
#define IDENT_ADD2(x) indent ## x
#define IDENT_ADD(x) IDENT_ADD2(x)
#define __INDENT__ IDENT_ADD(__LINE__)
#define FP_ADD2(x) FP ## x
#define FP_ADD(x) FP_ADD2(x)
#define __FP__ FP_ADD(__LINE__)
#if defined (_X86_)
#define AddTraceLevel \
__if_not_exists(NetCfgFramePointer) \
{ \
DWORD NetCfgFramePointer; \
BOOL fForceC4715Check = TRUE; \
} \
if (fForceC4715Check) \
{ \
__asm { mov NetCfgFramePointer, ebp }; \
} \
__if_not_exists(NetCfgIndent) \
{ \
CTracingIndent NetCfgIndent; \
} \
NetCfgIndent.AddTrace(__FUNCTION__, __FUNCDNAME__, __FILE__, __LINE__, _ReturnAddress(), NetCfgFramePointer);
#elif defined (_IA64_)
#define AddTraceLevel \
__if_not_exists(NetCfgIndent) \
{ \
CTracingIndent NetCfgIndent; \
} \
NetCfgIndent.AddTrace(__FUNCTION__, __FUNCDNAME__, __FILE__, __LINE__, _ReturnAddress(), 0, 0, 0);
// NetCfgIndent.AddTrace(__FUNCTION__, __FUNCDNAME__, __FILE__, __LINE__, _ReturnAddress(), GetR32, GetR33, GetR34);
// ISSUE: GetR32, GetR33, GetR34 is inherently unsafe and can cause an STATUS_REG_NAT_CONSUMPTION exception
// if a register is being read that has the NAT bit set. Removing this for now until the compiler
// team provides a safe version of __getReg
#elif defined (_AMD64_)
#define AddTraceLevel \
__if_not_exists(NetCfgIndent) \
{ \
CTracingIndent NetCfgIndent; \
} \
NetCfgIndent.AddTrace(__FUNCTION__, __FUNCDNAME__, __FILE__, __LINE__, _ReturnAddress(), 0);
#else
#define AddTraceLevel \
__if_not_exists(NetCfgIndent) \
{ \
CTracingIndent NetCfgIndent; \
} \
NetCfgIndent.AddTrace(__FUNCTION__, __FUNCDNAME__, __FILE__, __LINE__);
#endif
// Trace error functions. The leaading _ is to establish the real function,
// while adding a new macro so we can add __FILE__ and __LINE__ to the output.
//
VOID WINAPI TraceErrorFn (PCSTR pszaFile, INT nLine, PCSTR psza, HRESULT hr);
VOID WINAPI TraceErrorOptionalFn (PCSTR pszaFile, INT nLine, PCSTR psza, HRESULT hr, BOOL fOpt);
VOID WINAPI TraceErrorSkipFn (PCSTR pszaFile, INT nLine, PCSTR psza, HRESULT hr, UINT c, ...);
VOID WINAPIV TraceLastWin32ErrorFn (PCSTR pszaFile, INT nLine, PCSTR psza);
#define TraceError(sz, hr) TraceErrorFn(__FILE__, __LINE__, sz, hr);
#define TraceErrorOptional(sz, hr, _bool) TraceErrorOptionalFn(__FILE__, __LINE__, sz, hr, _bool);
#define TraceErrorSkip1(sz, hr, hr1) TraceErrorSkipFn(__FILE__, __LINE__, sz, hr, 1, hr1);
#define TraceErrorSkip2(sz, hr, hr1, hr2) TraceErrorSkipFn(__FILE__, __LINE__, sz, hr, 2, hr1, hr2);
#define TraceErrorSkip3(sz, hr, hr1, hr2, hr3) TraceErrorSkipFn(__FILE__, __LINE__, sz, hr, 3, hr1, hr2, hr3);
#define TraceLastWin32Error(sz) TraceLastWin32ErrorFn(__FILE__,__LINE__, sz);
VOID
WINAPIV
TraceHrFn (
TRACETAGID ttid,
PCSTR pszaFile,
INT nLine,
HRESULT hr,
BOOL fIgnore,
PCSTR pszaFmt,
...);
VOID
WINAPIV
TraceHrFn (
TRACETAGID ttid,
PCSTR pszaFile,
INT nLine,
PCSTR pszaFunc,
HRESULT hr,
BOOL fIgnore,
PCSTR pszaFmt,
...);
VOID
WINAPIV
TraceTagFn (
TRACETAGID ttid,
PCSTR pszaFmt,
...);
VOID
WINAPIV
TraceFileFuncFn (
TRACETAGID ttid);
#define TraceFileFunc(ttidWhich) AddTraceLevel; TraceFileFuncFn(ttidWhich);
#define TraceStack(ttidWhich) AddTraceLevel; CTracingIndent::TraceStackFn(ttidWhich);
#define TraceStackToString(szString, nSize) AddTraceLevel; CTracingIndent::TraceStackFn(szString, nSize);
#define TraceHr AddTraceLevel; TraceHrFn
#define TraceTag AddTraceLevel; TraceTagFn
#define TraceException(hr, szExceptionName) TraceHr(ttidError, FAL, hr, FALSE, "A (%s) exception occurred", szExceptionName);
LPCSTR DbgEvents(DWORD Event);
LPCSTR DbgEventManager(DWORD EventManager);
LPCSTR DbgNcm(DWORD ncm);
LPCSTR DbgNcs(DWORD ncs);
LPCSTR DbgNccf(DWORD nccf);
LPCSTR DbgNcsm(DWORD ncsm);
#else // !ENABLETRACE
#define FAL (void)0
#define TraceError(_sz, _hr)
#define TraceErrorOptional(_sz, _hr, _bool)
#define TraceErrorSkip1(_sz, _hr, _hr1)
#define TraceErrorSkip2(_sz, _hr, _hr1, _hr2)
#define TraceErrorSkip3(_sz, _hr, _hr1, _hr2, _hr3)
#define TraceLastWin32Error(_sz)
#define TraceHr NOP_FUNCTION
#define TraceTag NOP_FUNCTION
#define TraceFileFunc(ttidWhich) NOP_FUNCTION
#define TraceException(hr, szExceptionName) NOP_FUNCTION
#define TraceStack(ttidWhich) NOP_FUNCTION
#define TraceStackToString(szString, nSize) NOP_FUNCTION
#define DbgEvents(Event) ""
#define DbgEventManager(EventManager) ""
#define DbgNcm(ncm) ""
#define DbgNcs(ncs) ""
#define DbgNccf(nccf) ""
#define DbgNcsm(nccf) ""
#endif // ENABLETRACE
#ifdef ENABLETRACE
//---[ Initialization stuff ]-------------------------------------------------
HRESULT HrInitTracing();
HRESULT HrUnInitTracing();
HRESULT HrOpenTraceUI(HWND hwndOwner);
#endif // ENABLETRACE
#define ENABLELEAKDETECTION
#if (defined(ENABLETRACE) && defined(ENABLELEAKDETECTION))
template <class T> class CNetCfgDebug; // Fwd template to make this friendly to CObjectLeakTrack
//+---------------------------------------------------------------------------
//
// class: CObjectLeakTrack
//
// Purpose: Keep a list of all the CNetCfgDebug derived object instances and
// dump these out on request
//
// Author: deonb 7 July 2001
//
// Notes: The data types in here are of type LPVOID in order to minimize
// dependencies when including the trace header.
//
class CObjectLeakTrack
{
public:
CObjectLeakTrack();
~CObjectLeakTrack();
void DumpAllocatedObjects(IN TRACETAGID TraceTagId, IN LPCSTR szClassName);
BOOL AssertIfObjectsStillAllocated(IN LPCSTR szClassName);
protected:
// For these, pThis is really of type CNetCfgDebug<T> *. Since this should only ever be called
// from CNetCfgDebug or ISSUE_knownleak, we are ok with the lack of compile-time type checking.
void Insert(IN LPCVOID pThis, IN LPCSTR szdbgClassName, IN TAKEOWNERSHIP LPSTR pszConstructionStack);
void Remove(IN LPCVOID pThis);
friend class CNetCfgDebug;
friend void RemoveKnownleakFn(LPCVOID pThis);
protected:
LPVOID g_mapObjLeak; // This will actually be of type map<LPCVOID, pair<LPSTR, LPSTR> > ;
};
extern CObjectLeakTrack *g_pObjectLeakTrack; // The global list of NetConfig objects in the process.
// Call DumpAllocatedObjects on this to dump out the objects.
void RemoveKnownleakFn(LPCVOID pThis);
//+---------------------------------------------------------------------------
//
// class: CNetCfgDebug
//
// Purpose: In order to debug instance leaks of your class instances, you can
// derive your class from CNetCfgDebug. This adds no data members nor
// a v-table nor virtual functions to your class. It will add
// a constructor and destructor that will be called before & after yours
// respectively, in order to keep track of your class instances.
//
// This will only happen on CHK builds. On FRE builds deriving from this
// class has no effect, and is safe.
//
// Author: deonb 7 July 2001
//
// Notes:
// This is s an ATL style parent template derive, e.g.:
// CNetCfgDbg<parent>
// e.g.
//
// class CConnectionManager : public ClassX,
// public classY,
// public CNetCfgBase<CConnectionManager>
//
// No other interaction with your class is needed. This will now automatically
// keep a list of all the instances allocated of this class (in debug mode),
// with a stack trace where they were allocated from. This is a Tracing
// stack trace so it's only successful for functions inside the callstack which
// actually used a TraceXxx statement (any trace statement) before they called
// the child functions.
//
// e.g.
// void X()
// {
// TraceFileFunc(ttidSomething);
// void Y()
// {
// void Z()
// {
// TraceTag(ttidSomething, "allocation class");
// CConnectionManager *pConnectionManager = new CConnectionManager();
// }
// TraceTag(ttidSomething, "Z called");
// }
// }
//
// This will spew the following when the process terminates (or when TraceAllocatedObjects is called):
// ASSERT: "An object leak has been detected. Please attach a user or kernel mode debugger and hit
// IGNORE to dump the offending stacks"
//
// The object of type 'class CConnectionManager' allocated at 0x7fe2345 has not been freed:
// it was constructed from the stack below:
// Z [EBP: 0x731d3128] 0x00000001 0x00000000 0x0000000a
// X [EBP: 0x731d310f] 0x0000000f 0x0000000e 0x0000000a
//
// (since Y() did not contain a trace statement before the call to Z() )
//
template <class T>
class CNetCfgDebug
{
public:
CNetCfgDebug()
{
if (FIsDebugFlagSet(dfidTrackObjectLeaks))
{
if (g_csTracing && g_pObjectLeakTrack)
{
EnterCriticalSection(g_csTracing);
DWORD dwConstructionStackSize = 16384;
LPSTR pszConstructionStack = new CHAR[dwConstructionStackSize];
if (pszConstructionStack)
{
TraceStackToString(pszConstructionStack, &dwConstructionStackSize);
if (dwConstructionStackSize < 16384)
{
// Reduce the amount of memory required
LPSTR szTemp = new CHAR[dwConstructionStackSize];
if (szTemp)
{
memcpy(szTemp, pszConstructionStack, dwConstructionStackSize);
delete[] pszConstructionStack;
pszConstructionStack = szTemp;
}
}
else
{
}
}
TraceTag(ttidAllocations, "An object of type '%s' was allocated at '0x%08x'", typeid(T).name(), this);
g_pObjectLeakTrack->Insert(this, typeid(T).name(), pszConstructionStack); // ok to insert if pszConstructionStack is NULL.
LeaveCriticalSection(g_csTracing);
}
}
};
~CNetCfgDebug()
{
if (FIsDebugFlagSet(dfidTrackObjectLeaks))
{
if (g_csTracing && g_pObjectLeakTrack)
{
EnterCriticalSection(g_csTracing);
TraceTag(ttidAllocations, "An object of type '%s' was deleted at '0x%08x'", typeid(T).name(), this);
g_pObjectLeakTrack->Remove(this);
LeaveCriticalSection(g_csTracing);
}
}
};
};
#define ISSUE_knownleak(pThis) RemoveKnownleakFn(pThis);
#define TraceAllocatedObjects(ttidWhich, ClassName) g_pObjectLeakTrack->DumpAllocatedObjects(ttidWhich, typeid(ClassName).name());
#define AssertIfAllocatedObjects(ClassName) g_pObjectLeakTrack->AssertIfObjectsStillAllocated(typeid(ClassName).name());
#define TraceAllAllocatedObjects(ttidWhich) g_pObjectLeakTrack->DumpAllocatedObjects(ttidWhich, NULL);
#define AssertIfAnyAllocatedObjects() g_pObjectLeakTrack->AssertIfObjectsStillAllocated(NULL);
#else // ENABLETRACE && ENABLELEAKDETECTION
template <class T>
class CNetCfgDebug
{
};
#define ISSUE_knownleak(pThis) NOP_FUNCTION
#define TraceAllocatedObjects(ttidWhich, szClassName) NOP_FUNCTION
#define AssertNoAllocatedInstances(szClassName) NOP_FUNCTION
#endif // ENABLETRACE && ENABLELEAKDETECTION