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.

364 lines
8.9 KiB

  1. /*++
  2. Copyright (C) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. STKTRACE.CPP
  5. Abstract:
  6. Symbolic stack trace
  7. History:
  8. raymcc 27-May-99
  9. --*/
  10. #include <windows.h>
  11. #include <imagehlp.h>
  12. #include "kernel33.h"
  13. #include "stktrace.h"
  14. // Compiler bug workaround
  15. void xstrcat(TCHAR *p1, TCHAR *p2)
  16. {
  17. while (*p1++); p1--;
  18. while (*p1++ = *p2++);
  19. }
  20. static HANDLE s_hProcess = 0;
  21. static HANDLE s_hPrivateHeap = 0;
  22. // IMAGHLP.DLL Function pointers
  23. // =============================
  24. typedef BOOL (__stdcall *PFN_SymInitialize)(
  25. IN HANDLE hProcess,
  26. IN PSTR UserSearchPath,
  27. IN BOOL fInvadeProcess
  28. );
  29. typedef PVOID (__stdcall *PFN_SymFunctionTableAccess)(
  30. HANDLE hProcess,
  31. DWORD AddrBase
  32. );
  33. typedef BOOL (__stdcall *PFN_SymGetSymFromAddr)(
  34. IN HANDLE hProcess,
  35. IN DWORD dwAddr,
  36. OUT PDWORD pdwDisplacement,
  37. OUT PIMAGEHLP_SYMBOL Symbol
  38. );
  39. typedef BOOL (__stdcall *PFN_SymGetLineFromAddr)(
  40. IN HANDLE hProcess,
  41. IN DWORD dwAddr,
  42. OUT PDWORD pdwDisplacement,
  43. OUT PIMAGEHLP_LINE Line
  44. );
  45. typedef DWORD (__stdcall *PFN_SymGetModuleBase)(
  46. IN HANDLE hProcess,
  47. IN DWORD dwAddr
  48. );
  49. typedef BOOL (__stdcall *PFN_StackWalk)(
  50. DWORD MachineType,
  51. HANDLE hProcess,
  52. HANDLE hThread,
  53. LPSTACKFRAME StackFrame,
  54. PVOID ContextRecord,
  55. PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
  56. PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
  57. PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
  58. PTRANSLATE_ADDRESS_ROUTINE TranslateAddress
  59. );
  60. static PFN_SymInitialize pfSymInitialize = 0;
  61. static PFN_SymFunctionTableAccess pfSymFunctionTableAccess = 0;
  62. static PFN_SymGetSymFromAddr pfSymGetSymFromAddr = 0;
  63. static PFN_SymGetLineFromAddr pfSymGetLineFromAddr = 0;
  64. static PFN_SymGetModuleBase pfSymGetModuleBase = 0;
  65. static PFN_StackWalk pfStackWalk = 0;
  66. //***************************************************************************
  67. //
  68. //***************************************************************************
  69. BOOL m_bActive = FALSE;
  70. BOOL StackTrace_Init()
  71. {
  72. if (m_bActive) // Already running
  73. return TRUE;
  74. m_bActive = FALSE;
  75. TCHAR IniPath[MAX_PATH], buf[MAX_PATH], SymPath[MAX_PATH];
  76. *IniPath = 0;
  77. *buf = 0;
  78. *SymPath = 0;
  79. GetSystemDirectory(IniPath, MAX_PATH);
  80. xstrcat(IniPath, __TEXT("\\WBEM\\WMIDBG.INI")); // Compiler bug workaround
  81. DWORD dwRes = GetPrivateProfileString(
  82. __TEXT("WMI DEBUG"),
  83. __TEXT("DLLNAME"),
  84. __TEXT(""),
  85. buf,
  86. MAX_PATH,
  87. IniPath
  88. );
  89. dwRes = GetPrivateProfileString(
  90. __TEXT("WMI DEBUG"),
  91. __TEXT("SYMPATH"),
  92. __TEXT(""),
  93. SymPath,
  94. MAX_PATH,
  95. IniPath
  96. );
  97. HMODULE hMod = LoadLibrary(buf);
  98. if (hMod == 0)
  99. return FALSE;
  100. pfSymInitialize = (PFN_SymInitialize) GetProcAddress(hMod, "SymInitialize");
  101. pfSymFunctionTableAccess = (PFN_SymFunctionTableAccess) GetProcAddress(hMod, "SymFunctionTableAddress");
  102. pfSymGetSymFromAddr = (PFN_SymGetSymFromAddr) GetProcAddress(hMod, "SymGetSymFromAddr");
  103. pfSymGetLineFromAddr = (PFN_SymGetLineFromAddr) GetProcAddress(hMod, "SymGetLineFromAddr");
  104. pfSymGetModuleBase = (PFN_SymGetModuleBase) GetProcAddress(hMod, "SymGetModuleBase");
  105. pfStackWalk = (PFN_StackWalk) GetProcAddress(hMod, "StackWalk");
  106. if (pfStackWalk == 0 || pfSymInitialize == 0 || pfSymGetSymFromAddr == 0)
  107. {
  108. FreeLibrary(hMod);
  109. return FALSE;
  110. }
  111. s_hProcess = GetCurrentProcess();
  112. s_hPrivateHeap = HeapCreate(0, 0x8000, 0);
  113. char chSymPath[MAX_PATH];
  114. lstrcpy(chSymPath, SymPath);
  115. BOOL bRes = pfSymInitialize(s_hProcess, chSymPath, TRUE);
  116. if (!bRes)
  117. return FALSE;
  118. m_bActive = TRUE;
  119. return TRUE;
  120. }
  121. //***************************************************************************
  122. //
  123. //***************************************************************************
  124. //***************************************************************************
  125. //
  126. //***************************************************************************
  127. BOOL StackTrace_GetSymbolByAddr(
  128. LPVOID pAddr,
  129. DWORD *pdwDisp,
  130. int nBufSize,
  131. char *pBuf
  132. )
  133. {
  134. if (!m_bActive)
  135. return FALSE;
  136. BYTE Buf[256];
  137. char File[256];
  138. IMAGEHLP_SYMBOL *pSym = (IMAGEHLP_SYMBOL *) Buf;
  139. pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  140. pSym->Address = 0;
  141. pSym->Size = 0;
  142. pSym->Flags = 0;
  143. pSym->MaxNameLength = 128;
  144. pSym->Name[0] = 0;
  145. BOOL bRes = pfSymGetSymFromAddr(s_hProcess, DWORD(pAddr), pdwDisp, pSym);
  146. if (!bRes)
  147. {
  148. DWORD dwRes = GetLastError();
  149. if (dwRes == ERROR_INVALID_ADDRESS)
  150. lstrcpy(pBuf, "Invalid Address");
  151. else if (dwRes == ERROR_MOD_NOT_FOUND)
  152. lstrcpy(pBuf, "Error: Module Not Found");
  153. else
  154. wsprintf(pBuf, "Error: GetLastError() = %d\n", dwRes);
  155. return FALSE;
  156. }
  157. IMAGEHLP_LINE Line;
  158. Line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
  159. Line.Key = 0;
  160. Line.LineNumber = 0;
  161. Line.FileName = File;
  162. Line.Address = 0;
  163. /*if (pfSymGetLineFromAddr)
  164. {
  165. bRes = pfSymGetLineFromAddr(s_hProcess, DWORD(pAddr), pdwDisp, &Line);
  166. if (!bRes)
  167. return FALSE;
  168. }
  169. */
  170. lstrcpyn(pBuf, pSym->Name, nBufSize);
  171. return TRUE;
  172. }
  173. void StackTrace_Delete(StackTrace *pMem)
  174. {
  175. pfnHeapFree(s_hPrivateHeap, 0, pMem);
  176. }
  177. //***************************************************************************
  178. //
  179. //***************************************************************************
  180. void _FillMemory(LPVOID pMem, LONG lCount, BYTE b)
  181. {
  182. LPBYTE pArray = LPBYTE(pMem);
  183. for (int i = 0; i < lCount; i++)
  184. {
  185. pArray[i] = b;
  186. }
  187. }
  188. //***************************************************************************
  189. //
  190. //***************************************************************************
  191. StackTrace *StackTrace__NewTrace()
  192. {
  193. if (!m_bActive)
  194. return NULL;
  195. HANDLE hThread = GetCurrentThread();
  196. // Get the thread context, registers, etc.
  197. // =======================================
  198. CONTEXT ctx;
  199. _FillMemory(&ctx, sizeof(ctx), 0);
  200. ctx.ContextFlags = CONTEXT_FULL;
  201. GetThreadContext(hThread, &ctx);
  202. // Set up the starting stack frame.
  203. // ================================
  204. STACKFRAME sf;
  205. _FillMemory(&sf, sizeof(sf), 0);
  206. sf.AddrPC.Offset = ctx.Eip;
  207. sf.AddrPC.Mode = AddrModeFlat;
  208. sf.AddrStack.Offset = ctx.Esp;
  209. sf.AddrStack.Mode = AddrModeFlat;
  210. sf.AddrFrame.Offset = ctx.Ebp;
  211. sf.AddrFrame.Mode = AddrModeFlat;
  212. // Walk the stack.
  213. // ===============
  214. const DWORD dwMaxAddresses = 128;
  215. DWORD Addresses[dwMaxAddresses];
  216. DWORD dwNumAddresses = 0;
  217. for (int i = 0; ;i++)
  218. {
  219. BOOL bRes = pfStackWalk(
  220. IMAGE_FILE_MACHINE_I386,
  221. s_hProcess,
  222. hThread,
  223. &sf,
  224. &ctx,
  225. 0,
  226. pfSymFunctionTableAccess,
  227. pfSymGetModuleBase,
  228. NULL
  229. );
  230. if (bRes == FALSE)
  231. break;
  232. if (i == 0)
  233. continue; // Skip the StackWalk frame itself
  234. if (sf.AddrPC.Offset == 0)
  235. break;
  236. Addresses[dwNumAddresses++] = sf.AddrPC.Offset;
  237. if (dwNumAddresses == dwMaxAddresses)
  238. break;
  239. }
  240. // Now, allocate a StackTrace struct to return to user.
  241. // ====================================================
  242. StackTrace *pTrace = (StackTrace *) pfnHeapAlloc(s_hPrivateHeap, HEAP_ZERO_MEMORY,
  243. sizeof(StackTrace) + sizeof(DWORD) * dwNumAddresses - 1);
  244. pTrace->m_dwCount = dwNumAddresses;
  245. for (DWORD dwIx = 0; dwIx < dwNumAddresses; dwIx++)
  246. pTrace->m_dwAddresses[dwIx] = Addresses[dwIx];
  247. return pTrace;
  248. }
  249. //***************************************************************************
  250. //
  251. //***************************************************************************
  252. char *StackTrace_Dump(StackTrace *pTrace)
  253. {
  254. if (!m_bActive)
  255. return 0;
  256. char Buf[64];
  257. char Buf2[256];
  258. static char Buf3[8192];
  259. *Buf3 = 0;
  260. lstrcat(Buf, "---block---\r\n");
  261. for (DWORD dwIx = 0; dwIx < pTrace->m_dwCount; dwIx++)
  262. {
  263. DWORD dwAddress = pTrace->m_dwAddresses[dwIx];
  264. wsprintf(Buf, " 0x%08x ", dwAddress);
  265. ///////////////
  266. char Name[128];
  267. lstrcpy(Name, "<no symbol>\n");
  268. DWORD dwDisp;
  269. *Name = 0;
  270. StackTrace_GetSymbolByAddr(LPVOID(dwAddress), &dwDisp, 127, Name);
  271. ////////////
  272. wsprintf(Buf2, "%s disp=0x%04x <%s>\r\n", Buf, dwDisp, Name);
  273. lstrcat(Buf3, Buf2);
  274. }
  275. return Buf3;
  276. }