Leaked source code of windows server 2003
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.

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