SpBaseRoutine.cpp 11 KB

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