SpBaseRoutine.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. #include "stdafx.h"
  2. #include <vector>
  3. using namespace std;
  4. #include <imagehlp.h>
  5. #include "SpBase.h"
  6. #include "SpBaseRoutine.h"
  7. #define WIN32_LEAN_AND_MEAN
  8. #define _WIN32_WINNT 0x400
  9. #include <locale.h>
  10. #include <windows.h>
  11. #include <psapi.h>
  12. #include <Tlhelp32.h>
  13. #include <map>
  14. ////////////////////////////////////////////////////////////
  15. //DumpStack part
  16. #ifndef _countof
  17. #define _countof(array) (sizeof(array)/sizeof(array[0]))
  18. #endif
  19. const DWORD MODULE_NAME_LEN=64;
  20. const DWORD SYMBOL_NAME_LEN=128;
  21. struct tagSYMBOL_INFO
  22. {
  23. DWORD dwAddress;
  24. DWORD dwOffset;
  25. char szModule[MODULE_NAME_LEN];
  26. char szSymbol[SYMBOL_NAME_LEN];
  27. };
  28. static tagSYMBOL_INFO ResolveSymbol(HANDLE hProcess, DWORD dwAddress)
  29. {
  30. union
  31. {
  32. CHAR rgchSymbol[sizeof(IMAGEHLP_SYMBOL) + 255];
  33. IMAGEHLP_SYMBOL sym;
  34. };
  35. char szUndec[256];
  36. char szWithOffset[256];
  37. char *pszSymbol = NULL;
  38. IMAGEHLP_MODULE mi;
  39. tagSYMBOL_INFO siSymbol;
  40. memset(&mi,0,sizeof(mi));
  41. memset(&siSymbol,0,sizeof(siSymbol));
  42. siSymbol.dwAddress = dwAddress;
  43. mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  44. if (!SymGetModuleInfo(hProcess, dwAddress, &mi))
  45. lstrcpyA(siSymbol.szModule, "<no module>");
  46. else
  47. {
  48. char *pszModule = strchr(mi.ImageName, '\\');
  49. if (pszModule == NULL)
  50. pszModule = mi.ImageName;
  51. else
  52. pszModule++;
  53. lstrcpynA(siSymbol.szModule, pszModule, _countof(siSymbol.szModule));
  54. lstrcatA(siSymbol.szModule, "! ");
  55. }
  56. __try
  57. {
  58. sym.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  59. sym.Address = dwAddress;
  60. sym.MaxNameLength = 255;
  61. if (SymGetSymFromAddr(hProcess, dwAddress, &(siSymbol.dwOffset), &sym))
  62. {
  63. pszSymbol = sym.Name;
  64. if (UnDecorateSymbolName(sym.Name, szUndec, _countof(szUndec),
  65. UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS))
  66. {
  67. pszSymbol = szUndec;
  68. }
  69. else if (SymUnDName(&sym, szUndec, _countof(szUndec)))
  70. {
  71. pszSymbol = szUndec;
  72. }
  73. if (siSymbol.dwOffset != 0)
  74. {
  75. wsprintfA(szWithOffset, "%s + %d bytes", pszSymbol, siSymbol.dwOffset);
  76. pszSymbol = szWithOffset;
  77. }
  78. }
  79. else
  80. pszSymbol = "<no symbol>";
  81. }
  82. __except (EXCEPTION_EXECUTE_HANDLER)
  83. {
  84. pszSymbol = "<EX: no symbol>";
  85. siSymbol.dwOffset = dwAddress - mi.BaseOfImage;
  86. }
  87. lstrcpynA(siSymbol.szSymbol, pszSymbol, _countof(siSymbol.szSymbol));
  88. return siSymbol;
  89. }
  90. static DWORD __stdcall GetModuleBase( HANDLE hProcess, DWORD dwReturnAddress )
  91. {
  92. IMAGEHLP_MODULE moduleInfo;
  93. if ( SymGetModuleInfo( hProcess, dwReturnAddress, &moduleInfo ) )
  94. return moduleInfo.BaseOfImage;
  95. MEMORY_BASIC_INFORMATION mbInfo;
  96. if ( VirtualQueryEx( hProcess, (LPCVOID)dwReturnAddress, &mbInfo, sizeof( mbInfo ) ) )
  97. {
  98. char szFile[ MAX_PATH ] = { 0 };
  99. DWORD cch = GetModuleFileNameA( (HINSTANCE)mbInfo.AllocationBase, szFile, MAX_PATH );
  100. // Ignore the return code since we can't do anything with it.
  101. if ( SymLoadModule( hProcess, NULL, cch ? szFile : NULL, NULL,
  102. (DWORD)mbInfo.AllocationBase, 0 ) )
  103. return (DWORD) mbInfo.AllocationBase;
  104. }
  105. return SymGetModuleBase( hProcess, dwReturnAddress );
  106. }
  107. static bool DumpStackVector(vector<tagSYMBOL_INFO> &CallStacks)
  108. {
  109. HANDLE hProcess = ::GetCurrentProcess();
  110. if (!::SymInitialize(hProcess, NULL, FALSE))
  111. return false;
  112. // force undecorated names to get params
  113. DWORD dw = ::SymGetOptions();
  114. dw &= ~SYMOPT_UNDNAME;
  115. ::SymSetOptions(dw);
  116. HANDLE hThread = ::GetCurrentThread();
  117. CONTEXT threadContext;
  118. threadContext.ContextFlags = CONTEXT_FULL;
  119. if (::GetThreadContext(hThread, &threadContext))
  120. {
  121. STACKFRAME stackFrame;
  122. memset(&stackFrame, 0, sizeof(stackFrame));
  123. stackFrame.AddrPC.Mode = AddrModeFlat;
  124. DWORD dwMachType(0);
  125. dwMachType = IMAGE_FILE_MACHINE_I386;
  126. // program counter, stack pointer, and frame pointer
  127. stackFrame.AddrPC.Offset = threadContext.Eip;
  128. stackFrame.AddrStack.Offset = threadContext.Esp;
  129. stackFrame.AddrStack.Mode = AddrModeFlat;
  130. stackFrame.AddrFrame.Offset = threadContext.Ebp;
  131. stackFrame.AddrFrame.Mode = AddrModeFlat;
  132. for (int nFrame = 0; nFrame < 1024; nFrame++)
  133. {
  134. if (!::StackWalk(dwMachType, hProcess, hThread,
  135. &stackFrame, &threadContext, NULL,
  136. SymFunctionTableAccess, GetModuleBase, NULL))
  137. {
  138. break;
  139. }
  140. CallStacks.push_back(ResolveSymbol(hProcess, stackFrame.AddrPC.Offset));
  141. }
  142. }
  143. return true;
  144. }
  145. CSimpleStringA DumpStack(DWORD nSkipLevel)
  146. {
  147. CSimpleStringA strStack;
  148. vector<tagSYMBOL_INFO> CallStacks;
  149. if(!DumpStackVector(CallStacks))
  150. {
  151. strStack.Format("DumpStack Error: IMAGEHLP.DLL wasn't found. GetLastError() returned 0x%8.8X\r\n",GetLastError());
  152. return strStack;
  153. }
  154. strStack="\r\n===begin===\r\n";
  155. // dump it out now
  156. int cAddresses = CallStacks.size();
  157. for (DWORD nAddress = nSkipLevel+1; nAddress < (DWORD)cAddresses; nAddress++)
  158. {
  159. tagSYMBOL_INFO info = CallStacks[nAddress];
  160. CSimpleStringA strLine;
  161. strLine.Format("%8.8X: %s%s\r\n",info.dwAddress,info.szModule,info.szSymbol);
  162. strStack+=strLine;
  163. }
  164. strStack+="===end===";
  165. return strStack;
  166. }
  167. CSimpleStringA GetCallerFunctionName(DWORD nSkipLevel)
  168. {
  169. vector<tagSYMBOL_INFO> CallStacks;
  170. if(!DumpStackVector(CallStacks))
  171. return "";
  172. tagSYMBOL_INFO info=CallStacks[nSkipLevel];
  173. CSimpleStringA strStack;
  174. strStack.Format("Address:%8.8X,Modual:\"%s\",Function:\"%s\"",info.dwAddress,info.szModule,info.szSymbol);
  175. return strStack;
  176. }
  177. typedef enum _THREADINFOCLASS {
  178. ThreadBasicInformation,
  179. ThreadTimes,
  180. ThreadPriority,
  181. ThreadBasePriority,
  182. ThreadAffinityMask,
  183. ThreadImpersonationToken,
  184. ThreadDescriptorTableEntry,
  185. ThreadEnableAlignmentFaultFixup,
  186. ThreadEventPair_Reusable,
  187. ThreadQuerySetWin32StartAddress,
  188. ThreadZeroTlsCell,
  189. ThreadPerformanceCount,
  190. ThreadAmILastThread,
  191. ThreadIdealProcessor,
  192. ThreadPriorityBoost,
  193. ThreadSetTlsArrayAddress,
  194. ThreadIsIoPending,
  195. ThreadHideFromDebugger,
  196. ThreadBreakOnTermination,
  197. MaxThreadInfoClass
  198. } THREADINFOCLASS;
  199. typedef struct _CLIENT_ID {
  200. HANDLE UniqueProcess;
  201. HANDLE UniqueThread;
  202. } CLIENT_ID;
  203. typedef CLIENT_ID *PCLIENT_ID;
  204. typedef struct _THREAD_BASIC_INFORMATION { // Information Class 0
  205. LONG ExitStatus;
  206. PVOID TebBaseAddress;
  207. CLIENT_ID ClientId;
  208. LONG AffinityMask;
  209. LONG Priority;
  210. LONG BasePriority;
  211. } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
  212. extern "C" LONG (__stdcall *ZwQueryInformationThread) (
  213. IN HANDLE ThreadHandle,
  214. IN THREADINFOCLASS ThreadInformationClass,
  215. OUT PVOID ThreadInformation,
  216. IN ULONG ThreadInformationLength,
  217. OUT PULONG ReturnLength OPTIONAL
  218. ) = NULL;
  219. extern "C" LONG (__stdcall *RtlNtStatusToDosError) (
  220. IN ULONG status) = NULL;
  221. BOOL ShowThreadInfo (DWORD tid)
  222. {
  223. static BOOL isInit = FALSE;
  224. static std::map<DWORD, string> threadInModule;
  225. if (!isInit)
  226. {
  227. setlocale (LC_ALL, ".ACP");
  228. HINSTANCE hNTDLL = ::GetModuleHandle (TEXT ("ntdll"));
  229. (FARPROC&)ZwQueryInformationThread =
  230. ::GetProcAddress (hNTDLL, "ZwQueryInformationThread");
  231. (FARPROC&)RtlNtStatusToDosError =
  232. ::GetProcAddress (hNTDLL, "RtlNtStatusToDosError");
  233. threadInModule.clear();
  234. isInit = TRUE;
  235. }
  236. std::map<DWORD, string>::iterator it = threadInModule.find(tid);
  237. if (threadInModule.end() != it)
  238. return TRUE;
  239. THREAD_BASIC_INFORMATION tbi;
  240. PVOID startaddr;
  241. LONG status;
  242. HANDLE thread, process;
  243. thread = ::OpenThread (THREAD_ALL_ACCESS, FALSE, tid);
  244. if (thread == NULL)
  245. return FALSE;
  246. //thread ÆðʼµØÖ·
  247. status = ZwQueryInformationThread (thread, ThreadQuerySetWin32StartAddress, &startaddr, sizeof (startaddr), NULL);
  248. if (status < 0)
  249. {
  250. CloseHandle (thread);
  251. SetLastError (RtlNtStatusToDosError (status));
  252. return FALSE;
  253. };
  254. status = ZwQueryInformationThread (thread, ThreadBasicInformation, &tbi, sizeof (tbi), NULL);
  255. if (status < 0)
  256. {
  257. CloseHandle (thread);
  258. SetLastError (RtlNtStatusToDosError (status));
  259. return FALSE;
  260. };
  261. process = ::OpenProcess (PROCESS_ALL_ACCESS, FALSE, (DWORD)tbi.ClientId.UniqueProcess);
  262. if (process == NULL)
  263. {
  264. DWORD error = ::GetLastError ();
  265. CloseHandle (thread);
  266. SetLastError (error);
  267. return FALSE;
  268. };
  269. TCHAR modname [0x100];
  270. ::GetModuleFileNameEx (process, NULL, modname, 0x100);
  271. GetMappedFileName(process, startaddr, modname, 0x100);
  272. vector<tagSYMBOL_INFO> callStack;
  273. DumpStackVector(callStack);
  274. //MessageBox(NULL, NULL, NULL, 0);
  275. threadInModule[tid] = std::string(modname);
  276. CloseHandle (process);
  277. CloseHandle (thread);
  278. return TRUE;
  279. };
  280. class stackTrace
  281. {
  282. public:
  283. static void InitTrack();
  284. static CSimpleStringA StackTrack();
  285. static void UninitTrack();
  286. static HANDLE g_hHandle;
  287. static CONTEXT g_context;
  288. };
  289. HANDLE stackTrace::g_hHandle = NULL;
  290. CONTEXT stackTrace::g_context = { CONTEXT_FULL };
  291. CSimpleStringA TraceStack()
  292. {
  293. static CRITICAL_SECTION cs_;
  294. static bool isInit = false;
  295. if (!isInit)
  296. InitializeCriticalSection(&cs_);
  297. EnterCriticalSection(&cs_);
  298. HANDLE hThread = GetCurrentThread();
  299. GetThreadContext(hThread, &stackTrace::g_context);
  300. __asm{call $ + 5}
  301. __asm{pop eax}
  302. __asm{mov stackTrace::g_context.Eip, eax}
  303. __asm{mov stackTrace::g_context.Ebp, ebp}
  304. __asm{mov stackTrace::g_context.Esp, esp}
  305. stackTrace::InitTrack();
  306. CSimpleStringA resultModule = stackTrace::StackTrack();
  307. stackTrace::UninitTrack();
  308. LeaveCriticalSection(&cs_);
  309. return resultModule;
  310. }
  311. void stackTrace::InitTrack()
  312. {
  313. g_hHandle = GetCurrentProcess();
  314. SymInitialize(g_hHandle, NULL, TRUE);
  315. }
  316. CSimpleStringA stackTrace::StackTrack()
  317. {
  318. HANDLE m_hThread = GetCurrentThread();
  319. STACKFRAME sf = { 0 };
  320. sf.AddrPC.Offset = g_context.Eip;
  321. sf.AddrPC.Mode = AddrModeFlat;
  322. sf.AddrFrame.Offset = g_context.Ebp;
  323. sf.AddrFrame.Mode = AddrModeFlat;
  324. sf.AddrStack.Offset = g_context.Esp;
  325. sf.AddrStack.Mode = AddrModeFlat;
  326. typedef struct tag_SYMBOL_INFO
  327. {
  328. IMAGEHLP_SYMBOL symInfo;
  329. TCHAR szBuffer[MAX_PATH];
  330. } SYMBOL_INFO, *LPSYMBOL_INFO;
  331. DWORD dwDisplament = 0;
  332. SYMBOL_INFO stack_info = { 0 };
  333. PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)&stack_info;
  334. pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  335. pSym->MaxNameLength = sizeof(SYMBOL_INFO) - offsetof(SYMBOL_INFO, symInfo.Name);
  336. IMAGEHLP_LINE ImageLine = { 0 };
  337. ImageLine.SizeOfStruct = sizeof(IMAGEHLP_LINE);
  338. while (StackWalk(IMAGE_FILE_MACHINE_I386, g_hHandle, m_hThread, &sf, &g_context, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
  339. {
  340. IMAGEHLP_MODULE mi;
  341. memset(&mi,0,sizeof(mi));
  342. mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  343. SymGetModuleInfo(g_hHandle, sf.AddrPC.Offset, &mi);
  344. string moduleName = mi.ModuleName;
  345. if (-1 != moduleName.find("mod_"))
  346. return CSimpleStringA(mi.ModuleName);
  347. }
  348. return CSimpleStringA("");
  349. }
  350. void stackTrace::UninitTrack()
  351. {
  352. HANDLE hProcess = GetCurrentProcess();
  353. SymCleanup(g_hHandle);
  354. g_hHandle = NULL;
  355. }