home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / dumpstak.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  10KB  |  378 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #include <imagehlp.h>
  14. #pragma comment(lib, "imagehlp.lib")
  15.  
  16. #ifdef AFX_AUX_SEG
  17. #pragma code_seg(AFX_AUX_SEG)
  18. #endif
  19.  
  20. /////////////////////////////////////////////////////////////////////////////
  21. // Routine to produce stack dump
  22.  
  23. static LPVOID __stdcall FunctionTableAccess(HANDLE hProcess, DWORD dwPCAddress);
  24. static DWORD __stdcall GetModuleBase(HANDLE hProcess, DWORD dwReturnAddress);
  25.  
  26. #define MODULE_NAME_LEN 64
  27. #define SYMBOL_NAME_LEN 128
  28.  
  29. struct SYMBOL_INFO
  30. {
  31.     DWORD dwAddress;
  32.     DWORD dwOffset;
  33.     CHAR    szModule[MODULE_NAME_LEN];
  34.     CHAR    szSymbol[SYMBOL_NAME_LEN];
  35. };
  36.  
  37. static LPVOID __stdcall FunctionTableAccess(HANDLE hProcess, DWORD dwPCAddress)
  38. {
  39.     return SymFunctionTableAccess(hProcess, dwPCAddress);
  40. }
  41.  
  42. static DWORD __stdcall GetModuleBase(HANDLE hProcess, DWORD dwReturnAddress)
  43. {
  44.     IMAGEHLP_MODULE moduleInfo;
  45.  
  46.     if (SymGetModuleInfo(hProcess, dwReturnAddress, &moduleInfo))
  47.         return moduleInfo.BaseOfImage;
  48.     else
  49.     {
  50.         MEMORY_BASIC_INFORMATION memoryBasicInfo;
  51.  
  52.         if (::VirtualQueryEx(hProcess, (LPVOID) dwReturnAddress,
  53.             &memoryBasicInfo, sizeof(memoryBasicInfo)))
  54.         {
  55.             DWORD cch = 0;
  56.             char szFile[MAX_PATH] = { 0 };
  57.  
  58.          cch = GetModuleFileNameA((HINSTANCE)memoryBasicInfo.AllocationBase,
  59.                                          szFile, MAX_PATH);
  60.  
  61.          // Ignore the return code since we can't do anything with it.
  62.          if (!SymLoadModule(hProcess,
  63.                NULL, ((cch) ? szFile : NULL),
  64.                NULL, (DWORD) memoryBasicInfo.AllocationBase, 0))
  65.             {
  66.                 DWORD dwError = GetLastError();
  67.                 TRACE1("Error: %d\n", dwError);
  68.             }
  69.          return (DWORD) memoryBasicInfo.AllocationBase;
  70.       }
  71.         else
  72.             TRACE1("Error is %d\n", GetLastError());
  73.     }
  74.  
  75.     return 0;
  76. }
  77.  
  78. static BOOL ResolveSymbol(HANDLE hProcess, DWORD dwAddress,
  79.     SYMBOL_INFO &siSymbol)
  80. {
  81.     BOOL fRetval = TRUE;
  82.  
  83.     siSymbol.dwAddress = dwAddress;
  84.  
  85.     union {
  86.         CHAR rgchSymbol[sizeof(IMAGEHLP_SYMBOL) + 255];
  87.         IMAGEHLP_SYMBOL  sym;
  88.     };
  89.  
  90.     CHAR szUndec[256];
  91.     CHAR szWithOffset[256];
  92.     LPSTR pszSymbol = NULL;
  93.     IMAGEHLP_MODULE mi;
  94.  
  95.     memset(&siSymbol, 0, sizeof(SYMBOL_INFO));
  96.     mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  97.  
  98.     if (!SymGetModuleInfo(hProcess, dwAddress, &mi))
  99.         lstrcpyA(siSymbol.szModule, "<no module>");
  100.     else
  101.     {
  102.         LPSTR pszModule = strchr(mi.ImageName, '\\');
  103.         if (pszModule == NULL)
  104.             pszModule = mi.ImageName;
  105.         else
  106.             pszModule++;
  107.  
  108.         lstrcpynA(siSymbol.szModule, pszModule, _countof(siSymbol.szModule));
  109.        lstrcatA(siSymbol.szModule, "! ");
  110.     }
  111.  
  112.     __try
  113.     {
  114.         sym.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  115.         sym.Address = dwAddress;
  116.         sym.MaxNameLength = 255;
  117.  
  118.         if (SymGetSymFromAddr(hProcess, dwAddress, &(siSymbol.dwOffset), &sym))
  119.         {
  120.             pszSymbol = sym.Name;
  121.  
  122.             if (UnDecorateSymbolName(sym.Name, szUndec, _countof(szUndec),
  123.                 UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS))
  124.             {
  125.                 pszSymbol = szUndec;
  126.             }
  127.             else if (SymUnDName(&sym, szUndec, _countof(szUndec)))
  128.             {
  129.                 pszSymbol = szUndec;
  130.             }
  131.  
  132.             if (siSymbol.dwOffset != 0)
  133.             {
  134.                 wsprintfA(szWithOffset, "%s + %d bytes", pszSymbol, siSymbol.dwOffset);
  135.                 pszSymbol = szWithOffset;
  136.             }
  137.       }
  138.       else
  139.           pszSymbol = "<no symbol>";
  140.     }
  141.     __except (EXCEPTION_EXECUTE_HANDLER)
  142.     {
  143.         pszSymbol = "<EX: no symbol>";
  144.         siSymbol.dwOffset = dwAddress - mi.BaseOfImage;
  145.     }
  146.  
  147.     lstrcpynA(siSymbol.szSymbol, pszSymbol, _countof(siSymbol.szSymbol));
  148.     return fRetval;
  149. }
  150.  
  151. class CTraceClipboardData
  152. {
  153.     HGLOBAL m_hMemory;
  154.     DWORD   m_dwSize;
  155.     DWORD m_dwUsed;
  156.     DWORD m_dwTarget;
  157.  
  158. public:
  159.     void SendOut(LPCSTR pszData);
  160.     CTraceClipboardData(DWORD dwTarget);
  161.     ~CTraceClipboardData();
  162. };
  163.  
  164. CTraceClipboardData::CTraceClipboardData(DWORD dwTarget)
  165.     : m_dwTarget(dwTarget), m_dwSize(0), m_dwUsed(0), m_hMemory(NULL)
  166. {
  167. }
  168.  
  169. CTraceClipboardData::~CTraceClipboardData()
  170. {
  171.     if (m_hMemory != NULL)
  172.     {
  173.         // chuck it onto the clipboard
  174.         // don't free it unless there's an error
  175.  
  176.         if (!OpenClipboard(NULL))
  177.             GlobalFree(m_hMemory);
  178.         else if (!EmptyClipboard() ||
  179.                 SetClipboardData(CF_TEXT, m_hMemory) == NULL)
  180.         {
  181.             GlobalFree(m_hMemory);
  182.         }
  183.         else
  184.             CloseClipboard();
  185.     }
  186. }
  187.  
  188. void CTraceClipboardData::SendOut(LPCSTR pszData)
  189. {
  190.     int nLength;
  191.     if (pszData == NULL || (nLength = lstrlenA(pszData)) == 0)
  192.         return;
  193.  
  194.     // send it to TRACE (can be redirected)
  195.     if (m_dwTarget & AFX_STACK_DUMP_TARGET_TRACE)
  196.         TRACE1("%hs", pszData);
  197.  
  198.     // send it to OutputDebugString() (can't redirect)
  199.     if (m_dwTarget & AFX_STACK_DUMP_TARGET_ODS)
  200.         OutputDebugStringA(pszData);
  201.  
  202.     // build a buffer for the clipboard
  203.     if (m_dwTarget & AFX_STACK_DUMP_TARGET_CLIPBOARD)
  204.     {
  205.         if (m_hMemory == NULL)
  206.         {
  207.            m_hMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, 1024);
  208.             if (m_hMemory == NULL)
  209.             {
  210.                 TRACE0("AfxDumpStack Error: No memory available for clipboard.\n");
  211.                 m_dwTarget &= ~AFX_STACK_DUMP_TARGET_CLIPBOARD;
  212.             }
  213.             else
  214.             {
  215.                 m_dwUsed = nLength;
  216.                 m_dwSize = 1024;
  217.                 LPSTR pstr = (LPSTR) GlobalLock(m_hMemory);
  218.                 if (pstr != NULL)
  219.                 {
  220.                     lstrcpyA(pstr, pszData);
  221.                     GlobalUnlock(m_hMemory);
  222.                 }
  223.                 else
  224.                 {
  225.                     TRACE0("AfxDumpStack Error: Couldn't lock memory!\n");
  226.                     GlobalFree(m_hMemory);
  227.                     m_hMemory = NULL;
  228.                     m_dwTarget &= ~AFX_STACK_DUMP_TARGET_CLIPBOARD;
  229.                 }
  230.             }
  231.         }
  232.         else
  233.         {
  234.             if ((m_dwUsed + nLength + 1) >= m_dwSize)
  235.             {
  236.                 // grow by leaps and bounds
  237.                 m_dwSize *= 2;
  238.                 if (m_dwSize > (1024L*1024L))
  239.                 {
  240.                     TRACE0("AfxDumpStack Error: more than one megabyte on clipboard.\n");
  241.                     m_dwTarget &= ~AFX_STACK_DUMP_TARGET_CLIPBOARD;
  242.                 }
  243.  
  244.                 HGLOBAL hMemory = GlobalReAlloc(m_hMemory, m_dwSize, GMEM_MOVEABLE);
  245.                 if (hMemory == NULL)
  246.                 {
  247.                     TRACE1("AfxDumpStack Error: Couldn't get %d bytes!\n", m_dwSize);
  248.                     m_dwTarget &= ~AFX_STACK_DUMP_TARGET_CLIPBOARD;
  249.                 }
  250.                 else
  251.                     m_hMemory = hMemory;
  252.             }
  253.  
  254.             LPSTR pstr = (LPSTR) GlobalLock(m_hMemory);
  255.             if (pstr != NULL)
  256.             {
  257.                 lstrcpyA(pstr + m_dwUsed, pszData);
  258.                 m_dwUsed += nLength;
  259.                 GlobalUnlock(m_hMemory);
  260.             }
  261.             else
  262.             {
  263.                 TRACE0("AfxDumpStack Error: Couldn't lock memory!\n");
  264.                 m_dwTarget &= ~AFX_STACK_DUMP_TARGET_CLIPBOARD;
  265.             }
  266.         }
  267.     }
  268.  
  269.     return;
  270. }
  271.  
  272. /////////////////////////////////////////////////////////////////////////////
  273. // AfxDumpStack API
  274.  
  275. void AFXAPI AfxDumpStack(DWORD dwTarget /* = AFX_STACK_DUMP_TARGET_DEFAULT */)
  276. {
  277.     CTraceClipboardData clipboardData(dwTarget);
  278.  
  279.     clipboardData.SendOut("=== begin AfxDumpStack output ===\r\n");
  280.  
  281.     CDWordArray adwAddress;
  282.     HANDLE hProcess = ::GetCurrentProcess();
  283.     if (SymInitialize(hProcess, NULL, FALSE))
  284.     {
  285.         // force undecorated names to get params
  286.         DWORD dw = SymGetOptions();
  287.         dw &= ~SYMOPT_UNDNAME;
  288.         SymSetOptions(dw);
  289.  
  290.         HANDLE hThread = ::GetCurrentThread();
  291.         CONTEXT threadContext;
  292.  
  293.         threadContext.ContextFlags = CONTEXT_FULL;
  294.  
  295.         if (::GetThreadContext(hThread, &threadContext))
  296.         {
  297.             STACKFRAME stackFrame;
  298.             memset(&stackFrame, 0, sizeof(stackFrame));
  299.             stackFrame.AddrPC.Mode = AddrModeFlat;
  300.  
  301.             DWORD dwMachType;
  302.  
  303. #if defined(_M_IX86)
  304.             dwMachType                  = IMAGE_FILE_MACHINE_I386;
  305.  
  306.             // program counter, stack pointer, and frame pointer
  307.             stackFrame.AddrPC.Offset    = threadContext.Eip;
  308.             stackFrame.AddrStack.Offset = threadContext.Esp;
  309.             stackFrame.AddrStack.Mode   = AddrModeFlat;
  310.             stackFrame.AddrFrame.Offset = threadContext.Ebp;
  311.             stackFrame.AddrFrame.Mode   = AddrModeFlat;
  312. #elif defined(_M_MRX000)
  313.             // only program counter
  314.             dwMachType                  = IMAGE_FILE_MACHINE_R4000;
  315.             stackFrame.AddrPC. Offset    = treadContext.Fir;
  316. #elif defined(_M_ALPHA)
  317.             // only program counter
  318.             dwMachType                  = IMAGE_FILE_MACHINE_ALPHA;
  319.             stackFrame.AddrPC.Offset    = (unsigned long) threadContext.Fir;
  320. #elif defined(_M_PPC)
  321.             // only program counter
  322.             dwMachType                  = IMAGE_FILE_MACHINE_POWERPC;
  323.             stackFrame.AddrPC.Offset    = threadContext.Iar;
  324. #elif
  325. #error("Unknown Target Machine");
  326. #endif
  327.  
  328.             adwAddress.SetSize(0, 16);
  329.  
  330.             int nFrame;
  331.             for (nFrame = 0; nFrame < 1024; nFrame++)
  332.             {
  333.                 if (!StackWalk(dwMachType, hProcess, hProcess,
  334.                     &stackFrame, &threadContext, NULL,
  335.                     FunctionTableAccess, GetModuleBase, NULL))
  336.                 {
  337.                     break;
  338.                 }
  339.  
  340.                 adwAddress.SetAtGrow(nFrame, stackFrame.AddrPC.Offset);
  341.             }
  342.         }
  343.     }
  344.     else
  345.     {
  346.         DWORD dw = GetLastError();
  347.         char sz[100];
  348.         wsprintfA(sz,
  349.             "AfxDumpStack Error: IMAGEHLP.DLL wasn't found. "
  350.             "GetLastError() returned 0x%8.8X\r\n", dw);
  351.         clipboardData.SendOut(sz);
  352.     }
  353.  
  354.     // dump it out now
  355.     int nAddress;
  356.     int cAddresses = adwAddress.GetSize();
  357.     for (nAddress = 0; nAddress < cAddresses; nAddress++)
  358.     {
  359.         SYMBOL_INFO info;
  360.         DWORD dwAddress = adwAddress[nAddress];
  361.  
  362.         char sz[20];
  363.         wsprintfA(sz, "%8.8X: ", dwAddress);
  364.         clipboardData.SendOut(sz);
  365.  
  366.         if (ResolveSymbol(hProcess, dwAddress, info))
  367.         {
  368.             clipboardData.SendOut(info.szModule);
  369.             clipboardData.SendOut(info.szSymbol);
  370.         }
  371.         else
  372.             clipboardData.SendOut("symbol not found");
  373.         clipboardData.SendOut("\r\n");
  374.     }
  375.  
  376.     clipboardData.SendOut("=== end AfxDumpStack() output ===\r\n");
  377. }
  378.