Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

478 lines
16 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: T R A C E . H
  7. //
  8. // Contents: Class definition for CTracing
  9. //
  10. // Notes:
  11. //
  12. // Author: jeffspr 15 Apr 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #pragma once
  16. #include "tracetag.h"
  17. #include "stlalgor.h"
  18. #include "stldeque.h"
  19. #include "stlmap.h"
  20. // ISSUE: The customized STL that we have conflicts with the declarations pulled in
  21. // from stdexcpt.h which gets included by typeinfo.h. This sucks!
  22. // Hence we can't include typeinfo.h to get RTTI's type_info structure,
  23. // so we have to declare type_info ourselves. This is a well documented
  24. // structure inside MSDN though.
  25. class type_info {
  26. public:
  27. _CRTIMP virtual ~type_info();
  28. _CRTIMP int operator==(const type_info& rhs) const;
  29. _CRTIMP int operator!=(const type_info& rhs) const;
  30. _CRTIMP int before(const type_info& rhs) const;
  31. _CRTIMP const char* name() const;
  32. _CRTIMP const char* raw_name() const;
  33. private:
  34. void *_m_data;
  35. char _m_d_name[1];
  36. type_info(const type_info& rhs);
  37. type_info& operator=(const type_info& rhs);
  38. };
  39. #define TAKEOWNERSHIP
  40. #ifdef ENABLETRACE
  41. // This is needed for TraceHr, since we can't use a macro (vargs), but we
  42. // need to get the file and line from the source.
  43. #define FAL __FILE__,__LINE__,__FUNCTION__
  44. // The Trace Stack functions
  45. #if defined (_IA64_)
  46. #include <ia64reg.h>
  47. extern "C" unsigned __int64 __getReg(int whichReg);
  48. extern "C" void __setReg(int whichReg, __int64 value);
  49. #pragma intrinsic(__getReg)
  50. #pragma intrinsic(__setReg)
  51. #define GetR32 __getReg(CV_IA64_IntR32)
  52. #define GetR33 __getReg(CV_IA64_IntR33)
  53. #define GetR34 __getReg(CV_IA64_IntR34)
  54. #endif // defined(_IA64_)
  55. extern "C" void* _ReturnAddress(void);
  56. #pragma intrinsic(_ReturnAddress)
  57. extern LPCRITICAL_SECTION g_csTracing;
  58. class CTracingIndent;
  59. class CTracingFuncCall
  60. {
  61. public:
  62. #if defined (_X86_) || defined (_AMD64_)
  63. CTracingFuncCall(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, const DWORD_PTR ReturnAddress, const DWORD_PTR dwFramePointer);
  64. #elif defined (_IA64_)
  65. CTracingFuncCall(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, const DWORD_PTR ReturnAddress, const __int64 Args1, const __int64 Args2, const __int64 Args3);
  66. #else
  67. CTracingFuncCall(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine);
  68. #endif
  69. CTracingFuncCall(const CTracingFuncCall& TracingFuncCall);
  70. ~CTracingFuncCall();
  71. public:
  72. LPSTR m_szFunctionName;
  73. LPSTR m_szFunctionDName;
  74. LPSTR m_szFile;
  75. DWORD_PTR m_ReturnAddress;
  76. #if defined (_X86_) || defined (_AMD64_)
  77. DWORD m_arguments[3];
  78. #elif defined (_IA64_ )
  79. __int64 m_arguments[3];
  80. #else
  81. // ... add other processors here
  82. #endif
  83. DWORD m_dwFramePointer;
  84. DWORD m_dwThreadId;
  85. DWORD m_dwLine;
  86. friend CTracingIndent;
  87. };
  88. class CTracingThreadInfo
  89. {
  90. public:
  91. CTracingThreadInfo();
  92. ~CTracingThreadInfo();
  93. public:
  94. LPVOID m_pfnStack;
  95. DWORD m_dwLevel;
  96. DWORD m_dwThreadId;
  97. friend CTracingIndent;
  98. };
  99. class CTracingIndent
  100. {
  101. LPSTR m_szFunctionDName;
  102. DWORD m_dwFramePointer;
  103. BOOL bFirstTrace;
  104. public:
  105. #if defined (_X86_) || defined (_AMD64_)
  106. void AddTrace(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, LPCVOID pReturnAddress, const DWORD_PTR dwFramePointer);
  107. #elif defined (_IA64_)
  108. void AddTrace(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, LPCVOID pReturnAddress, const __int64 Args1, const __int64 Args2, const __int64 Args3);
  109. #else
  110. void AddTrace(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine);
  111. #endif
  112. void RemoveTrace(LPCSTR szFunctionDName, const DWORD dwFramePointer);
  113. CTracingIndent();
  114. ~CTracingIndent();
  115. static CTracingThreadInfo* GetThreadInfo();
  116. static DWORD getspaces();
  117. static void TraceStackFn(TRACETAGID TraceTagId);
  118. static void TraceStackFn(IN OUT LPSTR szString, IN OUT LPDWORD pdwSize);
  119. };
  120. #define IDENT_ADD2(x) indent ## x
  121. #define IDENT_ADD(x) IDENT_ADD2(x)
  122. #define __INDENT__ IDENT_ADD(__LINE__)
  123. #define FP_ADD2(x) FP ## x
  124. #define FP_ADD(x) FP_ADD2(x)
  125. #define __FP__ FP_ADD(__LINE__)
  126. #if defined (_X86_)
  127. #define AddTraceLevel \
  128. __if_not_exists(NetCfgFramePointer) \
  129. { \
  130. DWORD NetCfgFramePointer; \
  131. BOOL fForceC4715Check = TRUE; \
  132. } \
  133. if (fForceC4715Check) \
  134. { \
  135. __asm { mov NetCfgFramePointer, ebp }; \
  136. } \
  137. __if_not_exists(NetCfgIndent) \
  138. { \
  139. CTracingIndent NetCfgIndent; \
  140. } \
  141. NetCfgIndent.AddTrace(__FUNCTION__, __FUNCDNAME__, __FILE__, __LINE__, _ReturnAddress(), NetCfgFramePointer);
  142. #elif defined (_IA64_)
  143. #define AddTraceLevel \
  144. __if_not_exists(NetCfgIndent) \
  145. { \
  146. CTracingIndent NetCfgIndent; \
  147. } \
  148. NetCfgIndent.AddTrace(__FUNCTION__, __FUNCDNAME__, __FILE__, __LINE__, _ReturnAddress(), 0, 0, 0);
  149. // NetCfgIndent.AddTrace(__FUNCTION__, __FUNCDNAME__, __FILE__, __LINE__, _ReturnAddress(), GetR32, GetR33, GetR34);
  150. // ISSUE: GetR32, GetR33, GetR34 is inherently unsafe and can cause an STATUS_REG_NAT_CONSUMPTION exception
  151. // if a register is being read that has the NAT bit set. Removing this for now until the compiler
  152. // team provides a safe version of __getReg
  153. #elif defined (_AMD64_)
  154. #define AddTraceLevel \
  155. __if_not_exists(NetCfgIndent) \
  156. { \
  157. CTracingIndent NetCfgIndent; \
  158. } \
  159. NetCfgIndent.AddTrace(__FUNCTION__, __FUNCDNAME__, __FILE__, __LINE__, _ReturnAddress(), 0);
  160. #else
  161. #define AddTraceLevel \
  162. __if_not_exists(NetCfgIndent) \
  163. { \
  164. CTracingIndent NetCfgIndent; \
  165. } \
  166. NetCfgIndent.AddTrace(__FUNCTION__, __FUNCDNAME__, __FILE__, __LINE__);
  167. #endif
  168. // Trace error functions. The leaading _ is to establish the real function,
  169. // while adding a new macro so we can add __FILE__ and __LINE__ to the output.
  170. //
  171. VOID WINAPI TraceErrorFn (PCSTR pszaFile, INT nLine, PCSTR psza, HRESULT hr);
  172. VOID WINAPI TraceErrorOptionalFn (PCSTR pszaFile, INT nLine, PCSTR psza, HRESULT hr, BOOL fOpt);
  173. VOID WINAPI TraceErrorSkipFn (PCSTR pszaFile, INT nLine, PCSTR psza, HRESULT hr, UINT c, ...);
  174. VOID WINAPIV TraceLastWin32ErrorFn (PCSTR pszaFile, INT nLine, PCSTR psza);
  175. #define TraceError(sz, hr) TraceErrorFn(__FILE__, __LINE__, sz, hr);
  176. #define TraceErrorOptional(sz, hr, _bool) TraceErrorOptionalFn(__FILE__, __LINE__, sz, hr, _bool);
  177. #define TraceErrorSkip1(sz, hr, hr1) TraceErrorSkipFn(__FILE__, __LINE__, sz, hr, 1, hr1);
  178. #define TraceErrorSkip2(sz, hr, hr1, hr2) TraceErrorSkipFn(__FILE__, __LINE__, sz, hr, 2, hr1, hr2);
  179. #define TraceErrorSkip3(sz, hr, hr1, hr2, hr3) TraceErrorSkipFn(__FILE__, __LINE__, sz, hr, 3, hr1, hr2, hr3);
  180. #define TraceLastWin32Error(sz) TraceLastWin32ErrorFn(__FILE__,__LINE__, sz);
  181. VOID
  182. WINAPIV
  183. TraceHrFn (
  184. TRACETAGID ttid,
  185. PCSTR pszaFile,
  186. INT nLine,
  187. HRESULT hr,
  188. BOOL fIgnore,
  189. PCSTR pszaFmt,
  190. ...);
  191. VOID
  192. WINAPIV
  193. TraceHrFn (
  194. TRACETAGID ttid,
  195. PCSTR pszaFile,
  196. INT nLine,
  197. PCSTR pszaFunc,
  198. HRESULT hr,
  199. BOOL fIgnore,
  200. PCSTR pszaFmt,
  201. ...);
  202. VOID
  203. WINAPIV
  204. TraceTagFn (
  205. TRACETAGID ttid,
  206. PCSTR pszaFmt,
  207. ...);
  208. VOID
  209. WINAPIV
  210. TraceFileFuncFn (
  211. TRACETAGID ttid);
  212. #define TraceFileFunc(ttidWhich) AddTraceLevel; TraceFileFuncFn(ttidWhich);
  213. #define TraceStack(ttidWhich) AddTraceLevel; CTracingIndent::TraceStackFn(ttidWhich);
  214. #define TraceStackToString(szString, nSize) AddTraceLevel; CTracingIndent::TraceStackFn(szString, nSize);
  215. #define TraceHr AddTraceLevel; TraceHrFn
  216. #define TraceTag AddTraceLevel; TraceTagFn
  217. #define TraceException(hr, szExceptionName) TraceHr(ttidError, FAL, hr, FALSE, "A (%s) exception occurred", szExceptionName);
  218. LPCSTR DbgEvents(DWORD Event);
  219. LPCSTR DbgEventManager(DWORD EventManager);
  220. LPCSTR DbgNcm(DWORD ncm);
  221. LPCSTR DbgNcs(DWORD ncs);
  222. LPCSTR DbgNccf(DWORD nccf);
  223. LPCSTR DbgNcsm(DWORD ncsm);
  224. #else // !ENABLETRACE
  225. #define FAL (void)0
  226. #define TraceError(_sz, _hr)
  227. #define TraceErrorOptional(_sz, _hr, _bool)
  228. #define TraceErrorSkip1(_sz, _hr, _hr1)
  229. #define TraceErrorSkip2(_sz, _hr, _hr1, _hr2)
  230. #define TraceErrorSkip3(_sz, _hr, _hr1, _hr2, _hr3)
  231. #define TraceLastWin32Error(_sz)
  232. #define TraceHr NOP_FUNCTION
  233. #define TraceTag NOP_FUNCTION
  234. #define TraceFileFunc(ttidWhich) NOP_FUNCTION
  235. #define TraceException(hr, szExceptionName) NOP_FUNCTION
  236. #define TraceStack(ttidWhich) NOP_FUNCTION
  237. #define TraceStackToString(szString, nSize) NOP_FUNCTION
  238. #define DbgEvents(Event) ""
  239. #define DbgEventManager(EventManager) ""
  240. #define DbgNcm(ncm) ""
  241. #define DbgNcs(ncs) ""
  242. #define DbgNccf(nccf) ""
  243. #define DbgNcsm(nccf) ""
  244. #endif // ENABLETRACE
  245. #ifdef ENABLETRACE
  246. //---[ Initialization stuff ]-------------------------------------------------
  247. HRESULT HrInitTracing();
  248. HRESULT HrUnInitTracing();
  249. HRESULT HrOpenTraceUI(HWND hwndOwner);
  250. #endif // ENABLETRACE
  251. #define ENABLELEAKDETECTION
  252. #if (defined(ENABLETRACE) && defined(ENABLELEAKDETECTION))
  253. template <class T> class CNetCfgDebug; // Fwd template to make this friendly to CObjectLeakTrack
  254. //+---------------------------------------------------------------------------
  255. //
  256. // class: CObjectLeakTrack
  257. //
  258. // Purpose: Keep a list of all the CNetCfgDebug derived object instances and
  259. // dump these out on request
  260. //
  261. // Author: deonb 7 July 2001
  262. //
  263. // Notes: The data types in here are of type LPVOID in order to minimize
  264. // dependencies when including the trace header.
  265. //
  266. class CObjectLeakTrack
  267. {
  268. public:
  269. CObjectLeakTrack();
  270. ~CObjectLeakTrack();
  271. void DumpAllocatedObjects(IN TRACETAGID TraceTagId, IN LPCSTR szClassName);
  272. BOOL AssertIfObjectsStillAllocated(IN LPCSTR szClassName);
  273. protected:
  274. // For these, pThis is really of type CNetCfgDebug<T> *. Since this should only ever be called
  275. // from CNetCfgDebug or ISSUE_knownleak, we are ok with the lack of compile-time type checking.
  276. void Insert(IN LPCVOID pThis, IN LPCSTR szdbgClassName, IN TAKEOWNERSHIP LPSTR pszConstructionStack);
  277. void Remove(IN LPCVOID pThis);
  278. friend class CNetCfgDebug;
  279. friend void RemoveKnownleakFn(LPCVOID pThis);
  280. protected:
  281. LPVOID g_mapObjLeak; // This will actually be of type map<LPCVOID, pair<LPSTR, LPSTR> > ;
  282. };
  283. extern CObjectLeakTrack *g_pObjectLeakTrack; // The global list of NetConfig objects in the process.
  284. // Call DumpAllocatedObjects on this to dump out the objects.
  285. void RemoveKnownleakFn(LPCVOID pThis);
  286. //+---------------------------------------------------------------------------
  287. //
  288. // class: CNetCfgDebug
  289. //
  290. // Purpose: In order to debug instance leaks of your class instances, you can
  291. // derive your class from CNetCfgDebug. This adds no data members nor
  292. // a v-table nor virtual functions to your class. It will add
  293. // a constructor and destructor that will be called before & after yours
  294. // respectively, in order to keep track of your class instances.
  295. //
  296. // This will only happen on CHK builds. On FRE builds deriving from this
  297. // class has no effect, and is safe.
  298. //
  299. // Author: deonb 7 July 2001
  300. //
  301. // Notes:
  302. // This is s an ATL style parent template derive, e.g.:
  303. // CNetCfgDbg<parent>
  304. // e.g.
  305. //
  306. // class CConnectionManager : public ClassX,
  307. // public classY,
  308. // public CNetCfgBase<CConnectionManager>
  309. //
  310. // No other interaction with your class is needed. This will now automatically
  311. // keep a list of all the instances allocated of this class (in debug mode),
  312. // with a stack trace where they were allocated from. This is a Tracing
  313. // stack trace so it's only successful for functions inside the callstack which
  314. // actually used a TraceXxx statement (any trace statement) before they called
  315. // the child functions.
  316. //
  317. // e.g.
  318. // void X()
  319. // {
  320. // TraceFileFunc(ttidSomething);
  321. // void Y()
  322. // {
  323. // void Z()
  324. // {
  325. // TraceTag(ttidSomething, "allocation class");
  326. // CConnectionManager *pConnectionManager = new CConnectionManager();
  327. // }
  328. // TraceTag(ttidSomething, "Z called");
  329. // }
  330. // }
  331. //
  332. // This will spew the following when the process terminates (or when TraceAllocatedObjects is called):
  333. // ASSERT: "An object leak has been detected. Please attach a user or kernel mode debugger and hit
  334. // IGNORE to dump the offending stacks"
  335. //
  336. // The object of type 'class CConnectionManager' allocated at 0x7fe2345 has not been freed:
  337. // it was constructed from the stack below:
  338. // Z [EBP: 0x731d3128] 0x00000001 0x00000000 0x0000000a
  339. // X [EBP: 0x731d310f] 0x0000000f 0x0000000e 0x0000000a
  340. //
  341. // (since Y() did not contain a trace statement before the call to Z() )
  342. //
  343. template <class T>
  344. class CNetCfgDebug
  345. {
  346. public:
  347. CNetCfgDebug()
  348. {
  349. if (FIsDebugFlagSet(dfidTrackObjectLeaks))
  350. {
  351. if (g_csTracing && g_pObjectLeakTrack)
  352. {
  353. EnterCriticalSection(g_csTracing);
  354. DWORD dwConstructionStackSize = 16384;
  355. LPSTR pszConstructionStack = new CHAR[dwConstructionStackSize];
  356. if (pszConstructionStack)
  357. {
  358. TraceStackToString(pszConstructionStack, &dwConstructionStackSize);
  359. if (dwConstructionStackSize < 16384)
  360. {
  361. // Reduce the amount of memory required
  362. LPSTR szTemp = new CHAR[dwConstructionStackSize];
  363. if (szTemp)
  364. {
  365. memcpy(szTemp, pszConstructionStack, dwConstructionStackSize);
  366. delete[] pszConstructionStack;
  367. pszConstructionStack = szTemp;
  368. }
  369. }
  370. else
  371. {
  372. }
  373. }
  374. TraceTag(ttidAllocations, "An object of type '%s' was allocated at '0x%08x'", typeid(T).name(), this);
  375. g_pObjectLeakTrack->Insert(this, typeid(T).name(), pszConstructionStack); // ok to insert if pszConstructionStack is NULL.
  376. LeaveCriticalSection(g_csTracing);
  377. }
  378. }
  379. };
  380. ~CNetCfgDebug()
  381. {
  382. if (FIsDebugFlagSet(dfidTrackObjectLeaks))
  383. {
  384. if (g_csTracing && g_pObjectLeakTrack)
  385. {
  386. EnterCriticalSection(g_csTracing);
  387. TraceTag(ttidAllocations, "An object of type '%s' was deleted at '0x%08x'", typeid(T).name(), this);
  388. g_pObjectLeakTrack->Remove(this);
  389. LeaveCriticalSection(g_csTracing);
  390. }
  391. }
  392. };
  393. };
  394. #define ISSUE_knownleak(pThis) RemoveKnownleakFn(pThis);
  395. #define TraceAllocatedObjects(ttidWhich, ClassName) g_pObjectLeakTrack->DumpAllocatedObjects(ttidWhich, typeid(ClassName).name());
  396. #define AssertIfAllocatedObjects(ClassName) g_pObjectLeakTrack->AssertIfObjectsStillAllocated(typeid(ClassName).name());
  397. #define TraceAllAllocatedObjects(ttidWhich) g_pObjectLeakTrack->DumpAllocatedObjects(ttidWhich, NULL);
  398. #define AssertIfAnyAllocatedObjects() g_pObjectLeakTrack->AssertIfObjectsStillAllocated(NULL);
  399. #else // ENABLETRACE && ENABLELEAKDETECTION
  400. template <class T>
  401. class CNetCfgDebug
  402. {
  403. };
  404. #define ISSUE_knownleak(pThis) NOP_FUNCTION
  405. #define TraceAllocatedObjects(ttidWhich, szClassName) NOP_FUNCTION
  406. #define AssertNoAllocatedInstances(szClassName) NOP_FUNCTION
  407. #endif // ENABLETRACE && ENABLELEAKDETECTION