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.

2933 lines
83 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: T R A C E . C P P
  7. //
  8. // Contents: The actual tracing code (loading from ini, calling the
  9. // trace routines, etc.
  10. //
  11. // Notes:
  12. //
  13. // Author: jeffspr 9 Apr 1997
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.h>
  17. #pragma hdrstop
  18. #ifdef ENABLETRACE
  19. #include <crtdbg.h>
  20. #include "ncdebug.h"
  21. #include "ncmisc.h"
  22. #include "stldeque.h"
  23. DWORD g_dwTlsTracing = 0;
  24. LPCRITICAL_SECTION g_csTracing = NULL;
  25. #define MAX_TRACE_LEN 4096
  26. //---[ CTracing class ]-------------------------------------------------------
  27. //
  28. // Don't give this class a constructor or destructor. We declare a global
  29. // (static to this module) instance of this class and, by definition, static
  30. // variables are automatically initialized to zero.
  31. //
  32. class CTracing
  33. {
  34. public:
  35. CTracing();
  36. ~CTracing();
  37. // Initialize/Deinitialize this class
  38. //
  39. private:
  40. HRESULT HrInit();
  41. HRESULT HrUnInit();
  42. public:
  43. VOID Trace( TraceTagId ttid,
  44. PCSTR pszaTrace );
  45. private:
  46. BOOL m_fInitialized; // Has the object been initialized
  47. BOOL m_fAttemptedLogFileOpen; // Already attempted to open log
  48. BOOL m_fDisableLogFile; // Disable use of file logging?
  49. UINT m_uiAllocOnWhichToBreak; // For _CrtSetBreakAlloc
  50. HANDLE m_hLogFile; // Handle for debug output file
  51. CHAR m_szLogFilePath[MAX_PATH+1]; // File for debug output
  52. BOOL m_fDebugFlagsLoaded; // Have these been loaded yet.
  53. VOID CorruptionCheck(); // Validate the tracetag structure
  54. HRESULT HrLoadOptionsFromIniFile();
  55. HRESULT HrLoadSectionsFromIniFile();
  56. HRESULT HrLoadDebugFlagsFromIniFile();
  57. HRESULT HrWriteDebugFlagsToIniFile();
  58. HRESULT HrOpenLogFile();
  59. HRESULT HrProcessTagSection(TraceTagElement * ptte);
  60. HRESULT HrGetPrivateProfileString( PCSTR lpAppName,
  61. PCSTR lpKeyName,
  62. PCSTR lpDefault,
  63. PSTR lpReturnedString,
  64. DWORD nSize,
  65. PCSTR lpFileName,
  66. DWORD * pcchReturn );
  67. HRESULT FIniFileInit(); // Returns S_OK if the file exist
  68. };
  69. //---[ Static Variables ]-----------------------------------------------------
  70. #pragma warning(disable:4073) // warning about the following init_seg statement
  71. #pragma init_seg(lib)
  72. static CTracing g_Tracing; // Our global tracing object
  73. //---[ Constants ]------------------------------------------------------------
  74. static const WCHAR c_szDebugIniFileName[] = L"netcfg.ini"; // .INI file
  75. CHAR c_szDebugIniFileNameA[MAX_PATH]; // .INI file
  76. static const CHAR c_szTraceLogFileNameA[] = "nctrace.log"; // .LOG file
  77. // constants for the INI file labels
  78. static const CHAR c_szaOptions[] = "Options";
  79. static const CHAR c_szaLogFilePath[] = "LogFilePath";
  80. static const CHAR c_szaDisableLogFile[] = "DisableLogFile";
  81. const INT c_iDefaultDisableLogFile = 0;
  82. static CHAR c_szLowMemory[] = "<low on memory>";
  83. //+---------------------------------------------------------------------------
  84. //
  85. // Function: HrInitTracing
  86. //
  87. // Purpose: Initialize the Tracing object and other random data.
  88. //
  89. // Arguments:
  90. // (none)
  91. //
  92. // Returns: S_OK or valid Win32 HRESULT
  93. //
  94. // Author: jeffspr 9 Apr 1997
  95. //
  96. // Notes:
  97. //
  98. HRESULT HrInitTracing()
  99. {
  100. return S_OK;
  101. }
  102. //+---------------------------------------------------------------------------
  103. //
  104. // Function: HrUnInitTracing
  105. //
  106. // Purpose: Uninitialize the tracing object.
  107. //
  108. // Arguments:
  109. // (none)
  110. //
  111. // Returns: S_OK or a valid Win32 HRESULT
  112. //
  113. // Author: jeffspr 14 Apr 1997
  114. //
  115. // Notes:
  116. //
  117. HRESULT HrUnInitTracing()
  118. {
  119. return S_OK;
  120. }
  121. const DWORD TI_HRESULT = 0x00000001;
  122. const DWORD TI_WIN32 = 0x00000002;
  123. const DWORD TI_IGNORABLE = 0x00000004;
  124. //+---------------------------------------------------------------------------
  125. //
  126. // Function: TraceInternal
  127. //
  128. // Purpose: The one and only place that a string to be traced is formed
  129. // and traced.
  130. //
  131. // Arguments:
  132. //
  133. // Returns: nothing.
  134. //
  135. // Author: shaunco 13 Mar 1998
  136. //
  137. // Notes: Restructured from lots of other code that was added to this
  138. // module over the past year.
  139. //
  140. VOID
  141. TraceInternal (
  142. TRACETAGID ttid,
  143. PCSTR pszaFile,
  144. INT nLine,
  145. DWORD dwFlags,
  146. PCSTR pszaCallerText,
  147. DWORD dwErrorCode,
  148. BOOL bTraceStackOnError)
  149. {
  150. // If this tracetag is turned off, don't do anything.
  151. //
  152. if (!g_TraceTags[ttid].fOutputDebugString &&
  153. !g_TraceTags[ttid].fOutputToFile)
  154. {
  155. return;
  156. }
  157. BOOL fError = dwFlags & (TI_HRESULT | TI_WIN32);
  158. BOOL fIgnorable = dwFlags & TI_IGNORABLE;
  159. HRESULT hr = (dwFlags & TI_HRESULT) ? dwErrorCode : S_OK;
  160. DWORD dwWin32Error = (dwFlags & TI_WIN32) ? dwErrorCode : ERROR_SUCCESS;
  161. // Ignore if told and we're not set to trace ignored errors or warnings.
  162. //
  163. if (fError && fIgnorable &&
  164. !FIsDebugFlagSet (dfidShowIgnoredErrors) &&
  165. !FIsDebugFlagSet (dfidExtremeTracing))
  166. {
  167. return;
  168. }
  169. // Don't do anything if we're tracing for an error and we don't have one,
  170. // unless the "Extreme Tracing" flag is on, in which case we trace
  171. // everything in the world (for debugger use only, really)
  172. // This is the path taken by TraceError ("...", S_OK) or
  173. // TraceLastWin32Error when there is no last Win32 error.
  174. //
  175. if (fError && !dwErrorCode && !FIsDebugFlagSet(dfidExtremeTracing))
  176. {
  177. return;
  178. }
  179. CHAR szaBuf [MAX_TRACE_LEN * 2];
  180. PSTR pcha = szaBuf;
  181. // Form the prefix, process id and thread id.
  182. //
  183. static const CHAR c_szaFmtPrefix [] = "NETCFG";
  184. lstrcpyA (pcha, c_szaFmtPrefix);
  185. pcha += lstrlenA (c_szaFmtPrefix);
  186. // Add process and thread ids if the debug flags indicate to do so.
  187. //
  188. if (FIsDebugFlagSet (dfidShowProcessAndThreadIds))
  189. {
  190. static const CHAR c_szaFmtPidAndTid [] = " %03x.%03x";
  191. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtPidAndTid,
  192. GetCurrentProcessId (),
  193. GetCurrentThreadId ());
  194. }
  195. // Add a time stamp if the debug flags indicate to do so.
  196. //
  197. if (FIsDebugFlagSet (dfidTracingTimeStamps))
  198. {
  199. static const CHAR c_szaFmtTime [] = " [%02dh%02d:%02d.%03d]";
  200. SYSTEMTIME stLocal;
  201. GetLocalTime (&stLocal);
  202. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtTime,
  203. stLocal.wHour,
  204. stLocal.wMinute,
  205. stLocal.wSecond,
  206. stLocal.wMilliseconds);
  207. }
  208. // Add a severity indicator if this trace is for an error or warning.
  209. //
  210. if (fError || (ttidError == ttid))
  211. {
  212. static const CHAR c_szaSevIgnored [] = " Ignored:";
  213. static const CHAR c_szaSevError [] = " *ERROR*:";
  214. static const CHAR c_szaSevWarning [] = " Warning:";
  215. PCSTR pszaSev = NULL;
  216. if (fError && SUCCEEDED(hr) && !dwWin32Error && !fIgnorable)
  217. {
  218. pszaSev = c_szaSevWarning;
  219. }
  220. else
  221. {
  222. if (fIgnorable && FIsDebugFlagSet (dfidShowIgnoredErrors))
  223. {
  224. pszaSev = c_szaSevIgnored;
  225. }
  226. else
  227. {
  228. pszaSev = c_szaSevError;
  229. }
  230. }
  231. Assert (pszaSev);
  232. lstrcatA (pcha, pszaSev);
  233. pcha += lstrlenA (pszaSev);
  234. }
  235. // Add the tracetag short name. Don't do this for ttidError if
  236. // we already have the severity indicator from above.
  237. //
  238. if (ttid && (ttid < g_nTraceTagCount) && (ttid != ttidError))
  239. {
  240. if (FIsDebugFlagSet(dfidTraceMultiLevel))
  241. {
  242. static const CHAR c_szaFmtTraceTag [] = " (%-16s)";
  243. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtTraceTag,
  244. g_TraceTags[ttid].szShortName);
  245. }
  246. else
  247. {
  248. static const CHAR c_szaFmtTraceTag [] = " (%s)";
  249. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtTraceTag,
  250. g_TraceTags[ttid].szShortName);
  251. }
  252. *pcha = ' ';
  253. pcha++;
  254. if (FIsDebugFlagSet(dfidTraceMultiLevel))
  255. {
  256. // Add the indentation text.
  257. DWORD dwNumSpaces = CTracingIndent::getspaces();
  258. Assert(dwNumSpaces >= 2);
  259. pcha += _snprintf(pcha, MAX_TRACE_LEN, "%1x", dwNumSpaces - 2);
  260. memset(pcha, '-', dwNumSpaces-1 );
  261. pcha += dwNumSpaces-1;
  262. }
  263. }
  264. else
  265. {
  266. *pcha = ' ';
  267. pcha++;
  268. }
  269. // Add the caller's text.
  270. //
  271. if (pszaCallerText)
  272. {
  273. static const CHAR c_szaFmtCallerText [] = "%s";
  274. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtCallerText,
  275. pszaCallerText);
  276. Assert (pcha > szaBuf);
  277. if ('\n' == *(pcha-1))
  278. {
  279. pcha--;
  280. *pcha = 0;
  281. }
  282. }
  283. // Add descriptive error text if this is an error and we can get some.
  284. //
  285. if (FAILED(hr) || dwWin32Error)
  286. {
  287. BOOL fFacilityWin32 = (FACILITY_WIN32 == HRESULT_FACILITY(hr));
  288. // dwError will be the error code we pass to FormatMessage. It may
  289. // come from hr or dwWin32Error. Give preference to hr.
  290. //
  291. DWORD dwError = 0;
  292. if (fFacilityWin32)
  293. {
  294. dwError = HRESULT_CODE(hr);
  295. }
  296. else if (FAILED(hr))
  297. {
  298. dwError = hr;
  299. }
  300. else
  301. {
  302. dwError = dwWin32Error;
  303. }
  304. Assert (dwError);
  305. if (!FIsDebugFlagSet (dfidNoErrorText))
  306. {
  307. PSTR pszaErrorText = NULL;
  308. FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  309. FORMAT_MESSAGE_FROM_SYSTEM,
  310. NULL, dwError,
  311. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  312. (PSTR)&pszaErrorText, 0, NULL);
  313. if (pszaErrorText)
  314. {
  315. // Strip off newline characters.
  316. //
  317. PSTR pchText = pszaErrorText;
  318. while (*pchText && (*pchText != '\r') && (*pchText != '\n'))
  319. {
  320. pchText++;
  321. }
  322. *pchText = 0;
  323. // Add the error text.
  324. //
  325. static const CHAR c_szaFmtErrorText [] = " [%s]";
  326. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtErrorText,
  327. pszaErrorText);
  328. LocalFree (pszaErrorText);
  329. }
  330. }
  331. // Add the Win32 error code.
  332. //
  333. if (fFacilityWin32 || dwWin32Error)
  334. {
  335. static const CHAR c_szaFmtWin32Error [] = " Win32=%d,0x%08X";
  336. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtWin32Error,
  337. dwError, dwError);
  338. }
  339. }
  340. // Add the HRESULT.
  341. //
  342. if (S_OK != hr)
  343. {
  344. static const CHAR c_szaFmtHresult [] = " hr=0x%08X";
  345. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtHresult,
  346. hr);
  347. }
  348. // Add the file and line.
  349. //
  350. if (pszaFile)
  351. {
  352. static const CHAR c_szaFmtFileAndLine [] = " File:%s,%d";
  353. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtFileAndLine,
  354. pszaFile, nLine);
  355. }
  356. // Add the newline.
  357. //
  358. lstrcatA (pcha, "\n");
  359. g_Tracing.Trace (ttid, szaBuf);
  360. // Now that the message is on the debugger, break if we have an error
  361. // and the debug flag to break on error is set.
  362. //
  363. if ((FAILED(hr) || dwWin32Error || (ttidError == ttid)) &&
  364. !fIgnorable && FIsDebugFlagSet(dfidBreakOnError))
  365. {
  366. DebugBreak();
  367. }
  368. if ( (bTraceStackOnError) && FIsDebugFlagSet(dfidTraceCallStackOnError) && (ttid == ttidError) )
  369. {
  370. CTracingIndent::TraceStackFn(ttidError);
  371. }
  372. }
  373. //+---------------------------------------------------------------------------
  374. //
  375. // Function: TraceInternal
  376. //
  377. // Purpose: The one and only place that a string to be traced is formed
  378. // and traced.
  379. //
  380. // Arguments:
  381. //
  382. // Returns: nothing.
  383. //
  384. // Author: shaunco 13 Mar 1998
  385. //
  386. // Notes: Restructured from lots of other code that was added to this
  387. // module over the past year.
  388. //
  389. VOID
  390. TraceInternal (
  391. TRACETAGID ttid,
  392. PCSTR pszaFile,
  393. INT nLine,
  394. PCSTR pszaFunc,
  395. DWORD dwFlags,
  396. PCSTR pszaCallerText,
  397. DWORD dwErrorCode,
  398. BOOL bTraceStackOnError)
  399. {
  400. // If this tracetag is turned off, don't do anything.
  401. //
  402. if (!g_TraceTags[ttid].fOutputDebugString &&
  403. !g_TraceTags[ttid].fOutputToFile)
  404. {
  405. return;
  406. }
  407. BOOL fError = dwFlags & (TI_HRESULT | TI_WIN32);
  408. BOOL fIgnorable = dwFlags & TI_IGNORABLE;
  409. HRESULT hr = (dwFlags & TI_HRESULT) ? dwErrorCode : S_OK;
  410. DWORD dwWin32Error = (dwFlags & TI_WIN32) ? dwErrorCode : ERROR_SUCCESS;
  411. // Ignore if told and we're not set to trace ignored errors or warnings.
  412. //
  413. if (fError && fIgnorable &&
  414. !FIsDebugFlagSet (dfidShowIgnoredErrors) &&
  415. !FIsDebugFlagSet (dfidExtremeTracing))
  416. {
  417. return;
  418. }
  419. // Don't do anything if we're tracing for an error and we don't have one,
  420. // unless the "Extreme Tracing" flag is on, in which case we trace
  421. // everything in the world (for debugger use only, really)
  422. // This is the path taken by TraceError ("...", S_OK) or
  423. // TraceLastWin32Error when there is no last Win32 error.
  424. //
  425. if (fError && !dwErrorCode && !FIsDebugFlagSet(dfidExtremeTracing))
  426. {
  427. return;
  428. }
  429. CHAR szaBuf [MAX_TRACE_LEN * 2];
  430. PSTR pcha = szaBuf;
  431. // Form the prefix, process id and thread id.
  432. //
  433. static const CHAR c_szaFmtPrefix [] = "NETCFG";
  434. lstrcpyA (pcha, c_szaFmtPrefix);
  435. pcha += lstrlenA (c_szaFmtPrefix);
  436. // Add process and thread ids if the debug flags indicate to do so.
  437. //
  438. if (FIsDebugFlagSet (dfidShowProcessAndThreadIds))
  439. {
  440. static const CHAR c_szaFmtPidAndTid [] = " %03d.%03d";
  441. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtPidAndTid,
  442. GetCurrentProcessId (),
  443. GetCurrentThreadId ());
  444. }
  445. // Add a time stamp if the debug flags indicate to do so.
  446. //
  447. if (FIsDebugFlagSet (dfidTracingTimeStamps))
  448. {
  449. static const CHAR c_szaFmtTime [] = " [%02d:%02d:%02d.%03d]";
  450. SYSTEMTIME stLocal;
  451. GetLocalTime (&stLocal);
  452. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtTime,
  453. stLocal.wHour,
  454. stLocal.wMinute,
  455. stLocal.wSecond,
  456. stLocal.wMilliseconds);
  457. }
  458. // Add a severity indicator if this trace is for an error or warning.
  459. //
  460. if (fError || (ttidError == ttid))
  461. {
  462. static const CHAR c_szaSevIgnored [] = " Ignored:";
  463. static const CHAR c_szaSevError [] = " *ERROR*:";
  464. static const CHAR c_szaSevWarning [] = " Warning:";
  465. PCSTR pszaSev = NULL;
  466. if (fError && SUCCEEDED(hr) && !dwWin32Error && !fIgnorable)
  467. {
  468. pszaSev = c_szaSevWarning;
  469. }
  470. else
  471. {
  472. if (fIgnorable && FIsDebugFlagSet (dfidShowIgnoredErrors))
  473. {
  474. pszaSev = c_szaSevIgnored;
  475. }
  476. else
  477. {
  478. pszaSev = c_szaSevError;
  479. }
  480. }
  481. Assert (pszaSev);
  482. lstrcatA (pcha, pszaSev);
  483. pcha += lstrlenA (pszaSev);
  484. }
  485. // Add the tracetag short name. Don't do this for ttidError if
  486. // we already have the severity indicator from above.
  487. //
  488. if (ttid && (ttid < g_nTraceTagCount) && (ttid != ttidError))
  489. {
  490. static const CHAR c_szaFmtTraceTag [] = " (%s)";
  491. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtTraceTag,
  492. g_TraceTags[ttid].szShortName);
  493. }
  494. // Add the caller's text.
  495. //
  496. if (pszaCallerText)
  497. {
  498. static const CHAR c_szaFmtCallerText [] = " %s";
  499. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtCallerText,
  500. pszaCallerText);
  501. Assert (pcha > szaBuf);
  502. if ('\n' == *(pcha-1))
  503. {
  504. pcha--;
  505. *pcha = 0;
  506. }
  507. }
  508. // Add descriptive error text if this is an error and we can get some.
  509. //
  510. if (FAILED(hr) || dwWin32Error)
  511. {
  512. BOOL fFacilityWin32 = (FACILITY_WIN32 == HRESULT_FACILITY(hr));
  513. // dwError will be the error code we pass to FormatMessage. It may
  514. // come from hr or dwWin32Error. Give preference to hr.
  515. //
  516. DWORD dwError = 0;
  517. if (fFacilityWin32)
  518. {
  519. dwError = HRESULT_CODE(hr);
  520. }
  521. else if (FAILED(hr))
  522. {
  523. dwError = hr;
  524. }
  525. else
  526. {
  527. dwError = dwWin32Error;
  528. }
  529. Assert (dwError);
  530. if (!FIsDebugFlagSet (dfidNoErrorText))
  531. {
  532. PSTR pszaErrorText = NULL;
  533. FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  534. FORMAT_MESSAGE_FROM_SYSTEM,
  535. NULL, dwError,
  536. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  537. (PSTR)&pszaErrorText, 0, NULL);
  538. if (pszaErrorText)
  539. {
  540. // Strip off newline characters.
  541. //
  542. PSTR pchText = pszaErrorText;
  543. while (*pchText && (*pchText != '\r') && (*pchText != '\n'))
  544. {
  545. pchText++;
  546. }
  547. *pchText = 0;
  548. // Add the error text.
  549. //
  550. static const CHAR c_szaFmtErrorText [] = " [%s]";
  551. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtErrorText,
  552. pszaErrorText);
  553. LocalFree (pszaErrorText);
  554. }
  555. }
  556. // Add the Win32 error code.
  557. //
  558. if (fFacilityWin32 || dwWin32Error)
  559. {
  560. static const CHAR c_szaFmtWin32Error [] = " Win32=%d,0x%08X";
  561. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtWin32Error,
  562. dwError, dwError);
  563. }
  564. }
  565. // Add the HRESULT.
  566. //
  567. if (S_OK != hr)
  568. {
  569. static const CHAR c_szaFmtHresult [] = " hr=0x%08X";
  570. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtHresult,
  571. hr);
  572. }
  573. // Add the file and line.
  574. //
  575. if (pszaFile)
  576. {
  577. static const CHAR c_szaFmtFileAndLine [] = " File:%s,%d";
  578. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtFileAndLine,
  579. pszaFile, nLine);
  580. }
  581. // Add the function name
  582. //
  583. if (pszaFunc)
  584. {
  585. static const CHAR c_szaFmtFunc[] = ":";
  586. pcha += _snprintf (pcha, MAX_TRACE_LEN, c_szaFmtFunc, pszaFunc);
  587. }
  588. // Add the newline.
  589. //
  590. lstrcatA (pcha, "\n");
  591. g_Tracing.Trace (ttid, szaBuf);
  592. // Now that the message is on the debugger, break if we have an error
  593. // and the debug flag to break on error is set.
  594. //
  595. if ((FAILED(hr) || dwWin32Error || (ttidError == ttid)) &&
  596. !fIgnorable && FIsDebugFlagSet(dfidBreakOnError))
  597. {
  598. DebugBreak();
  599. }
  600. if ( (bTraceStackOnError) && FIsDebugFlagSet(dfidTraceCallStackOnError) && (ttid == ttidError) )
  601. {
  602. CTracingIndent::TraceStackFn(ttidError);
  603. }
  604. }
  605. //+---------------------------------------------------------------------------
  606. //
  607. // Function: TraceErrorFn
  608. //
  609. // Purpose: Output debug trace of an HRESULT, allowing an additional
  610. // caller-defined error string.
  611. //
  612. // Arguments:
  613. // sz [] Caller-defined additional error text
  614. // hr [] The error HRESULT.
  615. //
  616. // Returns:
  617. //
  618. // Author: jeffspr 14 Apr 1997
  619. //
  620. // Notes:
  621. //
  622. VOID
  623. WINAPI
  624. TraceErrorFn (
  625. PCSTR pszaFile,
  626. INT nLine,
  627. PCSTR psza,
  628. HRESULT hr)
  629. {
  630. DWORD dwFlags = TI_HRESULT;
  631. if (S_FALSE == hr)
  632. {
  633. dwFlags |= TI_IGNORABLE;
  634. }
  635. TraceInternal (ttidError, pszaFile, nLine, dwFlags, psza, hr, TRUE);
  636. }
  637. //+---------------------------------------------------------------------------
  638. //
  639. // Function: TraceErrorOptionalFn
  640. //
  641. // Purpose: Implements TraceErrorOptional macro
  642. //
  643. // Arguments:
  644. // pszaFile [in] __FILE__ value
  645. // nLine [in] __LINE__ value
  646. // psza [in] String to trace.
  647. // hr [in] HRESULT value to trace.
  648. // fOpt [in] TRUE if error should be treated as optional, FALSE if
  649. // ERROR is not optional and should be reported thru
  650. // TraceError().
  651. //
  652. // Returns: Nothing.
  653. //
  654. // Author: danielwe 12 May 1997
  655. //
  656. // Notes:
  657. //
  658. VOID
  659. WINAPI
  660. TraceErrorOptionalFn (
  661. PCSTR pszaFile,
  662. INT nLine,
  663. PCSTR psza,
  664. HRESULT hr,
  665. BOOL fIgnorable)
  666. {
  667. DWORD dwFlags = TI_HRESULT;
  668. if (fIgnorable)
  669. {
  670. dwFlags |= TI_IGNORABLE;
  671. }
  672. TraceInternal (ttidError, pszaFile, nLine, dwFlags, psza, hr, TRUE);
  673. }
  674. //+---------------------------------------------------------------------------
  675. //
  676. // Function: TraceErrorSkipFn
  677. //
  678. // Purpose: Implements TraceErrorOptional macro
  679. //
  680. // Arguments:
  681. // pszaFile [in] __FILE__ value
  682. // nLine [in] __LINE__ value
  683. // psza [in] String to trace.
  684. // hr [in] HRESULT value to trace.
  685. // c [in] count of pass-through Hresults. if hr is any of these
  686. // the error is treated as optional.
  687. // ... [in] list of hresults.
  688. //
  689. // Returns: Nothing.
  690. //
  691. // Author: sumitc 08 Jan 1998
  692. //
  693. // Notes:
  694. //
  695. VOID WINAPI
  696. TraceErrorSkipFn (
  697. PCSTR pszaFile,
  698. INT nLine,
  699. PCSTR psza,
  700. HRESULT hr,
  701. UINT c, ...)
  702. {
  703. va_list valMarker;
  704. BOOL fIgnorable = FALSE;
  705. va_start(valMarker, c);
  706. for (UINT i = 0; i < c; ++i)
  707. {
  708. fIgnorable = (va_arg(valMarker, HRESULT) == hr);
  709. if (fIgnorable)
  710. {
  711. break;
  712. }
  713. }
  714. va_end(valMarker);
  715. DWORD dwFlags = TI_HRESULT;
  716. if (fIgnorable)
  717. {
  718. dwFlags |= TI_IGNORABLE;
  719. }
  720. TraceInternal (ttidError, pszaFile, nLine, dwFlags, psza, hr, TRUE);
  721. }
  722. //+---------------------------------------------------------------------------
  723. //
  724. // Function: TraceLastWin32ErrorFn
  725. //
  726. // Purpose: Trace the last Win32 error, which we get with GetLastError().
  727. // Not a whole lot to it.
  728. //
  729. // Arguments:
  730. // sz [] Additional error text.
  731. //
  732. // Returns:
  733. //
  734. // Author: jeffspr 14 Apr 1997
  735. //
  736. // Notes:
  737. //
  738. VOID
  739. WINAPIV
  740. TraceLastWin32ErrorFn (
  741. PCSTR pszaFile,
  742. INT nLine,
  743. PCSTR psza)
  744. {
  745. TraceInternal (ttidError, pszaFile, nLine, TI_WIN32, psza, GetLastError(), TRUE);
  746. }
  747. //+---------------------------------------------------------------------------
  748. //
  749. // Function: TraceHrFn
  750. //
  751. // Purpose: Generic replacement for the TraceErrorOptional, TraceError,
  752. // and a couple other random functions.
  753. //
  754. // Arguments:
  755. // ttid [] TraceTag to use for the debug output
  756. // pszaFile [] Source file to log
  757. // nLine [] Line number to log
  758. // hr [] Error to log
  759. // fIgnorable [] Ignore this error? (The optional bit)
  760. // pszaFmt [] Format of the vargs
  761. //
  762. // Returns:
  763. //
  764. // Author: jeffspr 10 Oct 1997
  765. //
  766. // Notes:
  767. //
  768. VOID
  769. WINAPIV
  770. TraceHrFn (
  771. TRACETAGID ttid,
  772. PCSTR pszaFile,
  773. INT nLine,
  774. HRESULT hr,
  775. BOOL fIgnorable,
  776. PCSTR pszaFmt,
  777. ...)
  778. {
  779. // If this tracetag is turned off, don't do anything.
  780. //
  781. if (!g_TraceTags[ttid].fOutputDebugString &&
  782. !g_TraceTags[ttid].fOutputToFile)
  783. {
  784. return;
  785. }
  786. CHAR szaBuf [MAX_TRACE_LEN];
  787. // Build the string from the varg list
  788. //
  789. va_list valMarker;
  790. va_start (valMarker, pszaFmt);
  791. vsprintf (szaBuf, pszaFmt, valMarker);
  792. va_end (valMarker);
  793. DWORD dwFlags = TI_HRESULT;
  794. if (fIgnorable)
  795. {
  796. dwFlags |= TI_IGNORABLE;
  797. }
  798. TraceInternal (ttid, pszaFile, nLine, dwFlags, szaBuf, hr, TRUE);
  799. }
  800. //+---------------------------------------------------------------------------
  801. //
  802. // Function: TraceHrFn
  803. //
  804. // Purpose: Generic replacement for the TraceErrorOptional, TraceError,
  805. // and a couple other random functions.
  806. //
  807. // Arguments:
  808. // ttid [] TraceTag to use for the debug output
  809. // pszaFile [] Source file to log
  810. // nLine [] Line number to log
  811. // hr [] Error to log
  812. // fIgnorable [] Ignore this error? (The optional bit)
  813. // pszaFmt [] Format of the vargs
  814. //
  815. // Returns:
  816. //
  817. // Author: jeffspr 10 Oct 1997
  818. //
  819. // Notes:
  820. //
  821. VOID
  822. WINAPIV
  823. TraceHrFn (
  824. TRACETAGID ttid,
  825. PCSTR pszaFile,
  826. INT nLine,
  827. PCSTR pszaFunc,
  828. HRESULT hr,
  829. BOOL fIgnorable,
  830. PCSTR pszaFmt,
  831. ...)
  832. {
  833. // If this tracetag is turned off, don't do anything.
  834. //
  835. if (!g_TraceTags[ttid].fOutputDebugString &&
  836. !g_TraceTags[ttid].fOutputToFile)
  837. {
  838. return;
  839. }
  840. CHAR szaBuf [MAX_TRACE_LEN];
  841. // Build the string from the varg list
  842. //
  843. va_list valMarker;
  844. va_start (valMarker, pszaFmt);
  845. _vsnprintf (szaBuf, MAX_TRACE_LEN, pszaFmt, valMarker);
  846. va_end (valMarker);
  847. DWORD dwFlags = TI_HRESULT;
  848. if (fIgnorable)
  849. {
  850. dwFlags |= TI_IGNORABLE;
  851. }
  852. TraceInternal (ttid, pszaFile, nLine, pszaFunc, dwFlags, szaBuf, hr, TRUE);
  853. }
  854. //+---------------------------------------------------------------------------
  855. //
  856. // Function: TraceTagFn
  857. //
  858. // Purpose: Output a debug trace to one or more trace targets (ODS,
  859. // File, COM port, etc.). This function determines the targets
  860. // and performs the actual trace.
  861. //
  862. // Arguments:
  863. // ttid [] TraceTag to use for the debug output
  864. // pszaFmt [] Format of the vargs.
  865. //
  866. // Returns:
  867. //
  868. // Author: jeffspr 14 Apr 1997
  869. //
  870. // Notes:
  871. //
  872. VOID
  873. WINAPIV
  874. TraceTagFn (
  875. TRACETAGID ttid,
  876. PCSTR pszaFmt,
  877. ...)
  878. {
  879. // If this tracetag is turned off, don't do anything.
  880. //
  881. if (!g_TraceTags[ttid].fOutputDebugString &&
  882. !g_TraceTags[ttid].fOutputToFile)
  883. {
  884. return;
  885. }
  886. CHAR szaBuf [MAX_TRACE_LEN];
  887. // Build the string from the varg list
  888. //
  889. va_list valMarker;
  890. va_start (valMarker, pszaFmt);
  891. _vsnprintf (szaBuf, MAX_TRACE_LEN, pszaFmt, valMarker);
  892. va_end (valMarker);
  893. TraceInternal (ttid, NULL, 0, 0, szaBuf, 0, TRUE);
  894. }
  895. //+---------------------------------------------------------------------------
  896. //
  897. // Member: CTracing::CTracing
  898. //
  899. // Purpose: Constructor for CTracing. Initialize all vars.
  900. //
  901. // Arguments:
  902. // (none)
  903. //
  904. // Returns:
  905. //
  906. // Author: jeffspr 23 Jan 1999
  907. //
  908. // Notes:
  909. //
  910. CTracing::CTracing()
  911. {
  912. m_fInitialized = FALSE; // Has the object been initialized
  913. m_fAttemptedLogFileOpen = FALSE; // Already attempted to open log
  914. m_fDisableLogFile = FALSE; // Disable use of file logging?
  915. m_uiAllocOnWhichToBreak = 0; // For _CrtSetBreakAlloc
  916. m_hLogFile = NULL; // Handle for debug output file
  917. m_szLogFilePath[0] = '\0'; // File for debug output
  918. m_fDebugFlagsLoaded = FALSE; // Have these been loaded yet.
  919. g_dwTlsTracing = NULL;
  920. HrInit();
  921. }
  922. CTracing::~CTracing()
  923. {
  924. HrUnInit();
  925. }
  926. //+---------------------------------------------------------------------------
  927. //
  928. // Member: CTracing::HrInit
  929. //
  930. // Purpose: Initialize the CTracing object.
  931. //
  932. // Arguments:
  933. // (none)
  934. //
  935. // Returns: S_OK or valid Win32 HRESULT
  936. //
  937. // Author: jeffspr 9 Apr 1997
  938. //
  939. // Notes: This should get called from some standard exe initialization
  940. // point. And make sure to call HrDeinit when you're done, eh?
  941. //
  942. HRESULT CTracing::HrInit()
  943. {
  944. HRESULT hr = S_OK;
  945. AssertSz(!m_fInitialized,
  946. "CTracing::HrInit -- Let's not go overboard. Already initialized");
  947. g_csTracing = new CRITICAL_SECTION;
  948. Assert(g_csTracing);
  949. InitializeCriticalSection(g_csTracing);
  950. g_dwTlsTracing = TlsAlloc();
  951. AssertSz(g_dwTlsTracing, "g_dwTlsTracing could not aquire a TLS slot");
  952. hr = FIniFileInit();
  953. if (FAILED(hr))
  954. {
  955. goto Exit;
  956. }
  957. // Temporarily set this so the called functions don't believe that we're
  958. // uninitialized. At Exit, if we fail, we'll set it back so no-one tries
  959. // to call these functions when uninitialized.
  960. //
  961. m_fInitialized = TRUE;
  962. // Check for corruptions in the tracing structure. This can't fail, but
  963. // it will send up asserts all over the place if something is amiss.
  964. //
  965. CorruptionCheck();
  966. // Load the "options" section from the ini file
  967. //
  968. hr = HrLoadOptionsFromIniFile();
  969. if (FAILED(hr))
  970. {
  971. goto Exit;
  972. }
  973. // Load the DebugFlags section from the ini file.
  974. //
  975. hr = HrLoadDebugFlagsFromIniFile();
  976. if (FAILED(hr))
  977. {
  978. goto Exit;
  979. }
  980. // Load the tracetag sections from the ini file.
  981. // Make sure this is called after HrLoadDebugFlagsFromIniFile(),
  982. // as those options will affect the tracetag sections (we also
  983. // assert on this)
  984. //
  985. hr = HrLoadSectionsFromIniFile();
  986. if (FAILED(hr))
  987. {
  988. goto Exit;
  989. }
  990. // If certain tracetags are on, we want others to be off because some
  991. // encompase the functionality of others.
  992. //
  993. if (g_TraceTags[ttidBeDiag].fOutputDebugString)
  994. {
  995. g_TraceTags[ttidNetCfgPnp].fOutputDebugString = FALSE;
  996. }
  997. #ifdef ENABLELEAKDETECTION
  998. if (FIsDebugFlagSet(dfidTrackObjectLeaks))
  999. {
  1000. g_pObjectLeakTrack = new CObjectLeakTrack;
  1001. Assert(g_pObjectLeakTrack);
  1002. }
  1003. #endif
  1004. Exit:
  1005. if (FAILED(hr))
  1006. {
  1007. m_fInitialized = FALSE;
  1008. }
  1009. return hr;
  1010. }
  1011. //+---------------------------------------------------------------------------
  1012. //
  1013. // Member: CTracing::HrUnInit
  1014. //
  1015. // Purpose: Uninitialize the Tracing object
  1016. //
  1017. // Arguments:
  1018. // (none)
  1019. //
  1020. // Returns: S_OK or valid Win32 HRESULT
  1021. //
  1022. // Author: jeffspr 12 Apr 1997
  1023. //
  1024. // Notes:
  1025. //
  1026. HRESULT CTracing::HrUnInit()
  1027. {
  1028. HRESULT hr = S_OK;
  1029. #ifdef ENABLELEAKDETECTION
  1030. if (FIsDebugFlagSet(dfidTrackObjectLeaks))
  1031. {
  1032. BOOL fAsserted = g_pObjectLeakTrack->AssertIfObjectsStillAllocated(NULL);
  1033. delete g_pObjectLeakTrack;
  1034. if (fAsserted)
  1035. {
  1036. AssertSz(FALSE, "Spew is completed - press RETRY to look at spew and map ReturnAddr values to symbols");
  1037. }
  1038. }
  1039. #endif
  1040. if (g_dwTlsTracing)
  1041. {
  1042. TlsFree(g_dwTlsTracing);
  1043. g_dwTlsTracing = 0;
  1044. }
  1045. if (g_csTracing)
  1046. {
  1047. {
  1048. __try
  1049. {
  1050. EnterCriticalSection(g_csTracing);
  1051. }
  1052. __finally
  1053. {
  1054. LeaveCriticalSection(g_csTracing);
  1055. }
  1056. }
  1057. DeleteCriticalSection(g_csTracing);
  1058. delete g_csTracing;
  1059. g_csTracing = NULL;
  1060. }
  1061. // Don't assert on m_fInitialized here, because we allow this to
  1062. // be called even if initialization failed.
  1063. //
  1064. if (m_fInitialized)
  1065. {
  1066. hr = HrWriteDebugFlagsToIniFile();
  1067. if (FAILED(hr))
  1068. {
  1069. // continue on, but I want to know why this is failing.
  1070. AssertSz(FALSE, "Whoa, why can't we write the debug flags?");
  1071. }
  1072. // Close the log file, if there's one open
  1073. //
  1074. if (m_hLogFile)
  1075. {
  1076. CloseHandle(m_hLogFile);
  1077. m_hLogFile = NULL;
  1078. }
  1079. // Mark us as being uninitialized.
  1080. //
  1081. m_fInitialized = FALSE;
  1082. }
  1083. return hr;
  1084. }
  1085. //+---------------------------------------------------------------------------
  1086. //
  1087. // Member: CTracing::HrGetPrivateProfileString
  1088. //
  1089. // Purpose:
  1090. //
  1091. // Arguments:
  1092. // lpAppName [] points to section name
  1093. // lpKeyName [] points to key name
  1094. // lpDefault [] points to default string
  1095. // lpReturnedString [] points to destination buffer
  1096. // nSize [] size of destination buffer
  1097. // lpFileName [] points to initialization filename
  1098. // pcchReturn return buffer for the old Win32 API return code
  1099. //
  1100. //
  1101. // Returns: S_OK or valid Win32 HRESULT
  1102. //
  1103. // Author: jeffspr 12 Apr 1997
  1104. //
  1105. // Notes:
  1106. //
  1107. HRESULT CTracing::HrGetPrivateProfileString( PCSTR lpAppName,
  1108. PCSTR lpKeyName,
  1109. PCSTR lpDefault,
  1110. PSTR lpReturnedString,
  1111. DWORD nSize,
  1112. PCSTR lpFileName,
  1113. DWORD* pcchReturn
  1114. )
  1115. {
  1116. HRESULT hr = S_OK;
  1117. Assert(m_fInitialized);
  1118. // Assert on the known conditions required for this API call
  1119. //
  1120. Assert(lpDefault);
  1121. Assert(lpFileName);
  1122. // Call the Win32 API
  1123. //
  1124. DWORD dwGPPSResult = GetPrivateProfileStringA(
  1125. lpAppName,
  1126. lpKeyName,
  1127. lpDefault,
  1128. lpReturnedString,
  1129. nSize,
  1130. lpFileName);
  1131. // Check to see if we've gotten a string-size error
  1132. if (lpAppName && lpKeyName)
  1133. {
  1134. // If we get back (nSize - 1), then our string buffer wasn't
  1135. // large enough
  1136. //
  1137. if (dwGPPSResult == (nSize - 1))
  1138. {
  1139. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1140. goto Exit;
  1141. }
  1142. }
  1143. else
  1144. {
  1145. // Since either of the app name or key name are NULL, then
  1146. // we're supposed to be receiving a doubly-NULL terminated
  1147. // list of strings. If we're at (nSize - 2), that means
  1148. // our buffer was too small.
  1149. //
  1150. if (dwGPPSResult == (nSize - 2))
  1151. {
  1152. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1153. goto Exit;
  1154. }
  1155. }
  1156. Exit:
  1157. *pcchReturn = dwGPPSResult;
  1158. return hr;
  1159. }
  1160. //+---------------------------------------------------------------------------
  1161. //
  1162. // Member: CTracing::HrLoadOptionsFromIniFile
  1163. //
  1164. // Purpose: Load the options section from the ini file, and set our
  1165. // state accordingly
  1166. //
  1167. // Arguments:
  1168. // (none)
  1169. //
  1170. // Returns: S_OK or valid Win32 HRESULT
  1171. //
  1172. // Author: jeffspr 10 Apr 1997
  1173. //
  1174. // Notes:
  1175. //
  1176. HRESULT CTracing::HrLoadOptionsFromIniFile()
  1177. {
  1178. HRESULT hr = S_OK;
  1179. DWORD cchReturnBufferSize = 0;
  1180. WCHAR szLogFilePath[MAX_PATH+1] = { 0 };
  1181. DWORD dwTempPathLength = 0;
  1182. // Get the explicit log file path, if any. If it doesn't exist, then
  1183. // use the default path, which is the temp file path plus the default
  1184. // trace file name
  1185. //
  1186. // Get the location of the "temporary files" path
  1187. dwTempPathLength = GetTempPath(MAX_PATH, szLogFilePath);
  1188. if ((dwTempPathLength == 0) ||
  1189. (dwTempPathLength > MAX_PATH))
  1190. {
  1191. TraceLastWin32Error("GetTempPath failure");
  1192. hr = HrFromLastWin32Error();
  1193. goto Exit;
  1194. }
  1195. // Tack the log file name onto the end.
  1196. //
  1197. _snprintf(m_szLogFilePath, MAX_TRACE_LEN, "%s%s", szLogFilePath, c_szTraceLogFileNameA);
  1198. // This will overwrite the log file path if one exists in the INI file
  1199. //
  1200. hr = HrGetPrivateProfileString(
  1201. c_szaOptions, // "Options"
  1202. c_szaLogFilePath, // "LogFilePath
  1203. m_szLogFilePath, // Default string, already filled
  1204. m_szLogFilePath, // Return string (same string)
  1205. MAX_PATH+1,
  1206. c_szDebugIniFileNameA,
  1207. &cchReturnBufferSize);
  1208. if (FAILED(hr))
  1209. {
  1210. // This should not cause problems with recursive failure, since
  1211. // Traces will work regardless of the state of trace initialization.
  1212. //
  1213. TraceError(
  1214. "GetPrivateProfileString failed on Options::LogFilePath", hr);
  1215. goto Exit;
  1216. }
  1217. // Get the "disable log file option". No return code here.
  1218. m_fDisableLogFile = GetPrivateProfileIntA(
  1219. c_szaOptions, // "Options"
  1220. c_szaDisableLogFile, // "DisableLogFile"
  1221. c_iDefaultDisableLogFile,
  1222. c_szDebugIniFileNameA);
  1223. if (FAILED(hr))
  1224. {
  1225. TraceError(
  1226. "GetPrivateProfileInt failed on Options::DisableLogFile", hr);
  1227. goto Exit;
  1228. }
  1229. Exit:
  1230. return hr;
  1231. }
  1232. //+---------------------------------------------------------------------------
  1233. //
  1234. // Member: CTracing::HrLoadSectionsFromIniFile
  1235. //
  1236. // Purpose: Load the individual tracetag sections from the ini file, and
  1237. // set our array elements accordingly, defaulting if necessary.
  1238. //
  1239. // Arguments:
  1240. // (none)
  1241. //
  1242. // Returns: S_OK or valid Win32 HRESULT
  1243. //
  1244. // Author: jeffspr 10 Apr 1997
  1245. //
  1246. // Notes:
  1247. //
  1248. HRESULT CTracing::HrLoadSectionsFromIniFile()
  1249. {
  1250. HRESULT hr = S_OK;
  1251. // Make sure that we've loaded the debug flags first, as they can
  1252. // affect each tracetag section
  1253. //
  1254. Assert(m_fDebugFlagsLoaded);
  1255. // Loop through the array and load the data.
  1256. //
  1257. for (INT nLoop = 0; nLoop < g_nTraceTagCount; nLoop++ )
  1258. {
  1259. // Process the individual lines from the section
  1260. hr = HrProcessTagSection(&(g_TraceTags[nLoop]));
  1261. if (FAILED(hr))
  1262. {
  1263. break;
  1264. }
  1265. }
  1266. return hr;
  1267. }
  1268. //+---------------------------------------------------------------------------
  1269. //
  1270. // Member: CTracing::HrLoadDebugFlagsFromIniFile
  1271. //
  1272. // Purpose: Load the individual debugflag values from the ini file, and
  1273. // set our array elements accordingly, defaulting if necessary.
  1274. //
  1275. // Arguments:
  1276. // (none)
  1277. //
  1278. // Returns: S_OK or valid Win32 HRESULT
  1279. //
  1280. // Author: jeffspr 10 Apr 1997
  1281. //
  1282. // Notes:
  1283. //
  1284. HRESULT CTracing::HrLoadDebugFlagsFromIniFile()
  1285. {
  1286. HRESULT hr = S_OK;
  1287. INT nLoop;
  1288. // Loop through the array and load the data.
  1289. //
  1290. for (nLoop = 0; nLoop < g_nDebugFlagCount; nLoop++)
  1291. {
  1292. switch(nLoop)
  1293. {
  1294. case dfidBreakOnAlloc:
  1295. // Get the "break on alloc" alloc count.
  1296. //
  1297. m_uiAllocOnWhichToBreak = GetPrivateProfileIntA(
  1298. "DebugFlags",
  1299. g_DebugFlags[nLoop].szShortName,
  1300. FALSE,
  1301. c_szDebugIniFileNameA);
  1302. g_DebugFlags[nLoop].dwValue = (m_uiAllocOnWhichToBreak > 0);
  1303. // If there was a value set, set the break..
  1304. //
  1305. if (m_uiAllocOnWhichToBreak != 0)
  1306. _CrtSetBreakAlloc(m_uiAllocOnWhichToBreak);
  1307. break;
  1308. default:
  1309. // Get the enabled file param
  1310. //
  1311. g_DebugFlags[nLoop].dwValue = GetPrivateProfileIntA(
  1312. "DebugFlags",
  1313. g_DebugFlags[nLoop].szShortName,
  1314. FALSE,
  1315. c_szDebugIniFileNameA);
  1316. break;
  1317. }
  1318. }
  1319. if (SUCCEEDED(hr))
  1320. {
  1321. m_fDebugFlagsLoaded = TRUE;
  1322. }
  1323. return hr;
  1324. }
  1325. HRESULT CTracing::FIniFileInit()
  1326. {
  1327. HRESULT hr = E_FAIL;
  1328. WCHAR szWindowsPath[MAX_PATH+1] = L"";
  1329. WCHAR szPath[MAX_PATH+1] = L"";
  1330. UINT uiCharsReturned = 0;
  1331. HANDLE hFile = INVALID_HANDLE_VALUE;
  1332. uiCharsReturned = GetWindowsDirectory(szWindowsPath, MAX_PATH);
  1333. if ((uiCharsReturned == 0) || (uiCharsReturned > MAX_PATH))
  1334. {
  1335. AssertSz(FALSE, "GetWindowsDirectory failed in CTracing::FIniFileInit");
  1336. hr = E_UNEXPECTED;
  1337. goto Exit;
  1338. }
  1339. wcscpy (szPath, szWindowsPath);
  1340. wcscat (szPath, L"\\");
  1341. wcscat (szPath, c_szDebugIniFileName);
  1342. hFile = CreateFile(
  1343. szPath,
  1344. GENERIC_READ,
  1345. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1346. NULL,
  1347. OPEN_EXISTING,
  1348. FILE_ATTRIBUTE_NORMAL,
  1349. NULL);
  1350. if (hFile == INVALID_HANDLE_VALUE)
  1351. {
  1352. DWORD dwLastError = GetLastError();
  1353. if (dwLastError != ERROR_FILE_NOT_FOUND)
  1354. {
  1355. AssertSz(FALSE, "FIniFileInit failed for some reason other than FILE_NOT_FOUND");
  1356. hr = HRESULT_FROM_WIN32(dwLastError);
  1357. goto Exit;
  1358. }
  1359. }
  1360. else
  1361. {
  1362. hr = S_OK;
  1363. wcstombs(c_szDebugIniFileNameA, szPath, MAX_PATH);
  1364. goto Exit;
  1365. }
  1366. _wsplitpath(szWindowsPath, szPath, NULL, NULL, NULL);
  1367. wcscat (szPath, L"\\");
  1368. wcscat (szPath, c_szDebugIniFileName);
  1369. hFile = CreateFile(
  1370. szPath,
  1371. GENERIC_READ,
  1372. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1373. NULL,
  1374. OPEN_EXISTING,
  1375. FILE_ATTRIBUTE_NORMAL,
  1376. NULL);
  1377. if (hFile == INVALID_HANDLE_VALUE)
  1378. {
  1379. DWORD dwLastError = GetLastError();
  1380. hr = HRESULT_FROM_WIN32(dwLastError);
  1381. if (dwLastError != ERROR_FILE_NOT_FOUND)
  1382. {
  1383. AssertSz(FALSE, "FIniFileInit failed for some reason other than FILE_NOT_FOUND");
  1384. }
  1385. }
  1386. else
  1387. {
  1388. wcstombs(c_szDebugIniFileNameA, szPath, MAX_PATH);
  1389. hr = S_OK;
  1390. }
  1391. Exit:
  1392. if (hFile)
  1393. {
  1394. CloseHandle(hFile);
  1395. hFile = NULL;
  1396. }
  1397. return hr;
  1398. }
  1399. HRESULT CTracing::HrWriteDebugFlagsToIniFile()
  1400. {
  1401. HRESULT hr = S_OK;
  1402. // First, check to see if the file exists. If it doesn't, then we don't want
  1403. // to write the entries.
  1404. //
  1405. if (FIniFileInit())
  1406. {
  1407. // Loop through the array and write the data.
  1408. //
  1409. for (INT nLoop = 0; nLoop < g_nDebugFlagCount; nLoop++)
  1410. {
  1411. CHAR szInt[16]; // Sure, it's arbitrary, but it's also OK.
  1412. switch(nLoop)
  1413. {
  1414. // BreakOnAlloc is special case -- no associated flag entry
  1415. //
  1416. case dfidBreakOnAlloc:
  1417. _snprintf(szInt, MAX_TRACE_LEN, "%d", m_uiAllocOnWhichToBreak);
  1418. break;
  1419. // These store a DWORD in its standard form
  1420. //
  1421. case dfidBreakOnHr:
  1422. case dfidBreakOnHrIteration:
  1423. case dfidBreakOnIteration:
  1424. _snprintf( szInt, MAX_TRACE_LEN, "%d", g_DebugFlags[nLoop].dwValue);
  1425. break;
  1426. // default are treated as boolean, and stored that way
  1427. //
  1428. default:
  1429. // !! means it will always be 1 or 0.
  1430. _snprintf( szInt, MAX_TRACE_LEN, "%d", (!!g_DebugFlags[nLoop].dwValue));
  1431. break;
  1432. }
  1433. // Write the param to the ini file
  1434. WritePrivateProfileStringA(
  1435. "DebugFlags",
  1436. g_DebugFlags[nLoop].szShortName,
  1437. szInt,
  1438. c_szDebugIniFileNameA);
  1439. }
  1440. }
  1441. // For now, this is always S_OK, since there's nothing above that can
  1442. // fail.
  1443. //
  1444. return hr;
  1445. }
  1446. //+---------------------------------------------------------------------------
  1447. //
  1448. // Member: CTracing::HrProcessTagSection
  1449. //
  1450. // Purpose: Grab the parameters from the ini file. If they're not
  1451. // available, then use the settings in default. Note - this
  1452. // will always work because ttidDefault will always be the first
  1453. // element. If a [default] section wasn't present, then it will
  1454. // be using the settings that were in the struct initialization,
  1455. // which is also fine.
  1456. //
  1457. // Arguments:
  1458. // ptte [] TraceTag element to load
  1459. //
  1460. // Returns:
  1461. //
  1462. // Author: jeffspr 15 Apr 1997
  1463. //
  1464. // Notes:
  1465. //
  1466. HRESULT CTracing::HrProcessTagSection( TraceTagElement * ptte )
  1467. {
  1468. HRESULT hr = S_OK;
  1469. AssertSz(m_fInitialized,
  1470. "CTracing::HrProcessTagSection. Class not initialized");
  1471. AssertSz(ptte, "CTracing::HrProcessTagSection -- invalid ptte");
  1472. // Get the output to file param
  1473. //
  1474. ptte->fOutputToFile = GetPrivateProfileIntA(
  1475. ptte->szShortName,
  1476. "OutputToFile",
  1477. ptte->fVerboseOnly ?
  1478. FALSE : g_TraceTags[ttidDefault].fOutputToFile,
  1479. c_szDebugIniFileNameA);
  1480. // Get the OutputDebugString param. Require that the error tag
  1481. // always has at least output debug string on.
  1482. //
  1483. if (ptte->ttid == ttidError)
  1484. {
  1485. ptte->fOutputDebugString = TRUE;
  1486. }
  1487. else
  1488. {
  1489. // Load the OutputToDebug
  1490. ptte->fOutputDebugString = GetPrivateProfileIntA(
  1491. ptte->szShortName,
  1492. "OutputToDebug",
  1493. ptte->fVerboseOnly ?
  1494. FALSE : g_TraceTags[ttidDefault].fOutputDebugString,
  1495. c_szDebugIniFileNameA);
  1496. }
  1497. return hr;
  1498. }
  1499. //+---------------------------------------------------------------------------
  1500. //
  1501. // Member: CTracing::CorruptionCheck
  1502. //
  1503. // Purpose: Validate the tracetag array. Check to see that the
  1504. // shortnames are valid, that the descriptions are valid,
  1505. // and that the tracetag elements are not out of order.
  1506. // Also verify that the correct number of tracetag elements
  1507. // exist.
  1508. //
  1509. // Arguments:
  1510. // (none)
  1511. //
  1512. // Returns:
  1513. //
  1514. // Author: jeffspr 15 Apr 1997
  1515. //
  1516. // Notes:
  1517. // (shaunco) 16 Jul 1997: This is #if'defd out until JVert
  1518. // gives us a fix for the alpha compiler. It blows up compiling this
  1519. // function in retail.
  1520. //
  1521. // (jeffspr) Tough noogies for JVert - I need this code. Hopefully
  1522. // this has been fixed by now.
  1523. //
  1524. VOID CTracing::CorruptionCheck()
  1525. {
  1526. INT nLoop = 0;
  1527. // Validate the tracetag structure
  1528. //
  1529. for (nLoop = 0; nLoop < g_nTraceTagCount; nLoop++)
  1530. {
  1531. // Verify that we're not out of order or missing ttids
  1532. //
  1533. AssertSz(g_TraceTags[nLoop].ttid == nLoop,
  1534. "Invalid ttid in the tracetag structure. Out of order. " \
  1535. "CTracing::CorruptionCheck");
  1536. AssertSz(g_TraceTags[nLoop].ttid < g_nTraceTagCount,
  1537. "Invalid ttid (out of range) in CTracing::CorruptionCheck");
  1538. // Validate the shortname (verify not NULL or empty strings)
  1539. //
  1540. AssertSz(g_TraceTags[nLoop].szShortName,
  1541. "Invalid tracetag short name (NULL) in CTracing::CorruptionCheck");
  1542. AssertSz(g_TraceTags[nLoop].szShortName[0] != 0,
  1543. "Invalid tracetagshort name (empty) in CTracing::CorruptionCheck");
  1544. // Validate the descriptions (verify not NULL or empty strings)
  1545. //
  1546. AssertSz(g_TraceTags[nLoop].szDescription,
  1547. "Invalid tracetagdescription in CTracing::CorruptionCheck");
  1548. AssertSz(g_TraceTags[nLoop].szDescription[0] != 0,
  1549. "Invalid tracetagdescription (empty) in CTracing::CorruptionCheck");
  1550. }
  1551. // Validate the debug flags structure
  1552. //
  1553. for (nLoop = 0; nLoop < g_nDebugFlagCount; nLoop++)
  1554. {
  1555. // Verify that we're not out of order or missing dfids
  1556. //
  1557. AssertSz(g_DebugFlags[nLoop].dfid == nLoop,
  1558. "Invalid dfid in the debugflag structure. Out of order. " \
  1559. "CTracing::CorruptionCheck");
  1560. AssertSz(g_DebugFlags[nLoop].dfid < g_nDebugFlagCount,
  1561. "Invalid dfid (out of range) in CTracing::CorruptionCheck");
  1562. // Validate the shortname (verify not NULL or empty strings)
  1563. //
  1564. AssertSz(g_DebugFlags[nLoop].szShortName,
  1565. "Invalid debug flag short name (NULL) in CTracing::CorruptionCheck");
  1566. AssertSz(g_DebugFlags[nLoop].szShortName[0] != 0,
  1567. "Invalid debug flag short name (empty) in CTracing::CorruptionCheck");
  1568. // Validate the descriptions (verify not NULL or empty strings)
  1569. //
  1570. AssertSz(g_DebugFlags[nLoop].szDescription,
  1571. "Invalid debug flag description in CTracing::CorruptionCheck");
  1572. AssertSz(g_DebugFlags[nLoop].szDescription[0] != 0,
  1573. "Invalid debug flag description (empty) in CTracing::CorruptionCheck");
  1574. }
  1575. return;
  1576. }
  1577. //+---------------------------------------------------------------------------
  1578. //
  1579. // Member: CTracing::Trace
  1580. //
  1581. // Purpose: The actual trace call that takes care of doing the output
  1582. // to each trace target (file, OutputDebugString, etc.)
  1583. //
  1584. // Arguments:
  1585. // ttid [] The tracetag to use for output
  1586. // pszaTrace [] The trace string itself.
  1587. //
  1588. // Returns:
  1589. //
  1590. // Author: jeffspr 12 Apr 1997
  1591. //
  1592. // Notes:
  1593. //
  1594. VOID CTracing::Trace( TraceTagId ttid,
  1595. PCSTR pszaTrace )
  1596. {
  1597. // HrInit should have called a corruption checker for the entire trace
  1598. // block, but we'll check again just to make sure.
  1599. //
  1600. AssertSz(g_nTraceTagCount > ttid, "ttid out of range in CTracing::Trace");
  1601. AssertSz(g_TraceTags[ttid].ttid == ttid,
  1602. "TraceTag structure is corrupt in CTracing::Trace");
  1603. // If they want debug string output
  1604. //
  1605. if (g_TraceTags[ttid].fOutputDebugString)
  1606. {
  1607. // Then output the string
  1608. //
  1609. OutputDebugStringA(pszaTrace);
  1610. }
  1611. // If they want file output
  1612. if (g_TraceTags[ttid].fOutputToFile)
  1613. {
  1614. if (!m_hLogFile)
  1615. {
  1616. // Assuming that we haven't already tried to open the file
  1617. // and failed, open it.
  1618. if (!m_fAttemptedLogFileOpen)
  1619. {
  1620. HRESULT hr = HrOpenLogFile();
  1621. if (FAILED(hr))
  1622. {
  1623. AssertSz(FALSE, "Failed to open log file for tracing. No, "
  1624. "this isn't a coding error, but hey, figured that "
  1625. "you'd want to know...");
  1626. }
  1627. }
  1628. }
  1629. // If we were already open, or the open has now succeeded, do the
  1630. // trace
  1631. //
  1632. if (m_hLogFile)
  1633. {
  1634. Assert(pszaTrace);
  1635. // Since pszTrace is guaranteed to be a single-byte trace, we
  1636. // don't need to do the WCHAR multiply on the length, just
  1637. // a char multiply.
  1638. //
  1639. DWORD dwBytesToWrite = lstrlenA(pszaTrace) * sizeof(CHAR);
  1640. DWORD dwBytesWritten = 0;
  1641. BOOL fWriteResult = FALSE;
  1642. fWriteResult = WriteFile(
  1643. m_hLogFile, // handle to file to write to
  1644. pszaTrace, // pointer to data to write to file
  1645. dwBytesToWrite, // size of trace
  1646. &dwBytesWritten, // Bytes actually written.
  1647. NULL ); // No overlapped
  1648. if (!fWriteResult || (dwBytesToWrite != dwBytesWritten))
  1649. {
  1650. AssertSz(FALSE, "CTracing failure: Can't write to log file."
  1651. " Can't trace or we'll be recursing on this failure.");
  1652. }
  1653. }
  1654. }
  1655. }
  1656. HRESULT CTracing::HrOpenLogFile()
  1657. {
  1658. HRESULT hr = S_OK;
  1659. AssertSz(m_fInitialized,
  1660. "CTracing not initialized in HrOpenLogFile()");
  1661. AssertSz(!m_hLogFile,
  1662. "File already open before call to HrOpenLogFile()");
  1663. // Mark us as having attempted to open the file, so we don't call this
  1664. // function everytime we log, if we can't open it.
  1665. //
  1666. m_fAttemptedLogFileOpen = TRUE;
  1667. // $$TODO (jeffspr) - Allow flags in the Options section of the ini
  1668. // file specify the create flags and attributes, which would allow
  1669. // us to control the overwriting of log files and/or the write-through
  1670. // properties.
  1671. //
  1672. // Actually open the file, creating if necessary.
  1673. //
  1674. m_hLogFile = CreateFileA(
  1675. m_szLogFilePath, // Pointer to name of file
  1676. GENERIC_WRITE, // access (read-write) mode
  1677. FILE_SHARE_READ, // share mode (allow read access)
  1678. NULL, // pointer to security attributes
  1679. CREATE_ALWAYS, // how to create
  1680. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
  1681. NULL);
  1682. if (INVALID_HANDLE_VALUE == m_hLogFile)
  1683. {
  1684. m_hLogFile = NULL;
  1685. hr = HrFromLastWin32Error();
  1686. goto Exit;
  1687. }
  1688. Exit:
  1689. return hr;
  1690. }
  1691. using namespace std;
  1692. typedef deque<CTracingFuncCall> TRACING_FUNCTIONSTACK;
  1693. CTracingFuncCall::CTracingFuncCall(const CTracingFuncCall& TracingFuncCall)
  1694. {
  1695. Assert(g_csTracing);
  1696. m_szFunctionName = new CHAR[strlen(TracingFuncCall.m_szFunctionName)+1];
  1697. if (m_szFunctionName)
  1698. {
  1699. strcpy(m_szFunctionName, TracingFuncCall.m_szFunctionName);
  1700. }
  1701. else
  1702. {
  1703. m_szFunctionName = c_szLowMemory;
  1704. }
  1705. m_szFunctionDName = new CHAR[strlen(TracingFuncCall.m_szFunctionDName)+1];
  1706. if (m_szFunctionDName)
  1707. {
  1708. strcpy(m_szFunctionDName, TracingFuncCall.m_szFunctionDName);
  1709. }
  1710. else
  1711. {
  1712. m_szFunctionDName = c_szLowMemory;
  1713. }
  1714. m_szFile = new CHAR[strlen(TracingFuncCall.m_szFile)+1];
  1715. if (m_szFile)
  1716. {
  1717. strcpy(m_szFile, TracingFuncCall.m_szFile);
  1718. }
  1719. else
  1720. {
  1721. m_szFile = c_szLowMemory;
  1722. }
  1723. m_dwLine = TracingFuncCall.m_dwLine;
  1724. m_dwFramePointer = TracingFuncCall.m_dwFramePointer;
  1725. m_dwThreadId = TracingFuncCall.m_dwThreadId;
  1726. m_ReturnAddress = TracingFuncCall.m_ReturnAddress;
  1727. #if defined(_X86_) || defined(_AMD64_)
  1728. m_arguments[0] = TracingFuncCall.m_arguments[0];
  1729. m_arguments[1] = TracingFuncCall.m_arguments[1];
  1730. m_arguments[2] = TracingFuncCall.m_arguments[2];
  1731. #elif defined (_IA64_)
  1732. m_arguments[0] = TracingFuncCall.m_arguments[0];
  1733. m_arguments[1] = TracingFuncCall.m_arguments[1];
  1734. m_arguments[2] = TracingFuncCall.m_arguments[2];
  1735. #else
  1736. // add other processors here
  1737. #endif
  1738. }
  1739. #if defined (_X86_) || defined (_AMD64_)
  1740. CTracingFuncCall::CTracingFuncCall(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, DWORD_PTR dwpReturnAddress, const DWORD_PTR dwFramePointer)
  1741. #elif defined (_IA64_)
  1742. CTracingFuncCall::CTracingFuncCall(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, DWORD_PTR dwpReturnAddress, const __int64 Args1, const __int64 Args2, const __int64 Args3)
  1743. #else
  1744. CTracingFuncCall::CTracingFuncCall(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine)
  1745. #endif
  1746. {
  1747. Assert(g_csTracing);
  1748. m_szFunctionName = new CHAR[strlen(szFunctionName)+1];
  1749. if (m_szFunctionName)
  1750. {
  1751. strcpy(m_szFunctionName, szFunctionName);
  1752. }
  1753. else
  1754. {
  1755. m_szFunctionName = c_szLowMemory;
  1756. }
  1757. m_szFunctionDName = new CHAR[strlen(szFunctionDName)+1];
  1758. if (m_szFunctionDName)
  1759. {
  1760. strcpy(m_szFunctionDName, szFunctionDName);
  1761. }
  1762. else
  1763. {
  1764. m_szFunctionDName = c_szLowMemory;
  1765. }
  1766. m_szFile = new CHAR[strlen(szFile)+1];
  1767. if (m_szFile)
  1768. {
  1769. strcpy(m_szFile, szFile);
  1770. }
  1771. else
  1772. {
  1773. m_szFile = c_szLowMemory;
  1774. }
  1775. m_dwLine = dwLine;
  1776. m_ReturnAddress = dwpReturnAddress;
  1777. #if defined (_X86_) || defined (_AMD64_)
  1778. m_dwFramePointer = dwFramePointer;
  1779. if (dwFramePointer)
  1780. {
  1781. PDWORD_PTR pdwEbp = reinterpret_cast<PDWORD_PTR>(dwFramePointer);
  1782. pdwEbp++; // advance pass BaseEBP
  1783. pdwEbp++; // advance pass ReturnIP
  1784. m_arguments[0] = *pdwEbp; pdwEbp++;
  1785. m_arguments[1] = *pdwEbp; pdwEbp++;
  1786. m_arguments[2] = *pdwEbp;
  1787. }
  1788. else
  1789. {
  1790. m_arguments[0] = 0;
  1791. m_arguments[1] = 0;
  1792. m_arguments[2] = 0;
  1793. }
  1794. #elif defined (_IA64_)
  1795. m_dwFramePointer = 0;
  1796. m_arguments[0] = Args1;
  1797. m_arguments[1] = Args2;
  1798. m_arguments[2] = Args3;
  1799. #else
  1800. m_dwFramePointer = 0;
  1801. #endif
  1802. m_dwThreadId = GetCurrentThreadId();
  1803. }
  1804. CTracingFuncCall::~CTracingFuncCall()
  1805. {
  1806. Assert(g_csTracing);
  1807. if (c_szLowMemory != m_szFile)
  1808. {
  1809. delete[] m_szFile;
  1810. }
  1811. if (c_szLowMemory != m_szFunctionDName)
  1812. {
  1813. delete[] m_szFunctionDName;
  1814. }
  1815. if (c_szLowMemory != m_szFunctionName)
  1816. {
  1817. delete[] m_szFunctionName;
  1818. }
  1819. }
  1820. CTracingThreadInfo::CTracingThreadInfo()
  1821. {
  1822. Assert(g_csTracing);
  1823. m_dwLevel = 1;
  1824. m_dwThreadId = GetCurrentThreadId();
  1825. m_pfnStack = new TRACING_FUNCTIONSTACK;
  1826. }
  1827. CTracingThreadInfo::~CTracingThreadInfo()
  1828. {
  1829. Assert(g_csTracing);
  1830. TRACING_FUNCTIONSTACK *pfnStack = reinterpret_cast<TRACING_FUNCTIONSTACK *>(m_pfnStack);
  1831. delete pfnStack;
  1832. }
  1833. CTracingThreadInfo* CTracingIndent::GetThreadInfo()
  1834. {
  1835. CTracingThreadInfo *pThreadInfo = NULL;
  1836. AssertSz(g_dwTlsTracing, "Tracing not initialized... Did RawDllMain run?");
  1837. AssertSz(g_csTracing, "Tracing not initialized... Did RawDllMain run?");
  1838. pThreadInfo = reinterpret_cast<CTracingThreadInfo *>(TlsGetValue(g_dwTlsTracing));
  1839. if (!pThreadInfo)
  1840. {
  1841. pThreadInfo = new CTracingThreadInfo;
  1842. TlsSetValue(g_dwTlsTracing, pThreadInfo);
  1843. Assert(pThreadInfo == reinterpret_cast<CTracingThreadInfo *>(TlsGetValue(g_dwTlsTracing)));
  1844. }
  1845. Assert(pThreadInfo);
  1846. return pThreadInfo;
  1847. }
  1848. CTracingIndent::CTracingIndent()
  1849. {
  1850. bFirstTrace = TRUE;
  1851. m_szFunctionDName = NULL;
  1852. m_dwFramePointer = NULL;
  1853. }
  1854. #if defined (_X86_) || defined (_AMD64_)
  1855. void CTracingIndent::AddTrace(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, LPCVOID pReturnAddress, const DWORD_PTR dwFramePointer)
  1856. #elif defined (_IA64_)
  1857. void CTracingIndent::AddTrace(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine, LPCVOID pReturnAddress, const __int64 Args1, const __int64 Args2, const __int64 Args3)
  1858. #else
  1859. void CTracingIndent::AddTrace(LPCSTR szFunctionName, LPCSTR szFunctionDName, LPCSTR szFile, const DWORD dwLine)
  1860. #endif
  1861. {
  1862. Assert(szFunctionName);
  1863. Assert(szFunctionDName);
  1864. Assert(szFile);
  1865. if (!bFirstTrace)
  1866. {
  1867. #if defined (_X86_) || defined (_AMD64_)
  1868. RemoveTrace(szFunctionDName, dwFramePointer);
  1869. #elif defined (_IA64_)
  1870. RemoveTrace(szFunctionDName, 0);
  1871. #else
  1872. RemoveTrace(szFunctionDName, 0);
  1873. #endif
  1874. }
  1875. else
  1876. {
  1877. bFirstTrace = FALSE;
  1878. }
  1879. volatile CTracingThreadInfo *pThreadInfo = GetThreadInfo();
  1880. TRACING_FUNCTIONSTACK &fnStack = *reinterpret_cast<TRACING_FUNCTIONSTACK *>(pThreadInfo->m_pfnStack);
  1881. Assert(g_csTracing);
  1882. __try
  1883. {
  1884. EnterCriticalSection(g_csTracing);
  1885. #if defined (_X86_) || defined (_AMD64_)
  1886. CTracingFuncCall fnCall(szFunctionName, szFunctionDName, szFile, dwLine, reinterpret_cast<DWORD_PTR>(pReturnAddress), dwFramePointer);
  1887. #elif defined (_IA64_)
  1888. CTracingFuncCall fnCall(szFunctionName, szFunctionDName, szFile, dwLine, reinterpret_cast<DWORD_PTR>(pReturnAddress), Args1, Args2, Args3);
  1889. #else
  1890. CTracingFuncCall fnCall(szFunctionName, szFunctionDName, szFile, dwLine);
  1891. #endif
  1892. if (fnStack.size() == 0)
  1893. {
  1894. pThreadInfo->m_dwLevel++;
  1895. }
  1896. else
  1897. {
  1898. const CTracingFuncCall& fnTopOfStack = fnStack.front();
  1899. if ( (fnCall.m_dwFramePointer != fnTopOfStack.m_dwFramePointer) ||
  1900. strcmp(fnCall.m_szFunctionDName, fnTopOfStack.m_szFunctionDName))
  1901. {
  1902. pThreadInfo->m_dwLevel++;
  1903. }
  1904. }
  1905. m_szFunctionDName = new CHAR[strlen(fnCall.m_szFunctionDName)+1];
  1906. if (m_szFunctionDName)
  1907. {
  1908. strcpy(m_szFunctionDName, fnCall.m_szFunctionDName);
  1909. }
  1910. else
  1911. {
  1912. m_szFunctionDName = c_szLowMemory;
  1913. }
  1914. m_dwFramePointer = fnCall.m_dwFramePointer;
  1915. fnStack.push_front(fnCall);
  1916. }
  1917. __finally
  1918. {
  1919. LeaveCriticalSection(g_csTracing);
  1920. }
  1921. }
  1922. CTracingIndent::~CTracingIndent()
  1923. {
  1924. AssertSz(g_csTracing, "Tracing not initialized");
  1925. RemoveTrace(m_szFunctionDName, m_dwFramePointer);
  1926. }
  1927. void CTracingIndent::RemoveTrace(LPCSTR szFunctionDName, const DWORD dwFramePointer)
  1928. {
  1929. __try
  1930. {
  1931. EnterCriticalSection(g_csTracing);
  1932. volatile CTracingThreadInfo *pThreadInfo = GetThreadInfo();
  1933. TRACING_FUNCTIONSTACK &fnStack = *reinterpret_cast<TRACING_FUNCTIONSTACK *>(pThreadInfo->m_pfnStack);
  1934. Assert(szFunctionDName);
  1935. Assert(m_szFunctionDName);
  1936. Assert(g_csTracing);
  1937. if (
  1938. (fnStack.size() == 0)
  1939. ||
  1940. (
  1941. (
  1942. strcmp(m_szFunctionDName, szFunctionDName)
  1943. ||
  1944. strcmp(m_szFunctionDName, fnStack.front().m_szFunctionDName)
  1945. )
  1946. &&
  1947. (
  1948. (c_szLowMemory != m_szFunctionDName)
  1949. &&
  1950. (c_szLowMemory != fnStack.front().m_szFunctionDName)
  1951. &&
  1952. (c_szLowMemory != szFunctionDName)
  1953. )
  1954. )
  1955. ||
  1956. (m_dwFramePointer != fnStack.front().m_dwFramePointer)
  1957. ||
  1958. (dwFramePointer != m_dwFramePointer)
  1959. )
  1960. {
  1961. // Make sure to leave the critical section during the assert, so that it does not cause a deadlock.
  1962. LeaveCriticalSection(g_csTracing);
  1963. // This will trace the stack:
  1964. if (IsDebuggerPresent())
  1965. {
  1966. TraceTagFn(ttidError, "Tracing self-inconsistent - either a stack over/underwrite occurred or an exception was thrown in faulting stack:");
  1967. TraceStackFn(ttidError);
  1968. }
  1969. else
  1970. {
  1971. AssertSz(FALSE, "Tracing self-inconsistent - either a stack over/underwrite occurred or an exception was thrown.\r\nPlease attach a debugger and hit Ignore on this assert to spew info to the debugger (it will assert again).");
  1972. TraceTagFn(ttidError, "Tracing self-inconsistent - either a stack over/underwrite occurred or an exception was thrown in faulting stack:");
  1973. TraceStackFn(ttidError);
  1974. }
  1975. TraceTagFn(ttidError, "1) For complete stack info, .frame down to CTracingIndent__RemoveTrace, dv and find dwFramePointer (2nd parameter to CTracingIndent__RemoveTrace)");
  1976. TraceTagFn(ttidError, " Then do a kb=(value of dwFramePointer)");
  1977. TraceTagFn(ttidError, "2) For even more complete stack info, .frame down to CTracingIndent__RemoveTrace, dv and then dt -r on fnStack");
  1978. TraceTagFn(ttidError, " Then find the _Next, where m_szFunctionName == 'CTracingIndent::RemoveTrace'");
  1979. TraceTagFn(ttidError, " If it exists, find the value of m_dwFramePointer under _Next");
  1980. TraceTagFn(ttidError, " Then do a kb=(value of m_dwFramePointer)");
  1981. DebugBreak();
  1982. // Try to recover.
  1983. if (fnStack.size() > 0)
  1984. {
  1985. fnStack.pop_front();
  1986. }
  1987. EnterCriticalSection(g_csTracing);
  1988. }
  1989. else
  1990. {
  1991. DWORD dwOldFramePointer = fnStack.front().m_dwFramePointer;
  1992. fnStack.pop_front();
  1993. if ( (fnStack.size() == 0) ||
  1994. (dwOldFramePointer != fnStack.front().m_dwFramePointer) ||
  1995. strcmp(m_szFunctionDName, fnStack.front().m_szFunctionDName) )
  1996. {
  1997. pThreadInfo->m_dwLevel--;
  1998. Assert(pThreadInfo->m_dwLevel);
  1999. }
  2000. }
  2001. if (c_szLowMemory != m_szFunctionDName)
  2002. {
  2003. delete [] m_szFunctionDName;
  2004. }
  2005. }
  2006. __finally
  2007. {
  2008. LeaveCriticalSection(g_csTracing);
  2009. }
  2010. }
  2011. DWORD CTracingIndent::getspaces()
  2012. {
  2013. volatile CTracingThreadInfo *pThreadInfo = GetThreadInfo();
  2014. return pThreadInfo->m_dwLevel;
  2015. }
  2016. void CTracingIndent::TraceStackFn(TRACETAGID TraceTagId)
  2017. {
  2018. if (!g_TraceTags[TraceTagId].fOutputDebugString &&
  2019. !g_TraceTags[TraceTagId].fOutputToFile)
  2020. {
  2021. return;
  2022. }
  2023. volatile CTracingThreadInfo *pThreadInfo = GetThreadInfo();
  2024. TRACING_FUNCTIONSTACK &fnStack = *reinterpret_cast<TRACING_FUNCTIONSTACK *>(pThreadInfo->m_pfnStack);
  2025. Assert(g_csTracing);
  2026. __try
  2027. {
  2028. EnterCriticalSection(g_csTracing);
  2029. if (fnStack.size() == 0)
  2030. {
  2031. return;
  2032. }
  2033. #if defined (_X86_) || defined (_AMD64_)
  2034. TraceInternal(TraceTagId, NULL, 0, 0, "ChildEBP RetAddr Args to Child (reconstructed - ChildEBP is invalid now)", 0, FALSE);
  2035. #elif defined (_IA64_)
  2036. TraceInternal(TraceTagId, NULL, 0, 0, "RetAddr Args to Child (reconstructed - ChildEBP is invalid now)", 0, FALSE);
  2037. #else
  2038. TraceInternal(TraceTagId, NULL, 0, 0, "Function stack", 0, FALSE);
  2039. #endif
  2040. for (TRACING_FUNCTIONSTACK::const_iterator i = fnStack.begin(); i != fnStack.end(); i++)
  2041. {
  2042. CHAR szBuffer[MAX_TRACE_LEN];
  2043. #if defined (_X86_) || defined (_AMD64_)
  2044. _snprintf(szBuffer, MAX_TRACE_LEN, "%08x %08x %08x %08x %08x %s [%s @ %d]", i->m_dwFramePointer, i->m_ReturnAddress, i->m_arguments[0], i->m_arguments[1], i->m_arguments[2], i->m_szFunctionName, i->m_szFile, i->m_dwLine);
  2045. #elif defined (_IA64_)
  2046. _snprintf(szBuffer, MAX_TRACE_LEN, "%016I64x %016I64x 0x%016I64x 0x%016I64x %s [%s @ %d]", i->m_ReturnAddress, i->m_arguments[0], i->m_arguments[1], i->m_arguments[2], i->m_szFunctionName, i->m_szFile, i->m_dwLine);
  2047. #else
  2048. _snprintf(szBuffer, MAX_TRACE_LEN, "%s", i->m_szFunctionName);
  2049. #endif
  2050. TraceInternal (TraceTagId, NULL, 0, 0, szBuffer, 0, FALSE);
  2051. }
  2052. }
  2053. __finally
  2054. {
  2055. LeaveCriticalSection(g_csTracing);
  2056. }
  2057. }
  2058. void CTracingIndent::TraceStackFn(IN OUT LPSTR szString, IN OUT LPDWORD pdwSize)
  2059. {
  2060. volatile CTracingThreadInfo *pThreadInfo = GetThreadInfo();
  2061. TRACING_FUNCTIONSTACK &fnStack = *reinterpret_cast<TRACING_FUNCTIONSTACK *>(pThreadInfo->m_pfnStack);
  2062. Assert(g_csTracing);
  2063. __try
  2064. {
  2065. EnterCriticalSection(g_csTracing);
  2066. ZeroMemory(szString, *pdwSize);
  2067. if (fnStack.size() == 0)
  2068. {
  2069. return;
  2070. }
  2071. Assert(*pdwSize > MAX_TRACE_LEN);
  2072. LPSTR pszString = szString;
  2073. #if defined (_X86_) || defined (_AMD64_)
  2074. pszString += _snprintf(pszString, MAX_TRACE_LEN, " ChildEBP RetAddr Args to Child (reconstructed - ChildEBP is invalid now)\r\n");
  2075. #elif defined (_IA64_)
  2076. pszString += _snprintf(pszString, MAX_TRACE_LEN, " RetAddr Args to Child (reconstructed - ChildEBP is invalid now)\r\n");
  2077. #else
  2078. pszString += _snprintf(pszString, MAX_TRACE_LEN, " Function stack\r\n");
  2079. #endif
  2080. DWORD dwSizeIn = *pdwSize;
  2081. for (TRACING_FUNCTIONSTACK::const_iterator i = fnStack.begin(); i != fnStack.end(); i++)
  2082. {
  2083. CHAR szBuffer[1024];
  2084. #if defined (_X86_) || defined (_AMD64_)
  2085. _snprintf(szBuffer, MAX_TRACE_LEN, " %08x %08x %08x %08x %08x %s [%s @ %d]", i->m_dwFramePointer, i->m_ReturnAddress, i->m_arguments[0], i->m_arguments[1], i->m_arguments[2], i->m_szFunctionName, i->m_szFile, i->m_dwLine);
  2086. #elif defined (_IA64_)
  2087. _snprintf(szBuffer, MAX_TRACE_LEN, " %016I64x %016I64x 0x%016I64x 0x%016I64x %s [%s @ %d]", i->m_ReturnAddress, i->m_arguments[0], i->m_arguments[1], i->m_arguments[2], i->m_szFunctionName, i->m_szFile, i->m_dwLine);
  2088. #else
  2089. _snprintf(szBuffer, MAX_TRACE_LEN, " %s", i->m_szFunctionName);
  2090. #endif
  2091. pszString += _snprintf(pszString, MAX_TRACE_LEN, "%s\r\n", szBuffer);
  2092. if (pszString > (szString + (*pdwSize - celems(szBuffer))) ) // Can't use strlen since I need to know the length of the
  2093. // next element - not this one. Hence just take the maximum size.
  2094. {
  2095. pszString += _snprintf(pszString, MAX_TRACE_LEN, "...", szBuffer);
  2096. *pdwSize = dwSizeIn * 2; // Tell the caller to allocate more memory and call us back if they want more info.
  2097. break;
  2098. }
  2099. }
  2100. if (*pdwSize < dwSizeIn)
  2101. {
  2102. *pdwSize = pszString - szString;
  2103. }
  2104. }
  2105. __finally
  2106. {
  2107. LeaveCriticalSection(g_csTracing);
  2108. }
  2109. }
  2110. VOID
  2111. WINAPIV
  2112. TraceFileFuncFn (TRACETAGID ttid)
  2113. {
  2114. if (FIsDebugFlagSet (dfidTraceFileFunc))
  2115. {
  2116. CHAR szBuffer[MAX_TRACE_LEN];
  2117. volatile CTracingThreadInfo *pThreadInfo = CTracingIndent::GetThreadInfo();
  2118. TRACING_FUNCTIONSTACK &fnStack = *reinterpret_cast<TRACING_FUNCTIONSTACK *>(pThreadInfo->m_pfnStack);
  2119. Assert(g_csTracing);
  2120. __try
  2121. {
  2122. EnterCriticalSection(g_csTracing);
  2123. const CTracingFuncCall& fnCall = fnStack.front();
  2124. if (fnStack.size() != 0)
  2125. {
  2126. if (FIsDebugFlagSet (dfidTraceSource))
  2127. {
  2128. #if defined (_X86_) || defined (_AMD64_)
  2129. _snprintf(szBuffer, MAX_TRACE_LEN, "%s [0x%08x 0x%08x 0x%08x] %s:%d", fnCall.m_szFunctionName, fnCall.m_arguments[0], fnCall.m_arguments[1], fnCall.m_arguments[2], fnCall.m_szFile, fnCall.m_dwLine);
  2130. #elif defined (_IA64_)
  2131. _snprintf(szBuffer, MAX_TRACE_LEN, "%s [0x%016I64x 0x%016I64x 0x%016I64x] %s:%d", fnCall.m_szFunctionName, fnCall.m_arguments[0], fnCall.m_arguments[1], fnCall.m_arguments[2], fnCall.m_szFile, fnCall.m_dwLine);
  2132. #else
  2133. _snprintf(szBuffer, MAX_TRACE_LEN, "%s %s:%d", fnCall.m_szFunctionName, fnCall.m_szFile, fnCall.m_dwLine);
  2134. #endif
  2135. }
  2136. else
  2137. {
  2138. #if defined (_X86_) || defined (_AMD64_)
  2139. _snprintf(szBuffer, MAX_TRACE_LEN, "%s [0x%08x 0x%08x 0x%08x]", fnCall.m_szFunctionName, fnCall.m_arguments[0], fnCall.m_arguments[1], fnCall.m_arguments[2]);
  2140. #elif defined (_IA64_)
  2141. _snprintf(szBuffer, MAX_TRACE_LEN, "%s [0x%016I64x 0x%016I64x 0x%016I64x]", fnCall.m_szFunctionName, fnCall.m_arguments[0], fnCall.m_arguments[1], fnCall.m_arguments[2]);
  2142. #else
  2143. _snprintf(szBuffer, MAX_TRACE_LEN, "%s", fnCall.m_szFunctionName);
  2144. #endif
  2145. }
  2146. TraceTagFn(ttid, szBuffer);
  2147. }
  2148. else
  2149. {
  2150. AssertSz(FALSE, "Trace failure");
  2151. }
  2152. }
  2153. __finally
  2154. {
  2155. LeaveCriticalSection(g_csTracing);
  2156. }
  2157. }
  2158. }
  2159. LPCSTR DBG_EMNAMES[] =
  2160. {
  2161. "INVALID_EVENTMGR",
  2162. "EVENTMGR_CONMAN",
  2163. "EVENTMGR_EAPOLMAN"
  2164. };
  2165. LPCSTR DBG_CMENAMES[] =
  2166. {
  2167. "INVALID_TYPE",
  2168. "CONNECTION_ADDED",
  2169. "CONNECTION_BANDWIDTH_CHANGE",
  2170. "CONNECTION_DELETED",
  2171. "CONNECTION_MODIFIED",
  2172. "CONNECTION_RENAMED",
  2173. "CONNECTION_STATUS_CHANGE",
  2174. "REFRESH_ALL",
  2175. "CONNECTION_ADDRESS_CHANGE"
  2176. };
  2177. LPCSTR DBG_NCMNAMES[] =
  2178. {
  2179. "NCM_NONE",
  2180. "NCM_DIRECT",
  2181. "NCM_ISDN",
  2182. "NCM_LAN",
  2183. "NCM_PHONE",
  2184. "NCM_TUNNEL",
  2185. "NCM_PPPOE",
  2186. "NCM_BRIDGE",
  2187. "NCM_SHAREDACCESSHOST_LAN",
  2188. "NCM_SHAREDACCESSHOST_RAS"
  2189. };
  2190. LPCSTR DBG_NCSMNAMES[] =
  2191. {
  2192. "NCSM_NONE",
  2193. "NCSM_LAN",
  2194. "NCSM_WIRELESS",
  2195. "NCSM_ATM",
  2196. "NCSM_ELAN",
  2197. "NCSM_1394",
  2198. "NCSM_DIRECT",
  2199. "NCSM_IRDA",
  2200. "NCSM_CM",
  2201. };
  2202. LPCSTR DBG_NCSNAMES[] =
  2203. {
  2204. "NCS_DISCONNECTED",
  2205. "NCS_CONNECTING",
  2206. "NCS_CONNECTED",
  2207. "NCS_DISCONNECTING",
  2208. "NCS_HARDWARE_NOT_PRESENT",
  2209. "NCS_HARDWARE_DISABLED",
  2210. "NCS_HARDWARE_MALFUNCTION",
  2211. "NCS_MEDIA_DISCONNECTED",
  2212. "NCS_AUTHENTICATING",
  2213. "NCS_AUTHENTICATION_SUCCEEDED",
  2214. "NCS_AUTHENTICATION_FAILED",
  2215. "NCS_INVALID_ADDRESS",
  2216. "NCS_CREDENTIALS_REQUIRED"
  2217. };
  2218. // Shorten these to fit more in.
  2219. LPCSTR DBG_NCCSFLAGS[] =
  2220. {
  2221. "_NONE",
  2222. "_ALL_USERS",
  2223. "_ALLOW_DUPLICATION",
  2224. "_ALLOW_REMOVAL",
  2225. "_ALLOW_RENAME",
  2226. "_SHOW_ICON",
  2227. "_INCOMING_ONLY",
  2228. "_OUTGOING_ONLY",
  2229. "_BRANDED",
  2230. "_SHARED",
  2231. "_BRIDGED",
  2232. "_FIREWALLED",
  2233. "_DEFAULT"
  2234. };
  2235. LPCSTR DbgEvents(DWORD Event)
  2236. {
  2237. if (Event < celems(DBG_CMENAMES))
  2238. {
  2239. return DBG_CMENAMES[Event];
  2240. }
  2241. else
  2242. {
  2243. return "UNKNOWN Event: Update DBG_CMENAMES table.";
  2244. }
  2245. }
  2246. LPCSTR DbgEventManager(DWORD EventManager)
  2247. {
  2248. if (EventManager < celems(DBG_EMNAMES))
  2249. {
  2250. return DBG_EMNAMES[EventManager];
  2251. }
  2252. else
  2253. {
  2254. return "UNKNOWN Event: Update DBG_EMNAMES table.";
  2255. }
  2256. }
  2257. LPCSTR DbgNcm(DWORD ncm)
  2258. {
  2259. if (ncm < celems(DBG_NCMNAMES))
  2260. {
  2261. return DBG_NCMNAMES[ncm];
  2262. }
  2263. else
  2264. {
  2265. return "UNKNOWN NCM: Update DBG_NCMNAMES table.";
  2266. }
  2267. }
  2268. LPCSTR DbgNcsm(DWORD ncsm)
  2269. {
  2270. if (ncsm < celems(DBG_NCSMNAMES))
  2271. {
  2272. return DBG_NCSMNAMES[ncsm];
  2273. }
  2274. else
  2275. {
  2276. return "UNKNOWN NCM: Update DBG_NCSMNAMES table.";
  2277. }
  2278. }
  2279. LPCSTR DbgNcs(DWORD ncs)
  2280. {
  2281. if (ncs < celems(DBG_NCSNAMES))
  2282. {
  2283. return DBG_NCSNAMES[ncs];
  2284. }
  2285. else
  2286. {
  2287. return "UNKNOWN NCS: Update DBG_NCSNAMES table.";
  2288. }
  2289. }
  2290. LPCSTR DbgNccf(DWORD nccf)
  2291. {
  2292. static CHAR szName[MAX_PATH];
  2293. if (nccf >= (1 << celems(DBG_NCCSFLAGS)) )
  2294. {
  2295. return "UNKNOWN NCCF: Update DBG_NCCSFLAGS table.";
  2296. }
  2297. if (0 == nccf)
  2298. {
  2299. strcpy(szName, DBG_NCCSFLAGS[0]);
  2300. }
  2301. else
  2302. {
  2303. szName[0] = '\0';
  2304. LPSTR szTemp = szName;
  2305. BOOL bFirst = TRUE;
  2306. for (DWORD x = 0; x < celems(DBG_NCCSFLAGS); x++)
  2307. {
  2308. if (nccf & (1 << x))
  2309. {
  2310. if (!bFirst)
  2311. {
  2312. szTemp += _snprintf(szTemp, MAX_TRACE_LEN, "+");
  2313. }
  2314. else
  2315. {
  2316. szTemp += _snprintf(szTemp, MAX_TRACE_LEN, "NCCF:");
  2317. }
  2318. bFirst = FALSE;
  2319. szTemp += _snprintf(szTemp, MAX_TRACE_LEN, "%s", DBG_NCCSFLAGS[x+1]);
  2320. }
  2321. }
  2322. }
  2323. return szName;
  2324. }
  2325. #ifdef ENABLELEAKDETECTION
  2326. CObjectLeakTrack *g_pObjectLeakTrack = NULL;
  2327. // First LPSTR is classname
  2328. // Second LPSTR is stack trace
  2329. typedef pair<LPSTR, LPSTR> MAPOBJLEAKPAIR;
  2330. typedef map<LPCVOID, MAPOBJLEAKPAIR> MAPOBJLEAK;
  2331. //+---------------------------------------------------------------------------
  2332. //
  2333. // Member: CObjectLeakTrack::CObjectLeakTrack
  2334. //
  2335. // Purpose: Constructor
  2336. //
  2337. // Arguments:
  2338. //
  2339. // Returns:
  2340. //
  2341. // Author: deonb 7 July 2001
  2342. //
  2343. // Notes: We are allocating our g_mapObjLeak here
  2344. //
  2345. CObjectLeakTrack::CObjectLeakTrack()
  2346. {
  2347. Assert(FIsDebugFlagSet(dfidTrackObjectLeaks));
  2348. g_mapObjLeak = new MAPOBJLEAK;
  2349. }
  2350. //+---------------------------------------------------------------------------
  2351. //
  2352. // Member: CObjectLeakTrack::CObjectLeakTrack
  2353. //
  2354. // Purpose: Destructor
  2355. //
  2356. // Arguments:
  2357. //
  2358. // Returns: none
  2359. //
  2360. // Author: deonb 7 July 2001
  2361. //
  2362. // Notes: We are deleting our g_mapObjLeak here. We have to typecast it
  2363. // first since the data types exported by trace.h to the world is
  2364. // LPVOID, to minimize dependencies in order to include tracing.
  2365. //
  2366. CObjectLeakTrack::~CObjectLeakTrack()
  2367. {
  2368. Assert(FIsDebugFlagSet(dfidTrackObjectLeaks));
  2369. delete reinterpret_cast<MAPOBJLEAK *>(g_mapObjLeak);
  2370. }
  2371. //+---------------------------------------------------------------------------
  2372. //
  2373. // Member: CObjectLeakTrack::Insert
  2374. //
  2375. // Purpose: Insert an object instance in the list
  2376. //
  2377. // Arguments: [in] pThis - This pointer of the object instance. This must
  2378. // be the same as the this pointer of the ::Remove
  2379. // [in] szdbgClassName - The classname of the object
  2380. // [in own] pszConstructionStack - The stacktrace of the object constructor.
  2381. // (or any other information that is useful to describe
  2382. // the origin of the object).
  2383. // This must be allocated with the global new operator
  2384. // since we will take ownership and free this
  2385. // Returns: none
  2386. //
  2387. // Author: deonb 7 July 2001
  2388. //
  2389. // Notes:
  2390. //
  2391. void CObjectLeakTrack::Insert(IN LPCVOID pThis, IN LPCSTR szdbgClassName, IN TAKEOWNERSHIP LPSTR pszConstructionStack)
  2392. {
  2393. Assert(FIsDebugFlagSet(dfidTrackObjectLeaks));
  2394. if (g_mapObjLeak)
  2395. {
  2396. MAPOBJLEAK &rmapObjLeak = *reinterpret_cast<MAPOBJLEAK *>(g_mapObjLeak);
  2397. LPSTR szdbgClassNameCopy = NULL;
  2398. if (szdbgClassName)
  2399. {
  2400. // We have to take a copy of the classname here. This is a bit cointerintuitive, but typeid(T).name() actually calls
  2401. // into _UnDName to undecorate the name, and this points to an inner static - not directly to a location in
  2402. // our binary containing the class name.
  2403. szdbgClassNameCopy = new CHAR[strlen(szdbgClassName) + 1];
  2404. if (szdbgClassNameCopy)
  2405. {
  2406. strcpy(szdbgClassNameCopy, szdbgClassName);
  2407. }
  2408. }
  2409. rmapObjLeak[pThis] = MAPOBJLEAKPAIR(szdbgClassNameCopy, pszConstructionStack);
  2410. }
  2411. }
  2412. //+---------------------------------------------------------------------------
  2413. //
  2414. // Member: CObjectLeakTrack::Remove
  2415. //
  2416. // Purpose: Remove an object instance from the list
  2417. //
  2418. // Arguments: [in] pThis - This pointer of the object instance. This must
  2419. // be the same as the this pointer of the ::Insert
  2420. //
  2421. // Returns:
  2422. //
  2423. // Author: deonb 7 July 2001
  2424. //
  2425. // Notes:
  2426. //
  2427. void CObjectLeakTrack::Remove(IN LPCVOID pThis)
  2428. {
  2429. Assert(FIsDebugFlagSet(dfidTrackObjectLeaks));
  2430. if (g_mapObjLeak)
  2431. {
  2432. MAPOBJLEAK &rmapObjLeak = *reinterpret_cast<MAPOBJLEAK *>(g_mapObjLeak);
  2433. MAPOBJLEAK::iterator iter = rmapObjLeak.find(pThis);
  2434. if (iter != rmapObjLeak.end())
  2435. {
  2436. delete [] iter->second.first; // The class name
  2437. iter->second.first = NULL;
  2438. delete [] iter->second.second; // The stack trace
  2439. iter->second.second = NULL;
  2440. rmapObjLeak.erase(iter);
  2441. }
  2442. }
  2443. }
  2444. void RemoveKnownleakFn(LPCVOID pThis)
  2445. {
  2446. if (FIsDebugFlagSet(dfidTrackObjectLeaks) && g_pObjectLeakTrack)
  2447. {
  2448. __try
  2449. {
  2450. EnterCriticalSection(g_csTracing);
  2451. TraceTag(ttidAllocations, "An object at '0x%08x' was marked as a known leak", pThis);
  2452. g_pObjectLeakTrack->Remove(pThis);
  2453. }
  2454. __finally
  2455. {
  2456. LeaveCriticalSection(g_csTracing);
  2457. }
  2458. }
  2459. }
  2460. //+---------------------------------------------------------------------------
  2461. //
  2462. // Member: CObjectLeakTrack::AssertIfObjectsStillAllocated
  2463. //
  2464. // Purpose: Assert if the the list of allocated objects in the process is not NULL.
  2465. // and call DumpAllocatedObjects to dump out this list.
  2466. //
  2467. // Arguments: [in] szClassName. The classname of the objects to assert that there are nothing of.
  2468. // This classname can be obtained by calling typeid(CLASS).name()
  2469. // on your class. (E.g. typeid(CConnectionManager).name() )
  2470. //
  2471. // Can also be NULL to ensure that there are NO objects allocated
  2472. // Returns: none
  2473. //
  2474. // Author: deonb 7 July 2001
  2475. //
  2476. // Notes: Don't call this from outside tracing - rather call AssertNoAllocatedInstances
  2477. // which is safe to call in CHK and FRE.
  2478. BOOL CObjectLeakTrack::AssertIfObjectsStillAllocated(IN LPCSTR szClassName)
  2479. {
  2480. if (!FIsDebugFlagSet(dfidTrackObjectLeaks))
  2481. {
  2482. return FALSE;
  2483. }
  2484. if (g_mapObjLeak)
  2485. {
  2486. __try
  2487. {
  2488. EnterCriticalSection(g_csTracing);
  2489. MAPOBJLEAK &rmapObjLeak = *reinterpret_cast<MAPOBJLEAK *>(g_mapObjLeak);
  2490. BOOL fFoundObjectOfType = FALSE;
  2491. for (MAPOBJLEAK::const_iterator iter = rmapObjLeak.begin(); iter != rmapObjLeak.end(); iter++)
  2492. {
  2493. if (szClassName)
  2494. {
  2495. if (0 == strcmp(iter->second.first, szClassName) )
  2496. {
  2497. fFoundObjectOfType = TRUE;
  2498. break;
  2499. }
  2500. }
  2501. else
  2502. {
  2503. fFoundObjectOfType = TRUE;
  2504. break;
  2505. }
  2506. }
  2507. if (fFoundObjectOfType)
  2508. {
  2509. AssertSz(FALSE, "An object leak has been detected. Please attach a user or kernel mode debugger and hit IGNORE to dump the offending stacks");
  2510. DumpAllocatedObjects(ttidError, szClassName);
  2511. return TRUE;
  2512. }
  2513. }
  2514. __finally
  2515. {
  2516. LeaveCriticalSection(g_csTracing);
  2517. }
  2518. }
  2519. return FALSE;
  2520. }
  2521. //+---------------------------------------------------------------------------
  2522. //
  2523. // Member: CObjectLeakTrack::DumpAllocatedObjects
  2524. //
  2525. // Purpose: Dump the list of the objects and their construction stacks
  2526. // for the objects that were allocated but not deleted yet. Dumps
  2527. // to the debugger.
  2528. //
  2529. // Arguments: [in] TraceTagId. The TraceTag to trace it to.
  2530. // [in] szClassName. The classname of the objects to dump out.
  2531. // This classname can be obtained by calling typeid(CLASS).name()
  2532. // on your class. (E.g. typeid(CConnectionManager).name() )
  2533. //
  2534. // Can also be NULL to dump out objects of ALL types.
  2535. //
  2536. // Returns: none
  2537. //
  2538. // Author: deonb 7 July 2001
  2539. //
  2540. // Notes: Don't call this from outside - rather call TraceAllocatedObjects
  2541. // which is safe to call in CHK and FRE.
  2542. //
  2543. void CObjectLeakTrack::DumpAllocatedObjects(IN TRACETAGID TraceTagId, IN LPCSTR szClassName)
  2544. {
  2545. if (!FIsDebugFlagSet(dfidTrackObjectLeaks))
  2546. {
  2547. return;
  2548. }
  2549. if (g_mapObjLeak)
  2550. {
  2551. __try
  2552. {
  2553. EnterCriticalSection(g_csTracing);
  2554. MAPOBJLEAK &rmapObjLeak = *reinterpret_cast<MAPOBJLEAK *>(g_mapObjLeak);
  2555. for (MAPOBJLEAK::const_iterator iter = rmapObjLeak.begin(); iter != rmapObjLeak.end(); iter++)
  2556. {
  2557. BOOL fMustSpew = TRUE;
  2558. if (szClassName)
  2559. {
  2560. if (0 != strcmp(iter->second.first, szClassName) )
  2561. {
  2562. fMustSpew = FALSE;
  2563. }
  2564. }
  2565. if (fMustSpew)
  2566. {
  2567. TraceTag(TraceTagId, "The object of type '%s' allocated at 0x%08x has not been freed:",
  2568. iter->second.first, iter->first);
  2569. if (*iter->second.second)
  2570. {
  2571. TraceTag (TraceTagId, "Callstack below:\r\n%s", iter->second.second);
  2572. }
  2573. else
  2574. {
  2575. TraceTag(TraceTagId, " <call stack information not available. See comments inside trace.h on how to increase call stack information>.");
  2576. }
  2577. }
  2578. }
  2579. }
  2580. __finally
  2581. {
  2582. LeaveCriticalSection(g_csTracing);
  2583. }
  2584. }
  2585. }
  2586. #endif // ENABLELEAKDETECTION
  2587. #endif // ENABLETRACE