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.

821 lines
24 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1999
  5. //
  6. // File: mmctrace.cpp
  7. //
  8. // Contents: Implementation of the debug trace code
  9. //
  10. // History: 15-Jul-99 VivekJ Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "stdafx.h"
  14. #include <imagehlp.h>
  15. #include "util.h"
  16. //--------------------------------------------------------------------------
  17. #ifdef DBG
  18. //--------------------------------------------------------------------------
  19. // a few global traces
  20. CTraceTag tagError (TEXT("Trace"), TEXT("Error"), TRACE_OUTPUTDEBUGSTRING);
  21. CTraceTag tagDirtyFlag (TEXT("Persistence"), TEXT("MMC Dirty Flags"));
  22. CTraceTag tagPersistError (TEXT("Persistence"), TEXT("Snapin Dirty Flags"));
  23. CTraceTag tagCoreLegacy (TEXT("LEGACY mmccore.lib"), TEXT("TRACE (legacy, mmccore.lib)"));
  24. CTraceTag tagConUILegacy (TEXT("LEGACY mmc.exe"), TEXT("TRACE (legacy, mmc.exe)"));
  25. CTraceTag tagNodemgrLegacy(TEXT("LEGACY mmcndmgr.dll"),TEXT("TRACE (legacy, mmcndmgr.dll)"));
  26. CTraceTag tagSnapinError (TEXT("Snapin Error"), TEXT("Snapin Error"), TRACE_OUTPUTDEBUGSTRING);
  27. // szTraceIniFile must be a sz, so it exists before "{" of WinMain.
  28. // if we make it a CStr, it may not be constructed when some of the
  29. // tags are constructed, so we won't restore their value.
  30. LPCTSTR const szTraceIniFile = TEXT("MMCTrace.INI");
  31. //############################################################################
  32. //############################################################################
  33. //
  34. // Implementation of global Trace functions
  35. //
  36. //############################################################################
  37. //############################################################################
  38. /*+-------------------------------------------------------------------------*
  39. *
  40. * Trace
  41. *
  42. * PURPOSE: Maps the Trace statement to the proper method call.
  43. * This is needed (instead of doing directly ptag->Trace())
  44. * to garantee that no code is added in the ship build.
  45. *
  46. * PARAMETERS:
  47. * CTraceTag & tag : the tag controlling the debug output
  48. * LPCTSTR szFormat : printf style formatting string
  49. * ... : printf style parameters, depends on szFormat
  50. *
  51. * RETURNS:
  52. * void
  53. *
  54. *+-------------------------------------------------------------------------*/
  55. void
  56. Trace( const CTraceTag & tag, LPCTSTR szFormat, ... )
  57. {
  58. va_list marker;
  59. va_start(marker, szFormat);
  60. tag.TraceFn(szFormat, marker);
  61. va_end(marker);
  62. }
  63. /*+-------------------------------------------------------------------------*
  64. *
  65. * TraceDirtyFlag
  66. *
  67. * PURPOSE: Used to trace into the objects that cause MMC to be in a dirty
  68. * state, requiring a save.
  69. *
  70. * PARAMETERS:
  71. * LPCTSTR szComponent : The class name
  72. * bool bDirty : whether or not the object is dirty.
  73. *
  74. * RETURNS:
  75. * void
  76. *
  77. *+-------------------------------------------------------------------------*/
  78. void
  79. TraceDirtyFlag (LPCTSTR szComponent, bool bDirty)
  80. {
  81. Trace(tagDirtyFlag, TEXT("%s : %s"), szComponent, bDirty ? TEXT("true") : TEXT("false"));
  82. }
  83. void
  84. TraceBaseLegacy (LPCTSTR szFormat, ... )
  85. {
  86. va_list marker;
  87. va_start(marker, szFormat);
  88. tagCoreLegacy.TraceFn(szFormat, marker);
  89. va_end(marker);
  90. }
  91. void
  92. TraceConuiLegacy (LPCTSTR szFormat, ... )
  93. {
  94. va_list marker;
  95. va_start(marker, szFormat);
  96. tagConUILegacy.TraceFn(szFormat, marker);
  97. va_end(marker);
  98. }
  99. void
  100. TraceNodeMgrLegacy(LPCTSTR szFormat, ... )
  101. {
  102. va_list marker;
  103. va_start(marker, szFormat);
  104. tagNodemgrLegacy.TraceFn(szFormat, marker);
  105. va_end(marker);
  106. }
  107. /*+-------------------------------------------------------------------------*
  108. *
  109. * TraceError
  110. *
  111. * PURPOSE: Used to send error traces.
  112. *
  113. * PARAMETERS:
  114. * LPCTSTR szModuleName : The module in which the error occurred.
  115. * SC sc : The error.
  116. *
  117. * RETURNS:
  118. * void
  119. *
  120. *+-------------------------------------------------------------------------*/
  121. void
  122. TraceError(LPCTSTR szModuleName, const SC& sc)
  123. {
  124. TCHAR szTemp[256];
  125. sc.GetErrorMessage (countof(szTemp), szTemp);
  126. StripTrailingWhitespace (szTemp);
  127. Trace(tagError, TEXT("Module %s, SC = 0x%08X = %d\r\n = \"%s\""),
  128. szModuleName, sc.GetCode(), LOWORD(sc.GetCode()), szTemp);
  129. }
  130. /*+-------------------------------------------------------------------------*
  131. *
  132. * TraceErrorMsg
  133. *
  134. * PURPOSE: Used to send formatted error traces. This is not SC-based, but
  135. * it does use tagError as its controlling trace tag.
  136. *
  137. * PARAMETERS:
  138. * LPCTSTR szErrorMsg : Error message to display.
  139. *
  140. * RETURNS:
  141. * void
  142. *
  143. *+-------------------------------------------------------------------------*/
  144. void
  145. TraceErrorMsg(LPCTSTR szFormat, ...)
  146. {
  147. va_list marker;
  148. va_start(marker, szFormat);
  149. tagError.TraceFn(szFormat, marker);
  150. va_end(marker);
  151. }
  152. /*+-------------------------------------------------------------------------*
  153. *
  154. * TraceSnapinError
  155. *
  156. * PURPOSE: Used to send snapin error traces. The method should use
  157. * DECLARE_SC so that we can get the method name from sc.
  158. *
  159. *
  160. * PARAMETERS:
  161. * LPCTSTR szError : Additional error message.
  162. * SC sc :
  163. *
  164. * RETURNS:
  165. * void
  166. *
  167. *+-------------------------------------------------------------------------*/
  168. void
  169. TraceSnapinError(LPCTSTR szError, const SC& sc)
  170. {
  171. TCHAR szTemp[256];
  172. sc.GetErrorMessage (countof(szTemp), szTemp);
  173. StripTrailingWhitespace (szTemp);
  174. Trace(tagSnapinError, TEXT("Snapin %s encountered in %s error %s, hr = 0x%08X\r\n = \"%s\""),
  175. sc.GetSnapinName(), sc.GetFunctionName(), szError, sc.ToHr(), szTemp);
  176. }
  177. /*+-------------------------------------------------------------------------*
  178. *
  179. * TraceSnapinPersistenceError
  180. *
  181. * PURPOSE: outputs traces for persistence and snapin error tags
  182. *
  183. * PARAMETERS:
  184. * LPCTSTR szError : Error message.
  185. *
  186. * RETURNS:
  187. * void
  188. *
  189. *+-------------------------------------------------------------------------*/
  190. void
  191. TraceSnapinPersistenceError(LPCTSTR szError)
  192. {
  193. Trace(tagSnapinError, szError);
  194. Trace(tagPersistError, szError);
  195. }
  196. //############################################################################
  197. //############################################################################
  198. //
  199. // Implementation of class CTraceTags
  200. //
  201. //############################################################################
  202. //############################################################################
  203. CTraceTags * GetTraceTags()
  204. {
  205. static CTraceTags s_traceTags;
  206. return &s_traceTags;
  207. }
  208. //############################################################################
  209. //############################################################################
  210. //
  211. // Implementation of class CTraceTag
  212. //
  213. //############################################################################
  214. //############################################################################
  215. CStr &
  216. CTraceTag::GetFilename()
  217. {
  218. /*
  219. * these statics are local to this function so we'll be sure they're
  220. * initialized, if this function is called during app/DLL initialization
  221. */
  222. static CStr strFile;
  223. static BOOL fInitialized = FALSE;
  224. if(!fInitialized)
  225. {
  226. TCHAR szTraceFile[OFS_MAXPATHNAME];
  227. ::GetPrivateProfileString(TEXT("Trace File"), TEXT("Trace File"),
  228. NULL, szTraceFile, OFS_MAXPATHNAME, szTraceIniFile);
  229. strFile = (_tcslen(szTraceFile)==0) ? TEXT("\\mmctrace.out") : szTraceFile;
  230. fInitialized = TRUE;
  231. }
  232. return strFile;
  233. }
  234. /*+-------------------------------------------------------------------------*
  235. *
  236. * CTraceTag::GetStackLevels
  237. *
  238. * PURPOSE: Returns a reference to the number of stack levels to display.
  239. * Auto initializes from the ini file.
  240. *
  241. * RETURNS:
  242. * unsigned int &
  243. *
  244. *+-------------------------------------------------------------------------*/
  245. unsigned int &
  246. CTraceTag::GetStackLevels()
  247. {
  248. static unsigned int nLevels = 3; // the default.
  249. static BOOL fInitialized = FALSE;
  250. if(!fInitialized)
  251. {
  252. TCHAR szStackLevels[OFS_MAXPATHNAME];
  253. ::GetPrivateProfileString(TEXT("Stack Levels"), TEXT("Stack Levels"),
  254. NULL, szStackLevels, OFS_MAXPATHNAME, szTraceIniFile);
  255. if(_tcslen(szStackLevels)!=0)
  256. nLevels = szStackLevels[0] - TEXT('0');
  257. fInitialized = TRUE;
  258. }
  259. return nLevels;
  260. }
  261. HANDLE CTraceTag::s_hfileCom2 = 0;
  262. HANDLE CTraceTag::s_hfile = 0;
  263. /*+-------------------------------------------------------------------------*
  264. *
  265. * CTraceTag::CTraceTag
  266. *
  267. * PURPOSE: Constructor
  268. *
  269. * PARAMETERS:
  270. * LPCTSTR szCategory : The category of the trace.
  271. * LPCTSTR szName : The name of the trace.
  272. * DWORD dwDefaultFlags : The initial (and default) output setting.
  273. *
  274. *+-------------------------------------------------------------------------*/
  275. CTraceTag::CTraceTag(LPCTSTR szCategory, LPCTSTR szName, DWORD dwDefaultFlags /*= 0*/)
  276. : m_szCategory(szCategory),
  277. m_szName(szName)
  278. {
  279. m_dwDefaultFlags = dwDefaultFlags;
  280. m_dwFlags = dwDefaultFlags;
  281. // Get the value from TRACE.INI
  282. m_dwFlags = ::GetPrivateProfileInt(szCategory, szName, dwDefaultFlags, szTraceIniFile);
  283. // add it to the end of the list.
  284. CTraceTags *pTraceTags = GetTraceTags();
  285. if(NULL != pTraceTags)
  286. pTraceTags->push_back(this); // add this tag to the list.
  287. // call the OnEnable function if any flags have been set.
  288. if(FAny())
  289. {
  290. OnEnable();
  291. }
  292. }
  293. /*+-------------------------------------------------------------------------*
  294. *
  295. * CTraceTag::~CTraceTag
  296. *
  297. * PURPOSE: Destructor
  298. *
  299. *+-------------------------------------------------------------------------*/
  300. CTraceTag::~CTraceTag()
  301. {
  302. // close the open handles.
  303. if (s_hfileCom2 && (s_hfileCom2 != INVALID_HANDLE_VALUE))
  304. {
  305. ::CloseHandle(s_hfileCom2);
  306. s_hfileCom2 = INVALID_HANDLE_VALUE;
  307. }
  308. if (s_hfile && (s_hfile != INVALID_HANDLE_VALUE))
  309. {
  310. ::CloseHandle(s_hfile);
  311. s_hfile = INVALID_HANDLE_VALUE;
  312. }
  313. }
  314. /*+-------------------------------------------------------------------------*
  315. *
  316. * CTraceTag::TraceFn
  317. *
  318. * PURPOSE: Processes a Trace statement based on the flags
  319. * of the tag.
  320. *
  321. * PARAMETERS:
  322. * LPCTSTR szFormat : printf style format string
  323. * va_list marker : argument block to pass to _vsnprintf
  324. *
  325. * RETURNS:
  326. * void
  327. *
  328. *+-------------------------------------------------------------------------*/
  329. void CTraceTag::TraceFn(LPCTSTR szFormat, va_list marker) const
  330. {
  331. CStr strT;
  332. CStr str;
  333. // Get out quick if no outputs are enabled.
  334. if (!FAny())
  335. return;
  336. // first, format the string as provided.
  337. strT.FormatV(szFormat, marker);
  338. // next, prepend the name of the tag.
  339. str.Format(TEXT("%s: %s\r\n"), GetName(), strT);
  340. // send the string to all appropriate outputs
  341. OutputString(str);
  342. if(FDumpStack()) // dump the caller's info to the stack.
  343. {
  344. DumpStack();
  345. }
  346. }
  347. /*+-------------------------------------------------------------------------*
  348. *
  349. * CTraceTag::OutputString
  350. *
  351. * PURPOSE: Outputs the specified string to all appropriate outputs
  352. * (Debug string, COM2, or file)
  353. *
  354. * PARAMETERS:
  355. * CStr & str :
  356. *
  357. * RETURNS:
  358. * void
  359. *
  360. *+-------------------------------------------------------------------------*/
  361. void CTraceTag::OutputString(const CStr &str) const
  362. {
  363. UINT cbActual = 0;
  364. //---------------------------------------------------------------
  365. // Output to OutputDebugString if needed
  366. //---------------------------------------------------------------
  367. if (FDebug())
  368. OutputDebugString(str);
  369. USES_CONVERSION;
  370. //---------------------------------------------------------------
  371. // Output to COM2 if needed
  372. //---------------------------------------------------------------
  373. if (FCom2())
  374. {
  375. // create the file if it hasn't been created yet.
  376. if (!s_hfileCom2)
  377. {
  378. s_hfileCom2 = CreateFile(TEXT("com2:"),
  379. GENERIC_WRITE,
  380. 0,
  381. NULL,
  382. OPEN_EXISTING,
  383. FILE_FLAG_WRITE_THROUGH,
  384. NULL);
  385. if (s_hfileCom2 == INVALID_HANDLE_VALUE)
  386. {
  387. //::MessageBox(TEXT("COM2 is not available for debug trace"), MB_OK | MB_ICONINFORMATION);
  388. }
  389. }
  390. // output to file.
  391. if (s_hfileCom2 != INVALID_HANDLE_VALUE)
  392. {
  393. ASSERT(::WriteFile(s_hfileCom2, T2A((LPTSTR)(LPCTSTR)str), str.GetLength(), (LPDWORD) &cbActual, NULL));
  394. ASSERT(::FlushFileBuffers(s_hfileCom2));
  395. }
  396. }
  397. //---------------------------------------------------------------
  398. // Output to File if needed
  399. //---------------------------------------------------------------
  400. if (FFile())
  401. {
  402. // create the file if it hasn't been created yet.
  403. if (!s_hfile)
  404. {
  405. s_hfile = CreateFile(GetFilename(),
  406. GENERIC_WRITE,
  407. FILE_SHARE_READ,
  408. NULL,
  409. OPEN_ALWAYS,
  410. FILE_FLAG_SEQUENTIAL_SCAN,
  411. NULL);
  412. if (s_hfile != INVALID_HANDLE_VALUE)
  413. {
  414. ::SetFilePointer(s_hfile, NULL, NULL, FILE_END);
  415. // for Unicode files, write the Unicode prefix when the file is first created (ie it has a length of zero)
  416. #ifdef UNICODE
  417. DWORD dwFileSize = 0;
  418. if( (::GetFileSize(s_hfile, &dwFileSize) == 0) && (dwFileSize == 0) )
  419. {
  420. const WCHAR chPrefix = 0xFEFF;
  421. const DWORD cbToWrite = sizeof (chPrefix);
  422. DWORD cbWritten = 0;
  423. ::WriteFile (s_hfile, &chPrefix, cbToWrite, &cbWritten, NULL);
  424. }
  425. #endif
  426. // write an initial line.
  427. CStr strInit = TEXT("\n*********************Start of debugging session*********************\r\n");
  428. ::WriteFile(s_hfile, ((LPTSTR)(LPCTSTR)strInit), strInit.GetLength() * sizeof(TCHAR), (LPDWORD) &cbActual, NULL);
  429. }
  430. }
  431. if (s_hfile == INVALID_HANDLE_VALUE)
  432. {
  433. static BOOL fOpenFailed = FALSE;
  434. if (!fOpenFailed)
  435. {
  436. CStr str;
  437. fOpenFailed = TRUE; // Do this first, so the MbbErrorBox and str.Format
  438. // do not cause problems with their trace statement.
  439. str.Format(TEXT("The DEBUG ONLY trace log file '%s' could not be opened"), GetFilename());
  440. //MbbErrorBox(str, ScFromWin32(::GetLastError()));
  441. }
  442. }
  443. else
  444. {
  445. // write to the file.
  446. ::WriteFile(s_hfile, ((LPTSTR)(LPCTSTR)str), str.GetLength() *sizeof(TCHAR), (LPDWORD) &cbActual, NULL);
  447. }
  448. }
  449. //---------------------------------------------------------------
  450. // DebugBreak if needed
  451. //---------------------------------------------------------------
  452. if (FBreak())
  453. MMCDebugBreak();
  454. }
  455. /*+-------------------------------------------------------------------------*
  456. *
  457. * CTraceTag::Commit
  458. *
  459. * PURPOSE: Sets the flags equal to the temporary flags setting.
  460. * If any flags are enabled where previously no flags were, also
  461. * calls OnEnable(). If no flags are enabled where previously flags
  462. * were enabled, calls OnDisable()
  463. *
  464. * RETURNS:
  465. * void
  466. *
  467. *+-------------------------------------------------------------------------*/
  468. void
  469. CTraceTag::Commit()
  470. {
  471. if((0 != m_dwFlags) && (0 == m_dwFlagsTemp))
  472. {
  473. // disable if flags have changed from non-zero to zero
  474. OnDisable();
  475. }
  476. else if((0 == m_dwFlags) && (0 != m_dwFlagsTemp))
  477. {
  478. // enable if flags have changed from 0 to non-zero
  479. OnEnable();
  480. }
  481. m_dwFlags = m_dwFlagsTemp;
  482. }
  483. //############################################################################
  484. //############################################################################
  485. //
  486. // Stack dump related code - copied from MFC with very few modifications.
  487. //
  488. //############################################################################
  489. //############################################################################
  490. static LPVOID __stdcall FunctionTableAccess(HANDLE hProcess, DWORD_PTR dwPCAddress);
  491. static DWORD_PTR __stdcall GetModuleBase(HANDLE hProcess, DWORD_PTR dwReturnAddress);
  492. #define MODULE_NAME_LEN 64
  493. #define SYMBOL_NAME_LEN 128
  494. struct MMC_SYMBOL_INFO
  495. {
  496. DWORD_PTR dwAddress;
  497. DWORD_PTR dwOffset;
  498. CHAR szModule[MODULE_NAME_LEN];
  499. CHAR szSymbol[SYMBOL_NAME_LEN];
  500. };
  501. static LPVOID __stdcall FunctionTableAccess(HANDLE hProcess, DWORD_PTR dwPCAddress)
  502. {
  503. return SymFunctionTableAccess(hProcess, dwPCAddress);
  504. }
  505. static DWORD_PTR __stdcall GetModuleBase(HANDLE hProcess, DWORD_PTR dwReturnAddress)
  506. {
  507. IMAGEHLP_MODULE moduleInfo;
  508. if (SymGetModuleInfo(hProcess, dwReturnAddress, &moduleInfo))
  509. return moduleInfo.BaseOfImage;
  510. else
  511. {
  512. MEMORY_BASIC_INFORMATION memoryBasicInfo;
  513. if (::VirtualQueryEx(hProcess, (LPVOID) dwReturnAddress,
  514. &memoryBasicInfo, sizeof(memoryBasicInfo)))
  515. {
  516. DWORD cch = 0;
  517. char szFile[MAX_PATH] = { 0 };
  518. cch = GetModuleFileNameA((HINSTANCE)memoryBasicInfo.AllocationBase,
  519. szFile, MAX_PATH);
  520. // Ignore the return code since we can't do anything with it.
  521. if (!SymLoadModule(hProcess,
  522. NULL, ((cch) ? szFile : NULL),
  523. NULL, (DWORD_PTR) memoryBasicInfo.AllocationBase, 0))
  524. {
  525. DWORD dwError = GetLastError();
  526. //TRACE1("Error: %d\n", dwError);
  527. }
  528. return (DWORD_PTR) memoryBasicInfo.AllocationBase;
  529. }
  530. else
  531. /*TRACE1("Error is %d\n", GetLastError())*/;
  532. }
  533. return 0;
  534. }
  535. /*+-------------------------------------------------------------------------*
  536. *
  537. * ResolveSymbol
  538. *
  539. * PURPOSE:
  540. *
  541. * PARAMETERS:
  542. * HANDLE hProcess :
  543. * DWORD dwAddress :
  544. * SYMBOL_INFO & siSymbol :
  545. *
  546. * RETURNS:
  547. * static BOOL
  548. *
  549. *+-------------------------------------------------------------------------*/
  550. static BOOL ResolveSymbol(HANDLE hProcess, DWORD_PTR dwAddress,
  551. MMC_SYMBOL_INFO &siSymbol)
  552. {
  553. BOOL fRetval = TRUE;
  554. siSymbol.dwAddress = dwAddress;
  555. union {
  556. CHAR rgchSymbol[sizeof(IMAGEHLP_SYMBOL) + 255];
  557. IMAGEHLP_SYMBOL sym;
  558. };
  559. CHAR szUndec[256];
  560. CHAR szWithOffset[256];
  561. LPSTR pszSymbol = NULL;
  562. IMAGEHLP_MODULE mi;
  563. memset(&siSymbol, 0, sizeof(MMC_SYMBOL_INFO));
  564. mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  565. if (!SymGetModuleInfo(hProcess, dwAddress, &mi))
  566. lstrcpyA(siSymbol.szModule, "<no module>");
  567. else
  568. {
  569. LPSTR pszModule = strchr(mi.ImageName, '\\');
  570. if (pszModule == NULL)
  571. pszModule = mi.ImageName;
  572. else
  573. pszModule++;
  574. lstrcpynA(siSymbol.szModule, pszModule, countof(siSymbol.szModule));
  575. lstrcatA(siSymbol.szModule, "! ");
  576. }
  577. __try
  578. {
  579. sym.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  580. sym.Address = dwAddress;
  581. sym.MaxNameLength = 255;
  582. if (SymGetSymFromAddr(hProcess, dwAddress, &(siSymbol.dwOffset), &sym))
  583. {
  584. pszSymbol = sym.Name;
  585. if (UnDecorateSymbolName(sym.Name, szUndec, countof(szUndec),
  586. UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS))
  587. {
  588. pszSymbol = szUndec;
  589. }
  590. else if (SymUnDName(&sym, szUndec, countof(szUndec)))
  591. {
  592. pszSymbol = szUndec;
  593. }
  594. if (siSymbol.dwOffset != 0)
  595. {
  596. wsprintfA(szWithOffset, "%s + %d bytes", pszSymbol, siSymbol.dwOffset);
  597. pszSymbol = szWithOffset;
  598. }
  599. }
  600. else
  601. pszSymbol = "<no symbol>";
  602. }
  603. __except (EXCEPTION_EXECUTE_HANDLER)
  604. {
  605. pszSymbol = "<EX: no symbol>";
  606. siSymbol.dwOffset = dwAddress - mi.BaseOfImage;
  607. }
  608. lstrcpynA(siSymbol.szSymbol, pszSymbol, countof(siSymbol.szSymbol));
  609. return fRetval;
  610. }
  611. /*+-------------------------------------------------------------------------*
  612. *
  613. * CTraceTag::DumpStack
  614. *
  615. * PURPOSE: Does a stack trace and sends it to the appropriate outputs.
  616. * Mostly copied from AfxDumpStack.
  617. *
  618. * RETURNS:
  619. * void
  620. *
  621. *+-------------------------------------------------------------------------*/
  622. void
  623. CTraceTag::DumpStack() const
  624. {
  625. const int UNINTERESTING_CALLS = 3; // the lines of display which are in CTraceTag code and should not be displayed.
  626. CStr str;
  627. //OutputString("=== Begin Stack Dump ===\r\n");
  628. std::vector<DWORD_PTR> adwAddress;
  629. HANDLE hProcess = ::GetCurrentProcess();
  630. if (SymInitialize(hProcess, NULL, FALSE))
  631. {
  632. // force undecorated names to get params
  633. DWORD dw = SymGetOptions();
  634. dw &= ~SYMOPT_UNDNAME;
  635. SymSetOptions(dw);
  636. HANDLE hThread = ::GetCurrentThread();
  637. CONTEXT threadContext;
  638. threadContext.ContextFlags = CONTEXT_FULL;
  639. if (::GetThreadContext(hThread, &threadContext))
  640. {
  641. STACKFRAME stackFrame;
  642. memset(&stackFrame, 0, sizeof(stackFrame));
  643. stackFrame.AddrPC.Mode = AddrModeFlat;
  644. DWORD dwMachType;
  645. #if defined(_M_IX86)
  646. dwMachType = IMAGE_FILE_MACHINE_I386;
  647. // program counter, stack pointer, and frame pointer
  648. stackFrame.AddrPC.Offset = threadContext.Eip;
  649. stackFrame.AddrStack.Offset = threadContext.Esp;
  650. stackFrame.AddrStack.Mode = AddrModeFlat;
  651. stackFrame.AddrFrame.Offset = threadContext.Ebp;
  652. stackFrame.AddrFrame.Mode = AddrModeFlat;
  653. #elif defined(_M_AMD64)
  654. // only program counter
  655. dwMachType = IMAGE_FILE_MACHINE_AMD64;
  656. stackFrame.AddrPC.Offset = threadContext.Rip;
  657. #elif defined(_M_IA64)
  658. // from <root>\com\ole32\common\stackwlk.cxx
  659. dwMachType = IMAGE_FILE_MACHINE_IA64;
  660. stackFrame.AddrPC.Offset = threadContext.StIIP;
  661. #else
  662. #error("Unknown Target Machine");
  663. #endif
  664. int nFrame;
  665. for (nFrame = 0; nFrame < GetStackLevels() + UNINTERESTING_CALLS; nFrame++)
  666. {
  667. if (!StackWalk(dwMachType, hProcess, hProcess,
  668. &stackFrame, &threadContext, NULL,
  669. FunctionTableAccess, GetModuleBase, NULL))
  670. {
  671. break;
  672. }
  673. adwAddress.push_back(stackFrame.AddrPC.Offset);
  674. }
  675. }
  676. }
  677. else
  678. {
  679. DWORD dw = GetLastError();
  680. char sz[100];
  681. wsprintfA(sz,
  682. "AfxDumpStack Error: IMAGEHLP.DLL wasn't found. "
  683. "GetLastError() returned 0x%8.8X\r\n", dw);
  684. OutputString(sz);
  685. }
  686. // dump it out now
  687. int nAddress;
  688. int cAddresses = adwAddress.size();
  689. for (nAddress = UNINTERESTING_CALLS; nAddress < cAddresses; nAddress++)
  690. {
  691. MMC_SYMBOL_INFO info;
  692. DWORD_PTR dwAddress = adwAddress[nAddress];
  693. char sz[20];
  694. wsprintfA(sz, " %8.8X: ", dwAddress);
  695. OutputString(sz);
  696. if (ResolveSymbol(hProcess, dwAddress, info))
  697. {
  698. OutputString(info.szModule);
  699. OutputString(info.szSymbol);
  700. }
  701. else
  702. OutputString("symbol not found");
  703. OutputString("\r\n");
  704. }
  705. //OutputString("=== End Stack Dump ===\r\n");
  706. }
  707. //--------------------------------------------------------------------------
  708. #endif // DBG
  709. //--------------------------------------------------------------------------